125210b06SDavid du Colombier /*
225210b06SDavid du Colombier * expand gzipped boot loader appended to this binary and execute it.
325210b06SDavid du Colombier *
425210b06SDavid du Colombier * due to Russ Cox, rsc@swtch.com.
525210b06SDavid du Colombier * see http://plan9.bell-labs.com/wiki/plan9/Replacing_9load
625210b06SDavid du Colombier */
725210b06SDavid du Colombier #include <u.h>
825210b06SDavid du Colombier #include <libc.h>
925210b06SDavid du Colombier #include <a.out.h>
1025210b06SDavid du Colombier #include <flate.h>
1125210b06SDavid du Colombier #include "mem.h"
1225210b06SDavid du Colombier #include "expand.h"
1325210b06SDavid du Colombier
1425210b06SDavid du Colombier #include "inflate.guts.c"
1525210b06SDavid du Colombier
1625210b06SDavid du Colombier #define KB 1024
1725210b06SDavid du Colombier #define MB (1024*1024)
1825210b06SDavid du Colombier
1925210b06SDavid du Colombier extern char edata[];
2025210b06SDavid du Colombier
2125210b06SDavid du Colombier /* ldecomp.s */
2225210b06SDavid du Colombier void mb586(void);
2325210b06SDavid du Colombier void splhi(void);
2425210b06SDavid du Colombier void wbinvd(void);
2525210b06SDavid du Colombier
2625210b06SDavid du Colombier /* inflate.guts.c */
2725210b06SDavid du Colombier int gunzip(uchar*, int, uchar*, int);
2825210b06SDavid du Colombier
2925210b06SDavid du Colombier int isexec(void*);
3025210b06SDavid du Colombier int isgzip(uchar*);
3125210b06SDavid du Colombier void run(void*);
3225210b06SDavid du Colombier
3325210b06SDavid du Colombier #pragma varargck type "d" ulong
3425210b06SDavid du Colombier #pragma varargck type "x" ulong
3525210b06SDavid du Colombier
3625210b06SDavid du Colombier static uchar *kernel = (uchar*)Bootkernaddr;
3725210b06SDavid du Colombier static char *dbrk = (char*)Mallocbase;
3825210b06SDavid du Colombier
3925210b06SDavid du Colombier ulong
swap(ulong p)4025210b06SDavid du Colombier swap(ulong p)
4125210b06SDavid du Colombier {
4225210b06SDavid du Colombier return p<<24 | p>>24 | (p<<8)&0x00FF0000 | (p>>8)&0x0000FF00;
4325210b06SDavid du Colombier }
4425210b06SDavid du Colombier
4525210b06SDavid du Colombier enum {
4625210b06SDavid du Colombier /* keyboard controller ports & cmds */
4725210b06SDavid du Colombier Data= 0x60, /* data port */
4825210b06SDavid du Colombier Status= 0x64, /* status port */
4925210b06SDavid du Colombier Inready= 0x01, /* input character ready */
5025210b06SDavid du Colombier Outbusy= 0x02, /* output busy */
5125210b06SDavid du Colombier Cmd= 0x64, /* command port (write only) */
5225210b06SDavid du Colombier
5325210b06SDavid du Colombier /* system control port a */
5425210b06SDavid du Colombier Sysctla= 0x92,
5525210b06SDavid du Colombier Sysctlreset= 1<<0,
5625210b06SDavid du Colombier Sysctla20ena= 1<<1,
5725210b06SDavid du Colombier };
5825210b06SDavid du Colombier
5925210b06SDavid du Colombier static int
isa20on(void)6025210b06SDavid du Colombier isa20on(void)
6125210b06SDavid du Colombier {
6225210b06SDavid du Colombier int r;
6325210b06SDavid du Colombier ulong o;
6425210b06SDavid du Colombier ulong *zp, *mb1p;
6525210b06SDavid du Colombier
6625210b06SDavid du Colombier zp = 0;
6725210b06SDavid du Colombier mb1p = (ulong *)MB;
6825210b06SDavid du Colombier o = *zp;
6925210b06SDavid du Colombier
7025210b06SDavid du Colombier *zp = 0x1234;
7125210b06SDavid du Colombier *mb1p = 0x8765;
7225210b06SDavid du Colombier mb586();
7325210b06SDavid du Colombier wbinvd();
7425210b06SDavid du Colombier r = *zp != *mb1p;
7525210b06SDavid du Colombier
7625210b06SDavid du Colombier *zp = o;
7725210b06SDavid du Colombier return r;
7825210b06SDavid du Colombier }
7925210b06SDavid du Colombier
8025210b06SDavid du Colombier static void
delay(uint ms)8125210b06SDavid du Colombier delay(uint ms) /* approximate */
8225210b06SDavid du Colombier {
8325210b06SDavid du Colombier int i;
8425210b06SDavid du Colombier
8525210b06SDavid du Colombier while(ms-- > 0)
8625210b06SDavid du Colombier for(i = 1000*1000; i > 0; i--)
8725210b06SDavid du Colombier ;
8825210b06SDavid du Colombier }
8925210b06SDavid du Colombier
9025210b06SDavid du Colombier static int
kbdinit(void)9125210b06SDavid du Colombier kbdinit(void)
9225210b06SDavid du Colombier {
9325210b06SDavid du Colombier int c, try;
9425210b06SDavid du Colombier
9525210b06SDavid du Colombier /* wait for a quiescent controller */
967d80c4cdSDavid du Colombier try = 500; /* was 1000 */
9725210b06SDavid du Colombier while(try-- > 0 && (c = inb(Status)) & (Outbusy | Inready)) {
9825210b06SDavid du Colombier if(c & Inready)
9925210b06SDavid du Colombier inb(Data);
10025210b06SDavid du Colombier delay(1);
10125210b06SDavid du Colombier }
10225210b06SDavid du Colombier return try <= 0? -1: 0;
10325210b06SDavid du Colombier }
10425210b06SDavid du Colombier
10525210b06SDavid du Colombier /*
10625210b06SDavid du Colombier * wait for output no longer busy (but not forever,
10725210b06SDavid du Colombier * there might not be a keyboard controller).
10825210b06SDavid du Colombier */
10925210b06SDavid du Colombier static void
outready(void)11025210b06SDavid du Colombier outready(void)
11125210b06SDavid du Colombier {
11225210b06SDavid du Colombier int i;
11325210b06SDavid du Colombier
11425210b06SDavid du Colombier for (i = 1000; i > 0 && inb(Status) & Outbusy; i--)
11525210b06SDavid du Colombier delay(1);
11625210b06SDavid du Colombier }
11725210b06SDavid du Colombier
11825210b06SDavid du Colombier /*
11925210b06SDavid du Colombier * ask 8042 to enable the use of address bit 20
12025210b06SDavid du Colombier */
12125210b06SDavid du Colombier int
i8042a20(void)12225210b06SDavid du Colombier i8042a20(void)
12325210b06SDavid du Colombier {
12425210b06SDavid du Colombier if (kbdinit() < 0)
12525210b06SDavid du Colombier return -1;
12625210b06SDavid du Colombier outready();
12725210b06SDavid du Colombier outb(Cmd, 0xD1);
12825210b06SDavid du Colombier outready();
12925210b06SDavid du Colombier outb(Data, 0xDF);
13025210b06SDavid du Colombier outready();
13125210b06SDavid du Colombier return 0;
13225210b06SDavid du Colombier }
13325210b06SDavid du Colombier
13425210b06SDavid du Colombier void
a20init(void)13525210b06SDavid du Colombier a20init(void)
13625210b06SDavid du Colombier {
13725210b06SDavid du Colombier int b;
13825210b06SDavid du Colombier
13925210b06SDavid du Colombier if (isa20on())
14025210b06SDavid du Colombier return;
14125210b06SDavid du Colombier if (i8042a20() < 0) { /* original method, via kbd ctlr */
14225210b06SDavid du Colombier /* newer method, last resort */
14325210b06SDavid du Colombier b = inb(Sysctla);
14425210b06SDavid du Colombier if (!(b & Sysctla20ena))
14525210b06SDavid du Colombier outb(Sysctla, (b & ~Sysctlreset) | Sysctla20ena);
14625210b06SDavid du Colombier }
147*084126e8SDavid du Colombier if (!isa20on()){
14825210b06SDavid du Colombier print("a20 didn't come on!\n");
149*084126e8SDavid du Colombier for(;;)
150*084126e8SDavid du Colombier ;
151*084126e8SDavid du Colombier }
15225210b06SDavid du Colombier }
15325210b06SDavid du Colombier
15425210b06SDavid du Colombier void
_main(void)15525210b06SDavid du Colombier _main(void)
15625210b06SDavid du Colombier {
15725210b06SDavid du Colombier int ksize;
15825210b06SDavid du Colombier Exec *exec;
15925210b06SDavid du Colombier
16025210b06SDavid du Colombier splhi();
16125210b06SDavid du Colombier a20init(); /* don't wrap addresses at 1MB boundaries */
16225210b06SDavid du Colombier ksize = Lowmemsz - (ulong)edata; /* payload size */
16325210b06SDavid du Colombier memmove(kernel, edata, ksize);
16425210b06SDavid du Colombier memset(edata, 0, end - edata);
16525210b06SDavid du Colombier
16625210b06SDavid du Colombier cgainit();
16725210b06SDavid du Colombier if(isgzip(kernel)) {
16825210b06SDavid du Colombier print("gz...");
16925210b06SDavid du Colombier memmove((uchar*)Unzipbuf, kernel, ksize);
17025210b06SDavid du Colombier
17125210b06SDavid du Colombier /* we have to uncompress the entire kernel to get OK status */
17225210b06SDavid du Colombier if(gunzip(kernel, Bootkernmax, (uchar*)Unzipbuf, ksize) < 0){
17325210b06SDavid du Colombier print("gzip failed.");
17425210b06SDavid du Colombier exits(0);
17525210b06SDavid du Colombier }
17625210b06SDavid du Colombier }
17725210b06SDavid du Colombier if(isexec(kernel))
17825210b06SDavid du Colombier run(kernel);
17925210b06SDavid du Colombier
18025210b06SDavid du Colombier exec = (Exec *)kernel;
18125210b06SDavid du Colombier print("unrecognized program; magic # 0x%x\n", swap(exec->magic));
18225210b06SDavid du Colombier exits(0);
18325210b06SDavid du Colombier }
18425210b06SDavid du Colombier
18525210b06SDavid du Colombier int
isexec(void * v)18625210b06SDavid du Colombier isexec(void *v)
18725210b06SDavid du Colombier {
18825210b06SDavid du Colombier Exec *exec;
18925210b06SDavid du Colombier
19025210b06SDavid du Colombier exec = v;
19125210b06SDavid du Colombier return swap(exec->magic) == I_MAGIC || swap(exec->magic) == S_MAGIC;
19225210b06SDavid du Colombier }
19325210b06SDavid du Colombier
19425210b06SDavid du Colombier void
run(void * v)19525210b06SDavid du Colombier run(void *v)
19625210b06SDavid du Colombier {
19725210b06SDavid du Colombier ulong entry, text, data;
19825210b06SDavid du Colombier uchar *base;
19925210b06SDavid du Colombier Exec *exec;
20025210b06SDavid du Colombier
20125210b06SDavid du Colombier base = v;
20225210b06SDavid du Colombier exec = v;
20325210b06SDavid du Colombier entry = swap(exec->entry) & ~KSEGM;
20425210b06SDavid du Colombier text = swap(exec->text);
20525210b06SDavid du Colombier data = swap(exec->data);
20625210b06SDavid du Colombier /*
20725210b06SDavid du Colombier * align data segment on the expected page boundary.
20825210b06SDavid du Colombier * sizeof(Exec)+text is offset from base to data segment.
20925210b06SDavid du Colombier */
21025210b06SDavid du Colombier memmove(base+PGROUND(sizeof(Exec)+text), base+sizeof(Exec)+text, data);
21125210b06SDavid du Colombier
21225210b06SDavid du Colombier print("starting protected-mode loader at 0x%x\n", entry);
21325210b06SDavid du Colombier ((void(*)(void))entry)();
21425210b06SDavid du Colombier
21525210b06SDavid du Colombier print("exec failed");
21625210b06SDavid du Colombier exits(0);
21725210b06SDavid du Colombier }
21825210b06SDavid du Colombier
21925210b06SDavid du Colombier int
isgzip(uchar * p)22025210b06SDavid du Colombier isgzip(uchar *p)
22125210b06SDavid du Colombier {
22225210b06SDavid du Colombier return p[0] == 0x1F && p[1] == 0x8B;
22325210b06SDavid du Colombier }
22425210b06SDavid du Colombier
22525210b06SDavid du Colombier void*
malloc(ulong n)22625210b06SDavid du Colombier malloc(ulong n)
22725210b06SDavid du Colombier {
22825210b06SDavid du Colombier void *v;
22925210b06SDavid du Colombier
23025210b06SDavid du Colombier v = dbrk;
23125210b06SDavid du Colombier dbrk += ROUND(n, BY2WD);
23225210b06SDavid du Colombier return v;
23325210b06SDavid du Colombier }
23425210b06SDavid du Colombier
23525210b06SDavid du Colombier void
free(void *)23625210b06SDavid du Colombier free(void*)
23725210b06SDavid du Colombier {
23825210b06SDavid du Colombier }
23925210b06SDavid du Colombier
24025210b06SDavid du Colombier void
puts(char * s)24125210b06SDavid du Colombier puts(char *s)
24225210b06SDavid du Colombier {
24325210b06SDavid du Colombier for(; *s; s++)
24425210b06SDavid du Colombier cgaputc(*s);
24525210b06SDavid du Colombier }
24625210b06SDavid du Colombier
24725210b06SDavid du Colombier int
print(char * fmt,...)24825210b06SDavid du Colombier print(char *fmt, ...)
24925210b06SDavid du Colombier {
25025210b06SDavid du Colombier int sign;
25125210b06SDavid du Colombier long d;
25225210b06SDavid du Colombier ulong x;
25325210b06SDavid du Colombier char *p, *s, buf[20];
25425210b06SDavid du Colombier va_list arg;
25525210b06SDavid du Colombier static char *hex = "0123456789abcdef";
25625210b06SDavid du Colombier
25725210b06SDavid du Colombier va_start(arg, fmt);
25825210b06SDavid du Colombier for(p = fmt; *p; p++){
25925210b06SDavid du Colombier if(*p != '%') {
26025210b06SDavid du Colombier cgaputc(*p);
26125210b06SDavid du Colombier continue;
26225210b06SDavid du Colombier }
26325210b06SDavid du Colombier SET(s);
26425210b06SDavid du Colombier switch(*++p){
26525210b06SDavid du Colombier case 'p':
26625210b06SDavid du Colombier case 'x':
26725210b06SDavid du Colombier x = va_arg(arg, ulong);
26825210b06SDavid du Colombier if(x == 0){
26925210b06SDavid du Colombier s = "0";
27025210b06SDavid du Colombier break;
27125210b06SDavid du Colombier }
27225210b06SDavid du Colombier s = buf+sizeof buf;
27325210b06SDavid du Colombier *--s = 0;
27425210b06SDavid du Colombier while(x > 0){
27525210b06SDavid du Colombier *--s = hex[x&15];
27625210b06SDavid du Colombier x /= 16;
27725210b06SDavid du Colombier }
27825210b06SDavid du Colombier if(s == buf+sizeof buf)
27925210b06SDavid du Colombier *--s = '0';
28025210b06SDavid du Colombier break;
28125210b06SDavid du Colombier case 'd':
28225210b06SDavid du Colombier d = va_arg(arg, ulong);
28325210b06SDavid du Colombier if(d == 0){
28425210b06SDavid du Colombier s = "0";
28525210b06SDavid du Colombier break;
28625210b06SDavid du Colombier }
28725210b06SDavid du Colombier if(d < 0){
28825210b06SDavid du Colombier d = -d;
28925210b06SDavid du Colombier sign = -1;
29025210b06SDavid du Colombier }else
29125210b06SDavid du Colombier sign = 1;
29225210b06SDavid du Colombier s = buf+sizeof buf;
29325210b06SDavid du Colombier *--s = 0;
29425210b06SDavid du Colombier while(d > 0){
29525210b06SDavid du Colombier *--s = (d%10)+'0';
29625210b06SDavid du Colombier d /= 10;
29725210b06SDavid du Colombier }
29825210b06SDavid du Colombier if(sign < 0)
29925210b06SDavid du Colombier *--s = '-';
30025210b06SDavid du Colombier break;
30125210b06SDavid du Colombier case 's':
30225210b06SDavid du Colombier s = va_arg(arg, char*);
30325210b06SDavid du Colombier break;
30425210b06SDavid du Colombier case 0:
30525210b06SDavid du Colombier return 0;
30625210b06SDavid du Colombier }
30725210b06SDavid du Colombier puts(s);
30825210b06SDavid du Colombier }
30925210b06SDavid du Colombier return 0;
31025210b06SDavid du Colombier }
31125210b06SDavid du Colombier
31225210b06SDavid du Colombier void
exits(char *)31325210b06SDavid du Colombier exits(char*)
31425210b06SDavid du Colombier {
31525210b06SDavid du Colombier for(;;)
31625210b06SDavid du Colombier ;
31725210b06SDavid du Colombier }
318