implemented virtualization exception feature
This commit is contained in:
parent
d38fce8218
commit
64df073617
@ -4407,6 +4407,7 @@ public: // for now...
|
||||
BX_SMF void VMexit_CR8_Write(bxInstruction_c *i) BX_CPP_AttrRegparmN(1);
|
||||
BX_SMF void VMexit_DR_Access(unsigned read, unsigned dr, unsigned reg);
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
BX_SMF void Virtualization_Exception(Bit64u qualification, Bit64u guest_physical, Bit64u guest_linear);
|
||||
BX_SMF void vmfunc_eptp_switching(void);
|
||||
#endif
|
||||
#endif
|
||||
|
@ -165,7 +165,7 @@ typedef bx_cpuid_t* (*bx_create_cpuid_method)(BX_CPU_C *cpu);
|
||||
#define BX_VMX_VINTR_DELIVERY (1 << 18) /* Virtual Interrupt Delivery */
|
||||
#define BX_VMX_POSTED_INSTERRUPTS (1 << 19) /* Posted Interrupts support - not implemented yet */
|
||||
#define BX_VMX_VMCS_SHADOWING (1 << 20) /* VMCS Shadowing */
|
||||
#define BX_VMX_EPT_EXCEPTION (1 << 21) /* EPT Violation (#VE) exception - not implemented yet */
|
||||
#define BX_VMX_EPT_EXCEPTION (1 << 21) /* EPT Violation (#VE) exception */
|
||||
|
||||
// CPUID defines - STD features CPUID[0x00000001].EDX
|
||||
// ----------------------------
|
||||
|
@ -1505,6 +1505,8 @@ bx_phy_address BX_CPU_C::nested_walk(bx_phy_address guest_paddr, unsigned rw, bx
|
||||
#define BX_EPT_ENTRY_WRITE_EXECUTE 0x06
|
||||
#define BX_EPT_ENTRY_READ_WRITE_EXECUTE 0x07
|
||||
|
||||
#define BX_SUPPRESS_EPT_VIOLATION_EXCEPTION BX_CONST64(0x8000000000000000)
|
||||
|
||||
// Format of a EPT Entry
|
||||
// -----------------------------------------------------------
|
||||
// 00 | Read access
|
||||
@ -1541,7 +1543,7 @@ bx_phy_address BX_CPU_C::translate_guest_physical(bx_phy_address guest_paddr, bx
|
||||
if (rw & 1) access_mask |= BX_EPT_WRITE; // write or r-m-w
|
||||
if (rw == BX_READ) access_mask |= BX_EPT_READ;
|
||||
|
||||
Bit32u vmexit_reason = 0, vmexit_qualification = access_mask;
|
||||
Bit32u vmexit_reason = 0;
|
||||
|
||||
for (leaf = BX_LEVEL_PML4;; --leaf) {
|
||||
entry_addr[leaf] = ppf + ((guest_paddr >> (9 + 9*leaf)) & 0xff8);
|
||||
@ -1611,19 +1613,26 @@ bx_phy_address BX_CPU_C::translate_guest_physical(bx_phy_address guest_paddr, bx
|
||||
if (vmexit_reason) {
|
||||
BX_ERROR(("VMEXIT: EPT %s for guest paddr 0x" FMT_ADDRX " laddr 0x" FMT_ADDRX,
|
||||
(vmexit_reason == VMX_VMEXIT_EPT_VIOLATION) ? "violation" : "misconfig", guest_paddr, guest_laddr));
|
||||
VMwrite64(VMCS_64BIT_GUEST_PHYSICAL_ADDR, guest_paddr);
|
||||
|
||||
if (vmexit_reason == VMX_VMEXIT_EPT_MISCONFIGURATION) {
|
||||
VMexit(VMX_VMEXIT_EPT_MISCONFIGURATION, 0);
|
||||
}
|
||||
else {
|
||||
Bit32u vmexit_qualification = 0;
|
||||
|
||||
if (vmexit_reason == VMX_VMEXIT_EPT_VIOLATION) {
|
||||
// no VMExit qualification for EPT Misconfiguration VMExit
|
||||
vmexit_qualification = access_mask | (combined_access << 3);
|
||||
if (guest_laddr_valid) {
|
||||
VMwrite_natural(VMCS_GUEST_LINEAR_ADDR, guest_laddr);
|
||||
vmexit_qualification |= 0x80;
|
||||
if (! is_page_walk) vmexit_qualification |= 0x100;
|
||||
}
|
||||
VMexit(VMX_VMEXIT_EPT_VIOLATION, vmexit_qualification | (combined_access << 3));
|
||||
|
||||
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_EPT_VIOLATION_EXCEPTION)) {
|
||||
if ((entry[leaf] & BX_SUPPRESS_EPT_VIOLATION_EXCEPTION) == 0)
|
||||
Virtualization_Exception(vmexit_qualification, guest_paddr, guest_laddr);
|
||||
}
|
||||
}
|
||||
|
||||
VMwrite64(VMCS_64BIT_GUEST_PHYSICAL_ADDR, guest_paddr);
|
||||
VMwrite_natural(VMCS_GUEST_LINEAR_ADDR, guest_laddr);
|
||||
VMexit(vmexit_reason, vmexit_qualification);
|
||||
}
|
||||
|
||||
if (BX_VMX_EPT_ACCESS_DIRTY_ENABLED) {
|
||||
|
@ -555,8 +555,11 @@ void BX_CPU_C::init_vmx_capabilities(void)
|
||||
if (BX_CPUID_SUPPORT_ISA_EXTENSION(BX_ISA_RDSEED))
|
||||
cap->vmx_vmexec_ctrl2_supported_bits |= VMX_VM_EXEC_CTRL3_RDSEED_VMEXIT;
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (BX_SUPPORT_VMX_EXTENSION(BX_VMX_EPT_EXCEPTION))
|
||||
if (BX_SUPPORT_VMX_EXTENSION(BX_VMX_EPT_EXCEPTION)) {
|
||||
if (! BX_SUPPORT_VMX_EXTENSION(BX_VMX_EPTP_SWITCHING))
|
||||
BX_PANIC(("#VE exception feature requires EPTP switching support !"));
|
||||
cap->vmx_vmexec_ctrl2_supported_bits |= VMX_VM_EXEC_CTRL3_EPT_VIOLATION_EXCEPTION;
|
||||
}
|
||||
#endif
|
||||
|
||||
// enable secondary vm exec controls if needed
|
||||
|
@ -691,6 +691,54 @@ bx_bool BX_CPP_AttrRegparmN(1) BX_CPU_C::Vmexit_Vmwrite(bxInstruction_c *i)
|
||||
|
||||
return BX_FALSE;
|
||||
}
|
||||
|
||||
void BX_CPU_C::Virtualization_Exception(Bit64u qualification, Bit64u guest_physical, Bit64u guest_linear)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR in_vmx_guest);
|
||||
|
||||
// A convertible EPT violation causes a virtualization exception if the following all hold:
|
||||
// - CR0.PE is set
|
||||
// - the logical processor is not in the process of delivering an event through the IDT
|
||||
// - the 32 bits at offset 4 in the virtualization-exception information area are all 0
|
||||
|
||||
if (! BX_CPU_THIS_PTR cr0.get_PE() || BX_CPU_THIS_PTR in_event) return;
|
||||
|
||||
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
||||
|
||||
Bit32u magic;
|
||||
access_read_physical(vm->ve_info_addr + 4, 4, &magic);
|
||||
BX_NOTIFY_PHY_MEMORY_ACCESS(vm->ve_info_addr + 4, 4, BX_READ, 0, &magic);
|
||||
if (magic != 0) return;
|
||||
|
||||
struct ve_info {
|
||||
Bit32u reason; // always VMX_VMEXIT_EPT_VIOLATION
|
||||
Bit32u magic;
|
||||
Bit64u qualification;
|
||||
Bit64u guest_linear_addr;
|
||||
Bit64u guest_physical_addr;
|
||||
Bit16u eptp_index;
|
||||
} ve_info = { VMX_VMEXIT_EPT_VIOLATION, 0xffffffff, qualification, guest_linear, guest_physical, vm->eptp_index };
|
||||
|
||||
access_write_physical(vm->ve_info_addr, 4, &ve_info.reason);
|
||||
BX_NOTIFY_PHY_MEMORY_ACCESS(vm->ve_info_addr, 4, BX_WRITE, 0, &ve_info.reason);
|
||||
|
||||
access_write_physical(vm->ve_info_addr + 4, 4, &ve_info.magic);
|
||||
BX_NOTIFY_PHY_MEMORY_ACCESS(vm->ve_info_addr + 4, 4, BX_WRITE, 0, &ve_info.magic);
|
||||
|
||||
access_write_physical(vm->ve_info_addr + 8, 8, &ve_info.qualification);
|
||||
BX_NOTIFY_PHY_MEMORY_ACCESS(vm->ve_info_addr + 8, 8, BX_WRITE, 0, &ve_info.qualification);
|
||||
|
||||
access_write_physical(vm->ve_info_addr + 16, 8, &ve_info.guest_linear_addr);
|
||||
BX_NOTIFY_PHY_MEMORY_ACCESS(vm->ve_info_addr + 16, 8, BX_WRITE, 0, &ve_info.guest_linear_addr);
|
||||
|
||||
access_write_physical(vm->ve_info_addr + 24, 8, &ve_info.guest_physical_addr);
|
||||
BX_NOTIFY_PHY_MEMORY_ACCESS(vm->ve_info_addr + 24, 8, BX_WRITE, 0, &ve_info.guest_physical_addr);
|
||||
|
||||
access_write_physical(vm->ve_info_addr + 32, 8, &ve_info.eptp_index);
|
||||
BX_NOTIFY_PHY_MEMORY_ACCESS(vm->ve_info_addr + 32, 8, BX_WRITE, 0, &ve_info.eptp_index);
|
||||
|
||||
exception(BX_VE_EXCEPTION, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BX_SUPPORT_VMX
|
||||
|
@ -2,7 +2,7 @@
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2011-2012 Stanislav Shwartsman
|
||||
// Copyright (c) 2011-2013 Stanislav Shwartsman
|
||||
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
@ -80,5 +80,10 @@ void BX_CPU_C::vmfunc_eptp_switching(void)
|
||||
vm->eptptr = temp_eptp;
|
||||
VMwrite64(VMCS_64BIT_CONTROL_EPTPTR, temp_eptp);
|
||||
TLB_flush();
|
||||
|
||||
if (BX_SUPPORT_VMX_EXTENSION(BX_VMX_EPT_EXCEPTION)) {
|
||||
vm->eptp_index = eptp_list_entry /* & 0xffff */ /* not needed because eptp_list_entry < 512 */;
|
||||
VMwrite16(VMCS_16BIT_CONTROL_EPTP_INDEX, vm->eptp_index);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -592,6 +592,14 @@ VMX_error_code BX_CPU_C::VMenterLoadCheckVmControls(void)
|
||||
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
||||
}
|
||||
}
|
||||
|
||||
if (vm->vmexec_ctrls3 & VMX_VM_EXEC_CTRL3_EPT_VIOLATION_EXCEPTION) {
|
||||
vm->ve_info_addr = (bx_phy_address) VMread64(VMCS_64BIT_CONTROL_VE_EXCEPTION_INFO_ADDR);
|
||||
if (! IsValidPageAlignedPhyAddr(vm->ve_info_addr)) {
|
||||
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: broken #VE information address"));
|
||||
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
@ -3644,6 +3652,10 @@ void BX_CPU_C::register_vmx_state(bx_param_c *parent)
|
||||
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, vmread_bitmap_addr, BX_CPU_THIS_PTR vmcs.vmread_bitmap_addr);
|
||||
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, vmwrite_bitmap_addr, BX_CPU_THIS_PTR vmcs.vmwrite_bitmap_addr);
|
||||
#endif
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, ve_info_addr, BX_CPU_THIS_PTR vmcs.ve_info_addr);
|
||||
BXRS_HEX_PARAM_FIELD(vmexec_ctrls, eptp_index, BX_CPU_THIS_PTR vmcs.eptp_index);
|
||||
#endif
|
||||
|
||||
//
|
||||
// VM-Exit Control Fields
|
||||
|
@ -682,6 +682,11 @@ typedef struct bx_VMCS
|
||||
bx_phy_address vmread_bitmap_addr, vmwrite_bitmap_addr;
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
bx_phy_address ve_info_addr;
|
||||
Bit16u eptp_index;
|
||||
#endif
|
||||
|
||||
//
|
||||
// VM-Exit Control Fields
|
||||
//
|
||||
|
Loading…
Reference in New Issue
Block a user