kernel: import 9front's PCI improvements
This commit is contained in:
parent
c2b06ebf80
commit
edd84db070
123
sys/src/kern/386/bios32.c
Normal file
123
sys/src/kern/386/bios32.c
Normal 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;
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"386": {
|
"386": {
|
||||||
"SourceFiles": [
|
"SourceFiles": [
|
||||||
|
"../386/bios32.c",
|
||||||
"../386/devether.c",
|
"../386/devether.c",
|
||||||
"../386/devrtc.c",
|
"../386/devrtc.c",
|
||||||
"../386/ether8139.c",
|
"../386/ether8139.c",
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -37,7 +37,8 @@ static Tbl *tblmap[64];
|
|||||||
Fadt fadt;
|
Fadt fadt;
|
||||||
Acpicfg acpicfg;
|
Acpicfg acpicfg;
|
||||||
|
|
||||||
static int
|
|
||||||
|
int
|
||||||
checksum(void *v, int n)
|
checksum(void *v, int n)
|
||||||
{
|
{
|
||||||
uint8_t *p, s;
|
uint8_t *p, s;
|
||||||
@ -49,6 +50,70 @@ checksum(void *v, int n)
|
|||||||
return s;
|
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
|
static uint32_t
|
||||||
get16(uint8_t *p)
|
get16(uint8_t *p)
|
||||||
{
|
{
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
|
* 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 Fxsave Fxsave;
|
||||||
typedef struct IOConf IOConf;
|
typedef struct IOConf IOConf;
|
||||||
typedef struct ISAConf ISAConf;
|
typedef struct ISAConf ISAConf;
|
||||||
@ -40,6 +42,7 @@ typedef uint64_t uintmem; /* horrible name */
|
|||||||
typedef struct Ureg Ureg;
|
typedef struct Ureg Ureg;
|
||||||
typedef struct Vctl Vctl;
|
typedef struct Vctl Vctl;
|
||||||
|
|
||||||
|
#pragma incomplete BIOS32si
|
||||||
#pragma incomplete Ureg
|
#pragma incomplete Ureg
|
||||||
|
|
||||||
#define MAXSYSARG 5 /* for mount(fd, afd, mpt, flag, arg) */
|
#define MAXSYSARG 5 /* for mount(fd, afd, mpt, flag, arg) */
|
||||||
@ -340,6 +343,15 @@ struct ISAConf {
|
|||||||
char* opt[NISAOPT];
|
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
|
* The Mach structures must be available via the per-processor
|
||||||
* MMU information array machptr, mainly for disambiguation and access to
|
* MMU information array machptr, mainly for disambiguation and access to
|
||||||
|
@ -20,6 +20,13 @@
|
|||||||
#define SUPPORT_MWAIT (m->cpuinfo[1][2] & (1<<3))
|
#define SUPPORT_MWAIT (m->cpuinfo[1][2] & (1<<3))
|
||||||
void onIdleSpin(void);
|
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);
|
void mouseenable(void);
|
||||||
int mousecmd(int);
|
int mousecmd(int);
|
||||||
|
|
||||||
@ -130,7 +137,7 @@ uint32_t pcibarsize(Pcidev*, int);
|
|||||||
int pcicap(Pcidev*, int);
|
int pcicap(Pcidev*, int);
|
||||||
int pcicfgr8(Pcidev*, int);
|
int pcicfgr8(Pcidev*, int);
|
||||||
int pcicfgr16(Pcidev*, int);
|
int pcicfgr16(Pcidev*, int);
|
||||||
uint32_t pcicfgr32(Pcidev*, int);
|
int pcicfgr32(Pcidev*, int);
|
||||||
void pcicfgw8(Pcidev*, int, int);
|
void pcicfgw8(Pcidev*, int, int);
|
||||||
void pcicfgw16(Pcidev*, int, int);
|
void pcicfgw16(Pcidev*, int, int);
|
||||||
void pcicfgw32(Pcidev*, int, int);
|
void pcicfgw32(Pcidev*, int, int);
|
||||||
|
@ -300,6 +300,7 @@ struct Pcidev
|
|||||||
Pcidev* list;
|
Pcidev* list;
|
||||||
Pcidev* link; /* next device on this bno */
|
Pcidev* link; /* next device on this bno */
|
||||||
|
|
||||||
|
Pcidev* parent; /* up a bus */
|
||||||
Pcidev* bridge; /* down a bus */
|
Pcidev* bridge; /* down a bus */
|
||||||
struct {
|
struct {
|
||||||
uint32_t bar;
|
uint32_t bar;
|
||||||
|
@ -261,6 +261,15 @@ wbinvd:
|
|||||||
WBINVD
|
WBINVD
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
/*
|
||||||
|
* BIOS32.
|
||||||
|
*/
|
||||||
|
.global bios32call
|
||||||
|
bios32call:
|
||||||
|
xorl %eax, %eax
|
||||||
|
incl %eax
|
||||||
|
ret
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Serialisation.
|
* Serialisation.
|
||||||
*/
|
*/
|
||||||
|
@ -135,3 +135,37 @@
|
|||||||
|
|
||||||
#define KVATOP (KSEG0&KSEG1&KSEG2)
|
#define KVATOP (KSEG0&KSEG1&KSEG2)
|
||||||
#define iskaddr(a) (((uintptr_t)(a)&KVATOP) == KVATOP)
|
#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)
|
||||||
|
@ -23,6 +23,7 @@ RMap rmapram = {"physical memory"};
|
|||||||
|
|
||||||
static RMap rmapunavail = {"unavailable physical addresses"};
|
static RMap rmapunavail = {"unavailable physical addresses"};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* called before first call to asmmapinit/asmmodinit or e820,
|
* called before first call to asmmapinit/asmmodinit or e820,
|
||||||
* to mark the kernel text and data out of bounds.
|
* 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;
|
sys->pmstart = end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
void
|
||||||
mpsinit(void)
|
mpsinit(void)
|
||||||
{
|
{
|
||||||
@ -441,7 +377,7 @@ mpsinit(void)
|
|||||||
}
|
}
|
||||||
if(mp->revision != 1 && mp->revision != 4)
|
if(mp->revision != 1 && mp->revision != 4)
|
||||||
return;
|
return;
|
||||||
if(sigchecksum(mp, mp->length*16) != 0)
|
if(checksum(mp, mp->length*16) != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if((pcmp = vmap(l32get(mp->addr), sizeof(PCMP))) == nil)
|
if((pcmp = vmap(l32get(mp->addr), sizeof(PCMP))) == nil)
|
||||||
@ -454,7 +390,7 @@ mpsinit(void)
|
|||||||
vunmap(pcmp, sizeof(PCMP));
|
vunmap(pcmp, sizeof(PCMP));
|
||||||
if((pcmp = vmap(l32get(mp->addr), n)) == nil)
|
if((pcmp = vmap(l32get(mp->addr), n)) == nil)
|
||||||
return;
|
return;
|
||||||
if(sigchecksum(pcmp, l16get(pcmp->length)) != 0){
|
if(checksum(pcmp, l16get(pcmp->length)) != 0){
|
||||||
vunmap(pcmp, n);
|
vunmap(pcmp, n);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -472,7 +408,7 @@ mpsinit(void)
|
|||||||
}
|
}
|
||||||
if(pcmp->xchecksum != 0){
|
if(pcmp->xchecksum != 0){
|
||||||
p = ((uint8_t*)pcmp) + l16get(pcmp->length);
|
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){
|
if(((i+pcmp->xchecksum) & 0xff) != 0){
|
||||||
print("extended table checksums to %#ux\n", i);
|
print("extended table checksums to %#ux\n", i);
|
||||||
vunmap(pcmp, n);
|
vunmap(pcmp, n);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user