ref: 9616f6187202900fa8d86d197d5b7bc56f83609b
parent: 174d7e52a3fd4b48bece311415fbdd9e1bb85ccc
author: aiju <devnull@localhost>
date: Thu Aug 24 03:53:10 EDT 2017
devvmx: more efficient data structure for memory map; simplified (more reliable) step function
--- a/sys/src/9/pc/devvmx.c
+++ b/sys/src/9/pc/devvmx.c
@@ -223,7 +223,7 @@
typedef struct VmIntr VmIntr;
struct VmMem {
- uvlong lo, hi;
+ uvlong addr;
Segment *seg;
uintptr off;
char *name;
@@ -271,10 +271,7 @@
enum {
GOTEXIT = 1,
GOTIRQACK = 2,
- GOTSTEP = 4,
- GOTSTEPERR = 8,
} got;
- VmMem *stepmap;
VmIntr exc, irq, irqack;
u64int *msrhost, *msrguest;
@@ -619,11 +616,11 @@
}
static void
-epttranslate(VmMem *mp)
+epttranslate(VmMem *mp, uvlong end)
{
uvlong p, v;
- if((mp->lo & 0xfff) != 0 || (mp->hi & 0xfff) != 0 || (uint)mp->attr >= 0x1000)
+ if((mp->addr & 0xfff) != 0 || (end & 0xfff) != 0 || (uint)mp->attr >= 0x1000)
error(Egreg);
if(mp->seg != nil){
switch(mp->seg->type & SG_TYPE){
@@ -633,13 +630,13 @@
case SG_STICKY:
break;
}
- if(mp->seg->base + mp->off + (mp->hi - mp->lo) > mp->seg->top)
+ if(mp->seg->base + mp->off + (end - mp->addr) > mp->seg->top)
error(Egreg);
- for(p = mp->lo, v = mp->off; p < mp->hi; p += BY2PG, v += BY2PG)
+ for(p = mp->addr, v = mp->off; p != end; p += BY2PG, v += BY2PG)
*eptwalk(p) = mp->seg->map[v/PTEMAPMEM]->pages[(v & PTEMAPMEM-1)/BY2PG]->pa | mp->attr;
}else {
- for(p = mp->lo; p < mp->hi; p += BY2PG)
- *eptwalk(p) = mp->attr;
+ for(p = mp->addr; p != end; p += BY2PG)
+ *eptwalk(p) = 0;
}
vmx.onentry |= FLUSHEPT;
}
@@ -657,7 +654,10 @@
p0 = va_arg(va, char *);
e = va_arg(va, char *);
p = p0;
+ if(p < e) *p = 0;
for(mp = vmx.mem.next; mp != &vmx.mem; mp = mp->next){
+ if(mp->seg == nil)
+ continue;
attr[0] = (mp->attr & 1) != 0 ? 'r' : '-';
attr[1] = (mp->attr & 2) != 0 ? 'w' : '-';
attr[2] = (mp->attr & 4) != 0 ? 'x' : '-';
@@ -665,26 +665,42 @@
*(ushort*)mt = *(u16int*)mtype[mp->attr >> 3 & 7];
mt[2] = (mp->attr & 0x40) != 0 ? '!' : 0;
mt[3] = 0;
- if(mp->name == nil)
- p = seprint(p, e, "%s %s %#llux %#llux\n", attr, mt, mp->lo, mp->hi);
- else
- p = seprint(p, e, "%s %s %#llux %#llux %s %#llux\n", attr, mt, mp->lo, mp->hi, mp->name, (uvlong)mp->off);
+ p = seprint(p, e, "%s %s %#llux %#llux %s %#llux\n", attr, mt, mp->addr, mp->next->addr, mp->name, (uvlong)mp->off);
}
return p - p0;
}
+static void
+vmmeminsert(VmMem *l, VmMem *p)
+{
+ p->prev = l->prev;
+ p->next = l;
+ p->prev->next = p;
+ p->next->prev = p;
+}
+
+static VmMem *
+vmmemremove(VmMem *p)
+{
+ VmMem *r;
+
+ r = p->next;
+ p->next->prev = p->prev;
+ p->prev->next = p->next;
+ free(p->name);
+ putseg(p->seg);
+ free(p);
+ return r;
+}
+
static int
cmdclearmeminfo(VmCmd *, va_list)
{
- VmMem *mp, *mn;
+ VmMem *mp;
eptfree(vmx.pml4, 0);
- for(mp = vmx.mem.next; mp != &vmx.mem; mp = mn){
- free(mp->name);
- putseg(mp->seg);
- mn = mp->next;
- free(mp);
- }
+ for(mp = vmx.mem.next; mp != &vmx.mem; )
+ mp = vmmemremove(mp);
vmx.mem.prev = &vmx.mem;
vmx.mem.next = &vmx.mem;
vmx.onentry |= FLUSHEPT;
@@ -691,6 +707,41 @@
return 0;
}
+
+static void
+vmmemupdate(VmMem *mp, uvlong end)
+{
+ VmMem *p, *q;
+
+ for(p = vmx.mem.prev; p != &vmx.mem; p = p->prev)
+ if(p->addr <= end || end == 0)
+ break;
+ if(p == &vmx.mem || p->addr < mp->addr){
+ q = smalloc(sizeof(VmMem));
+ *q = *p;
+ if(p->seg != nil){
+ incref(q->seg);
+ kstrdup(&q->name, p->name);
+ }
+ vmmeminsert(p->next, q);
+ }else
+ q = p;
+ if(q->seg != nil)
+ q->off += end - q->addr;
+ q->addr = end;
+ for(p = vmx.mem.next; p != &vmx.mem; p = p->next)
+ if(p->addr >= mp->addr)
+ break;
+ vmmeminsert(p, mp);
+ while(p != q)
+ p = vmmemremove(p);
+ for(p = vmx.mem.next; p != &vmx.mem; )
+ if(p->seg == p->prev->seg && (p->seg == nil || p->addr - p->prev->addr == p->off - p->prev->off))
+ p = vmmemremove(p);
+ else
+ p = p->next;
+}
+
extern Segment* (*_globalsegattach)(char*);
static int
@@ -701,6 +752,7 @@
char *f[10];
VmMem *mp;
int rc;
+ uvlong end;
if(vmx.pml4 == nil)
error(Egreg);
@@ -725,7 +777,10 @@
}
rc = tokenize(p, f, nelem(f));
p = q + 1;
- if(rc == 0) goto next;
+ if(rc == 0){
+ poperror();
+ continue;
+ }
if(rc != 4 && rc != 6) error("number of fields wrong");
for(q = f[0]; *q != 0; q++)
switch(*q){
@@ -743,27 +798,23 @@
if(j == 8 || strlen(f[1]) > 3) error("invalid memory type");
if(f[1][2] == '!') mp->attr |= 0x40;
else if(f[1][2] != 0) error("invalid memory type");
- mp->lo = strtoull(f[2], &r, 0);
- if(*r != 0 || !vmokpage(mp->lo)) error("invalid low guest physical address");
- mp->hi = strtoull(f[3], &r, 0);
- if(*r != 0 || !vmokpage(mp->hi) || mp->hi <= mp->lo) error("invalid high guest physical address");
- mp->off = strtoull(f[5], &r, 0);
- if(*r != 0 || !vmokpage(mp->off)) error("invalid offset");
+ mp->addr = strtoull(f[2], &r, 0);
+ if(*r != 0 || !vmokpage(mp->addr)) error("invalid low guest physical address");
+ end = strtoull(f[3], &r, 0);
+ if(*r != 0 || !vmokpage(end) || end <= mp->addr) error("invalid high guest physical address");
if((mp->attr & 7) != 0){
if(rc != 6) error("number of fields wrong");
mp->seg = _globalsegattach(f[4]);
if(mp->seg == nil) error("no such segment");
- if(mp->seg->base + mp->off + (mp->hi - mp->lo) > mp->seg->top) error("out of bounds");
+ if(mp->seg->base + mp->off + (end - mp->addr) > mp->seg->top) error("out of bounds");
kstrdup(&mp->name, f[4]);
+ mp->off = strtoull(f[5], &r, 0);
+ if(*r != 0 || !vmokpage(mp->off)) error("invalid offset");
}
- epttranslate(mp);
- mp->prev = vmx.mem.prev;
- mp->next = &vmx.mem;
- mp->prev->next = mp;
- mp->next->prev = mp;
- mp = nil;
- next:
poperror();
+ epttranslate(mp, end);
+ vmmemupdate(mp, end);
+ mp = nil;
}
free(mp);
return p - p0;
@@ -1089,7 +1140,6 @@
}
vmx.got = 0;
vmx.onentry = 0;
- vmx.stepmap = nil;
free(vmx.msrhost);
free(vmx.msrguest);
@@ -1121,22 +1171,10 @@
case 7: /* IRQ window */
case 8: /* NMI window */
return;
- case 37:
- if((vmx.onentry & STEP) != 0){
- vmx.state = VMXREADY;
- vmx.got |= GOTSTEP;
- vmx.onentry &= ~STEP;
- return;
- }
- break;
}
- if((vmx.onentry & STEP) != 0){
- print("VMX: exit reason %#x when expected step...\n", reason & 0xffff);
- vmx.onentry &= ~STEP;
- vmx.got |= GOTSTEP|GOTSTEPERR;
- }
vmx.state = VMXREADY;
vmx.got |= GOTEXIT;
+ vmx.onentry &= ~STEP;
}
static int
@@ -1252,12 +1290,15 @@
static int
cmdgo(VmCmd *, va_list va)
{
+ int step;
char *r;
if(vmx.state != VMXREADY)
error("VM not ready");
+ step = va_arg(va, int);
r = va_arg(va, char *);
if(r != nil) setregs(r, ';', "=");
+ if(step) vmx.onentry |= STEP;
vmx.state = VMXRUNNING;
return 0;
}
@@ -1342,43 +1383,6 @@
return p - p0;
}
-static int
-cmdstep(VmCmd *cp, va_list va)
-{
- switch(cp->retval){
- case 0:
- if((vmx.got & GOTSTEP) != 0 || (vmx.onentry & STEP) != 0)
- error(Einuse);
- if(vmx.state != VMXREADY){
- print("pre-step in state %s\n", statenames[vmx.state]);
- error("not ready");
- }
- vmx.stepmap = va_arg(va, VmMem *);
- vmx.onentry |= STEP;
- vmx.state = VMXRUNNING;
- cp->flags |= CMDFPOSTP;
- return 1;
- case 1:
- if(vmx.state != VMXREADY){
- print("post-step in state %s\n", statenames[vmx.state]);
- vmx.onentry &= ~STEP;
- vmx.got &= ~(GOTSTEP|GOTSTEPERR);
- error("not ready");
- }
- if((vmx.got & GOTSTEP) == 0){
- cp->flags |= CMDFPOSTP;
- return 1;
- }
- if((vmx.got & GOTSTEPERR) != 0){
- vmx.got &= ~(GOTSTEP|GOTSTEPERR);
- error("step failed");
- }
- vmx.got &= ~(GOTSTEP|GOTSTEPERR);
- return 1;
- }
- return 0;
-}
-
static void
eventparse(char *p, VmIntr *vi)
{
@@ -1548,28 +1552,6 @@
}
static void
-dostep(int setup)
-{
- static uvlong oldmap;
- static uvlong *mapptr;
-
- if(setup){
- if(vmx.stepmap != nil){
- mapptr = eptwalk(vmx.stepmap->lo);
- oldmap = *mapptr;
- epttranslate(vmx.stepmap);
- }
- }else{
- vmcswrite(PROCB_CTLS, vmcsread(PROCB_CTLS) & ~(uvlong)PROCB_MONTRAP);
- if(vmx.stepmap != nil){
- *mapptr = oldmap;
- vmx.stepmap = nil;
- vmx.onentry |= FLUSHEPT;
- }
- }
-}
-
-static void
vmxproc(void *)
{
int init, rc, x;
@@ -1594,14 +1576,8 @@
runcmd();
if(vmx.state == VMXRUNNING){
procbctls = defprocbctls;
- if((vmx.onentry & STEP) != 0){
- procbctls |= PROCB_MONTRAP;
- dostep(1);
- if(waserror()){
- dostep(0);
- nexterror();
- }
- }
+ if((vmx.onentry & STEP) != 0)
+ defprocbctls |= PROCB_MONTRAP;
if((vmx.onentry & POSTEX) != 0){
vmcswrite(VMENTRY_INTRINFO, vmx.exc.info);
vmcswrite(VMENTRY_INTRCODE, vmx.exc.code);
@@ -1648,10 +1624,6 @@
if(rc < 0)
error("vmlaunch failed");
vmx.launched = 1;
- if((vmx.onentry & STEP) != 0){
- dostep(0);
- poperror();
- }
processexit();
}else{
up->psstate = "Idle";
@@ -1853,8 +1825,6 @@
Cmdtab *ct;
char *s;
int rc;
- int i;
- VmMem tmpmem;
switch((ulong)c->qid.path){
case Qdir:
@@ -1886,6 +1856,7 @@
vmxcmd(cmdquit);
break;
case CMgo:
+ case CMstep:
s = nil;
if(cb->nf == 2) kstrdup(&s, cb->f[1]);
else if(cb->nf != 1) error(Ebadarg);
@@ -1893,32 +1864,12 @@
free(s);
nexterror();
}
- vmxcmd(cmdgo, s);
+ vmxcmd(cmdgo, ct->index == CMstep, s);
poperror();
free(s);
break;
case CMstop:
vmxcmd(cmdstop);
- break;
- case CMstep:
- rc = 0;
- for(i = 1; i < cb->nf; i++)
- if(strcmp(cb->f[i], "-map") == 0){
- rc = 1;
- if(i+4 > cb->nf) error("missing argument");
- memset(&tmpmem, 0, sizeof(tmpmem));
- tmpmem.lo = strtoull(cb->f[i+1], &s, 0);
- if(*s != 0 || !vmokpage(tmpmem.lo)) error("invalid address");
- tmpmem.hi = tmpmem.lo + BY2PG;
- tmpmem.attr = 0x407;
- tmpmem.seg = _globalsegattach(cb->f[i+2]);
- if(tmpmem.seg == nil) error("unknown segment");
- tmpmem.off = strtoull(cb->f[i+3], &s, 0);
- if(*s != 0 || !vmokpage(tmpmem.off)) error("invalid offset");
- i += 3;
- }else
- error(Ebadctl);
- vmxcmd(cmdstep, rc ? &tmpmem : nil);
break;
case CMexc:
s = nil;