pc, pc64: adapt devvmx to work on pc64
This commit is contained in:
parent
9fb2001658
commit
becb89bae5
10 changed files with 365 additions and 69 deletions
|
@ -332,6 +332,18 @@ enum {
|
|||
Rdrnd = 1<<30, /* RDRAND support bit */
|
||||
};
|
||||
|
||||
/* model-specific registers, for compatibility with pc64 code */
|
||||
enum {
|
||||
Efer = 0xc0000080, /* Extended Feature Enable */
|
||||
Star = 0xc0000081, /* Legacy Target IP and [CS]S */
|
||||
Lstar = 0xc0000082, /* Long Mode Target IP */
|
||||
Cstar = 0xc0000083, /* Compatibility Target IP */
|
||||
Sfmask = 0xc0000084, /* SYSCALL Flags Mask */
|
||||
FSbase = 0xc0000100, /* 64-bit FS Base Address */
|
||||
GSbase = 0xc0000101, /* 64-bit GS Base Address */
|
||||
KernelGSbase = 0xc0000102, /* SWAPGS instruction */
|
||||
};
|
||||
|
||||
/*
|
||||
* a parsed plan9.ini line
|
||||
*/
|
||||
|
|
|
@ -55,6 +55,7 @@ enum {
|
|||
PROCB_EXITMOVDR = 1<<23,
|
||||
PROCB_EXITIO = 1<<24,
|
||||
PROCB_MONTRAP = 1<<27,
|
||||
PROCB_MSRBITMAP = 1<<28,
|
||||
PROCB_EXITMONITOR = 1<<29,
|
||||
PROCB_EXITPAUSE = 1<<30,
|
||||
PROCB_USECTLS2 = 1<<31,
|
||||
|
@ -69,6 +70,7 @@ enum {
|
|||
PFAULT_MASK = 0x4006,
|
||||
PFAULT_MATCH = 0x4008,
|
||||
CR3_TARGCNT = 0x400a,
|
||||
MSR_BITMAP = 0x2004,
|
||||
|
||||
VMEXIT_CTLS = 0x400c,
|
||||
VMEXIT_ST_DEBUG = 1<<2,
|
||||
|
@ -81,6 +83,9 @@ enum {
|
|||
|
||||
VMEXIT_MSRSTCNT = 0x400e,
|
||||
VMEXIT_MSRLDCNT = 0x4010,
|
||||
VMEXIT_MSRSTADDR = 0x2006,
|
||||
VMEXIT_MSRLDADDR = 0x2008,
|
||||
VMENTRY_MSRLDADDR = 0x200A,
|
||||
|
||||
VMENTRY_CTLS = 0x4012,
|
||||
VMENTRY_LD_DEBUG = 1<<2,
|
||||
|
@ -204,10 +209,14 @@ enum {
|
|||
CR4SMXE = 1<<14,
|
||||
CR4PKE = 1<<22,
|
||||
|
||||
CR0KERNEL = CR0RSVD | (uintptr)0xFFFFFFFF00000000ULL,
|
||||
CR0KERNEL = CR0RSVD | 0x30 | (uintptr)0xFFFFFFFF00000000ULL,
|
||||
CR4KERNEL = CR4RSVD | CR4VMXE | CR4SMXE | CR4MCE | CR4PKE | (uintptr)0xFFFFFFFF00000000ULL
|
||||
};
|
||||
|
||||
enum {
|
||||
MAXMSR = 512,
|
||||
};
|
||||
|
||||
typedef struct Vmx Vmx;
|
||||
typedef struct VmCmd VmCmd;
|
||||
typedef struct VmMem VmMem;
|
||||
|
@ -237,9 +246,11 @@ struct Vmx {
|
|||
} state;
|
||||
char errstr[ERRMAX];
|
||||
Ureg ureg;
|
||||
uintptr cr2;
|
||||
uintptr dr[8]; /* DR7 is also kept in VMCS */
|
||||
FPsave *fp;
|
||||
u8int launched;
|
||||
u8int on;
|
||||
u8int vpid;
|
||||
enum {
|
||||
FLUSHVPID = 1,
|
||||
|
@ -264,6 +275,10 @@ struct Vmx {
|
|||
} got;
|
||||
VmMem *stepmap;
|
||||
VmIntr exc, irq, irqack;
|
||||
|
||||
u64int *msrhost, *msrguest;
|
||||
u32int *msrbits;
|
||||
int nmsr;
|
||||
};
|
||||
|
||||
struct VmCmd {
|
||||
|
@ -330,14 +345,13 @@ vmcswrite(u32int addr, u64int val)
|
|||
}
|
||||
|
||||
static uvlong
|
||||
parseval(char *s, int sz)
|
||||
parseval(char *s)
|
||||
{
|
||||
uvlong v;
|
||||
char *p;
|
||||
|
||||
if(sz == 0) sz = sizeof(uintptr);
|
||||
|
||||
v = strtoull(s, &p, 0);
|
||||
if(p == s || *p != 0 || v >> sz * 8 != 0) error("invalid value");
|
||||
if(p == s || *p != 0) error("invalid value");
|
||||
return v;
|
||||
}
|
||||
|
||||
|
@ -363,13 +377,30 @@ cr4fakeread(char *p, char *e)
|
|||
return seprint(p, e, "%#.*ullx", sizeof(uintptr) * 2, guest & ~mask | shadow & mask);
|
||||
}
|
||||
|
||||
static void
|
||||
updatelma(void)
|
||||
{
|
||||
uvlong cr0, efer, nefer, ectrl;
|
||||
|
||||
if(sizeof(uintptr) != 8) return;
|
||||
cr0 = vmcsread(GUEST_CR0);
|
||||
efer = vmcsread(GUEST_IA32_EFER);
|
||||
nefer = efer & ~0x400 | efer << 2 & cr0 >> 21 & 0x400;
|
||||
if(efer == nefer) return;
|
||||
vmcswrite(GUEST_IA32_EFER, nefer);
|
||||
ectrl = vmcsread(VMENTRY_CTLS);
|
||||
ectrl = ectrl & ~0x200 | nefer >> 1 & 0x200;
|
||||
vmcswrite(VMENTRY_CTLS, ectrl);
|
||||
}
|
||||
|
||||
static int
|
||||
cr0realwrite(char *s)
|
||||
{
|
||||
uvlong v;
|
||||
|
||||
v = parseval(s, 8);
|
||||
v = parseval(s);
|
||||
vmcswrite(GUEST_CR0, vmcsread(GUEST_CR0) & CR0KERNEL | v & ~CR0KERNEL);
|
||||
updatelma();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -378,8 +409,19 @@ cr0maskwrite(char *s)
|
|||
{
|
||||
uvlong v;
|
||||
|
||||
v = parseval(s, 8);
|
||||
vmcswrite(GUEST_CR0MASK, vmcsread(GUEST_CR0MASK) | CR0KERNEL);
|
||||
v = parseval(s);
|
||||
vmcswrite(GUEST_CR0MASK, v | CR0KERNEL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
eferwrite(char *s)
|
||||
{
|
||||
uvlong v;
|
||||
|
||||
v = parseval(s);
|
||||
vmcswrite(GUEST_IA32_EFER, v);
|
||||
updatelma();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -388,7 +430,7 @@ cr4realwrite(char *s)
|
|||
{
|
||||
uvlong v;
|
||||
|
||||
v = parseval(s, 8);
|
||||
v = parseval(s);
|
||||
vmcswrite(GUEST_CR4, vmcsread(GUEST_CR4) & CR4KERNEL | v & ~CR4KERNEL);
|
||||
return 0;
|
||||
}
|
||||
|
@ -398,8 +440,8 @@ cr4maskwrite(char *s)
|
|||
{
|
||||
uvlong v;
|
||||
|
||||
v = parseval(s, 8);
|
||||
vmcswrite(GUEST_CR4MASK, vmcsread(GUEST_CR4MASK) | CR4KERNEL);
|
||||
v = parseval(s);
|
||||
vmcswrite(GUEST_CR4MASK, v | CR4KERNEL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -408,7 +450,7 @@ dr7write(char *s)
|
|||
{
|
||||
uvlong v;
|
||||
|
||||
v = (u32int) parseval(s, 8);
|
||||
v = (u32int) parseval(s);
|
||||
vmcswrite(GUEST_DR7, vmx.dr[7] = (u32int) v);
|
||||
return 0;
|
||||
}
|
||||
|
@ -424,7 +466,7 @@ dr6write(char *s)
|
|||
{
|
||||
uvlong v;
|
||||
|
||||
v = parseval(s, 8);
|
||||
v = parseval(s);
|
||||
vmx.dr[6] = (u32int) v;
|
||||
return 0;
|
||||
}
|
||||
|
@ -450,6 +492,16 @@ static GuestReg guestregs[] = {
|
|||
{UREG(bp), 0, "bp"},
|
||||
{UREG(si), 0, "si"},
|
||||
{UREG(di), 0, "di"},
|
||||
#ifdef RMACH
|
||||
{UREG(r8), 0, "r8"},
|
||||
{UREG(r9), 0, "r9"},
|
||||
{UREG(r10), 0, "r10"},
|
||||
{UREG(r11), 0, "r11"},
|
||||
{UREG(r12), 0, "r12"},
|
||||
{UREG(r13), 0, "r13"},
|
||||
{UREG(r14), 0, "r14"},
|
||||
{UREG(r15), 0, "r15"},
|
||||
#endif
|
||||
{GUEST_GDTRBASE, 0, "gdtrbase"},
|
||||
{GUEST_GDTRLIMIT, 4, "gdtrlimit"},
|
||||
{GUEST_IDTRBASE, 0, "idtrbase"},
|
||||
|
@ -489,13 +541,13 @@ static GuestReg guestregs[] = {
|
|||
{GUEST_CR0, 0, "cr0real", nil, cr0realwrite},
|
||||
{GUEST_CR0SHADOW, 0, "cr0fake", cr0fakeread},
|
||||
{GUEST_CR0MASK, 0, "cr0mask", nil, cr0maskwrite},
|
||||
{UREG(trap), 0, "cr2"},
|
||||
{VMXVAR(cr2), 0, "cr2"},
|
||||
{GUEST_CR3, 0, "cr3"},
|
||||
{GUEST_CR4, 0, "cr4real", nil, cr4realwrite},
|
||||
{GUEST_CR4SHADOW, 0, "cr4fake", cr4fakeread},
|
||||
{GUEST_CR4MASK, 0, "cr4mask", nil, cr4maskwrite},
|
||||
{GUEST_IA32_PAT, 8, "pat"},
|
||||
{GUEST_IA32_EFER, 8, "efer"},
|
||||
{GUEST_IA32_EFER, 8, "efer", nil, eferwrite},
|
||||
{VMXVAR(dr[0]), 0, "dr0"},
|
||||
{VMXVAR(dr[1]), 0, "dr1"},
|
||||
{VMXVAR(dr[2]), 0, "dr2"},
|
||||
|
@ -529,6 +581,7 @@ eptwalk(uvlong addr)
|
|||
int i;
|
||||
|
||||
tab = vmx.pml4;
|
||||
if(tab == nil) error(Egreg);
|
||||
for(i = 3; i >= 1; i--){
|
||||
tab += addr >> 12 + 9 * i & 0x1ff;
|
||||
v = *tab;
|
||||
|
@ -550,6 +603,7 @@ eptfree(uvlong *tab, int level)
|
|||
int i;
|
||||
uvlong v, *t;
|
||||
|
||||
if(tab == nil) error(Egreg);
|
||||
if(level < 3){
|
||||
for(i = 0; i < 512; i++){
|
||||
v = tab[i];
|
||||
|
@ -611,7 +665,7 @@ static int
|
|||
cmdclearmeminfo(VmCmd *, va_list)
|
||||
{
|
||||
VmMem *mp, *mn;
|
||||
|
||||
|
||||
eptfree(vmx.pml4, 0);
|
||||
for(mp = vmx.mem.next; mp != &vmx.mem; mp = mn){
|
||||
mn = mp->next;
|
||||
|
@ -633,7 +687,9 @@ cmdsetmeminfo(VmCmd *, va_list va)
|
|||
char *f[10];
|
||||
VmMem *mp;
|
||||
int rc;
|
||||
|
||||
|
||||
if(vmx.pml4 == nil)
|
||||
error(Egreg);
|
||||
p0 = va_arg(va, char *);
|
||||
p = p0;
|
||||
mp = nil;
|
||||
|
@ -725,8 +781,46 @@ vmxreset(void)
|
|||
static void
|
||||
vmxshutdown(void)
|
||||
{
|
||||
if(vmx.state != NOVMX && vmx.state != VMXINACTIVE)
|
||||
if(vmx.on){
|
||||
vmxoff();
|
||||
vmx.on = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
vmxaddmsr(u32int msr, u64int gval)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(vmx.nmsr >= MAXMSR)
|
||||
error("too many MSRs");
|
||||
i = 2 * vmx.nmsr++;
|
||||
vmx.msrhost[i] = msr;
|
||||
rdmsr(msr, (vlong *) &vmx.msrhost[i+1]);
|
||||
vmx.msrguest[i] = msr;
|
||||
vmx.msrguest[i+1] = gval;
|
||||
vmcswrite(VMENTRY_MSRLDCNT, vmx.nmsr);
|
||||
vmcswrite(VMEXIT_MSRSTCNT, vmx.nmsr);
|
||||
vmcswrite(VMEXIT_MSRLDCNT, vmx.nmsr);
|
||||
}
|
||||
|
||||
static void
|
||||
vmxtrapmsr(u32int msr, enum { TRAPRD = 1, TRAPWR = 2 } state)
|
||||
{
|
||||
u32int m;
|
||||
|
||||
if(msr >= 0x2000 && (u32int)(msr - 0xc0000000) >= 0x2000)
|
||||
return;
|
||||
msr = msr & 0x1fff | msr >> 18 & 0x2000;
|
||||
m = 1<<(msr & 31);
|
||||
if((state & TRAPRD) != 0)
|
||||
vmx.msrbits[msr / 32] |= m;
|
||||
else
|
||||
vmx.msrbits[msr / 32] &= ~m;
|
||||
if((state & TRAPWR) != 0)
|
||||
vmx.msrbits[msr / 32 + 512] |= m;
|
||||
else
|
||||
vmx.msrbits[msr / 32 + 512] &= ~m;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -737,7 +831,7 @@ vmcsinit(void)
|
|||
|
||||
memset(&vmx.ureg, 0, sizeof(vmx.ureg));
|
||||
vmx.launched = 0;
|
||||
vmx.onentry = 0;
|
||||
vmx.onentry = 0;
|
||||
|
||||
if(rdmsr(VMX_BASIC_MSR, &msr) < 0) error("rdmsr(VMX_BASIC_MSR) failed");
|
||||
if((msr & 1ULL<<55) != 0){
|
||||
|
@ -757,7 +851,7 @@ vmcsinit(void)
|
|||
if(rdmsr(VMX_PROCB_CTLS_MSR, &msr) < 0) error("rdmsr(VMX_PROCB_CTLS_MSR failed");
|
||||
x = (u32int)procb_ctls | 1<<1 | 7<<4 | 1<<8 | 1<<13 | 1<<14 | 1<<26; /* currently reserved default1 bits */
|
||||
x |= PROCB_EXITHLT | PROCB_EXITMWAIT;
|
||||
x |= PROCB_EXITMOVDR | PROCB_EXITIO | PROCB_EXITMONITOR;
|
||||
x |= PROCB_EXITMOVDR | PROCB_EXITIO | PROCB_EXITMONITOR | PROCB_MSRBITMAP;
|
||||
x |= PROCB_USECTLS2;
|
||||
x &= msr >> 32;
|
||||
vmcswrite(PROCB_CTLS, x);
|
||||
|
@ -770,21 +864,17 @@ 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 | VMEXIT_ST_DEBUG;
|
||||
x |= VMEXIT_LD_IA32_PAT | VMEXIT_LD_IA32_EFER | VMEXIT_ST_DEBUG | VMEXIT_ST_IA32_EFER;
|
||||
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 | VMENTRY_LD_DEBUG;
|
||||
x &= msr >> 32;
|
||||
vmcswrite(VMENTRY_CTLS, x);
|
||||
|
||||
vmcswrite(CR3_TARGCNT, 0);
|
||||
vmcswrite(VMEXIT_MSRLDCNT, 0);
|
||||
vmcswrite(VMEXIT_MSRSTCNT, 0);
|
||||
vmcswrite(VMENTRY_MSRLDCNT, 0);
|
||||
vmcswrite(VMENTRY_INTRINFO, 0);
|
||||
vmcswrite(VMCS_LINK, -1);
|
||||
|
||||
|
@ -798,16 +888,16 @@ vmcsinit(void)
|
|||
vmcswrite(HOST_CR0, getcr0() & ~0xe);
|
||||
vmcswrite(HOST_CR3, getcr3());
|
||||
vmcswrite(HOST_CR4, getcr4());
|
||||
rdmsr(0xc0000100, &msr);
|
||||
rdmsr(FSbase, &msr);
|
||||
vmcswrite(HOST_FSBASE, msr);
|
||||
rdmsr(0xc0000101, &msr);
|
||||
rdmsr(GSbase, &msr);
|
||||
vmcswrite(HOST_GSBASE, msr);
|
||||
vmcswrite(HOST_TRBASE, (uintptr) m->tss);
|
||||
vmcswrite(HOST_GDTR, (uintptr) m->gdt);
|
||||
vmcswrite(HOST_IDTR, IDTADDR);
|
||||
if(rdmsr(0x277, &msr) < 0) error("rdmsr(IA32_PAT) failed");
|
||||
vmcswrite(HOST_IA32_PAT, msr);
|
||||
if(rdmsr(0xc0000080, &msr) < 0) error("rdmsr(IA32_EFER) failed");
|
||||
if(rdmsr(Efer, &msr) < 0) error("rdmsr(IA32_EFER) failed");
|
||||
vmcswrite(HOST_IA32_EFER, msr);
|
||||
|
||||
vmcswrite(EXC_BITMAP, 1<<18|1<<1);
|
||||
|
@ -836,16 +926,16 @@ vmcsinit(void)
|
|||
|
||||
vmcswrite(GUEST_CR0MASK, CR0KERNEL);
|
||||
vmcswrite(GUEST_CR4MASK, CR4KERNEL);
|
||||
vmcswrite(GUEST_CR0, getcr0() & ~(1<<31));
|
||||
vmcswrite(GUEST_CR0, getcr0() & CR0KERNEL | 0x31);
|
||||
vmcswrite(GUEST_CR3, 0);
|
||||
vmcswrite(GUEST_CR4, getcr4());
|
||||
vmcswrite(GUEST_CR0SHADOW, getcr0());
|
||||
vmcswrite(GUEST_CR4SHADOW, getcr4() & ~CR4VMXE);
|
||||
vmcswrite(GUEST_CR4, getcr4() & CR4KERNEL);
|
||||
vmcswrite(GUEST_CR0SHADOW, getcr0() & CR0KERNEL | 0x31);
|
||||
vmcswrite(GUEST_CR4SHADOW, getcr4() & ~CR4VMXE & CR4KERNEL);
|
||||
|
||||
vmcswrite(GUEST_IA32_PAT, 0x0007040600070406ULL);
|
||||
vmcswrite(GUEST_IA32_EFER, 0);
|
||||
|
||||
vmcswrite(GUEST_TRBASE, (uintptr) m->tss);
|
||||
vmcswrite(GUEST_TRBASE, 0);
|
||||
vmcswrite(GUEST_TRLIMIT, 0xffff);
|
||||
vmcswrite(GUEST_TRPERM, (SEGTSS|SEGPL(0)|SEGP) >> 8 | 2);
|
||||
|
||||
|
@ -864,15 +954,53 @@ vmcsinit(void)
|
|||
error(Enomem);
|
||||
fpinit();
|
||||
fpsave(vmx.fp);
|
||||
|
||||
vmx.msrhost = mallocalign(MAXMSR*16, 16, 0, 0);
|
||||
vmx.msrguest = mallocalign(MAXMSR*16, 16, 0, 0);
|
||||
vmx.msrbits = mallocalign(4096, 4096, 0, 0);
|
||||
if(vmx.msrhost == nil || vmx.msrguest == nil || vmx.msrbits == nil)
|
||||
error(Enomem);
|
||||
memset(vmx.msrbits, -1, 4096);
|
||||
vmxtrapmsr(Efer, 0);
|
||||
vmcswrite(VMENTRY_MSRLDADDR, PADDR(vmx.msrguest));
|
||||
vmcswrite(VMEXIT_MSRSTADDR, PADDR(vmx.msrguest));
|
||||
vmcswrite(VMEXIT_MSRLDADDR, PADDR(vmx.msrhost));
|
||||
vmcswrite(MSR_BITMAP, PADDR(vmx.msrbits));
|
||||
|
||||
if(sizeof(uintptr) == 8){
|
||||
vmxaddmsr(Star, 0);
|
||||
vmxaddmsr(Lstar, 0);
|
||||
vmxaddmsr(Cstar, 0);
|
||||
vmxaddmsr(Sfmask, 0);
|
||||
vmxaddmsr(KernelGSbase, 0);
|
||||
vmxtrapmsr(Star, 0);
|
||||
vmxtrapmsr(Lstar, 0);
|
||||
vmxtrapmsr(Cstar, 0);
|
||||
vmxtrapmsr(Sfmask, 0);
|
||||
vmxtrapmsr(FSbase, 0);
|
||||
vmxtrapmsr(GSbase, 0);
|
||||
vmxtrapmsr(KernelGSbase, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
vmxstart(void)
|
||||
{
|
||||
static uchar *vmcs; /* also vmxon region */
|
||||
vlong msr, msr2;
|
||||
uintptr cr;
|
||||
vlong x;
|
||||
|
||||
putcr4(getcr4() | 0x2000);
|
||||
putcr4(getcr4() | 0x2000); /* set VMXE */
|
||||
putcr0(getcr0() | 0x20); /* set NE */
|
||||
cr = getcr0();
|
||||
if(rdmsr(VMX_CR0_FIXED0, &msr) < 0) error("rdmsr(VMX_CR0_FIXED0) failed");
|
||||
if(rdmsr(VMX_CR0_FIXED1, &msr2) < 0) error("rdmsr(VMX_CR0_FIXED1) failed");
|
||||
if((cr & ~msr & ~msr2 | ~cr & msr & msr2) != 0) error("invalid CR0 value");
|
||||
cr = getcr4();
|
||||
if(rdmsr(VMX_CR4_FIXED0, &msr) < 0) error("rdmsr(VMX_CR4_FIXED0) failed");
|
||||
if(rdmsr(VMX_CR4_FIXED1, &msr2) < 0) error("rdmsr(VMX_CR4_FIXED1) failed");
|
||||
if((cr & ~msr & ~msr2 | ~cr & msr & msr2) != 0) error("invalid CR4 value");
|
||||
|
||||
if(vmcs == nil){
|
||||
vmcs = mallocalign(8192, 4096, 0, 0);
|
||||
|
@ -885,6 +1013,7 @@ vmxstart(void)
|
|||
*(ulong*)&vmcs[4096] = x;
|
||||
if(vmxon(PADDR(vmcs + 4096)) < 0)
|
||||
error("vmxon failed");
|
||||
vmx.on = 1;
|
||||
if(vmclear(PADDR(vmcs)) < 0)
|
||||
error("vmclear failed");
|
||||
if(vmptrld(PADDR(vmcs)) < 0)
|
||||
|
@ -931,16 +1060,25 @@ static int
|
|||
cmdquit(VmCmd *p, va_list va)
|
||||
{
|
||||
vmx.state = VMXENDING;
|
||||
cmdclearmeminfo(p, va);
|
||||
killcmds(p);
|
||||
|
||||
free(vmx.pml4);
|
||||
vmx.pml4 = nil;
|
||||
if(vmx.pml4 != nil){
|
||||
cmdclearmeminfo(p, va);
|
||||
free(vmx.pml4);
|
||||
vmx.pml4 = nil;
|
||||
}
|
||||
vmx.got = 0;
|
||||
vmx.onentry = 0;
|
||||
vmx.stepmap = nil;
|
||||
|
||||
free(vmx.msrhost);
|
||||
free(vmx.msrguest);
|
||||
vmx.msrhost = nil;
|
||||
vmx.msrguest = nil;
|
||||
vmx.nmsr = 0;
|
||||
|
||||
vmxoff();
|
||||
if(vmx.on)
|
||||
vmxoff();
|
||||
vmx.state = VMXINACTIVE;
|
||||
cmdrelease(p, 0);
|
||||
pexit(Equit, 1);
|
||||
|
@ -973,7 +1111,7 @@ processexit(void)
|
|||
break;
|
||||
}
|
||||
if((vmx.onentry & STEP) != 0){
|
||||
iprint("VMX: exit reason %#x when expected step...\n", reason & 0xffff);
|
||||
print("VMX: exit reason %#x when expected step...\n", reason & 0xffff);
|
||||
vmx.onentry &= ~STEP;
|
||||
vmx.got |= GOTSTEP|GOTSTEPERR;
|
||||
}
|
||||
|
@ -1042,7 +1180,7 @@ setregs(char *p0, char rs, char *fs)
|
|||
val = strtoull(f[1], &rp, 0);
|
||||
sz = r->size;
|
||||
if(sz == 0) sz = sizeof(uintptr);
|
||||
if(rp == f[1] || *rp != 0 || val >> 8 * sz != 0) error("invalid value");
|
||||
if(rp == f[1] || *rp != 0) error("invalid value");
|
||||
if(r->offset >= 0)
|
||||
vmcswrite(r->offset, val);
|
||||
else{
|
||||
|
@ -1192,7 +1330,7 @@ cmdstep(VmCmd *cp, va_list va)
|
|||
if((vmx.got & GOTSTEP) != 0 || (vmx.onentry & STEP) != 0)
|
||||
error(Einuse);
|
||||
if(vmx.state != VMXREADY){
|
||||
iprint("pre-step in state %s\n", statenames[vmx.state]);
|
||||
print("pre-step in state %s\n", statenames[vmx.state]);
|
||||
error("not ready");
|
||||
}
|
||||
vmx.stepmap = va_arg(va, VmMem *);
|
||||
|
@ -1202,7 +1340,7 @@ cmdstep(VmCmd *cp, va_list va)
|
|||
return 1;
|
||||
case 1:
|
||||
if(vmx.state != VMXREADY){
|
||||
iprint("post-step in state %s\n", statenames[vmx.state]);
|
||||
print("post-step in state %s\n", statenames[vmx.state]);
|
||||
vmx.onentry &= ~STEP;
|
||||
vmx.got &= ~(GOTSTEP|GOTSTEPERR);
|
||||
error("not ready");
|
||||
|
@ -1404,6 +1542,7 @@ vmxproc(void *)
|
|||
{
|
||||
int init, rc, x;
|
||||
u32int procbctls, defprocbctls;
|
||||
vlong v;
|
||||
|
||||
procwired(up, 0);
|
||||
sched();
|
||||
|
@ -1462,11 +1601,17 @@ vmxproc(void *)
|
|||
vmx.got &= ~GOTEXIT;
|
||||
|
||||
x = splhi();
|
||||
if(sizeof(uintptr) == 8){
|
||||
rdmsr(FSbase, &v);
|
||||
vmwrite(HOST_FSBASE, v);
|
||||
}
|
||||
if((vmx.dr[7] & ~0xd400) != 0)
|
||||
putdr01236(vmx.dr);
|
||||
fpsserestore0(vmx.fp);
|
||||
fpsserestore(vmx.fp);
|
||||
putcr2(vmx.cr2);
|
||||
rc = vmlaunch(&vmx.ureg, vmx.launched);
|
||||
fpssesave0(vmx.fp);
|
||||
vmx.cr2 = getcr2();
|
||||
fpssesave(vmx.fp);
|
||||
splx(x);
|
||||
if(rc < 0)
|
||||
error("vmlaunch failed");
|
||||
|
|
|
@ -164,6 +164,7 @@ void procsave(Proc*);
|
|||
void procsetup(Proc*);
|
||||
void procfork(Proc*);
|
||||
void putcr0(ulong);
|
||||
void putcr2(ulong);
|
||||
void putcr3(ulong);
|
||||
void putcr4(ulong);
|
||||
void putdr(u32int*);
|
||||
|
|
|
@ -437,6 +437,11 @@ TEXT getcr2(SB), $0 /* CR2 - page fault linear address */
|
|||
MOVL CR2, AX
|
||||
RET
|
||||
|
||||
TEXT putcr2(SB), $0
|
||||
MOVL cr2+0(FP), AX
|
||||
MOVL AX, CR2
|
||||
RET
|
||||
|
||||
TEXT getcr3(SB), $0 /* CR3 - page directory base */
|
||||
MOVL CR3, AX
|
||||
RET
|
||||
|
@ -910,8 +915,6 @@ TEXT vmlaunch(SB), $0
|
|||
MOVL resume+4(FP), AX
|
||||
TESTL AX, AX
|
||||
MOVL ureg+0(FP), DI
|
||||
MOVL 32(DI), AX
|
||||
MOVL AX, CR2
|
||||
MOVL 4(DI), SI
|
||||
MOVL 8(DI), BP
|
||||
MOVL 16(DI), BX
|
||||
|
@ -920,10 +923,10 @@ TEXT vmlaunch(SB), $0
|
|||
MOVL 28(DI), AX
|
||||
MOVL 0(DI), DI
|
||||
JNE _vmresume
|
||||
BYTE $0x0f; BYTE $0x01; BYTE $0xc2 /* VMLAUNCH */
|
||||
BYTE $0x0f; BYTE $0x01; BYTE $0xc2 /* VMLAUNCH */
|
||||
JMP _vmout
|
||||
_vmresume:
|
||||
BYTE $0x0f; BYTE $0x01; BYTE $0xc3 /* VMRESUME */
|
||||
BYTE $0x0f; BYTE $0x01; BYTE $0xc3 /* VMRESUME */
|
||||
JMP _vmout
|
||||
|
||||
TEXT vmrestore(SB), $0
|
||||
|
@ -936,8 +939,6 @@ TEXT vmrestore(SB), $0
|
|||
MOVL DX, 20(DI)
|
||||
MOVL CX, 24(DI)
|
||||
MOVL AX, 28(DI)
|
||||
MOVL CR2, AX
|
||||
MOVL AX, 32(DI)
|
||||
XORL AX, AX
|
||||
RET
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ multibootargs(void)
|
|||
if((multiboot[0] & (1<<6)) != 0 && (l = multiboot[11]) >= 24){
|
||||
cp = seprint(cp, ep, "*e820=");
|
||||
m = KADDR(multiboot[12]);
|
||||
while(m[0] >= 20 && m[0] <= l-4){
|
||||
while(m[0] >= 20 && m[0]+4 <= l){
|
||||
uvlong base, size;
|
||||
m++;
|
||||
base = ((uvlong)m[0] | (uvlong)m[1]<<32);
|
||||
|
|
|
@ -34,6 +34,7 @@ int ecinit(int cmdport, int dataport);
|
|||
int ecread(uchar addr);
|
||||
int ecwrite(uchar addr, uchar val);
|
||||
#define evenaddr(x) /* x86 doesn't care */
|
||||
void fpinit(void);
|
||||
void (*fprestore)(FPsave*);
|
||||
void (*fpsave)(FPsave*);
|
||||
void fpsserestore(FPsave*);
|
||||
|
@ -108,6 +109,7 @@ char* mtrr(uvlong, uvlong, char *);
|
|||
void mtrrclock(void);
|
||||
int mtrrprint(char *, long);
|
||||
void mtrrsync(void);
|
||||
void netconsole(void);
|
||||
void noteret(void);
|
||||
uchar nvramread(int);
|
||||
void nvramwrite(int, uchar);
|
||||
|
@ -157,9 +159,11 @@ void procsave(Proc*);
|
|||
void procsetup(Proc*);
|
||||
void procfork(Proc*);
|
||||
void putcr0(u64int);
|
||||
void putcr2(u64int);
|
||||
void putcr3(u64int);
|
||||
void putcr4(u64int);
|
||||
void putdr(u64int*);
|
||||
void putdr01236(u64int*);
|
||||
void putdr6(u64int);
|
||||
void putdr7(u64int);
|
||||
void* rampage(void);
|
||||
|
|
|
@ -379,6 +379,10 @@ TEXT getcr2(SB), 1, $-4 /* #PF Linear Address */
|
|||
MOVQ CR2, AX
|
||||
RET
|
||||
|
||||
TEXT putcr2(SB), 1, $-4
|
||||
MOVQ BP, CR2
|
||||
RET
|
||||
|
||||
TEXT getcr3(SB), 1, $-4 /* PML4 Base */
|
||||
MOVQ CR3, AX
|
||||
RET
|
||||
|
@ -694,9 +698,11 @@ f3:
|
|||
|
||||
/* debug register access */
|
||||
|
||||
TEXT putdr(SB), $0
|
||||
TEXT putdr(SB), 1, $-4
|
||||
MOVQ 56(BP), AX
|
||||
MOVQ AX, DR7
|
||||
/* wet floor */
|
||||
TEXT putdr01236(SB), 1, $-4
|
||||
MOVQ 0(BP), AX
|
||||
MOVQ AX, DR0
|
||||
MOVQ 8(BP), AX
|
||||
|
@ -709,18 +715,134 @@ TEXT putdr(SB), $0
|
|||
MOVQ AX, DR6
|
||||
RET
|
||||
|
||||
TEXT getdr6(SB), $0
|
||||
TEXT getdr6(SB), 1, $-4
|
||||
MOVQ DR6, AX
|
||||
RET
|
||||
|
||||
TEXT putdr6(SB), $0
|
||||
TEXT putdr6(SB), 1, $-4
|
||||
MOVQ BP, DR6
|
||||
RET
|
||||
|
||||
TEXT putdr7(SB), $0
|
||||
TEXT putdr7(SB), 1, $-4
|
||||
MOVQ BP, DR7
|
||||
RET
|
||||
|
||||
/* VMX instructions */
|
||||
TEXT vmxon(SB), 1, $-4
|
||||
MOVQ BP, 8(SP)
|
||||
/* VMXON 8(SP) */
|
||||
BYTE $0xf3; BYTE $0x0f; BYTE $0xc7; BYTE $0x74; BYTE $0x24; BYTE $0x08
|
||||
JMP _vmout
|
||||
|
||||
TEXT vmxoff(SB), 1, $-4
|
||||
BYTE $0x0f; BYTE $0x01; BYTE $0xc4
|
||||
JMP _vmout
|
||||
|
||||
TEXT vmclear(SB), 1, $-4
|
||||
MOVQ BP, 8(SP)
|
||||
/* VMCLEAR 8(SP) */
|
||||
BYTE $0x66; BYTE $0x0f; BYTE $0xc7; BYTE $0x74; BYTE $0x24; BYTE $0x08
|
||||
JMP _vmout
|
||||
|
||||
TEXT vmlaunch(SB), 1, $-4
|
||||
MOVL $0x6C14, DI
|
||||
MOVQ SP, DX
|
||||
BYTE $0x0f; BYTE $0x79; BYTE $0xfa /* VMWRITE DX, DI */
|
||||
JBE _vmout
|
||||
MOVL $0x6C16, DI
|
||||
MOVQ $vmrestore(SB), DX
|
||||
BYTE $0x0f; BYTE $0x79; BYTE $0xfa /* VMWRITE DX, DI */
|
||||
JBE _vmout
|
||||
|
||||
MOVQ BP, ureg+0(FP)
|
||||
MOVL resume+8(FP), AX
|
||||
TESTL AX, AX
|
||||
MOVQ 0x00(BP), AX
|
||||
MOVQ 0x08(BP), BX
|
||||
MOVQ 0x10(BP), CX
|
||||
MOVQ 0x18(BP), DX
|
||||
MOVQ 0x20(BP), SI
|
||||
MOVQ 0x28(BP), DI
|
||||
MOVQ 0x38(BP), R8
|
||||
MOVQ 0x40(BP), R9
|
||||
MOVQ 0x48(BP), R10
|
||||
MOVQ 0x50(BP), R11
|
||||
MOVQ 0x58(BP), R12
|
||||
MOVQ 0x60(BP), R13
|
||||
MOVQ 0x68(BP), R14
|
||||
MOVQ 0x70(BP), R15
|
||||
MOVQ 0x30(BP), BP
|
||||
JNE _vmresume
|
||||
BYTE $0x0f; BYTE $0x01; BYTE $0xc2 /* VMLAUNCH */
|
||||
JMP _vmout
|
||||
_vmresume:
|
||||
BYTE $0x0f; BYTE $0x01; BYTE $0xc3 /* VMRESUME */
|
||||
JMP _vmout
|
||||
|
||||
TEXT vmrestore(SB), 1, $-4
|
||||
PUSHQ BP
|
||||
MOVQ ureg+0(FP), BP
|
||||
MOVQ AX, 0x00(BP)
|
||||
MOVQ BX, 0x08(BP)
|
||||
MOVQ CX, 0x10(BP)
|
||||
MOVQ DX, 0x18(BP)
|
||||
MOVQ SI, 0x20(BP)
|
||||
MOVQ DI, 0x28(BP)
|
||||
POPQ 0x30(BP)
|
||||
MOVQ R8, 0x38(BP)
|
||||
MOVQ R9, 0x40(BP)
|
||||
MOVQ R10, 0x48(BP)
|
||||
MOVQ R11, 0x50(BP)
|
||||
MOVQ R12, 0x58(BP)
|
||||
MOVQ R13, 0x60(BP)
|
||||
MOVQ R14, 0x68(BP)
|
||||
MOVQ R15, 0x70(BP)
|
||||
|
||||
BYTE $0x65; MOVQ 0, RMACH /* MOVQ GS:(0), RMACH */
|
||||
MOVQ 16(RMACH), RUSER
|
||||
XORL AX, AX
|
||||
RET
|
||||
|
||||
TEXT vmptrld(SB), 1, $-4
|
||||
MOVQ BP, 8(SP)
|
||||
/* VMMPTRLD 8(SP) */
|
||||
BYTE $0x0f; BYTE $0xc7; BYTE $0x74; BYTE $0x24; BYTE $0x08
|
||||
JMP _vmout
|
||||
|
||||
TEXT vmwrite(SB), 1, $-4
|
||||
MOVQ val+8(FP), DX
|
||||
/* VMWRITE DX, BP */
|
||||
BYTE $0x0f; BYTE $0x79; BYTE $0xea
|
||||
JMP _vmout
|
||||
|
||||
TEXT vmread(SB), 1, $-4
|
||||
MOVQ valp+8(FP), DI
|
||||
/* VMREAD BP, (DI) */
|
||||
BYTE $0x0f; BYTE $0x78; BYTE $0x2f
|
||||
JMP _vmout
|
||||
|
||||
TEXT invept(SB), 1, $-4
|
||||
/* INVEPT BP, 16(SP) */
|
||||
BYTE $0x66; BYTE $0x0f; BYTE $0x38; BYTE $0x80; BYTE $0x6c; BYTE $0x24; BYTE $0x10
|
||||
JMP _vmout
|
||||
|
||||
TEXT invvpid(SB), 1, $-4
|
||||
/* INVVPID BP, 16(SP) */
|
||||
BYTE $0x66; BYTE $0x0f; BYTE $0x38; BYTE $0x81; BYTE $0x6c; BYTE $0x24; BYTE $0x10
|
||||
JMP _vmout
|
||||
|
||||
_vmout:
|
||||
JC _vmout1
|
||||
JZ _vmout2
|
||||
XORL AX, AX
|
||||
RET
|
||||
_vmout1:
|
||||
MOVQ $-1, AX
|
||||
RET
|
||||
_vmout2:
|
||||
MOVQ $-2, AX
|
||||
RET
|
||||
|
||||
/*
|
||||
*/
|
||||
TEXT touser(SB), 1, $-4
|
||||
|
|
|
@ -57,7 +57,7 @@ multibootargs(void)
|
|||
if((multiboot[0] & (1<<6)) != 0 && (l = multiboot[11]) >= 24){
|
||||
cp = seprint(cp, ep, "*e820=");
|
||||
m = KADDR(multiboot[12]);
|
||||
while(m[0] >= 20 && m[0] <= l-4){
|
||||
while(m[0] >= 20 && m[0]+4 <= l){
|
||||
uvlong base, size;
|
||||
m++;
|
||||
base = ((uvlong)m[0] | (uvlong)m[1]<<32);
|
||||
|
@ -514,6 +514,7 @@ main()
|
|||
}else
|
||||
links();
|
||||
chandevreset();
|
||||
netconsole();
|
||||
preallocpages();
|
||||
pageinit();
|
||||
swapinit();
|
||||
|
@ -688,6 +689,24 @@ simderror(Ureg *ureg, void*)
|
|||
mathnote(up->fpsave.mxcsr & 0x3f, ureg->pc);
|
||||
}
|
||||
|
||||
void
|
||||
fpinit(void)
|
||||
{
|
||||
/*
|
||||
* A process tries to use the FPU for the
|
||||
* first time and generates a 'device not available'
|
||||
* exception.
|
||||
* Turn the FPU on and initialise it for use.
|
||||
* Set the precision and mask the exceptions
|
||||
* we don't care about from the generic Mach value.
|
||||
*/
|
||||
_clts();
|
||||
_fninit();
|
||||
_fwait();
|
||||
_fldcw(0x0232);
|
||||
_ldmxcsr(0x1900);
|
||||
}
|
||||
|
||||
/*
|
||||
* math coprocessor emulation fault
|
||||
*/
|
||||
|
@ -703,19 +722,7 @@ mathemu(Ureg *ureg, void*)
|
|||
}
|
||||
switch(up->fpstate){
|
||||
case FPinit:
|
||||
/*
|
||||
* A process tries to use the FPU for the
|
||||
* first time and generates a 'device not available'
|
||||
* exception.
|
||||
* Turn the FPU on and initialise it for use.
|
||||
* Set the precision and mask the exceptions
|
||||
* we don't care about from the generic Mach value.
|
||||
*/
|
||||
_clts();
|
||||
_fninit();
|
||||
_fwait();
|
||||
_fldcw(0x0232);
|
||||
_ldmxcsr(0x1900);
|
||||
fpinit();
|
||||
up->fpstate = FPactive;
|
||||
break;
|
||||
case FPinactive:
|
||||
|
|
|
@ -99,6 +99,7 @@
|
|||
#define SELECTOR(i, t, p) (((i)<<3) | (t) | (p))
|
||||
|
||||
#define NULLSEL SELECTOR(NULLSEG, SELGDT, 0)
|
||||
#define KDSEL NULLSEL
|
||||
#define KESEL SELECTOR(KESEG, SELGDT, 0)
|
||||
#define UE32SEL SELECTOR(UE32SEG, SELGDT, 3)
|
||||
#define UDSEL SELECTOR(UDSEG, SELGDT, 3)
|
||||
|
|
|
@ -36,6 +36,9 @@ dev
|
|||
# i82365 cis
|
||||
uart
|
||||
usb
|
||||
|
||||
segment
|
||||
vmx
|
||||
|
||||
link
|
||||
# devpccard
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue