kernel: import 9front's PCI improvements

This commit is contained in:
Giacomo Tesio 2017-01-22 03:34:17 +01:00
parent c2b06ebf80
commit edd84db070
11 changed files with 900 additions and 447 deletions

123
sys/src/kern/386/bios32.c Normal file
View File

@ -0,0 +1,123 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#define VFLAG(...) if(vflag) print(__VA_ARGS__)
#define UPTR2INT(p) ((uintptr_t)(p))
#define l16get(p) (((p)[1]<<8)|(p)[0])
#define l32get(p) (((uint32_t)l16get(p+2)<<16)|l16get(p))
static int vflag = 0;
typedef struct BIOS32sdh { /* BIOS32 Service Directory Header */
uint8_t signature[4]; /* "_32_" */
uint8_t physaddr[4]; /* physical address of entry point */
uint8_t revision;
uint8_t length; /* of header in paragraphs */
uint8_t checksum; /* */
uint8_t reserved[5];
} BIOS32sdh;
typedef struct BIOS32si { /* BIOS32 Service Interface */
uint8_t* base; /* base address of service */
int length; /* length of service */
uint32_t offset; /* service entry-point from base */
uint16_t ptr[3]; /* far pointer m16:32 */
} BIOS32si;
static Lock bios32lock;
static uint16_t bios32ptr[3];
static void* bios32entry;
int
bios32ci(BIOS32si* si, BIOS32ci* ci)
{
int r;
lock(&bios32lock);
r = bios32call(ci, si->ptr);
unlock(&bios32lock);
return r;
}
static int
bios32locate(void)
{
uintptr_t ptr;
BIOS32sdh *sdh;
VFLAG("bios32link\n");
if((sdh = sigsearch("_32_")) == nil)
return -1;
if(checksum(sdh, sizeof(BIOS32sdh)))
return -1;
VFLAG("sdh @ %#p, entry %#ux\n", sdh, l32get(sdh->physaddr));
bios32entry = vmap(l32get(sdh->physaddr), 4096+1);
VFLAG("entry @ %#p\n", bios32entry);
ptr = UPTR2INT(bios32entry);
bios32ptr[0] = ptr & 0xffff;
bios32ptr[1] = (ptr>>16) & 0xffff;
bios32ptr[2] = KESEL;
VFLAG("bios32link: ptr %ux %ux %ux\n",
bios32ptr[0], bios32ptr[1], bios32ptr[2]);
return 0;
}
void
BIOS32close(BIOS32si* si)
{
vunmap(si->base, si->length);
free(si);
}
BIOS32si*
bios32open(char* id)
{
uint32_t ptr;
BIOS32ci ci;
BIOS32si *si;
lock(&bios32lock);
if(bios32ptr[2] == 0 && bios32locate() < 0){
unlock(&bios32lock);
return nil;
}
VFLAG("bios32si: %s\n", id);
memset(&ci, 0, sizeof(BIOS32ci));
ci.eax = (id[3]<<24|(id[2]<<16)|(id[1]<<8)|id[0]);
bios32call(&ci, bios32ptr);
unlock(&bios32lock);
VFLAG("bios32si: eax %ux\n", ci.eax);
if(ci.eax & 0xff)
return nil;
VFLAG("bios32si: base %#ux length %#ux offset %#ux\n",
ci.ebx, ci.ecx, ci.edx);
if((si = malloc(sizeof(BIOS32si))) == nil)
return nil;
if((si->base = vmap(ci.ebx, ci.ecx)) == nil){
free(si);
return nil;
}
si->length = ci.ecx;
ptr = UPTR2INT(si->base)+ci.edx;
si->ptr[0] = ptr & 0xffff;
si->ptr[1] = (ptr>>16) & 0xffff;
si->ptr[2] = KESEL;
VFLAG("bios32si: eax entry %ux\n", ptr);
return si;
}

View File

