]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/bios32.c
Import sources from 2011-03-30 iso image - lib
[plan9front.git] / sys / src / 9 / 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 }