unrestricted guests support (VMXx2)
This commit is contained in:
parent
82900311da
commit
955e237e46
@ -7,7 +7,8 @@ Brief summary :
|
||||
- Implemented X2APIC extensions (Stanislav)
|
||||
- Implemented Intel VMXx2 extensions (Stanislav)
|
||||
- Extended VMX capability MSRs, APIC Virtualization,
|
||||
Extended Page Tables (EPT), VPID, new VMX controls support
|
||||
X2APIC Virtualization, Extended Page Tables (EPT),
|
||||
VPID, Unrestricted Guests, new VMX controls.
|
||||
- Implemented PCLMULQDQ AES instruction
|
||||
- Extended Bochs internal debugger functionality
|
||||
- USB HP DeskJet 920C printer device emulation (Ben Lunt)
|
||||
@ -52,6 +53,7 @@ Detailed change log :
|
||||
- Implemented Virtualize X2APIC mode control
|
||||
- Implemented Virtual Process ID (VPID)
|
||||
- Implemented WBINVD VMEXIT control
|
||||
- Implemented Unrestricted Guest mode
|
||||
In order to enable emulation of VMXx2 extensions configure with
|
||||
--enable-vmx=2 option (x86-64 must be enabled)
|
||||
- Bugfixes for CPU emulation correctness
|
||||
|
@ -1,5 +1,5 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id: crregs.cc,v 1.11 2010-04-08 15:50:39 sshwarts Exp $
|
||||
// $Id: crregs.cc,v 1.12 2010-04-09 11:31:55 sshwarts Exp $
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2010 Stanislav Shwartsman
|
||||
@ -788,10 +788,16 @@ bx_bool BX_CPP_AttrRegparmN(1) BX_CPU_C::check_CR0(bx_address cr0_val)
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
if (BX_CPU_THIS_PTR in_vmx) {
|
||||
if (!temp_cr0.get_PE() || !temp_cr0.get_NE() || !temp_cr0.get_PG()) {
|
||||
BX_ERROR(("check_CR0(0x%08x): attempt to clear CR0.PE/CR0.NE/CR0.PG in vmx mode !", temp_cr0.get32()));
|
||||
if (!temp_cr0.get_NE()) {
|
||||
BX_ERROR(("check_CR0(0x%08x): attempt to clear CR0.NE in vmx mode !", temp_cr0.get32()));
|
||||
return 0;
|
||||
}
|
||||
if (!BX_CPU_THIS_PTR in_vmx_guest && !SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_UNRESTRICTED_GUEST)) {
|
||||
if (!temp_cr0.get_PE() || !temp_cr0.get_PG()) {
|
||||
BX_ERROR(("check_CR0(0x%08x): attempt to clear CR0.PE/CR0.PG in vmx mode !", temp_cr0.get32()));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
111
bochs/cpu/vmx.cc
111
bochs/cpu/vmx.cc
@ -1,5 +1,5 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id: vmx.cc,v 1.61 2010-04-08 17:00:55 sshwarts Exp $
|
||||
// $Id: vmx.cc,v 1.62 2010-04-09 11:31:55 sshwarts Exp $
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2009-2010 Stanislav Shwartsman
|
||||
@ -464,6 +464,12 @@ VMX_error_code BX_CPU_C::VMenterLoadCheckVmControls(void)
|
||||
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (vm->vmexec_ctrls3 & VMX_VM_EXEC_CTRL3_UNRESTRICTED_GUEST) {
|
||||
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: unrestricted guest without EPT"));
|
||||
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
||||
}
|
||||
}
|
||||
|
||||
if (vm->vmexec_ctrls3 & VMX_VM_EXEC_CTRL3_VPID_ENABLE) {
|
||||
vm->vpid = VMread16(VMCS_16BIT_CONTROL_VPID);
|
||||
@ -622,9 +628,12 @@ VMX_error_code BX_CPU_C::VMenterLoadCheckVmControls(void)
|
||||
}
|
||||
|
||||
if (push_error != push_error_reference) {
|
||||
BX_ERROR(("VMFAIL: VMENTRY bad injected event vector %d", vector));
|
||||
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
||||
if (! (vm->vmexec_ctrls3 & VMX_VM_EXEC_CTRL3_UNRESTRICTED_GUEST)) {
|
||||
BX_ERROR(("VMFAIL: VMENTRY injected event vector %d should push error", vector));
|
||||
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
||||
}
|
||||
}
|
||||
|
||||
if (error_code & 0x7fff0000) {
|
||||
BX_ERROR(("VMFAIL: VMENTRY bad error code 0x%08x for injected event %d", error_code, vector));
|
||||
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
||||
@ -891,9 +900,28 @@ Bit32u BX_CPU_C::VMenterLoadCheckGuestState(Bit64u *qualification)
|
||||
}
|
||||
|
||||
guest.cr0 = VMread64(VMCS_GUEST_CR0);
|
||||
if (~guest.cr0 & VMX_MSR_CR0_FIXED0) {
|
||||
BX_ERROR(("VMENTER FAIL: VMCS guest invalid CR0"));
|
||||
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (vm->vmexec_ctrls3 & VMX_VM_EXEC_CTRL3_UNRESTRICTED_GUEST) {
|
||||
if (~guest.cr0 & (VMX_MSR_CR0_FIXED0 & ~0x80000001 /* PG and PE bits */)) {
|
||||
BX_ERROR(("VMENTER FAIL: VMCS guest invalid CR0"));
|
||||
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
||||
}
|
||||
|
||||
bx_bool pe = guest.cr0 & 0x1;
|
||||
bx_bool pg = (guest.cr0 >> 31) & 0x1;
|
||||
if (pg && !pe) {
|
||||
BX_ERROR(("VMENTER FAIL: VMCS unrestricted guest CR0.PG without CR0.PE"));
|
||||
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (~guest.cr0 & VMX_MSR_CR0_FIXED0) {
|
||||
BX_ERROR(("VMENTER FAIL: VMCS guest invalid CR0"));
|
||||
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
if (guest.cr0 & ~VMX_MSR_CR0_FIXED1) {
|
||||
@ -901,6 +929,12 @@ Bit32u BX_CPU_C::VMenterLoadCheckGuestState(Bit64u *qualification)
|
||||
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
bx_bool real_mode_guest = 0;
|
||||
if (! (guest.cr0 & 0x1))
|
||||
real_mode_guest = 1;
|
||||
#endif
|
||||
|
||||
guest.cr3 = VMread64(VMCS_GUEST_CR3);
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (! IsValidPhyAddr(guest.cr3)) {
|
||||
@ -1018,7 +1052,7 @@ Bit32u BX_CPU_C::VMenterLoadCheckGuestState(Bit64u *qualification)
|
||||
case BX_CODE_EXEC_ONLY_ACCESSED:
|
||||
case BX_CODE_EXEC_READ_ACCESSED:
|
||||
// non-conforming segment
|
||||
if (guest.sregs[n].selector.rpl != guest.sregs[n].cache.dpl) {
|
||||
if (guest.sregs[BX_SEG_REG_CS].selector.rpl != guest.sregs[BX_SEG_REG_CS].cache.dpl) {
|
||||
BX_ERROR(("VMENTER FAIL: VMCS guest non-conforming CS.RPL <> CS.DPL"));
|
||||
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
||||
}
|
||||
@ -1026,11 +1060,22 @@ Bit32u BX_CPU_C::VMenterLoadCheckGuestState(Bit64u *qualification)
|
||||
case BX_CODE_EXEC_ONLY_CONFORMING_ACCESSED:
|
||||
case BX_CODE_EXEC_READ_CONFORMING_ACCESSED:
|
||||
// conforming segment
|
||||
if (guest.sregs[n].selector.rpl < guest.sregs[n].cache.dpl) {
|
||||
if (guest.sregs[BX_SEG_REG_CS].selector.rpl < guest.sregs[BX_SEG_REG_CS].cache.dpl) {
|
||||
BX_ERROR(("VMENTER FAIL: VMCS guest non-conforming CS.RPL < CS.DPL"));
|
||||
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
||||
}
|
||||
break;
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
case BX_DATA_READ_WRITE_ACCESSED:
|
||||
if (vm->vmexec_ctrls3 & VMX_VM_EXEC_CTRL3_UNRESTRICTED_GUEST) {
|
||||
if (guest.sregs[BX_SEG_REG_CS].cache.dpl != 0) {
|
||||
BX_ERROR(("VMENTER FAIL: VMCS unrestricted guest CS.DPL != 0"));
|
||||
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// fall through
|
||||
#endif
|
||||
default:
|
||||
BX_ERROR(("VMENTER FAIL: VMCS guest CS.TYPE"));
|
||||
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
||||
@ -1070,26 +1115,39 @@ Bit32u BX_CPU_C::VMenterLoadCheckGuestState(Bit64u *qualification)
|
||||
}
|
||||
}
|
||||
|
||||
if (guest.sregs[n].cache.type < 11) {
|
||||
// data segment or non-conforming code segment
|
||||
if (guest.sregs[n].selector.rpl > guest.sregs[n].cache.dpl) {
|
||||
BX_ERROR(("VMENTER FAIL: VMCS guest non-conforming %s.RPL < %s.DPL", segname[n], segname[n]));
|
||||
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
||||
if (! (vm->vmexec_ctrls3 & VMX_VM_EXEC_CTRL3_UNRESTRICTED_GUEST)) {
|
||||
if (guest.sregs[n].cache.type < 11) {
|
||||
// data segment or non-conforming code segment
|
||||
if (guest.sregs[n].selector.rpl > guest.sregs[n].cache.dpl) {
|
||||
BX_ERROR(("VMENTER FAIL: VMCS guest non-conforming %s.RPL < %s.DPL", segname[n], segname[n]));
|
||||
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! v8086_guest) {
|
||||
if (guest.sregs[BX_SEG_REG_SS].selector.rpl != guest.sregs[BX_SEG_REG_CS].selector.rpl) {
|
||||
BX_ERROR(("VMENTER FAIL: VMCS guest CS.RPL != SS.RPL"));
|
||||
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
||||
if (! (vm->vmexec_ctrls3 & VMX_VM_EXEC_CTRL3_UNRESTRICTED_GUEST)) {
|
||||
if (guest.sregs[BX_SEG_REG_SS].selector.rpl != guest.sregs[BX_SEG_REG_CS].selector.rpl) {
|
||||
BX_ERROR(("VMENTER FAIL: VMCS guest CS.RPL != SS.RPL"));
|
||||
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
||||
}
|
||||
if (guest.sregs[BX_SEG_REG_SS].selector.rpl != guest.sregs[BX_SEG_REG_SS].cache.dpl) {
|
||||
BX_ERROR(("VMENTER FAIL: VMCS guest SS.RPL <> SS.DPL"));
|
||||
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
||||
}
|
||||
}
|
||||
|
||||
if (guest.sregs[BX_SEG_REG_SS].selector.rpl != guest.sregs[BX_SEG_REG_SS].cache.dpl) {
|
||||
BX_ERROR(("VMENTER FAIL: VMCS guest SS.RPL <> SS.DPL"));
|
||||
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
else { // unrestricted guest
|
||||
if (real_mode_guest || guest.sregs[BX_SEG_REG_CS].cache.type == BX_DATA_READ_WRITE_ACCESSED) {
|
||||
if (guest.sregs[BX_SEG_REG_SS].cache.dpl != 0) {
|
||||
BX_ERROR(("VMENTER FAIL: VMCS unrestricted guest SS.DPL != 0"));
|
||||
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
@ -1782,6 +1840,19 @@ void BX_CPU_C::VMexitSaveGuestState(void)
|
||||
if (BX_CPU_THIS_PTR disable_NMI)
|
||||
interruptibility_state |= BX_VMX_INTERRUPTS_BLOCKED_NMI_BLOCKED;
|
||||
VMwrite32(VMCS_32BIT_GUEST_INTERRUPTIBILITY_STATE, interruptibility_state);
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (VMX_MSR_MISC & 0x20) {
|
||||
// VMEXITs store the value of EFER.LMA into the “x86-64 guest" VMENTRY control
|
||||
// must be set if unrestricted guest is supported
|
||||
if (long_mode())
|
||||
vm->vmentry_ctrls |= VMX_VMENTRY_CTRL1_X86_64_GUEST;
|
||||
else
|
||||
vm->vmentry_ctrls &= ~VMX_VMENTRY_CTRL1_X86_64_GUEST;
|
||||
|
||||
VMwrite32(VMCS_32BIT_CONTROL_VMENTRY_CONTROLS, vm->vmentry_ctrls);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPU_C::VMexitLoadHostState(void)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id: vmx.h,v 1.28 2010-04-08 15:50:39 sshwarts Exp $
|
||||
// $Id: vmx.h,v 1.29 2010-04-09 11:31:55 sshwarts Exp $
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2009 Stanislav Shwartsman
|
||||
@ -596,7 +596,8 @@ typedef struct bx_VMCS
|
||||
VMX_VM_EXEC_CTRL3_RDTSCP | \
|
||||
VMX_VM_EXEC_CTRL3_VIRTUALIZE_X2APIC_MODE | \
|
||||
VMX_VM_EXEC_CTRL3_VPID_ENABLE | \
|
||||
VMX_VM_EXEC_CTRL3_WBINVD_VMEXIT)
|
||||
VMX_VM_EXEC_CTRL3_WBINVD_VMEXIT | \
|
||||
VMX_VM_EXEC_CTRL3_UNRESTRICTED_GUEST)
|
||||
|
||||
#endif
|
||||
|
||||
@ -910,7 +911,7 @@ enum VMX_Activity_State {
|
||||
|
||||
// [4:0] - TSC:VMX_PREEMPTION_TIMER ratio
|
||||
// [5] - VMEXITs store the value of EFER.LMA into the “x86-64 guest"
|
||||
// VMENTRY control (set to '1 if 'unrestricted guest' is supported)
|
||||
// VMENTRY control (must set to '1 if 'unrestricted guest' is supported)
|
||||
// [6] - support VMENTER to HLT state
|
||||
// [7] - support VMENTER to SHUTDOWN state
|
||||
// [8] - support VMENTER to WAIT_FOR_SIPI state
|
||||
@ -918,7 +919,14 @@ enum VMX_Activity_State {
|
||||
// [27:25] - (N+1)*512 - recommended maximum MSRs in MSR store list
|
||||
// [63:32] - MSEG revision ID used by processor
|
||||
|
||||
#define VMX_MSR_MISC (VMX_CR3_TARGET_MAX_CNT << 16)
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
#define VMX_MISC_STORE_LMA_TO_X86_64_GUEST_VMENTRY_CONTROL (1<<5)
|
||||
#else
|
||||
#define VMX_MISC_STORE_LMA_TO_X86_64_GUEST_VMENTRY_CONTROL (0)
|
||||
#endif
|
||||
|
||||
#define VMX_MSR_MISC ((VMX_CR3_TARGET_MAX_CNT << 16) | \
|
||||
VMX_MISC_STORE_LMA_TO_X86_64_GUEST_VMENTRY_CONTROL)
|
||||
|
||||
//
|
||||
// IA32_VMX_CR0_FIXED0 MSR (0x486) IA32_VMX_CR0_FIXED1 MSR (0x487)
|
||||
|
Loading…
Reference in New Issue
Block a user