/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * expand gzipped boot loader appended to this binary and execute it. * * due to Russ Cox, rsc@swtch.com. * see http://plan9.bell-labs.com/wiki/plan9/Replacing_9load */#include <u.h>#include <libc.h>#include <a.out.h>#include <flate.h>#include "mem.h"#include "expand.h" #include "inflate.guts.c" #define KB 1024#define MB (1024*1024) extern char edata[]; /* ldecomp.s */void mb586(void);void splhi(void);void wbinvd(void); /* inflate.guts.c */int gunzip(uchar*, int, uchar*, int); int isexec(void*);int isgzip(uchar*);void run(void*); #pragma varargck type "d" ulong#pragma varargck type "x" ulong static uchar *kernel = (uchar*)Bootkernaddr;static char *dbrk = (char*)Mallocbase; ulongswap(ulong p){ return p<<24 | p>>24 | (p<<8)&0x00FF0000 | (p>>8)&0x0000FF00;} enum { /* keyboard controller ports & cmds */ Data= 0x60, /* data port */ Status= 0x64, /* status port */ Inready= 0x01, /* input character ready */ Outbusy= 0x02, /* output busy */ Cmd= 0x64, /* command port (write only) */ /* system control port a */ Sysctla= 0x92, Sysctlreset= 1<<0, Sysctla20ena= 1<<1,}; static intisa20on(void){ int r; ulong o; ulong *zp, *mb1p; zp = 0; mb1p = (ulong *)MB; o = *zp; *zp = 0x1234; *mb1p = 0x8765; mb586(); wbinvd(); r = *zp != *mb1p; *zp = o; return r;} static voiddelay(uint ms) /* approximate */{ int i; while(ms-- > 0) for(i = 1000*1000; i > 0; i--) ;} static intkbdinit(void){ int c, try; /* wait for a quiescent controller */ try = 500; /* was 1000 */ while(try-- > 0 && (c = inb(Status)) & (Outbusy | Inready)) { if(c & Inready) inb(Data); delay(1); } return try <= 0? -1: 0;} /* * wait for output no longer busy (but not forever, * there might not be a keyboard controller). */static voidoutready(void){ int i; for (i = 1000; i > 0 && inb(Status) & Outbusy; i--) delay(1);} /* * ask 8042 to enable the use of address bit 20 */inti8042a20(void){ if (kbdinit() < 0) return -1; outready(); outb(Cmd, 0xD1); outready(); outb(Data, 0xDF); outready(); return 0;} voida20init(void){ int b; if (isa20on()) return; if (i8042a20() < 0) { /* original method, via kbd ctlr */ /* newer method, last resort */ b = inb(Sysctla); if (!(b & Sysctla20ena)) outb(Sysctla, (b & ~Sysctlreset) | Sysctla20ena); } if (!isa20on()) print("a20 didn't come on!\n");} void_main(void){ int ksize; Exec *exec; splhi(); a20init(); /* don't wrap addresses at 1MB boundaries */ ksize = Lowmemsz - (ulong)edata; /* payload size */ memmove(kernel, edata, ksize); memset(edata, 0, end - edata); cgainit(); if(isgzip(kernel)) { print("gz..."); memmove((uchar*)Unzipbuf, kernel, ksize); /* we have to uncompress the entire kernel to get OK status */ if(gunzip(kernel, Bootkernmax, (uchar*)Unzipbuf, ksize) < 0){ print("gzip failed."); exits(0); } } if(isexec(kernel)) run(kernel); exec = (Exec *)kernel; print("unrecognized program; magic # 0x%x\n", swap(exec->magic)); exits(0);} intisexec(void *v){ Exec *exec; exec = v; return swap(exec->magic) == I_MAGIC || swap(exec->magic) == S_MAGIC;} voidrun(void *v){ ulong entry, text, data; uchar *base; Exec *exec; base = v; exec = v; entry = swap(exec->entry) & ~KSEGM; text = swap(exec->text); data = swap(exec->data); /* * align data segment on the expected page boundary. * sizeof(Exec)+text is offset from base to data segment. */ memmove(base+PGROUND(sizeof(Exec)+text), base+sizeof(Exec)+text, data); print("starting protected-mode loader at 0x%x\n", entry); ((void(*)(void))entry)(); print("exec failed"); exits(0);} intisgzip(uchar *p){ return p[0] == 0x1F && p[1] == 0x8B;} void*malloc(ulong n){ void *v; v = dbrk; dbrk += ROUND(n, BY2WD); return v;} voidfree(void*){} voidputs(char *s){ for(; *s; s++) cgaputc(*s);} intprint(char *fmt, ...){ int sign; long d; ulong x; char *p, *s, buf[20]; va_list arg; static char *hex = "0123456789abcdef"; va_start(arg, fmt); for(p = fmt; *p; p++){ if(*p != '%') { cgaputc(*p); continue; } SET(s); switch(*++p){ case 'p': case 'x': x = va_arg(arg, ulong); if(x == 0){ s = "0"; break; } s = buf+sizeof buf; *--s = 0; while(x > 0){ *--s = hex[x&15]; x /= 16; } if(s == buf+sizeof buf) *--s = '0'; break; case 'd': d = va_arg(arg, ulong); if(d == 0){ s = "0"; break; } if(d < 0){ d = -d; sign = -1; }else sign = 1; s = buf+sizeof buf; *--s = 0; while(d > 0){ *--s = (d%10)+'0'; d /= 10; } if(sign < 0) *--s = '-'; break; case 's': s = va_arg(arg, char*); break; case 0: return 0; } puts(s); } return 0;} voidexits(char*){ for(;;) ;}
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
/*
* expand gzipped boot loader appended to this binary and execute it.
*
* due to Russ Cox, rsc@swtch.com.
* see http://plan9.bell-labs.com/wiki/plan9/Replacing_9load
*/
#include <u.h>
#include <libc.h>
#include <a.out.h>
#include <flate.h>
#include "mem.h"
#include "expand.h"
#include "inflate.guts.c"
#define KB 1024
#define MB (1024*1024)
extern char edata[];
/* ldecomp.s */
void mb586(void);
void splhi(void);
void wbinvd(void);
/* inflate.guts.c */
int gunzip(uchar*, int, uchar*, int);
int isexec(void*);
int isgzip(uchar*);
void run(void*);
#pragma varargck type "d" ulong
#pragma varargck type "x" ulong
static uchar *kernel = (uchar*)Bootkernaddr;
static char *dbrk = (char*)Mallocbase;
ulong
swap(ulong p)
{
return p<<24 | p>>24 | (p<<8)&0x00FF0000 | (p>>8)&0x0000FF00;
}
enum {
/* keyboard controller ports & cmds */
Data= 0x60, /* data port */
Status= 0x64, /* status port */
Inready= 0x01, /* input character ready */
Outbusy= 0x02, /* output busy */
Cmd= 0x64, /* command port (write only) */
/* system control port a */
Sysctla= 0x92,
Sysctlreset= 1<<0,
Sysctla20ena= 1<<1,
};
static int
isa20on(void)
{
int r;
ulong o;
ulong *zp, *mb1p;
zp = 0;
mb1p = (ulong *)MB;
o = *zp;
*zp = 0x1234;
*mb1p = 0x8765;
mb586();
wbinvd();
r = *zp != *mb1p;
*zp = o;
return r;
}
static void
delay(uint ms) /* approximate */
{
int i;
while(ms-- > 0)
for(i = 1000*1000; i > 0; i--)
;
}
static int
kbdinit(void)
{
int c, try;
/* wait for a quiescent controller */
try = 500; /* was 1000 */
while(try-- > 0 && (c = inb(Status)) & (Outbusy | Inready)) {
if(c & Inready)
inb(Data);
delay(1);
}
return try <= 0? -1: 0;
}
/*
* wait for output no longer busy (but not forever,
* there might not be a keyboard controller).
*/
static void
outready(void)
{
int i;
for (i = 1000; i > 0 && inb(Status) & Outbusy; i--)
delay(1);
}
/*
* ask 8042 to enable the use of address bit 20
*/
int
i8042a20(void)
{
if (kbdinit() < 0)
return -1;
outready();
outb(Cmd, 0xD1);
outready();
outb(Data, 0xDF);
outready();
return 0;
}
void
a20init(void)
{
int b;
if (isa20on())
return;
if (i8042a20() < 0) { /* original method, via kbd ctlr */
/* newer method, last resort */
b = inb(Sysctla);
if (!(b & Sysctla20ena))
outb(Sysctla, (b & ~Sysctlreset) | Sysctla20ena);
}
if (!isa20on())
print("a20 didn't come on!\n");
}
void
_main(void)
{
int ksize;
Exec *exec;
splhi();
a20init(); /* don't wrap addresses at 1MB boundaries */
ksize = Lowmemsz - (ulong)edata; /* payload size */
memmove(kernel, edata, ksize);
memset(edata, 0, end - edata);
cgainit();
if(isgzip(kernel)) {
print("gz...");
memmove((uchar*)Unzipbuf, kernel, ksize);
/* we have to uncompress the entire kernel to get OK status */
if(gunzip(kernel, Bootkernmax, (uchar*)Unzipbuf, ksize) < 0){
print("gzip failed.");
exits(0);
}
}
if(isexec(kernel))
run(kernel);
exec = (Exec *)kernel;
print("unrecognized program; magic # 0x%x\n", swap(exec->magic));
exits(0);
}
int
isexec(void *v)
{
Exec *exec;
exec = v;
return swap(exec->magic) == I_MAGIC || swap(exec->magic) == S_MAGIC;
}
void
run(void *v)
{
ulong entry, text, data;
uchar *base;
Exec *exec;
base = v;
exec = v;
entry = swap(exec->entry) & ~KSEGM;
text = swap(exec->text);
data = swap(exec->data);
/*
* align data segment on the expected page boundary.
* sizeof(Exec)+text is offset from base to data segment.
*/
memmove(base+PGROUND(sizeof(Exec)+text), base+sizeof(Exec)+text, data);
print("starting protected-mode loader at 0x%x\n", entry);
((void(*)(void))entry)();
print("exec failed");
exits(0);
}
int
isgzip(uchar *p)
{
return p[0] == 0x1F && p[1] == 0x8B;
}
void*
malloc(ulong n)
{
void *v;
v = dbrk;
dbrk += ROUND(n, BY2WD);
return v;
}
void
free(void*)
{
}
void
puts(char *s)
{
for(; *s; s++)
cgaputc(*s);
}
int
print(char *fmt, ...)
{
int sign;
long d;
ulong x;
char *p, *s, buf[20];
va_list arg;
static char *hex = "0123456789abcdef";
va_start(arg, fmt);
for(p = fmt; *p; p++){
if(*p != '%') {
cgaputc(*p);
continue;
}
SET(s);
switch(*++p){
case 'p':
case 'x':
x = va_arg(arg, ulong);
if(x == 0){
s = "0";
break;
}
s = buf+sizeof buf;
*--s = 0;
while(x > 0){
*--s = hex[x&15];
x /= 16;
}
if(s == buf+sizeof buf)
*--s = '0';
break;
case 'd':
d = va_arg(arg, ulong);
if(d == 0){
s = "0";
break;
}
if(d < 0){
d = -d;
sign = -1;
}else
sign = 1;
s = buf+sizeof buf;
*--s = 0;
while(d > 0){
*--s = (d%10)+'0';
d /= 10;
}
if(sign < 0)
*--s = '-';
break;
case 's':
s = va_arg(arg, char*);
break;
case 0:
return 0;
}
puts(s);
}
return 0;
}
void
exits(char*)
{
for(;;)
;
}