vmx(1): clean up region handling code; changes to support amd64

This commit is contained in:
aiju 2017-06-20 15:15:53 +00:00
parent becb89bae5
commit 164588e3e2
5 changed files with 115 additions and 91 deletions

View file

@ -35,7 +35,14 @@ enum {
struct Region { struct Region {
uintptr start, end; uintptr start, end;
enum { REGNO, REGMEM, REGFB } type; enum {
REGALLOC = 1, /* allocate memory for region */
REGRO = 2, /* read-only */
/* E820 types, 0 == omitted from memory map */
REGFREE = 1<<8, /* report to OS as free */
REGRES = 2<<8, /* report to OS as reserved */
} type;
char *segname; char *segname;
uvlong segoff; uvlong segoff;
void *v, *ve; void *v, *ve;

View file

@ -33,7 +33,7 @@ stepmmio(uvlong pa, uvlong *val, int size, ExitInfo *ei)
extern uchar *tmp; extern uchar *tmp;
extern uvlong tmpoff; extern uvlong tmpoff;
void *targ; void *targ;
uvlong pc, si; uvlong pc;
char buf[ERRMAX]; char buf[ERRMAX];
extern int getexit; extern int getexit;
@ -46,7 +46,6 @@ stepmmio(uvlong pa, uvlong *val, int size, ExitInfo *ei)
case 8: *(u64int*)targ = *val; break; case 8: *(u64int*)targ = *val; break;
} }
pc = rget(RPC); pc = rget(RPC);
si = rget("si");
rcflush(0); rcflush(0);
if(ctl("step -map %#ullx vm %#ullx", pa & ~0xfff, tmpoff) < 0){ if(ctl("step -map %#ullx vm %#ullx", pa & ~0xfff, tmpoff) < 0){
rerrstr(buf, sizeof(buf)); rerrstr(buf, sizeof(buf));
@ -262,7 +261,10 @@ cpuid(ExitInfo *ei)
ax = cp->ax; ax = cp->ax;
bx = 0; bx = 0;
cx = cp->cx & 0x121; cx = cp->cx & 0x121;
dx = cp->dx & 0x04100000; if(sizeof(uintptr) == 8)
dx = cp->dx & 0x24100800;
else
dx = cp->dx & 0x04100000;
break; break;
case 0x80000002: goto literal; /* brand string */ case 0x80000002: goto literal; /* brand string */
case 0x80000003: goto literal; /* brand string */ case 0x80000003: goto literal; /* brand string */
@ -308,10 +310,6 @@ rdwrmsr(ExitInfo *ei)
if(rd) val = rget("pat"); if(rd) val = rget("pat");
else rset("pat", val); else rset("pat", val);
break; break;
case 0xC0000080:
if(rd) val = rget("efer");
else rset("efer", val);
break;
case 0x8B: val = 0; break; /* microcode update */ case 0x8B: val = 0; break; /* microcode update */
default: default:
if(rd){ if(rd){
@ -376,7 +374,7 @@ movcr(ExitInfo *ei)
} }
break; break;
case 4: case 4:
switch(ei->qual >> 4 & 3){ switch(q >> 4 & 3){
case 0: case 0:
vmdebug("illegal CR4 write, value %#ux", rget(x86reg[q >> 8 & 15])); vmdebug("illegal CR4 write, value %#ux", rget(x86reg[q >> 8 & 15]));
rset("cr4real", rget(x86reg[q >> 8 & 15])); rset("cr4real", rget(x86reg[q >> 8 & 15]));

View file

@ -14,27 +14,48 @@ extern char **bootmod;
extern int cmdlinen; extern int cmdlinen;
extern char **cmdlinev; extern char **cmdlinev;
static int elf64;
static int static int
isusermem(Region *r) biostype(Region *r)
{ {
return r->type == REGMEM; return r->type >> 8 & 0xff;
}
static void *
pack(void *v, char *fmt, ...)
{
uchar *p;
va_list va;
p = v;
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);
return p;
} }
static int static int
putmmap(uchar *p0) putmmap(uchar *p0)
{ {
u32int *p; uchar *p;
Region *r; Region *r;
int t;
p = (u32int *) p0; p = p0;
for(r = mmap; r != nil; r = r->next){ for(r = mmap; r != nil; r = r->next){
if(!isusermem(r)) continue; t = biostype(r);
if(gavail(p) < 20) sysfatal("out of guest memory"); if(t == 0) continue;
p[0] = 20; if(gavail(p) < 24) sysfatal("out of guest memory");
p[1] = r->start; p = pack(p, "ivvi", 20, (uvlong) r->start, (uvlong)(r->end - r->start), t);
p[2] = r->end - r->start;
p[3] = 1;
} }
return (uchar *) p - p0; return (uchar *) p - p0;
} }
@ -131,6 +152,7 @@ trymultiboot(void)
bssend = -(-bssend & -BY2PG); bssend = -(-bssend & -BY2PG);
p = gptr(bssend, 128); p = gptr(bssend, 128);
if(p == nil) sysfatal("no space for multiboot structure"); if(p == nil) sysfatal("no space for multiboot structure");
memset(p, 0, 128);
p[0] = 1<<0; p[0] = 1<<0;
p[1] = gavail(gptr(0, 0)) >> 10; p[1] = gavail(gptr(0, 0)) >> 10;
if(p[1] > 640) p[1] = 640; if(p[1] > 640) p[1] = 640;
@ -165,7 +187,6 @@ trymultiboot(void)
return 1; return 1;
} }
static int elf64;
typedef struct ELFHeader ELFHeader; typedef struct ELFHeader ELFHeader;
struct ELFHeader { struct ELFHeader {
uintptr entry, phoff, shoff; uintptr entry, phoff, shoff;
@ -283,11 +304,19 @@ static void
elfsymbol(ELFSymbol *s, uchar *p, uchar *e) elfsymbol(ELFSymbol *s, uchar *p, uchar *e)
{ {
s->iname = elff(&p, e, 4); s->iname = elff(&p, e, 4);
s->addr = elff(&p, e, -1); if(elf64){
s->size = elff(&p, e, -1); s->info = elff(&p, e, 1);
s->info = elff(&p, e, 1); s->other = elff(&p, e, 1);
s->other = elff(&p, e, 1); s->shndx = elff(&p, e, 2);
s->shndx = elff(&p, e, 2); s->addr = elff(&p, e, -1);
s->size = elff(&p, e, -1);
}else{
s->addr = elff(&p, e, -1);
s->size = elff(&p, e, -1);
s->info = elff(&p, e, 1);
s->other = elff(&p, e, 1);
s->shndx = elff(&p, e, 2);
}
} }
static void static void
@ -442,7 +471,7 @@ symaddr(ELFSymbol *s)
} }
static uchar *obsdarg, *obsdarg0, *obsdargnext; static uchar *obsdarg, *obsdarg0, *obsdargnext;
static int obsdargc; static int obsdarglen;
static int obsdconsdev = 12 << 8, obsddbcons = -1, obsdbootdev; static int obsdconsdev = 12 << 8, obsddbcons = -1, obsdbootdev;
enum { enum {
@ -459,35 +488,8 @@ enum {
BOOTARG_BOOTSR, BOOTARG_BOOTSR,
BOOTARG_EFIINFO, BOOTARG_EFIINFO,
BOOTARG_END = -1, BOOTARG_END = -1,
BIOS_MAP_END = 0,
BIOS_MAP_FREE,
BIOS_MAP_RES,
BIOS_MAP_ACPI,
BIOS_MAP_NVS,
}; };
static void *
pack(void *v, char *fmt, ...)
{
uchar *p;
va_list va;
p = v;
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);
return p;
}
static void static void
obsdelfload(void) obsdelfload(void)
{ {
@ -546,28 +548,25 @@ obsdend(void)
{ {
if(obsdarg == obsdarg0 + 12) obsdarg += 4; if(obsdarg == obsdarg0 + 12) obsdarg += 4;
PUT32(obsdarg0, 4, obsdarg - obsdarg0); /* size */ PUT32(obsdarg0, 4, obsdarg - obsdarg0); /* size */
obsdarglen += obsdarg - obsdarg0;
PUT32(obsdargnext, 0, gpa(obsdarg0)); PUT32(obsdargnext, 0, gpa(obsdarg0));
obsdargnext = obsdarg0 + 8; obsdargnext = obsdarg0 + 8;
obsdarg0 = nil; obsdarg0 = nil;
obsdargc++;
} }
static void static void
obsdargs(void) obsdargs(void)
{ {
Region *r; Region *r;
uvlong s, e; int t;
obsdstart(BOOTARG_MEMMAP); obsdstart(BOOTARG_MEMMAP);
obsdpack("vvi", (uvlong)0, (uvlong)0xa0000, BIOS_MAP_FREE);
for(r = mmap; r != nil; r = r->next){ for(r = mmap; r != nil; r = r->next){
s = r->start; t = biostype(r);
e = r->end; if(t == 0) continue;
if(s < (1<<20)) s = 1<<20; obsdpack("vvi", (uvlong)r->start, (uvlong)(r->end - r->start), t);
if(e <= s || r->type == REGFB) continue;
obsdpack("vvi", s, e - s, isusermem(r) ? BIOS_MAP_FREE : BIOS_MAP_RES);
} }
obsdpack("vvi", 0ULL, 0ULL, BIOS_MAP_END); obsdpack("vvi", 0ULL, 0ULL, 0);
obsdend(); obsdend();
obsdstart(BOOTARG_CONSDEV); obsdpack("iiii", obsdconsdev, -1, -1, 0); obsdend(); obsdstart(BOOTARG_CONSDEV); obsdpack("iiii", obsdconsdev, -1, -1, 0); obsdend();
if(obsddbcons != -1){ if(obsddbcons != -1){
@ -668,7 +667,7 @@ obsdload(void)
obsdargnext = &v[32]; /* bootargv */ obsdargnext = &v[32]; /* bootargv */
obsdargs(); obsdargs();
assert(obsdarg0 == nil); assert(obsdarg0 == nil);
PUT32(v, 28, obsdargc); /* bootargc */ PUT32(v, 28, obsdarglen); /* bootargc */
rset(RSP, sp); rset(RSP, sp);
rset(RPC, eh.entry); rset(RPC, eh.entry);
return 1; return 1;
@ -708,7 +707,6 @@ linuxbootmod(char *fn, void *zp, u32int kend)
if(addr >= memend) addr = memend - 1; if(addr >= memend) addr = memend - 1;
if((addr - (sz - 1) & -4) < kend) sysfatal("linux: no room for initrd"); if((addr - (sz - 1) & -4) < kend) sysfatal("linux: no room for initrd");
addr = addr - (sz - 1) & -4; addr = addr - (sz - 1) & -4;
print("%#ux %#ux\n", addr, (u32int)sz);
v = gptr(addr, sz); v = gptr(addr, sz);
if(v == nil) sysfatal("linux: initrd: gptr failed"); if(v == nil) sysfatal("linux: initrd: gptr failed");
seek(fd, 0, 0); seek(fd, 0, 0);
@ -799,18 +797,15 @@ linuxe820(uchar *zp)
{ {
Region *r; Region *r;
uchar *v; uchar *v;
uvlong s, e; int t;
int n; int n;
v = zp + 0x2d0; v = zp + 0x2d0;
v = pack(v, "vvi", (uvlong)0, (uvlong)0xa0000, BIOS_MAP_FREE);
n = 1; n = 1;
for(r = mmap; r != nil; r = r->next){ for(r = mmap; r != nil; r = r->next){
s = r->start; t = biostype(r);
e = r->end; if(t == 0) continue;
if(s < (1<<20)) s = 1<<20; v = pack(v, "vvi", r->start, r->end - r->start, t);
if(e <= s || r->type == REGFB) continue;
v = pack(v, "vvi", s, e - s, isusermem(r) ? BIOS_MAP_FREE : BIOS_MAP_RES);
n++; n++;
} }
PUT8(zp, 0x1e8, n); PUT8(zp, 0x1e8, n);

View file

@ -86,7 +86,7 @@ vioirq_(void *arg)
int val; int val;
d = ((void**)arg)[0]; d = ((void**)arg)[0];
val = (int) ((void**)arg)[1]; val = (uintptr)((void**)arg)[1];
if(val != 0) if(val != 0)
d->isrstat |= val; d->isrstat |= val;
else else

View file

@ -64,7 +64,9 @@ vmxsetup(void)
static int fd; static int fd;
static char buf[128]; static char buf[128];
Region *r; Region *r;
int rc; uvlong start, end, off;
char *name;
int rc, type;
fd = open("#X/status", OREAD); fd = open("#X/status", OREAD);
if(fd < 0) sysfatal("open: %r"); if(fd < 0) sysfatal("open: %r");
@ -85,9 +87,26 @@ vmxsetup(void)
fd = open("#X/map", OWRITE|OTRUNC); fd = open("#X/map", OWRITE|OTRUNC);
if(fd < 0) sysfatal("open: %r"); if(fd < 0) sysfatal("open: %r");
for(r = mmap; r != nil; r = r->next) for(r = mmap; r != nil; ){
if(r->segname != nil && fprint(fd, "rwx wb %#ullx %#ullx %s %#ullx\n", (uvlong)r->start, (uvlong)r->end, r->segname, r->segoff) < 0) if(r->segname == nil){
r = r->next;
continue;
}
start = r->start;
end = r->end;
name = r->segname;
off = r->segoff;
type = r->type;
while(r = r->next, r != nil){
if(r->segname == nil)
continue;
if(r->start != end || r->segoff != off + end - start || ((r->type ^ type) & REGRO) != 0)
break;
end = r->end;
}
if(fprint(fd, "r%cx wb %#ullx %#ullx %s %#ullx\n", (type & REGRO) != 0 ? '-' : 'w', start, end, name, off) < 0)
sysfatal("writing memory map: %r"); sysfatal("writing memory map: %r");
}
close(fd); close(fd);
waitfd = open("#X/wait", OREAD); waitfd = open("#X/wait", OREAD);
@ -205,16 +224,15 @@ goti:
} }
Region * Region *
mkregion(u64int pa, u64int len, int type) mkregion(u64int pa, u64int end, int type)
{ {
Region *r, **rp; Region *r, **rp;
assert(pa + len >= pa);
r = emalloc(sizeof(Region)); r = emalloc(sizeof(Region));
if((pa & BY2PG-1) != 0) sysfatal("address %p not page aligned", (void*)pa); if(end < pa) sysfatal("end of region %p before start of region %p", (void*)end, (void*)pa);
if((pa & BY2PG-1) != 0 || (end & BY2PG-1) != 0) sysfatal("address %p not page aligned", (void*)pa);
r->start = pa; r->start = pa;
len = -(-len & -BY2PG); r->end = end;
r->end = pa + len;
r->type = type; r->type = type;
for(rp = &mmap; *rp != nil; rp = &(*rp)->next) for(rp = &mmap; *rp != nil; rp = &(*rp)->next)
; ;
@ -245,7 +263,7 @@ gpa(void *v)
for(r = mmap; r != nil; r = r->next) for(r = mmap; r != nil; r = r->next)
if(v >= r->v && v < r->ve) if(v >= r->v && v < r->ve)
return (uchar *) v - (uchar *) r->v; return (uchar *) v - (uchar *) r->v + r->start;
return -1; return -1;
} }
@ -280,10 +298,8 @@ mksegment(char *sn)
sz = BY2PG; sz = BY2PG;
for(r = mmap; r != nil; r = r->next){ for(r = mmap; r != nil; r = r->next){
switch(r->type){ if((r->type & REGALLOC) == 0)
case REGMEM: case REGFB: break; continue;
default: continue;
}
r->segname = sn; r->segname = sn;
if(sz + (r->end - r->start) < sz) if(sz + (r->end - r->start) < sz)
sysfatal("out of address space"); sysfatal("out of address space");
@ -304,7 +320,7 @@ mksegment(char *sn)
gmem = segattach(0, sn, nil, sz); gmem = segattach(0, sn, nil, sz);
if(gmem == (void*)-1) sysfatal("segattach: %r"); if(gmem == (void*)-1) sysfatal("segattach: %r");
} }
memset(gmem, 0, sz > 1>>24 ? 1>>24 : sz); memset(gmem, 0, sz > 1<<24 ? 1<<24 : sz);
p = gmem; p = gmem;
for(r = mmap; r != nil; r = r->next){ for(r = mmap; r != nil; r = r->next){
if(r->segname == nil) continue; if(r->segname == nil) continue;
@ -537,11 +553,19 @@ threadmain(int argc, char **argv)
cmdlinen = argc - 1; cmdlinen = argc - 1;
cmdlinev = argv + 1; cmdlinev = argv + 1;
mkregion(0, gmemsz, REGMEM); if(gmemsz < 1<<20) sysfatal("640 KB of RAM is not enough for everyone");
mkregion(0, 0xa0000, REGALLOC|REGFREE);
mkregion(0xa0000, 0xc0000, REGALLOC);
mkregion(0xc0000, 0x100000, REGALLOC|REGRES);
if(fbsz != 0 && fbaddr < gmemsz){
mkregion(0x100000, fbaddr, REGALLOC|REGFREE);
mkregion(fbaddr + fbsz, gmemsz, REGALLOC|REGFREE);
}else
mkregion(0x100000, gmemsz, REGALLOC|REGFREE);
if(fbsz != 0){ if(fbsz != 0){
if(fbaddr + fbsz < fbaddr) sysfatal("invalid fb address"); if(fbaddr < 1<<20) sysfatal("framebuffer must not be within first 1 MB");
if(fbaddr + fbsz < gmemsz) sysfatal("framebuffer overlaps with physical memory"); if(fbaddr != (u32int) fbaddr || (u32int)(fbaddr+fbsz) < fbaddr) sysfatal("framebuffer must be within first 4 GB");
mkregion(fbaddr, fbsz, REGFB); mkregion(fbaddr, fbaddr+fbsz, REGALLOC);
} }
mksegment("vm"); mksegment("vm");
vmxsetup(); vmxsetup();