diff --git a/sys/src/cmd/vmx/dat.h b/sys/src/cmd/vmx/dat.h index 35b69f2b8..156fdaa58 100644 --- a/sys/src/cmd/vmx/dat.h +++ b/sys/src/cmd/vmx/dat.h @@ -35,7 +35,14 @@ enum { 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; diff --git a/sys/src/cmd/vmx/exith.c b/sys/src/cmd/vmx/exith.c index 0c27bc9bd..939763dcd 100644 --- a/sys/src/cmd/vmx/exith.c +++ b/sys/src/cmd/vmx/exith.c @@ -33,7 +33,7 @@ stepmmio(uvlong pa, uvlong *val, int size, ExitInfo *ei) extern uchar *tmp; extern uvlong tmpoff; void *targ; - uvlong pc, si; + uvlong pc; char buf[ERRMAX]; extern int getexit; @@ -46,7 +46,6 @@ stepmmio(uvlong pa, uvlong *val, int size, ExitInfo *ei) 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 @@ cpuid(ExitInfo *ei) 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 @@ rdwrmsr(ExitInfo *ei) 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 @@ movcr(ExitInfo *ei) } 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])); diff --git a/sys/src/cmd/vmx/ksetup.c b/sys/src/cmd/vmx/ksetup.c index 3dac6de8b..db3cc56d9 100644 --- a/sys/src/cmd/vmx/ksetup.c +++ b/sys/src/cmd/vmx/ksetup.c @@ -14,27 +14,48 @@ extern char **bootmod; 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 @@ trymultiboot(void) 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 @@ trymultiboot(void) return 1; } -static int elf64; typedef struct ELFHeader ELFHeader; struct ELFHeader { uintptr entry, phoff, shoff; @@ -283,11 +304,19 @@ static void 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 @@ symaddr(ELFSymbol *s) } static uchar *obsdarg, *obsdarg0, *obsdargnext; -static int obsdargc; +static int obsdarglen; static int obsdconsdev = 12 << 8, obsddbcons = -1, obsdbootdev; enum { @@ -459,35 +488,8 @@ enum { 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,28 +548,25 @@ obsdend(void) { 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 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 @@ obsdload(void) 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 @@ linuxbootmod(char *fn, void *zp, u32int kend) 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 @@ linuxe820(uchar *zp) { 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); diff --git a/sys/src/cmd/vmx/virtio.c b/sys/src/cmd/vmx/virtio.c index d4d573fc7..420974a7d 100644 --- a/sys/src/cmd/vmx/virtio.c +++ b/sys/src/cmd/vmx/virtio.c @@ -86,7 +86,7 @@ vioirq_(void *arg) int val; d = ((void**)arg)[0]; - val = (int) ((void**)arg)[1]; + val = (uintptr)((void**)arg)[1]; if(val != 0) d->isrstat |= val; else diff --git a/sys/src/cmd/vmx/vmx.c b/sys/src/cmd/vmx/vmx.c index e868d7266..902405c8a 100644 --- a/sys/src/cmd/vmx/vmx.c +++ b/sys/src/cmd/vmx/vmx.c @@ -64,7 +64,9 @@ vmxsetup(void) 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 @@ vmxsetup(void) 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 @@ goti: } 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 @@ gpa(void *v) 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 @@ mksegment(char *sn) 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 @@ mksegment(char *sn) 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 @@ threadmain(int argc, char **argv) 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();