vmx(1): clean up region handling code; changes to support amd64
This commit is contained in:
parent
becb89bae5
commit
164588e3e2
5 changed files with 115 additions and 91 deletions
|
@ -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;
|
||||
|
|
|
@ -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]));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue