ref: 2fe3b28f86ed4aa291fb8a620b948abe9c6a1f84
parent: 1c4fa7b000384af9bb79ebf6a62ef9968dab99b4
author: aiju <devnull@localhost>
date: Thu Jun 15 11:58:25 EDT 2017
vmx: obsd: load kernel symbol table and allow setting root device
--- a/sys/src/cmd/vmx/ksetup.c
+++ b/sys/src/cmd/vmx/ksetup.c
@@ -1,6 +1,7 @@
#include <u.h>
#include <libc.h>
#include <thread.h>
+#include <libsec.h>
#include "dat.h"
#include "fns.h"
@@ -195,6 +196,7 @@
enum {
SHT_SYMTAB = 2,
SHT_STRTAB = 3,
+ SHF_ALLOC = 2,
};
typedef struct ELFSymbol ELFSymbol;
struct ELFSymbol {
@@ -211,7 +213,6 @@
static int nsym;
static uintptr elfmax;
-
static u64int
elff(uchar **p, uchar *e, int sz)
{
@@ -308,7 +309,7 @@
if(hdr[5] != 1 || hdr[6] != 1 || hdr[0x14] != 1) return 0;
switch(hdr[4]){
case 1: elf64 = 0; break;
- case 2: elf64 = 1; break;
+ case 2: elf64 = 1; if(sizeof(uintptr) == 4) sysfatal("64-bit binaries not supported on 32-bit host"); break;
default: return 0;
}
elfheader(&eh, hdr + 0x18, hdr + sizeof(hdr));
@@ -350,7 +351,6 @@
switch(ph[i].type){
case PT_NULL:
case PT_GNU_RELRO:
- case PT_OPENBSD_RANDOMIZE:
case PT_NOTE:
continue;
case PT_DYNAMIC:
@@ -360,17 +360,22 @@
sysfatal("elf: unknown program header type %#ux", (int)ph[i].type);
case PT_LOAD:
case PT_PHDR:
+ case PT_OPENBSD_RANDOMIZE:
break;
}
v = gptr(ph[i].paddr, ph[i].memsz);
if(v == nil)
sysfatal("invalid address %p (length=%p) in elf", (void*)ph[i].paddr, (void*)ph[i].memsz);
- if(ph[i].filesz > ph[i].memsz)
- sysfatal("elf: header entry shorter in memory than in the file (%p < %p)", (void*)ph[i].memsz, (void*)ph[i].filesz);
- if(ph[i].filesz != 0)
- epreadn(v, ph[i].filesz, ph[i].offset, "elfdata");
- if(ph[i].filesz < ph[i].memsz)
- memset((uchar*)v + ph[i].filesz, 0, ph[i].memsz - ph[i].filesz);
+ if(ph[i].type == PT_OPENBSD_RANDOMIZE)
+ genrandom(v, ph[i].memsz);
+ else{
+ if(ph[i].filesz > ph[i].memsz)
+ sysfatal("elf: header entry shorter in memory than in the file (%p < %p)", (void*)ph[i].memsz, (void*)ph[i].filesz);
+ if(ph[i].filesz != 0)
+ epreadn(v, ph[i].filesz, ph[i].offset, "elfdata");
+ if(ph[i].filesz < ph[i].memsz)
+ memset((uchar*)v + ph[i].filesz, 0, ph[i].memsz - ph[i].filesz);
+ }
if(ph[i].paddr + ph[i].memsz > elfmax)
elfmax = ph[i].paddr + ph[i].memsz;
}
@@ -437,7 +442,7 @@
static uchar *obsdarg, *obsdarg0, *obsdargnext;
static int obsdargc;
-static int obsdconsdev = 12 << 8, obsddbcons = -1;
+static int obsdconsdev = 12 << 8, obsddbcons = -1, obsdbootdev;
enum {
BOOTARG_MEMMAP,
@@ -471,8 +476,11 @@
va_start(va, fmt);
for(; *fmt != 0; fmt++)
switch(*fmt){
+ case '.': p++; break;
+ case 's': PUT16(p, 0, va_arg(va, int)); p += 2; break;
case 'i': PUT32(p, 0, va_arg(va, u32int)); p += 4; break;
case 'v': PUT64(p, 0, va_arg(va, u64int)); p += 8; break;
+ case 'z': if(elf64) {PUT64(p, 0, va_arg(va, uintptr)); p += 8;} else {PUT32(p, 0, va_arg(va, uintptr)); p += 4;} break;
default: sysfatal("pack: unknown fmt character %c", *fmt);
}
va_end(va);
@@ -479,6 +487,48 @@
return p;
}
+static void
+obsdelfload(void)
+{
+ void *v, *w, *hdrfix;
+ int shentsize;
+ int saddr;
+ ELFSHeader *s;
+ uintptr off;
+
+ saddr = elf64 ? 8 : 4;
+ elfmax = -(-elfmax & -saddr);
+ v = gptr(elfmax, eh.ehsize);
+ if(v == nil)
+space: sysfatal("out of space for kernel");
+ epreadn(v, eh.ehsize, 0, "obsdelfload");
+ elfmax += -(-eh.ehsize & -saddr);
+ hdrfix = (uchar*)v + (elf64 ? 0x20 : 0x1c);
+
+ shentsize = 40 + 24*elf64;
+ v = gptr(elfmax, shentsize * eh.shnum);
+ if(v == nil) goto space;
+ off = shentsize * eh.shnum;
+ elfmax += off;
+ off += -(-eh.ehsize & -saddr);
+ for(s = sh; s < sh + eh.shnum; s++)
+ if(s->type == SHT_SYMTAB || s->type == SHT_STRTAB ||
+ s->name != nil && (strcmp(s->name, ".debug_line") == 0 || strcmp(s->name, ".SUNW_ctf") == 0)){
+ w = gptr(elfmax, s->size);
+ if(w == nil) goto space;
+ epreadn(w, s->size, s->offset, "obsdelfload");
+ v = pack(v, "iizzzziizz",
+ s->iname, s->type, s->flags | SHF_ALLOC, (uintptr)0,
+ off, s->size, s->link, s->info, s->addralign, s->entsize);
+ elfmax += -(-s->size & -saddr);
+ off += -(-s->size & -saddr);
+ }else{
+ memset(v, 0, shentsize);
+ v = (uchar*)v + shentsize;
+ }
+ pack(hdrfix, "zz......sss", (uintptr)0, -(-eh.ehsize & -saddr), 0, 0, shentsize);
+}
+
#define obsdpack(...) (obsdarg = pack(obsdarg, __VA_ARGS__))
static void
@@ -528,7 +578,7 @@
obsdcmdline(int argc, char **argv)
{
char *p;
- char *q;
+ char *q, *r;
int howto;
howto = 0;
@@ -548,7 +598,25 @@
q = strchr(p, '=');
if(q == nil) goto usage;
*q++ = 0;
- if(strcmp(p, "tty") == 0){
+ if(strcmp(p, "device") == 0){
+ obsdbootdev = 0;
+ switch(*q){
+ case 'w': break;
+ case 'f': obsdbootdev = 2; break;
+ case 's': obsdbootdev = 4; break;
+ case 'c': obsdbootdev = 6; break;
+ case 'r': obsdbootdev = 17; break;
+ case 'v': obsdbootdev = 14; if(*++q != 'n') goto nodev; break;
+ default: nodev: sysfatal("invalid device");
+ }
+ if(*++q != 'd') goto nodev;
+ obsdbootdev |= strtoul(++q, &r, 10) << 16;
+ if(r == q || (obsdbootdev & 0xfff00000) != 0) goto nodev;
+ if(*r < 'a' || *r > 'p') goto nodev;
+ obsdbootdev |= *r - 'a' << 8;
+ if(*++r != 0) goto nodev;
+ obsdbootdev |= 0xa0000000;
+ }else if(strcmp(p, "tty") == 0){
if(strcmp(q, "com0") == 0)
obsdconsdev = 8 << 8;
else if(strcmp(q, "com1") == 0)
@@ -568,7 +636,7 @@
}
return howto;
usage:
- fprint(2, "openbsd cmdline usage: kernel [-asdc] [var=value ...]\nsupported vars: tty db_console\n");
+ fprint(2, "openbsd cmdline usage: kernel [-asdc] [var=value ...]\nsupported vars: device tty db_console\n");
threadexitsall("usage");
return 0;
}
@@ -580,6 +648,7 @@
int howto;
uchar *v;
+ obsdelfload();
sp = 0xfffc;
sp -= 36;
v = gptr(sp, 36);
@@ -586,7 +655,7 @@
howto = obsdcmdline(cmdlinen, cmdlinev);
assert(v != nil);
PUT32(v, 4, howto); /* howto */
- PUT32(v, 8, 0); /* bootdev */
+ PUT32(v, 8, obsdbootdev); /* bootdev */
PUT32(v, 12, 0xa); /* bootapiver */
PUT32(v, 16, elfmax); /* esym */
PUT32(v, 20, 0); /* extmem */