diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2014-10-18 02:13:02 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2014-10-18 02:13:02 +0200 |
commit | 6f3dfb57eba2eb9ab21e4a0d06c8415cccf45fb1 (patch) | |
tree | 871ec1925cc8500c081000d2d3050fcfff4d1d4a /sys/src/boot/efi/sub.c | |
parent | 0a6439a1f564de17bfad7a327178e47483a86e1a (diff) |
efi: add experimental efi bootloader
this is basically a port of 9boot to EFI. theres
support for IA32 (386) and X64 (amd64).
has been tested only under qemu with OVMF so far.
Diffstat (limited to 'sys/src/boot/efi/sub.c')
-rw-r--r-- | sys/src/boot/efi/sub.c | 382 |
1 files changed, 382 insertions, 0 deletions
diff --git a/sys/src/boot/efi/sub.c b/sys/src/boot/efi/sub.c new file mode 100644 index 000000000..ee951bd9f --- /dev/null +++ b/sys/src/boot/efi/sub.c @@ -0,0 +1,382 @@ +#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; + + putc(' '); + p = data; + e = p + len; + while(p < e){ + if(((ulong)p & 0xF000) == 0){ + putc('\b'); + putc(hex[((ulong)p>>16)&0xF]); + } + if((len = read(f, p, e - p)) <= 0) + break; + p += len; + } + putc('\b'); + + 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){ + 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((ulong)t); + memset(t, 0, d - t); + n = beswal(ex.data); + if(readn(f, d, n) != n) + goto Error; + d += n; + t = (uchar*)PGROUND((ulong)d); + t += PGROUND(beswal(ex.bss)); + memset(d, 0, t - d); + + close(f); + unload(); + + jump(e); + +Error: + return "i/o error"; +} |