1 /*
2 * expand gzipped boot loader appended to this binary and execute it.
3 *
4 * due to Russ Cox, rsc@swtch.com.
5 * see http://plan9.bell-labs.com/wiki/plan9/Replacing_9load
6 */
7 #include <u.h>
8 #include <libc.h>
9 #include <a.out.h>
10 #include <flate.h>
11 #include "mem.h"
12 #include "expand.h"
13
14 #include "inflate.guts.c"
15
16 #define KB 1024
17 #define MB (1024*1024)
18
19 extern char edata[];
20
21 /* ldecomp.s */
22 void mb586(void);
23 void splhi(void);
24 void wbinvd(void);
25
26 /* inflate.guts.c */
27 int gunzip(uchar*, int, uchar*, int);
28
29 int isexec(void*);
30 int isgzip(uchar*);
31 void run(void*);
32
33 #pragma varargck type "d" ulong
34 #pragma varargck type "x" ulong
35
36 static uchar *kernel = (uchar*)Bootkernaddr;
37 static char *dbrk = (char*)Mallocbase;
38
39 ulong
swap(ulong p)40 swap(ulong p)
41 {
42 return p<<24 | p>>24 | (p<<8)&0x00FF0000 | (p>>8)&0x0000FF00;
43 }
44
45 enum {
46 /* keyboard controller ports & cmds */
47 Data= 0x60, /* data port */
48 Status= 0x64, /* status port */
49 Inready= 0x01, /* input character ready */
50 Outbusy= 0x02, /* output busy */
51 Cmd= 0x64, /* command port (write only) */
52
53 /* system control port a */
54 Sysctla= 0x92,
55 Sysctlreset= 1<<0,
56 Sysctla20ena= 1<<1,
57 };
58
59 static int
isa20on(void)60 isa20on(void)
61 {
62 int r;
63 ulong o;
64 ulong *zp, *mb1p;
65
66 zp = 0;
67 mb1p = (ulong *)MB;
68 o = *zp;
69
70 *zp = 0x1234;
71 *mb1p = 0x8765;
72 mb586();
73 wbinvd();
74 r = *zp != *mb1p;
75
76 *zp = o;
77 return r;
78 }
79
80 static void
delay(uint ms)81 delay(uint ms) /* approximate */
82 {
83 int i;
84
85 while(ms-- > 0)
86 for(i = 1000*1000; i > 0; i--)
87 ;
88 }
89
90 static int
kbdinit(void)91 kbdinit(void)
92 {
93 int c, try;
94
95 /* wait for a quiescent controller */
96 try = 500; /* was 1000 */
97 while(try-- > 0 && (c = inb(Status)) & (Outbusy | Inready)) {
98 if(c & Inready)
99 inb(Data);
100 delay(1);
101 }
102 return try <= 0? -1: 0;
103 }
104
105 /*
106 * wait for output no longer busy (but not forever,
107 * there might not be a keyboard controller).
108 */
109 static void
outready(void)110 outready(void)
111 {
112 int i;
113
114 for (i = 1000; i > 0 && inb(Status) & Outbusy; i--)
115 delay(1);
116 }
117
118 /*
119 * ask 8042 to enable the use of address bit 20
120 */
121 int
i8042a20(void)122 i8042a20(void)
123 {
124 if (kbdinit() < 0)
125 return -1;
126 outready();
127 outb(Cmd, 0xD1);
128 outready();
129 outb(Data, 0xDF);
130 outready();
131 return 0;
132 }
133
134 void
a20init(void)135 a20init(void)
136 {
137 int b;
138
139 if (isa20on())
140 return;
141 if (i8042a20() < 0) { /* original method, via kbd ctlr */
142 /* newer method, last resort */
143 b = inb(Sysctla);
144 if (!(b & Sysctla20ena))
145 outb(Sysctla, (b & ~Sysctlreset) | Sysctla20ena);
146 }
147 if (!isa20on()){
148 print("a20 didn't come on!\n");
149 for(;;)
150 ;
151 }
152 }
153
154 void
_main(void)155 _main(void)
156 {
157 int ksize;
158 Exec *exec;
159
160 splhi();
161 a20init(); /* don't wrap addresses at 1MB boundaries */
162 ksize = Lowmemsz - (ulong)edata; /* payload size */
163 memmove(kernel, edata, ksize);
164 memset(edata, 0, end - edata);
165
166 cgainit();
167 if(isgzip(kernel)) {
168 print("gz...");
169 memmove((uchar*)Unzipbuf, kernel, ksize);
170
171 /* we have to uncompress the entire kernel to get OK status */
172 if(gunzip(kernel, Bootkernmax, (uchar*)Unzipbuf, ksize) < 0){
173 print("gzip failed.");
174 exits(0);
175 }
176 }
177 if(isexec(kernel))
178 run(kernel);
179
180 exec = (Exec *)kernel;
181 print("unrecognized program; magic # 0x%x\n", swap(exec->magic));
182 exits(0);
183 }
184
185 int
isexec(void * v)186 isexec(void *v)
187 {
188 Exec *exec;
189
190 exec = v;
191 return swap(exec->magic) == I_MAGIC || swap(exec->magic) == S_MAGIC;
192 }
193
194 void
run(void * v)195 run(void *v)
196 {
197 ulong entry, text, data;
198 uchar *base;
199 Exec *exec;
200
201 base = v;
202 exec = v;
203 entry = swap(exec->entry) & ~KSEGM;
204 text = swap(exec->text);
205 data = swap(exec->data);
206 /*
207 * align data segment on the expected page boundary.
208 * sizeof(Exec)+text is offset from base to data segment.
209 */
210 memmove(base+PGROUND(sizeof(Exec)+text), base+sizeof(Exec)+text, data);
211
212 print("starting protected-mode loader at 0x%x\n", entry);
213 ((void(*)(void))entry)();
214
215 print("exec failed");
216 exits(0);
217 }
218
219 int
isgzip(uchar * p)220 isgzip(uchar *p)
221 {
222 return p[0] == 0x1F && p[1] == 0x8B;
223 }
224
225 void*
malloc(ulong n)226 malloc(ulong n)
227 {
228 void *v;
229
230 v = dbrk;
231 dbrk += ROUND(n, BY2WD);
232 return v;
233 }
234
235 void
free(void *)236 free(void*)
237 {
238 }
239
240 void
puts(char * s)241 puts(char *s)
242 {
243 for(; *s; s++)
244 cgaputc(*s);
245 }
246
247 int
print(char * fmt,...)248 print(char *fmt, ...)
249 {
250 int sign;
251 long d;
252 ulong x;
253 char *p, *s, buf[20];
254 va_list arg;
255 static char *hex = "0123456789abcdef";
256
257 va_start(arg, fmt);
258 for(p = fmt; *p; p++){
259 if(*p != '%') {
260 cgaputc(*p);
261 continue;
262 }
263 SET(s);
264 switch(*++p){
265 case 'p':
266 case 'x':
267 x = va_arg(arg, ulong);
268 if(x == 0){
269 s = "0";
270 break;
271 }
272 s = buf+sizeof buf;
273 *--s = 0;
274 while(x > 0){
275 *--s = hex[x&15];
276 x /= 16;
277 }
278 if(s == buf+sizeof buf)
279 *--s = '0';
280 break;
281 case 'd':
282 d = va_arg(arg, ulong);
283 if(d == 0){
284 s = "0";
285 break;
286 }
287 if(d < 0){
288 d = -d;
289 sign = -1;
290 }else
291 sign = 1;
292 s = buf+sizeof buf;
293 *--s = 0;
294 while(d > 0){
295 *--s = (d%10)+'0';
296 d /= 10;
297 }
298 if(sign < 0)
299 *--s = '-';
300 break;
301 case 's':
302 s = va_arg(arg, char*);
303 break;
304 case 0:
305 return 0;
306 }
307 puts(s);
308 }
309 return 0;
310 }
311
312 void
exits(char *)313 exits(char*)
314 {
315 for(;;)
316 ;
317 }
318