ref: 164588e3e2aca1f6deac1dd4bcf962a0867a26fc
parent: becb89bae53e01785bfd843478737eeb77a9419f
author: aiju <devnull@localhost>
date: Tue Jun 20 11:15:53 EDT 2017
vmx(1): clean up region handling code; changes to support amd64
--- a/sys/src/cmd/vmx/dat.h
+++ b/sys/src/cmd/vmx/dat.h
@@ -35,7 +35,14 @@
struct Region {
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;
uvlong segoff;
void *v, *ve;
--- a/sys/src/cmd/vmx/exith.c
+++ b/sys/src/cmd/vmx/exith.c
@@ -33,7 +33,7 @@
extern uchar *tmp;
extern uvlong tmpoff;
void *targ;
- uvlong pc, si;
+ uvlong pc;
char buf[ERRMAX];
extern int getexit;
@@ -46,7 +46,6 @@
case 8: *(u64int*)targ = *val; break;
}
pc = rget(RPC);
- si = rget("si");
rcflush(0);
if(ctl("step -map %#ullx vm %#ullx", pa & ~0xfff, tmpoff) < 0){
rerrstr(buf, sizeof(buf));
@@ -262,7 +261,10 @@
ax = cp->ax;
bx = 0;
cx = cp->cx & 0x121;
- dx = cp->dx & 0x04100000;
+ if(sizeof(uintptr) == 8)
+ dx = cp->dx & 0x24100800;
+ else
+ dx = cp->dx & 0x04100000;
break;
case 0x80000002: goto literal; /* brand string */
case 0x80000003: goto literal; /* brand string */
@@ -308,10 +310,6 @@
if(rd) val = rget("pat");
else rset("pat", val);
break;
- case 0xC0000080:
- if(rd) val = rget("efer");
- else rset("efer", val);
- break;
case 0x8B: val = 0; break; /* microcode update */
default:
if(rd){
@@ -376,7 +374,7 @@
}
break;
case 4:
- switch(ei->qual >> 4 & 3){
+ switch(q >> 4 & 3){
case 0:
vmdebug("illegal CR4 write, value %#ux", rget(x86reg[q >> 8 & 15]));
rset("cr4real", rget(x86reg[q >> 8 & 15]));
--- a/sys/src/cmd/vmx/ksetup.c
+++ b/sys/src/cmd/vmx/ksetup.c
@@ -14,27 +14,48 @@
extern int cmdlinen;
extern char **cmdlinev;
+static int elf64;
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
putmmap(uchar *p0)
{
- u32int *p;
+ uchar *p;
Region *r;
+ int t;
- p = (u32int *) p0;
+ p = p0;
for(r = mmap; r != nil; r = r->next){
- if(!isusermem(r)) continue;
- if(gavail(p) < 20) sysfatal("out of guest memory");
- p[0] = 20;
- p[1] = r->start;
- p[2] = r->end - r->start;
- p[3] = 1;
+ t = biostype(r);
+ if(t == 0) continue;
+ if(gavail(p) < 24) sysfatal("out of guest memory");
+ p = pack(p, "ivvi", 20, (uvlong) r->start, (uvlong)(r->end - r->start), t);
}
return (uchar *) p - p0;
}
@@ -131,6 +152,7 @@
bssend = -(-bssend & -BY2PG);
p = gptr(bssend, 128);
if(p == nil) sysfatal("no space for multiboot structure");
+ memset(p, 0, 128);
p[0] = 1<<0;
p[1] = gavail(gptr(0, 0)) >> 10;
if(p[1] > 640) p[1] = 640;
@@ -165,7 +187,6 @@
return 1;
}
-static int elf64;
typedef struct ELFHeader ELFHeader;
struct ELFHeader {
uintptr entry, phoff, shoff;
@@ -283,11 +304,19 @@
elfsymbol(ELFSymbol *s, uchar *p, uchar *e)
{
s->iname = elff(&p, e, 4);
- 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);
+ if(elf64){
+ s->info = elff(&p, e, 1);
+ s->other = elff(&p, e, 1);
+ 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
@@ -442,7 +471,7 @@
}
static uchar *obsdarg, *obsdarg0, *obsdargnext;
-static int obsdargc;
+static int obsdarglen;
static int obsdconsdev = 12 << 8, obsddbcons = -1, obsdbootdev;
enum {
@@ -459,35 +488,8 @@
BOOTARG_BOOTSR,
BOOTARG_EFIINFO,
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
obsdelfload(void)
{
@@ -546,10 +548,10 @@
{
if(obsdarg == obsdarg0 + 12) obsdarg += 4;
PUT32(obsdarg0, 4, obsdarg - obsdarg0); /* size */
+ obsdarglen += obsdarg - obsdarg0;
PUT32(obsdargnext, 0, gpa(obsdarg0));
obsdargnext = obsdarg0 + 8;
obsdarg0 = nil;
- obsdargc++;
}
static void
@@ -556,18 +558,15 @@
obsdargs(void)
{
Region *r;
- uvlong s, e;
+ int t;
obsdstart(BOOTARG_MEMMAP);
- obsdpack("vvi", (uvlong)0, (uvlong)0xa0000, BIOS_MAP_FREE);
for(r = mmap; r != nil; r = r->next){
- s = r->start;
- e = r->end;
- if(s < (1<<20)) s = 1<<20;
- if(e <= s || r->type == REGFB) continue;
- obsdpack("vvi", s, e - s, isusermem(r) ? BIOS_MAP_FREE : BIOS_MAP_RES);
+ t = biostype(r);
+ if(t == 0) continue;
+ obsdpack("vvi", (uvlong)r->start, (uvlong)(r->end - r->start), t);
}
- obsdpack("vvi", 0ULL, 0ULL, BIOS_MAP_END);
+ obsdpack("vvi", 0ULL, 0ULL, 0);
obsdend();
obsdstart(BOOTARG_CONSDEV); obsdpack("iiii", obsdconsdev, -1, -1, 0); obsdend();
if(obsddbcons != -1){
@@ -668,7 +667,7 @@
obsdargnext = &v[32]; /* bootargv */
obsdargs();
assert(obsdarg0 == nil);
- PUT32(v, 28, obsdargc); /* bootargc */
+ PUT32(v, 28, obsdarglen); /* bootargc */
rset(RSP, sp);
rset(RPC, eh.entry);
return 1;
@@ -708,7 +707,6 @@
if(addr >= memend) addr = memend - 1;
if((addr - (sz - 1) & -4) < kend) sysfatal("linux: no room for initrd");
addr = addr - (sz - 1) & -4;
- print("%#ux %#ux\n", addr, (u32int)sz);
v = gptr(addr, sz);
if(v == nil) sysfatal("linux: initrd: gptr failed");
seek(fd, 0, 0);
@@ -799,18 +797,15 @@
{
Region *r;
uchar *v;
- uvlong s, e;
+ int t;
int n;
v = zp + 0x2d0;
- v = pack(v, "vvi", (uvlong)0, (uvlong)0xa0000, BIOS_MAP_FREE);
n = 1;
for(r = mmap; r != nil; r = r->next){
- s = r->start;
- e = r->end;
- if(s < (1<<20)) s = 1<<20;
- if(e <= s || r->type == REGFB) continue;
- v = pack(v, "vvi", s, e - s, isusermem(r) ? BIOS_MAP_FREE : BIOS_MAP_RES);
+ t = biostype(r);
+ if(t == 0) continue;
+ v = pack(v, "vvi", r->start, r->end - r->start, t);
n++;
}
PUT8(zp, 0x1e8, n);
--- a/sys/src/cmd/vmx/virtio.c
+++ b/sys/src/cmd/vmx/virtio.c
@@ -86,7 +86,7 @@
int val;
d = ((void**)arg)[0];
- val = (int) ((void**)arg)[1];
+ val = (uintptr)((void**)arg)[1];
if(val != 0)
d->isrstat |= val;
else
--- a/sys/src/cmd/vmx/vmx.c
+++ b/sys/src/cmd/vmx/vmx.c
@@ -64,7 +64,9 @@
static int fd;
static char buf[128];
Region *r;
- int rc;
+ uvlong start, end, off;
+ char *name;
+ int rc, type;
fd = open("#X/status", OREAD);
if(fd < 0) sysfatal("open: %r");
@@ -85,9 +87,26 @@
fd = open("#X/map", OWRITE|OTRUNC);
if(fd < 0) sysfatal("open: %r");
- for(r = mmap; r != nil; r = r->next)
- if(r->segname != nil && fprint(fd, "rwx wb %#ullx %#ullx %s %#ullx\n", (uvlong)r->start, (uvlong)r->end, r->segname, r->segoff) < 0)
+ for(r = mmap; r != nil; ){
+ 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");
+ }
close(fd);
waitfd = open("#X/wait", OREAD);
@@ -205,16 +224,15 @@
}
Region *
-mkregion(u64int pa, u64int len, int type)
+mkregion(u64int pa, u64int end, int type)
{
Region *r, **rp;
-
- assert(pa + len >= pa);
+
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;
- len = -(-len & -BY2PG);
- r->end = pa + len;
+ r->end = end;
r->type = type;
for(rp = &mmap; *rp != nil; rp = &(*rp)->next)
;
@@ -245,7 +263,7 @@
for(r = mmap; r != nil; r = r->next)
if(v >= r->v && v < r->ve)
- return (uchar *) v - (uchar *) r->v;
+ return (uchar *) v - (uchar *) r->v + r->start;
return -1;
}
@@ -280,10 +298,8 @@
sz = BY2PG;
for(r = mmap; r != nil; r = r->next){
- switch(r->type){
- case REGMEM: case REGFB: break;
- default: continue;
- }
+ if((r->type & REGALLOC) == 0)
+ continue;
r->segname = sn;
if(sz + (r->end - r->start) < sz)
sysfatal("out of address space");
@@ -304,7 +320,7 @@
gmem = segattach(0, sn, nil, sz);
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;
for(r = mmap; r != nil; r = r->next){
if(r->segname == nil) continue;
@@ -537,11 +553,19 @@
cmdlinen = argc - 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(fbaddr + fbsz < fbaddr) sysfatal("invalid fb address");
- if(fbaddr + fbsz < gmemsz) sysfatal("framebuffer overlaps with physical memory");
- mkregion(fbaddr, fbsz, REGFB);
+ if(fbaddr < 1<<20) sysfatal("framebuffer must not be within first 1 MB");
+ if(fbaddr != (u32int) fbaddr || (u32int)(fbaddr+fbsz) < fbaddr) sysfatal("framebuffer must be within first 4 GB");
+ mkregion(fbaddr, fbaddr+fbsz, REGALLOC);
}
mksegment("vm");
vmxsetup();