unrestricted guests support (VMXx2)

This commit is contained in:
Stanislav Shwartsman 2010-04-09 11:31:55 +00:00
parent 82900311da
commit 955e237e46
4 changed files with 115 additions and 28 deletions

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)