summaryrefslogtreecommitdiff
path: root/sys/src/boot/efi/sub.c
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2014-10-18 02:13:02 +0200
committercinap_lenrek <cinap_lenrek@felloff.net>2014-10-18 02:13:02 +0200
commit6f3dfb57eba2eb9ab21e4a0d06c8415cccf45fb1 (patch)
tree871ec1925cc8500c081000d2d3050fcfff4d1d4a /sys/src/boot/efi/sub.c
parent0a6439a1f564de17bfad7a327178e47483a86e1a (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.c382
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";
+}