ref: 53fe82ee861967f0c02dbec7901660470da79098
dir: /sys/src/boot/efi/sub.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) { static char white[] = "\t "; char *p; p = buf; do{ if(f == nil) putc('>'); for(;;){ if(f == nil){ while((*p = getc()) == 0) ; if(p == buf && (*p == '\b' || strchr(white, *p) != nil)) continue; putc(*p); if(*p == '\r') putc('\n'); else if(*p == '\b'){ p--; putc(' '); putc('\b'); 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 */ 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 confaddr #define BOOTLINELEN 64 #define BOOTARGS (confaddr+BOOTLINELEN) #define BOOTARGSLEN (4096-0x200-BOOTLINELEN) extern char *confaddr; static char *confend; static char* findconf(char *s) { char *p, *e; int n = strlen(s); for(p = BOOTARGS; p < confend; p = e+1){ for(e = p; e < confend && *e != '\n'; e++){ if(*e == '\0') return nil; } if(e - p >= n && memcmp(p, s, n) == 0) return p; } return nil; } static char* getconf(char *s, char *buf) { char *p, *e; if((p = findconf(s)) == nil) return nil; p += strlen(s); for(e = p; *e != '\n'; e++) ; memmove(buf, p, e - p); buf[e - p] = '\0'; return buf; } static int delconf(char *s) { char *p, *e; if((p = findconf(s)) == nil) return 0; for(e = p; *e != '\n'; e++) ; e++; memmove(p, e, confend - e); confend -= e - p; *confend = '\0'; return 1; } char* configure(void *f, char *path) { char *line, *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 = confend+1) > 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 || i == 0 && (a>>32) != 0){ s = numfmt(s, 16, i ? i-8 : 0, 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]; } static uvlong beswall(uvlong l) { uchar *p = (uchar*)&l; return ((uvlong)p[0]<<56) | ((uvlong)p[1]<<48) | ((uvlong)p[2]<<40) | ((uvlong)p[3]<<32) | ((uvlong)p[4]<<24) | ((uvlong)p[5]<<16) | ((uvlong)p[6]<<8) | (uvlong)p[7]; } 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: case R_MAGIC: if(readn(f, &e, 8) != 8) goto Error; /* load low address */ e = (uchar*)(beswall((uvlong)e) & 0x0FFFFFFFUL); break; 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"); memconf(findconf("*e820=")?nil:&confend); unload(); jump(e, BOOTARGS); Error: return "i/o error"; }