@ -1,6 +1,7 @@
{
"386": {
"SourceFiles": [
"../386/bios32.c",
"../386/devether.c",
"../386/devrtc.c",
"../386/ether8139.c",

File diff suppressed because it is too large Load Diff

View File

@ -37,7 +37,8 @@ static Tbl *tblmap[64];
Fadt fadt;
Acpicfg acpicfg;
static int
int
checksum(void *v, int n)
{
uint8_t *p, s;
@ -49,6 +50,70 @@ checksum(void *v, int n)
return s;
}
static void*
sigscan(uint8_t* addr, int len, char* signature)
{
int sl;
uint8_t *e, *p;
e = addr+len;
sl = strlen(signature);
for(p = addr; p+sl < e; p += 16)
if(memcmp(p, signature, sl) == 0)
return p;
return nil;
}
static uintptr_t
convmemsize(void)
{
uintptr_t top;
uint8_t *bda;
bda = KADDR(0x400);
top = ((bda[0x14]<<8) | bda[0x13])*KiB;
if(top < 64*KiB || top > 640*KiB)
top = 640*KiB; /* sanity */
/* reserved for bios tables (EBDA) */
top -= 1*KiB;
return top;
}
void*
sigsearch(char* signature)
{
uintptr_t p;
uint8_t *bda;
void *r;
/*
* Search for the data structure:
* 1) within the first KiB of the Extended BIOS Data Area (EBDA), or
* 2) within the last KiB of system base memory if the EBDA segment
* is undefined, or
* 3) within the BIOS ROM address space between 0xf0000 and 0xfffff
* (but will actually check 0xe0000 to 0xfffff).
*/
bda = KADDR(0x400);
if(memcmp(KADDR(0xfffd9), "EISA", 4) == 0){
if((p = (bda[0x0f]<<8)|bda[0x0e]) != 0){
if((r = sigscan(KADDR(p<<4), 1024, signature)) != nil)
return r;
}
}
if((r = sigscan(KADDR(convmemsize()), 1024, signature)) != nil)
return r;
/* hack for virtualbox: look in KiB below 0xa0000 */
if((r = sigscan(KADDR(0xa0000-1024), 1024, signature)) != nil)
return r;
return sigscan(KADDR(0xe0000), 0x20000, signature);
}
static uint32_t
get16(uint8_t *p)
{

View File

@ -15,6 +15,8 @@
* You should have received a copy of the GNU General Public License
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
*/
typedef struct BIOS32si BIOS32si;
typedef struct BIOS32ci BIOS32ci;
typedef struct Fxsave Fxsave;
typedef struct IOConf IOConf;
typedef struct ISAConf ISAConf;
@ -40,6 +42,7 @@ typedef uint64_t uintmem; /* horrible name */
typedef struct Ureg Ureg;
typedef struct Vctl Vctl;
#pragma incomplete BIOS32si
#pragma incomplete Ureg
#define MAXSYSARG 5 /* for mount(fd, afd, mpt, flag, arg) */
@ -340,6 +343,15 @@ struct ISAConf {
char* opt[NISAOPT];
};
typedef struct BIOS32ci { /* BIOS32 Calling Interface */
uint32_t eax;
uint32_t ebx;
uint32_t ecx;
uint32_t edx;
uint32_t esi;
uint32_t edi;
} BIOS32ci;
/*
* The Mach structures must be available via the per-processor
* MMU information array machptr, mainly for disambiguation and access to

View File

@ -20,6 +20,13 @@
#define SUPPORT_MWAIT (m->cpuinfo[1][2] & (1<<3))
void onIdleSpin(void);
int bios32call(BIOS32ci*, uint16_t[3]);
int bios32ci(BIOS32si*, BIOS32ci*);
void bios32close(BIOS32si*);
BIOS32si* bios32open(char*);
void* sigsearch(char*);
int checksum(void *v, int n);
void mouseenable(void);
int mousecmd(int);
@ -130,7 +137,7 @@ uint32_t pcibarsize(Pcidev*, int);
int pcicap(Pcidev*, int);
int pcicfgr8(Pcidev*, int);
int pcicfgr16(Pcidev*, int);
uint32_t pcicfgr32(Pcidev*, int);
int pcicfgr32(Pcidev*, int);
void pcicfgw8(Pcidev*, int, int);
void pcicfgw16(Pcidev*, int, int);
void pcicfgw32(Pcidev*, int, int);

View File

@ -271,35 +271,36 @@ struct Pcisiz
typedef struct Pcidev Pcidev;
struct Pcidev
{
int tbdf; /* type+bus+device+function */
uint16_t vid; /* vendor ID */
uint16_t did; /* device ID */
int tbdf; /* type+bus+device+function */
uint16_t vid; /* vendor ID */
uint16_t did; /* device ID */
uint16_t svid; /* subsystem vid */
uint16_t sdid; /* subsystem did */
uint16_t pcr;
uint8_t rid;
uint8_t ccrp;
uint8_t ccru;
uint8_t ccrb;
uint8_t cls;
uint8_t ltr;
uint8_t rid;
uint8_t ccrp;
uint8_t ccru;
uint8_t ccrb;
uint8_t cls;
uint8_t ltr;
struct {
uint32_t bar; /* base address */
int size;
uint32_t bar; /* base address */
int size;
} mem[6];
struct {
uint32_t bar;
int size;
int size;
} rom;
uint8_t intl; /* interrupt line */
Pcidev* list;
Pcidev* link; /* next device on this bno */
Pcidev* parent; /* up a bus */
Pcidev* bridge; /* down a bus */
struct {
uint32_t bar;
@ -307,7 +308,7 @@ struct Pcidev
} ioa, mema;
int pmrb; /* power management register block */
void* xcfg; /* PCIe configuration block */
void* xcfg; /* PCIe configuration block */
};
#define PCIWINDOW 0

View File

@ -261,6 +261,15 @@ wbinvd:
WBINVD
ret
/*
* BIOS32.
*/
.global bios32call
bios32call:
xorl %eax, %eax
incl %eax
ret
/*
* Serialisation.
*/

View File

@ -135,3 +135,37 @@
#define KVATOP (KSEG0&KSEG1&KSEG2)
#define iskaddr(a) (((uintptr_t)(a)&KVATOP) == KVATOP)
/*
* known x86 segments (in GDT) and their selectors
*/
#define NULLSEG 0 /* null segment */
#define KDSEG 1 /* kernel data/stack */
#define KESEG 2 /* kernel executable */
#define UDSEG 3 /* user data/stack */
#define UESEG 4 /* user executable */
#define TSSSEG 5 /* task segment */
#define APMCSEG 6 /* APM code segment */
#define APMCSEG16 7 /* APM 16-bit code segment */
#define APMDSEG 8 /* APM data segment */
#define KESEG16 9 /* kernel executable 16-bit */
#define LDTSEG 10 /* local descriptor table */
#define PROCSEG0 11 /* per process descriptor0 */
#define NPROCSEG 3 /* number of per process descriptors */
#define NGDT 14 /* number of GDT entries required */
#define SELGDT (0<<2) /* selector is in gdt */
#define SELLDT (1<<2) /* selector is in ldt */
#define SELECTOR(i, t, p) (((i)<<3) | (t) | (p))
#define NULLSEL SELECTOR(NULLSEG, SELGDT, 0)
#define KDSEL SELECTOR(KDSEG, SELGDT, 0)
#define KESEL SELECTOR(KESEG, SELGDT, 0)
#define UESEL SELECTOR(UESEG, SELGDT, 3)
#define UDSEL SELECTOR(UDSEG, SELGDT, 3)
#define TSSSEL SELECTOR(TSSSEG, SELGDT, 0)
#define APMCSEL SELECTOR(APMCSEG, SELGDT, 0)
#define APMCSEL16 SELECTOR(APMCSEG16, SELGDT, 0)
#define APMDSEL SELECTOR(APMDSEG, SELGDT, 0)
#define LDTSEL SELECTOR(LDTSEG, SELGDT, 0)

View File

@ -23,6 +23,7 @@ RMap rmapram = {"physical memory"};
static RMap rmapunavail = {"unavailable physical addresses"};
/*
* called before first call to asmmapinit/asmmodinit or e820,
* to mark the kernel text and data out of bounds.
@ -263,3 +264,4 @@ asmmodinit(uint32_t start, uint32_t end, char* _1)
sys->pmstart = end;
}
}

View File

@ -358,70 +358,6 @@ mpparse(PCMP* pcmp)
}
}
static int
sigchecksum(void* address, int length)
{
uint8_t *p, sum;
sum = 0;
for(p = address; length-- > 0; p++)
sum += *p;
return sum;
}
static void*
sigscan(uint8_t* address, int length, char* signature)
{
uint8_t *e, *p;
int siglength;
DBG("check for %s in system base memory @ %#p\n", signature, address);
e = address+length;
siglength = strlen(signature);
for(p = address; p+siglength < e; p += 16){
if(memcmp(p, signature, siglength))
continue;
return p;
}
return nil;
}
static uintmem mptab[] = {0, 1024, 0x9fc00, 1024, 0xf0000, 0x10000};
static void*
sigsearch(char* signature)
{
uintmem p;
int i;
uint8_t *bda;
void *r;
/*
* Search for the data structure:
* 1) within the first KiB of the Extended BIOS Data Area (EBDA), or
* 2) within the last KiB of system base memory if the EBDA segment
* is undefined, or
* 3) within the BIOS ROM address space between 0xf0000 and 0xfffff
*/
for(i = 0; i < nelem(mptab); i += 2)
if(r = sigscan(KADDR(mptab[i]), mptab[i+1], signature))
return r;
bda = KADDR(0x400);
if((p = (bda[0x0F]<<8|bda[0x0E])<<4) != 0){
if((r = sigscan(KADDR(p), 1024, signature)) != nil)
return r;
}
if((p = ((bda[0x14]<<8)|bda[0x13])*1024) != 0){
if((r = sigscan(KADDR(p-1024), 1024, signature)) != nil)
return r;
}
return nil;
}
void
mpsinit(void)
{
@ -441,7 +377,7 @@ mpsinit(void)
}
if(mp->revision != 1 && mp->revision != 4)
return;
if(sigchecksum(mp, mp->length*16) != 0)
if(checksum(mp, mp->length*16) != 0)
return;
if((pcmp = vmap(l32get(mp->addr), sizeof(PCMP))) == nil)
@ -454,7 +390,7 @@ mpsinit(void)
vunmap(pcmp, sizeof(PCMP));
if((pcmp = vmap(l32get(mp->addr), n)) == nil)
return;
if(sigchecksum(pcmp, l16get(pcmp->length)) != 0){
if(checksum(pcmp, l16get(pcmp->length)) != 0){
vunmap(pcmp, n);
return;
}
@ -472,7 +408,7 @@ mpsinit(void)
}
if(pcmp->xchecksum != 0){
p = ((uint8_t*)pcmp) + l16get(pcmp->length);
i = sigchecksum(p, l16get(pcmp->xlength));
i = checksum(p, l16get(pcmp->xlength));
if(((i+pcmp->xchecksum) & 0xff) != 0){
print("extended table checksums to %#ux\n", i);
vunmap(pcmp, n);