xref: /plan9-contrib/sys/src/9/pc/bios32.c (revision e360d427b236104c3648116e6e2bbf9149c764be)
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