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