xref: /plan9/sys/src/9/pc/bios32.c (revision e360d427b236104c3648116e6e2bbf9149c764be)
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 
8 #define VFLAG(...)	if(vflag) print(__VA_ARGS__)
9 
10 #define UPTR2INT(p)	((uintptr)(p))
11 
12 static int vflag = 0;
13 
14 typedef struct BIOS32sdh {		/* BIOS32 Service Directory Header */
15 	u8int	signature[4];		/* "_32_" */
16 	u8int	physaddr[4];		/* physical address of entry point */
17 	u8int	revision;
18 	u8int	length;			/* of header in paragraphs */
19 	u8int	checksum;		/* */
20 	u8int	reserved[5];
21 } BIOS32sdh;
22 
23 typedef struct BIOS32si {		/* BIOS32 Service Interface */
24 	u8int*	base;			/* base address of service */
25 	int	length;			/* length of service */
26 	u32int	offset;			/* service entry-point from base */
27 
28 	u16int	ptr[3];			/* far pointer m16:32 */
29 } BIOS32si;
30 
31 static Lock bios32lock;
32 static u16int bios32ptr[3];
33 static void* bios32entry;
34 
35 int
bios32ci(BIOS32si * si,BIOS32ci * ci)36 bios32ci(BIOS32si* si, BIOS32ci* ci)
37 {
38 	int r;
39 
40 	lock(&bios32lock);
41 	r = bios32call(ci, si->ptr);
42 	unlock(&bios32lock);
43 
44 	return r;
45 }
46 
47 static void*
rsdchecksum(void * addr,int length)48 rsdchecksum(void* addr, int length)
49 {
50 	u8int *p, sum;
51 
52 	sum = 0;
53 	for(p = addr; length-- > 0; p++)
54 		sum += *p;
55 	if(sum == 0)
56 		return addr;
57 
58 	return nil;
59 }
60 
61 static void*
rsdscan(u8int * addr,int len,char * signature)62 rsdscan(u8int* addr, int len, char* signature)
63 {
64 	int sl;
65 	u8int *e, *p;
66 
67 	e = addr+len;
68 	sl = strlen(signature);
69 	for(p = addr; p+sl < e; p += 16){
70 		if(memcmp(p, signature, sl))
71 			continue;
72 		return p;
73 	}
74 
75 	return nil;
76 }
77 
78 static int
bios32locate(void)79 bios32locate(void)
80 {
81 	uintptr ptr;
82 	BIOS32sdh *sdh;
83 
84 	VFLAG("bios32link\n");
85 	if((sdh = rsdscan(BIOSSEG(0xE000), 0x20000, "_32_")) == nil)
86 		return -1;
87 	if(rsdchecksum(sdh, sizeof(BIOS32sdh)) == nil)
88 		return -1;
89 	VFLAG("sdh @ %#p, entry %#ux\n", sdh, L32GET(sdh->physaddr));
90 
91 	bios32entry = vmap(L32GET(sdh->physaddr), 4096+1);
92 	VFLAG("entry @ %#p\n", bios32entry);
93 	ptr = UPTR2INT(bios32entry);
94 	bios32ptr[0] = ptr & 0xffff;
95 	bios32ptr[1] = (ptr>>16) & 0xffff;
96 	bios32ptr[2] = KESEL;
97 	VFLAG("bios32link: ptr %ux %ux %ux\n",
98 		bios32ptr[0], bios32ptr[1], bios32ptr[2]);
99 
100 	return 0;
101 }
102 
103 void
BIOS32close(BIOS32si * si)104 BIOS32close(BIOS32si* si)
105 {
106 	vunmap(si->base, si->length);
107 	free(si);
108 }
109 
110 BIOS32si*
bios32open(char * id)111 bios32open(char* id)
112 {
113 	uint ptr;
114 	BIOS32ci ci;
115 	BIOS32si *si;
116 
117 	lock(&bios32lock);
118 	if(bios32ptr[2] == 0 && bios32locate() < 0){
119 		unlock(&bios32lock);
120 		return nil;
121 	}
122 
123 	VFLAG("bios32si: %s\n", id);
124 	memset(&ci, 0, sizeof(BIOS32ci));
125 	ci.eax = (id[3]<<24|(id[2]<<16)|(id[1]<<8)|id[0]);
126 
127 	bios32call(&ci, bios32ptr);
128 	unlock(&bios32lock);
129 
130 	VFLAG("bios32si: eax %ux\n", ci.eax);
131 	if(ci.eax & 0xff)
132 		return nil;
133 	VFLAG("bios32si: base %#ux length %#ux offset %#ux\n",
134 		ci.ebx, ci.ecx, ci.edx);
135 
136 	if((si = malloc(sizeof(BIOS32si))) == nil)
137 		return nil;
138 	if((si->base = vmap(ci.ebx, ci.ecx)) == nil){
139 		free(si);
140 		return nil;
141 	}
142 	si->length = ci.ecx;
143 
144 	ptr = UPTR2INT(si->base)+ci.edx;
145 	si->ptr[0] = ptr & 0xffff;
146 	si->ptr[1] = (ptr>>16) & 0xffff;
147 	si->ptr[2] = KESEL;
148 	VFLAG("bios32si: eax entry %ux\n", ptr);
149 
150 	return si;
151 }
152