14fafed5dSDavid du Colombier #include "u.h"
24fafed5dSDavid du Colombier #include "../port/lib.h"
34fafed5dSDavid du Colombier #include "mem.h"
44fafed5dSDavid du Colombier #include "dat.h"
54fafed5dSDavid du Colombier #include "fns.h"
64fafed5dSDavid du Colombier #include "io.h"
74fafed5dSDavid du Colombier
84fafed5dSDavid du Colombier #define VFLAG(...) if(vflag) print(__VA_ARGS__)
94fafed5dSDavid du Colombier
104fafed5dSDavid du Colombier #define UPTR2INT(p) ((uintptr)(p))
114fafed5dSDavid du Colombier
124fafed5dSDavid du Colombier static int vflag = 0;
134fafed5dSDavid du Colombier
144fafed5dSDavid du Colombier typedef struct BIOS32sdh { /* BIOS32 Service Directory Header */
154fafed5dSDavid du Colombier u8int signature[4]; /* "_32_" */
164fafed5dSDavid du Colombier u8int physaddr[4]; /* physical address of entry point */
174fafed5dSDavid du Colombier u8int revision;
184fafed5dSDavid du Colombier u8int length; /* of header in paragraphs */
194fafed5dSDavid du Colombier u8int checksum; /* */
204fafed5dSDavid du Colombier u8int reserved[5];
214fafed5dSDavid du Colombier } BIOS32sdh;
224fafed5dSDavid du Colombier
234fafed5dSDavid du Colombier typedef struct BIOS32si { /* BIOS32 Service Interface */
244fafed5dSDavid du Colombier u8int* base; /* base address of service */
254fafed5dSDavid du Colombier int length; /* length of service */
264fafed5dSDavid du Colombier u32int offset; /* service entry-point from base */
274fafed5dSDavid du Colombier
284fafed5dSDavid du Colombier u16int ptr[3]; /* far pointer m16:32 */
294fafed5dSDavid du Colombier } BIOS32si;
304fafed5dSDavid du Colombier
314fafed5dSDavid du Colombier static Lock bios32lock;
324fafed5dSDavid du Colombier static u16int bios32ptr[3];
334fafed5dSDavid du Colombier static void* bios32entry;
344fafed5dSDavid du Colombier
354fafed5dSDavid du Colombier int
bios32ci(BIOS32si * si,BIOS32ci * ci)364fafed5dSDavid du Colombier bios32ci(BIOS32si* si, BIOS32ci* ci)
374fafed5dSDavid du Colombier {
384fafed5dSDavid du Colombier int r;
394fafed5dSDavid du Colombier
404fafed5dSDavid du Colombier lock(&bios32lock);
414fafed5dSDavid du Colombier r = bios32call(ci, si->ptr);
424fafed5dSDavid du Colombier unlock(&bios32lock);
434fafed5dSDavid du Colombier
444fafed5dSDavid du Colombier return r;
454fafed5dSDavid du Colombier }
464fafed5dSDavid du Colombier
474fafed5dSDavid du Colombier static void*
rsdchecksum(void * addr,int length)484fafed5dSDavid du Colombier rsdchecksum(void* addr, int length)
494fafed5dSDavid du Colombier {
504fafed5dSDavid du Colombier u8int *p, sum;
514fafed5dSDavid du Colombier
524fafed5dSDavid du Colombier sum = 0;
534fafed5dSDavid du Colombier for(p = addr; length-- > 0; p++)
544fafed5dSDavid du Colombier sum += *p;
554fafed5dSDavid du Colombier if(sum == 0)
564fafed5dSDavid du Colombier return addr;
574fafed5dSDavid du Colombier
584fafed5dSDavid du Colombier return nil;
594fafed5dSDavid du Colombier }
604fafed5dSDavid du Colombier
614fafed5dSDavid du Colombier static void*
rsdscan(u8int * addr,int len,char * signature)624fafed5dSDavid du Colombier rsdscan(u8int* addr, int len, char* signature)
634fafed5dSDavid du Colombier {
644fafed5dSDavid du Colombier int sl;
654fafed5dSDavid du Colombier u8int *e, *p;
664fafed5dSDavid du Colombier
674fafed5dSDavid du Colombier e = addr+len;
684fafed5dSDavid du Colombier sl = strlen(signature);
694fafed5dSDavid du Colombier for(p = addr; p+sl < e; p += 16){
704fafed5dSDavid du Colombier if(memcmp(p, signature, sl))
714fafed5dSDavid du Colombier continue;
724fafed5dSDavid du Colombier return p;
734fafed5dSDavid du Colombier }
744fafed5dSDavid du Colombier
754fafed5dSDavid du Colombier return nil;
764fafed5dSDavid du Colombier }
774fafed5dSDavid du Colombier
784fafed5dSDavid du Colombier static int
bios32locate(void)794fafed5dSDavid du Colombier bios32locate(void)
804fafed5dSDavid du Colombier {
814fafed5dSDavid du Colombier uintptr ptr;
824fafed5dSDavid du Colombier BIOS32sdh *sdh;
834fafed5dSDavid du Colombier
844fafed5dSDavid du Colombier VFLAG("bios32link\n");
854fafed5dSDavid du Colombier if((sdh = rsdscan(BIOSSEG(0xE000), 0x20000, "_32_")) == nil)
864fafed5dSDavid du Colombier return -1;
874fafed5dSDavid du Colombier if(rsdchecksum(sdh, sizeof(BIOS32sdh)) == nil)
884fafed5dSDavid du Colombier return -1;
89*e360d427SDavid du Colombier VFLAG("sdh @ %#p, entry %#ux\n", sdh, L32GET(sdh->physaddr));
904fafed5dSDavid du Colombier
91*e360d427SDavid du Colombier bios32entry = vmap(L32GET(sdh->physaddr), 4096+1);
924fafed5dSDavid du Colombier VFLAG("entry @ %#p\n", bios32entry);
934fafed5dSDavid du Colombier ptr = UPTR2INT(bios32entry);
944fafed5dSDavid du Colombier bios32ptr[0] = ptr & 0xffff;
954fafed5dSDavid du Colombier bios32ptr[1] = (ptr>>16) & 0xffff;
964fafed5dSDavid du Colombier bios32ptr[2] = KESEL;
974fafed5dSDavid du Colombier VFLAG("bios32link: ptr %ux %ux %ux\n",
984fafed5dSDavid du Colombier bios32ptr[0], bios32ptr[1], bios32ptr[2]);
994fafed5dSDavid du Colombier
1004fafed5dSDavid du Colombier return 0;
1014fafed5dSDavid du Colombier }
1024fafed5dSDavid du Colombier
1034fafed5dSDavid du Colombier void
BIOS32close(BIOS32si * si)1044fafed5dSDavid du Colombier BIOS32close(BIOS32si* si)
1054fafed5dSDavid du Colombier {
1064fafed5dSDavid du Colombier vunmap(si->base, si->length);
1074fafed5dSDavid du Colombier free(si);
1084fafed5dSDavid du Colombier }
1094fafed5dSDavid du Colombier
1104fafed5dSDavid du Colombier BIOS32si*
bios32open(char * id)1114fafed5dSDavid du Colombier bios32open(char* id)
1124fafed5dSDavid du Colombier {
1134fafed5dSDavid du Colombier uint ptr;
1144fafed5dSDavid du Colombier BIOS32ci ci;
1154fafed5dSDavid du Colombier BIOS32si *si;
1164fafed5dSDavid du Colombier
1174fafed5dSDavid du Colombier lock(&bios32lock);
1184fafed5dSDavid du Colombier if(bios32ptr[2] == 0 && bios32locate() < 0){
1194fafed5dSDavid du Colombier unlock(&bios32lock);
1204fafed5dSDavid du Colombier return nil;
1214fafed5dSDavid du Colombier }
1224fafed5dSDavid du Colombier
1234fafed5dSDavid du Colombier VFLAG("bios32si: %s\n", id);
1244fafed5dSDavid du Colombier memset(&ci, 0, sizeof(BIOS32ci));
1254fafed5dSDavid du Colombier ci.eax = (id[3]<<24|(id[2]<<16)|(id[1]<<8)|id[0]);
1264fafed5dSDavid du Colombier
1274fafed5dSDavid du Colombier bios32call(&ci, bios32ptr);
1284fafed5dSDavid du Colombier unlock(&bios32lock);
1294fafed5dSDavid du Colombier
1304fafed5dSDavid du Colombier VFLAG("bios32si: eax %ux\n", ci.eax);
1314fafed5dSDavid du Colombier if(ci.eax & 0xff)
1324fafed5dSDavid du Colombier return nil;
1334fafed5dSDavid du Colombier VFLAG("bios32si: base %#ux length %#ux offset %#ux\n",
1344fafed5dSDavid du Colombier ci.ebx, ci.ecx, ci.edx);
1354fafed5dSDavid du Colombier
1364fafed5dSDavid du Colombier if((si = malloc(sizeof(BIOS32si))) == nil)
1374fafed5dSDavid du Colombier return nil;
1384fafed5dSDavid du Colombier if((si->base = vmap(ci.ebx, ci.ecx)) == nil){
1394fafed5dSDavid du Colombier free(si);
1404fafed5dSDavid du Colombier return nil;
1414fafed5dSDavid du Colombier }
1424fafed5dSDavid du Colombier si->length = ci.ecx;
1434fafed5dSDavid du Colombier
1444fafed5dSDavid du Colombier ptr = UPTR2INT(si->base)+ci.edx;
1454fafed5dSDavid du Colombier si->ptr[0] = ptr & 0xffff;
1464fafed5dSDavid du Colombier si->ptr[1] = (ptr>>16) & 0xffff;
1474fafed5dSDavid du Colombier si->ptr[2] = KESEL;
1484fafed5dSDavid du Colombier VFLAG("bios32si: eax entry %ux\n", ptr);
1494fafed5dSDavid du Colombier
1504fafed5dSDavid du Colombier return si;
1514fafed5dSDavid du Colombier }
152