plan9fox/sys/src/boot/efi/sub.c

380 lines
5.3 KiB
C

#include <u.h>
#include <a.out.h>
#include "fns.h"
#include "mem.h"
char hex[] = "0123456789abcdef";
void
print(char *s)
{
while(*s != 0){
if(*s == '\n')
putc('\r');
putc(*s++);
}
}
int
readn(void *f, void *data, int len)
{
uchar *p, *e;
p = data;
e = p + len;
while(p < e){
if((len = read(f, p, e - p)) <= 0)
break;
p += len;
}
return p - (uchar*)data;
}
void
memmove(void *dst, void *src, int n)
{
uchar *d = dst;
uchar *s = src;
if(d < s){
while(n-- > 0)
*d++ = *s++;
} else if(d > s){
s += n;
d += n;
while(n-- > 0)
*--d = *--s;
}
}
int
memcmp(void *src, void *dst, int n)
{
uchar *d = dst;
uchar *s = src;
int r = 0;
while(n-- > 0){
r = *d++ - *s++;
if(r != 0)
break;
}
return r;
}
int
strlen(char *s)
{
char *p = s;
while(*p != '\0')
p++;
return p - s;
}
char*
strchr(char *s, int c)
{
for(; *s != 0; s++)
if(*s == c)
return s;
return nil;
}
void
memset(void *dst, int v, int n)
{
uchar *d = dst;
while(n > 0){
*d++ = v;
n--;
}
}
static int
readline(void *f, char buf[64])
{
static char white[] = "\t ";
char *p;
p = buf;
do{
if(f == nil)
putc('>');
for(;;){
if(f == nil){
while((*p = getc()) == 0)
;
putc(*p);
if(*p == '\r')
putc('\n');
else if(*p == '\b' && p > buf){
putc(' ');
putc('\b');
p--;
continue;
}
}else if(read(f, p, 1) <= 0)
return 0;
if(strchr("\r\n", *p) != nil)
break;
if(p == buf && strchr(white, *p) != nil)
continue; /* whitespace on start of line */
if(p >= buf + 64-1){
if(f == nil){
putc('\b');
putc(' ');
putc('\b');
}
continue; /* line full do not advance */
}
p++;
}
while(p > buf && strchr(white, p[-1]))
p--;
}while(p == buf);
*p = 0;
return p - buf;
}
static int
timeout(int ms)
{
while(ms > 0){
if(getc() != 0)
return 1;
usleep(100000);
ms -= 100;
}
return 0;
}
#define BOOTLINE ((char*)CONFADDR)
#define BOOTLINELEN 64
#define BOOTARGS ((char*)(CONFADDR+BOOTLINELEN))
#define BOOTARGSLEN (4096-0x200-BOOTLINELEN)
char *confend;
static char*
getconf(char *s, char *buf)
{
char *p, *e;
int n;
n = strlen(s);
for(p = BOOTARGS; p < confend; p = e+1){
for(e = p+1; e < confend; e++)
if(*e == '\n')
break;
if(memcmp(p, s, n) == 0){
p += n;
n = e - p;
buf[n] = 0;
memmove(buf, p, n);
return buf;
}
}
return nil;
}
static int
delconf(char *s)
{
char *p, *e;
for(p = BOOTARGS; p < confend; p = e){
for(e = p+1; e < confend; e++){
if(*e == '\n'){
e++;
break;
}
}
if(memcmp(p, s, strlen(s)) == 0){
memmove(p, e, confend - e);
confend -= e - p;
*confend = 0;
return 1;
}
}
return 0;
}
char*
configure(void *f, char *path)
{
char line[64], *kern, *s, *p;
int inblock, nowait, n;
static int once = 1;
if(once){
once = 0;
Clear:
memset(BOOTLINE, 0, BOOTLINELEN);
confend = BOOTARGS;
memset(confend, 0, BOOTARGSLEN);
eficonfig(&confend);
}
nowait = 1;
inblock = 0;
Loop:
while(readline(f, line) > 0){
if(*line == 0 || strchr("#;=", *line) != nil)
continue;
if(*line == '['){
inblock = memcmp("[common]", line, 8) != 0;
continue;
}
if(memcmp("boot", line, 5) == 0){
nowait=1;
break;
}
if(memcmp("wait", line, 5) == 0){
nowait=0;
continue;
}
if(memcmp("show", line, 5) == 0){
print(BOOTARGS);
continue;
}
if(memcmp("clear", line, 5) == 0){
if(line[5] == '\0'){
print("ok\n");
goto Clear;
} else if(line[5] == ' ' && delconf(line+6))
print("ok\n");
continue;
}
if(inblock != 0 || (p = strchr(line, '=')) == nil)
continue;
*p++ = 0;
delconf(line);
s = confend;
memmove(confend, line, n = strlen(line)); confend += n;
*confend++ = '=';
memmove(confend, p, n = strlen(p)); confend += n;
*confend++ = '\n';
*confend = 0;
print(s);
}
kern = getconf("bootfile=", path);
if(f != nil){
close(f);
f = nil;
if(kern != nil && (nowait==0 || timeout(1000)))
goto Loop;
}
if(kern == nil){
print("no bootfile\n");
goto Loop;
}
while((p = strchr(kern, '!')) != nil)
kern = p+1;
return kern;
}
static char*
numfmt(char *s, ulong b, ulong i, ulong a)
{
char *r;
if(i == 0){
ulong v = a;
while(v != 0){
v /= b;
i++;
}
if(i == 0)
i = 1;
}
s += i;
r = s;
while(i > 0){
*--s = hex[a % b];
a /= b;
i--;
}
return r;
}
char*
hexfmt(char *s, int i, uvlong a)
{
if(i > 8){
s = numfmt(s, 16, i-8, a>>32);
i = 8;
}
return numfmt(s, 16, i, a);
}
char*
decfmt(char *s, int i, ulong a)
{
return numfmt(s, 10, i, a);
}
static ulong
beswal(ulong l)
{
uchar *p = (uchar*)&l;
return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
}
char*
bootkern(void *f)
{
uchar *e, *d, *t;
ulong n;
Exec ex;
if(readn(f, &ex, sizeof(ex)) != sizeof(ex))
return "bad header";
e = (uchar*)(beswal(ex.entry) & ~0xF0000000UL);
switch(beswal(ex.magic)){
case S_MAGIC:
if(readn(f, e, 8) != 8)
goto Error;
case I_MAGIC:
break;
default:
return "bad magic";
}
t = e;
n = beswal(ex.text);
if(readn(f, t, n) != n)
goto Error;
t += n;
d = (uchar*)PGROUND((uintptr)t);
memset(t, 0, d - t);
n = beswal(ex.data);
if(readn(f, d, n) != n)
goto Error;
d += n;
t = (uchar*)PGROUND((uintptr)d);
t += PGROUND(beswal(ex.bss));
memset(d, 0, t - d);
close(f);
print("boot\n");
unload();
jump(e);
Error:
return "i/o error";
}