devvmx: support debug registers; simplify assembly

This commit is contained in:
aiju 2017-06-17 22:38:16 +00:00
parent cbcd9b1d71
commit 2bb65c40ab
3 changed files with 62 additions and 43 deletions

View file

@ -10,7 +10,7 @@ extern int vmxon(u64int);
extern int vmxoff(void);
extern int vmclear(u64int);
extern int vmptrld(u64int);
extern int vmlaunch(Ureg *, int, FPsave *);
extern int vmlaunch(Ureg *, int);
extern int vmread(u32int, uintptr *);
extern int vmwrite(u32int, uintptr);
extern int invept(u32int, uvlong, uvlong);
@ -71,6 +71,7 @@ enum {
CR3_TARGCNT = 0x400a,
VMEXIT_CTLS = 0x400c,
VMEXIT_ST_DEBUG = 1<<2,
VMEXIT_HOST64 = 1<<9,
VMEXIT_LD_IA32_PERF_GLOBAL_CTRL = 1<<12,
VMEXIT_ST_IA32_PAT = 1<<18,
@ -82,6 +83,7 @@ enum {
VMEXIT_MSRLDCNT = 0x4010,
VMENTRY_CTLS = 0x4012,
VMENTRY_LD_DEBUG = 1<<2,
VMENTRY_GUEST64 = 1<<9,
VMENTRY_LD_IA32_PERF_GLOBAL_CTRL = 1<<13,
VMENTRY_LD_IA32_PAT = 1<<14,
@ -235,6 +237,7 @@ struct Vmx {
} state;
char errstr[ERRMAX];
Ureg ureg;
uintptr dr[8]; /* DR7 is also kept in VMCS */
FPsave *fp;
u8int launched;
u8int vpid;
@ -400,12 +403,32 @@ cr4maskwrite(char *s)
return 0;
}
static int
dr7write(char *s)
{
uvlong v;
v = (u32int) parseval(s, 8);
vmcswrite(GUEST_DR7, vmx.dr[7] = (u32int) v);
return 0;
}
static int
readonly(char *)
{
return -1;
}
static int
dr6write(char *s)
{
uvlong v;
v = parseval(s, 8);
vmx.dr[6] = (u32int) v;
return 0;
}
typedef struct GuestReg GuestReg;
struct GuestReg {
int offset;
@ -414,7 +437,8 @@ struct GuestReg {
char *(*read)(char *, char *);
int (*write)(char *);
};
#define UREG(x) ~(ulong)&((Ureg*)0)->x
#define VMXVAR(x) ~(ulong)&(((Vmx*)0)->x)
#define UREG(x) VMXVAR(ureg.x)
static GuestReg guestregs[] = {
{GUEST_RIP, 0, "pc"},
{GUEST_RSP, 0, "sp"},
@ -472,6 +496,12 @@ static GuestReg guestregs[] = {
{GUEST_CR4MASK, 0, "cr4mask", nil, cr4maskwrite},
{GUEST_IA32_PAT, 8, "pat"},
{GUEST_IA32_EFER, 8, "efer"},
{VMXVAR(dr[0]), 0, "dr0"},
{VMXVAR(dr[1]), 0, "dr1"},
{VMXVAR(dr[2]), 0, "dr2"},
{VMXVAR(dr[3]), 0, "dr3"},
{VMXVAR(dr[6]), 0, "dr6", nil, dr6write},
{GUEST_DR7, 0, "dr7", nil, dr7write},
{VM_INSTRERR, 4, "instructionerror", nil, readonly},
{VM_EXREASON, 4, "exitreason", nil, readonly},
{VM_EXQUALIF, 0, "exitqualification", nil, readonly},
@ -740,14 +770,14 @@ vmcsinit(void)
if(rdmsr(VMX_VMEXIT_CTLS_MSR, &msr) < 0) error("rdmsr(VMX_VMEXIT_CTLS_MSR failed");
x = (u32int)msr;
if(sizeof(uintptr) == 8) x |= VMEXIT_HOST64;
x |= VMEXIT_LD_IA32_PAT | VMEXIT_LD_IA32_EFER;
x |= VMEXIT_LD_IA32_PAT | VMEXIT_LD_IA32_EFER | VMEXIT_ST_DEBUG;
x &= msr >> 32;
vmcswrite(VMEXIT_CTLS, x);
if(rdmsr(VMX_VMENTRY_CTLS_MSR, &msr) < 0) error("rdmsr(VMX_VMENTRY_CTLS_MSR failed");
x = (u32int)msr;
if(sizeof(uintptr) == 8) x |= VMENTRY_GUEST64;
x |= VMENTRY_LD_IA32_PAT | VMENTRY_LD_IA32_EFER;
x |= VMENTRY_LD_IA32_PAT | VMENTRY_LD_IA32_EFER | VMENTRY_LD_DEBUG;
x &= msr >> 32;
vmcswrite(VMENTRY_CTLS, x);
@ -780,7 +810,7 @@ vmcsinit(void)
if(rdmsr(0xc0000080, &msr) < 0) error("rdmsr(IA32_EFER) failed");
vmcswrite(HOST_IA32_EFER, msr);
vmcswrite(EXC_BITMAP, 1<<18);
vmcswrite(EXC_BITMAP, 1<<18|1<<1);
vmcswrite(PFAULT_MASK, 0);
vmcswrite(PFAULT_MATCH, 0);
@ -967,7 +997,7 @@ cmdgetregs(VmCmd *, va_list va)
if(r->offset >= 0)
val = vmcsread(r->offset);
else
val = *(uintptr*)((uchar*)&vmx.ureg + ~r->offset);
val = *(uintptr*)((uchar*)&vmx + ~r->offset);
s = r->size;
if(s == 0) s = sizeof(uintptr);
p = seprint(p, e, "%s %#.*llux\n", r->name, s * 2, val);
@ -1011,12 +1041,12 @@ setregs(char *p0, char rs, char *fs)
if(r->offset >= 0)
vmcswrite(r->offset, val);
else{
assert((u32int)~r->offset + sz <= sizeof(Ureg));
assert((u32int)~r->offset + sz <= sizeof(Vmx));
switch(sz){
case 1: *(u8int*)((u8int*)&vmx.ureg + (u32int)~r->offset) = val; break;
case 2: *(u16int*)((u8int*)&vmx.ureg + (u32int)~r->offset) = val; break;
case 4: *(u32int*)((u8int*)&vmx.ureg + (u32int)~r->offset) = val; break;
case 8: *(u64int*)((u8int*)&vmx.ureg + (u32int)~r->offset) = val; break;
case 1: *(u8int*)((u8int*)&vmx + (u32int)~r->offset) = val; break;
case 2: *(u16int*)((u8int*)&vmx + (u32int)~r->offset) = val; break;
case 4: *(u32int*)((u8int*)&vmx + (u32int)~r->offset) = val; break;
case 8: *(u64int*)((u8int*)&vmx + (u32int)~r->offset) = val; break;
default: error(Egreg);
}
}
@ -1367,7 +1397,7 @@ dostep(int setup)
static void
vmxproc(void *)
{
int init;
int init, rc, x;
u32int procbctls, defprocbctls;
procwired(up, 0);
@ -1425,7 +1455,15 @@ vmxproc(void *)
}
vmcswrite(PROCB_CTLS, procbctls);
vmx.got &= ~GOTEXIT;
if(vmlaunch(&vmx.ureg, vmx.launched, vmx.fp) < 0)
x = splhi();
if((vmx.dr[7] & ~0xd400) != 0)
putdr01236(vmx.dr);
fpsserestore0(vmx.fp);
rc = vmlaunch(&vmx.ureg, vmx.launched);
fpssesave0(vmx.fp);
splx(x);
if(rc < 0)
error("vmlaunch failed");
vmx.launched = 1;
if((vmx.onentry & STEP) != 0){

View file

@ -167,6 +167,7 @@ void putcr0(ulong);
void putcr3(ulong);
void putcr4(ulong);
void putdr(u32int*);
void putdr01236(uintptr*);
void putdr6(u32int);
void putdr7(u32int);
void* rampage(void);

View file

@ -851,6 +851,7 @@ TEXT putdr(SB), $0
MOVL p+0(FP), SI
MOVL 28(SI), AX
MOVL AX, DR7
_putdr01236:
MOVL 0(SI), AX
MOVL AX, DR0
MOVL 4(SI), AX
@ -863,6 +864,10 @@ TEXT putdr(SB), $0
MOVL AX, DR6
RET
TEXT putdr01236(SB), $0
MOVL p+0(FP), SI
JMP _putdr01236
TEXT getdr6(SB), $0
MOVL DR6, AX
RET
@ -893,21 +898,14 @@ TEXT vmclear(SB), $0
JMP _vmout
TEXT vmlaunch(SB), $0
PUSHFL
CLI
MOVL $0x6C14, DI
MOVL SP, DX
BYTE $0x0f; BYTE $0x79; BYTE $0xfa /* VMWRITE DX, DI */
JBE _launchout
JBE _vmout
MOVL $0x6C16, DI
MOVL $vmrestore+1(SB), DX /* add 1 to skip extra PUSHFL */
MOVL $vmrestore(SB), DX
BYTE $0x0f; BYTE $0x79; BYTE $0xfa /* VMWRITE DX, DI */
JBE _launchout
FPON
MOVL fp+8(FP), AX
FXRSTOR 0(AX)
JBE _vmout
MOVL resume+4(FP), AX
TESTL AX, AX
@ -923,26 +921,12 @@ TEXT vmlaunch(SB), $0
MOVL 0(DI), DI
JNE _vmresume
BYTE $0x0f; BYTE $0x01; BYTE $0xc2 /* VMLAUNCH */
JMP _launchout
JMP _vmout
_vmresume:
BYTE $0x0f; BYTE $0x01; BYTE $0xc3 /* VMRESUME */
_launchout:
JC _launchout1
JZ _launchout2
XORL AX, AX
_launchret:
FPOFF
POPFL
RET
_launchout1:
MOVL $-1, AX
JMP _launchret
_launchout2:
MOVL $-2, AX
JMP _launchret
JMP _vmout
TEXT vmrestore(SB), $0
PUSHFL /* stupid hack to make 8l happy; nexer executed */
PUSHL DI
MOVL ureg+0(FP), DI
POPL 0(DI)
@ -954,11 +938,7 @@ TEXT vmrestore(SB), $0
MOVL AX, 28(DI)
MOVL CR2, AX
MOVL AX, 32(DI)
MOVL fp+8(FP), AX
FXSAVE 0(AX)
FPOFF
XORL AX, AX
POPFL
RET
TEXT vmptrld(SB), $0