xref: /plan9/sys/src/9/pcboot/expand.c (revision 084126e8a4f119eb0ee0e36d1d73ebf0b5608c3b)
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