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 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 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 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 91 kbdinit(void) 92 { 93 int c, try; 94 95 /* wait for a quiescent controller */ 96 try = 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 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 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 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 } 150 151 void 152 _main(void) 153 { 154 int ksize; 155 Exec *exec; 156 157 splhi(); 158 a20init(); /* don't wrap addresses at 1MB boundaries */ 159 ksize = Lowmemsz - (ulong)edata; /* payload size */ 160 memmove(kernel, edata, ksize); 161 memset(edata, 0, end - edata); 162 163 cgainit(); 164 if(isgzip(kernel)) { 165 print("gz..."); 166 memmove((uchar*)Unzipbuf, kernel, ksize); 167 168 /* we have to uncompress the entire kernel to get OK status */ 169 if(gunzip(kernel, Bootkernmax, (uchar*)Unzipbuf, ksize) < 0){ 170 print("gzip failed."); 171 exits(0); 172 } 173 } 174 if(isexec(kernel)) 175 run(kernel); 176 177 exec = (Exec *)kernel; 178 print("unrecognized program; magic # 0x%x\n", swap(exec->magic)); 179 exits(0); 180 } 181 182 int 183 isexec(void *v) 184 { 185 Exec *exec; 186 187 exec = v; 188 return swap(exec->magic) == I_MAGIC || swap(exec->magic) == S_MAGIC; 189 } 190 191 void 192 run(void *v) 193 { 194 ulong entry, text, data; 195 uchar *base; 196 Exec *exec; 197 198 base = v; 199 exec = v; 200 entry = swap(exec->entry) & ~KSEGM; 201 text = swap(exec->text); 202 data = swap(exec->data); 203 /* 204 * align data segment on the expected page boundary. 205 * sizeof(Exec)+text is offset from base to data segment. 206 */ 207 memmove(base+PGROUND(sizeof(Exec)+text), base+sizeof(Exec)+text, data); 208 209 print("starting protected-mode loader at 0x%x\n", entry); 210 ((void(*)(void))entry)(); 211 212 print("exec failed"); 213 exits(0); 214 } 215 216 int 217 isgzip(uchar *p) 218 { 219 return p[0] == 0x1F && p[1] == 0x8B; 220 } 221 222 void* 223 malloc(ulong n) 224 { 225 void *v; 226 227 v = dbrk; 228 dbrk += ROUND(n, BY2WD); 229 return v; 230 } 231 232 void 233 free(void*) 234 { 235 } 236 237 void 238 puts(char *s) 239 { 240 for(; *s; s++) 241 cgaputc(*s); 242 } 243 244 int 245 print(char *fmt, ...) 246 { 247 int sign; 248 long d; 249 ulong x; 250 char *p, *s, buf[20]; 251 va_list arg; 252 static char *hex = "0123456789abcdef"; 253 254 va_start(arg, fmt); 255 for(p = fmt; *p; p++){ 256 if(*p != '%') { 257 cgaputc(*p); 258 continue; 259 } 260 SET(s); 261 switch(*++p){ 262 case 'p': 263 case 'x': 264 x = va_arg(arg, ulong); 265 if(x == 0){ 266 s = "0"; 267 break; 268 } 269 s = buf+sizeof buf; 270 *--s = 0; 271 while(x > 0){ 272 *--s = hex[x&15]; 273 x /= 16; 274 } 275 if(s == buf+sizeof buf) 276 *--s = '0'; 277 break; 278 case 'd': 279 d = va_arg(arg, ulong); 280 if(d == 0){ 281 s = "0"; 282 break; 283 } 284 if(d < 0){ 285 d = -d; 286 sign = -1; 287 }else 288 sign = 1; 289 s = buf+sizeof buf; 290 *--s = 0; 291 while(d > 0){ 292 *--s = (d%10)+'0'; 293 d /= 10; 294 } 295 if(sign < 0) 296 *--s = '-'; 297 break; 298 case 's': 299 s = va_arg(arg, char*); 300 break; 301 case 0: 302 return 0; 303 } 304 puts(s); 305 } 306 return 0; 307 } 308 309 void 310 exits(char*) 311 { 312 for(;;) 313 ; 314 } 315