Implemented VMX 'Shadow Stack Prematurely Busy' and secondary VMEXIT controls
This commit is contained in:
parent
e14b126198
commit
38b1bbf4ff
@ -8,6 +8,7 @@ Brief summary :
|
||||
- Critical CPU emulation bugfixes for SHA and GFNI instructions, ADOX instruction (prevented boot of Win10)
|
||||
! SVM: Implemented SVM VM_CR_MSR and INIT redirect (required for booting SMP with SVM)
|
||||
! Implemented VMX MBE (Mode Based Execution Control) emulation required for Windows 11 guest
|
||||
! Implemented VMX 'Shadow Stack Prematurely Busy' control
|
||||
! Implemented MSR IA32_SPEC_CTRL Virtualization VMX extension
|
||||
! Implemented Posted-Interrupt Processing VMX extension emulation
|
||||
! Implemented Linear Address Separation (LASS) extension
|
||||
@ -42,6 +43,7 @@ Detailed change log :
|
||||
- SVM: Implemented SVM VM_CR_MSR and INIT redirect (required for booting SMP with SVM)
|
||||
- Implemented VMX MBE (Mode Based Execution Control) emulation required for Windows 11 guest
|
||||
- Implemented advanced VM-exit information for EPT violations (tied to MBE Control)
|
||||
- Implemented VMX 'Shadow Stack Prematurely Busy' control
|
||||
- Implemented MSR IA32_SPEC_CTRL Virtualization VMX extension
|
||||
- Implemented Posted-Interrupt Processing VMX extension emulation
|
||||
- Implemented Linear Address Separation (LASS) extension
|
||||
|
@ -2,7 +2,7 @@
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2005-2019 Stanislav Shwartsman
|
||||
// Copyright (c) 2005-2024 Stanislav Shwartsman
|
||||
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
@ -649,6 +649,11 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::shadow_stack_switch(bx_address new_SSP)
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::call_far_shadow_stack_push(Bit16u cs, bx_address lip, bx_address old_ssp)
|
||||
{
|
||||
#if BX_SUPPORT_VMX
|
||||
if (BX_CPU_THIS_PTR in_vmx_guest)
|
||||
BX_CPU_THIS_PTR vmcs.shadow_stack_prematurely_busy = true;
|
||||
#endif
|
||||
|
||||
if (SSP & 0x7) {
|
||||
shadow_stack_write_dword(SSP-4, CPL, 0);
|
||||
SSP &= ~BX_CONST64(0x7);
|
||||
@ -657,7 +662,12 @@ void BX_CPP_AttrRegparmN(1) BX_CPU_C::call_far_shadow_stack_push(Bit16u cs, bx_a
|
||||
shadow_stack_push_64(cs);
|
||||
shadow_stack_push_64(lip);
|
||||
shadow_stack_push_64(old_ssp);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
if (BX_CPU_THIS_PTR in_vmx_guest)
|
||||
BX_CPU_THIS_PTR vmcs.shadow_stack_prematurely_busy = false;
|
||||
#endif
|
||||
}
|
||||
#endif // BX_SUPPORT_CET
|
||||
|
||||
#endif // BX_SUPPORT_X86_64
|
||||
|
@ -89,6 +89,15 @@ void BX_CPU_C::cpu_loop(void)
|
||||
BX_CPU_THIS_PTR prev_rip = RIP; // commit new EIP
|
||||
BX_CPU_THIS_PTR speculative_rsp = false;
|
||||
|
||||
#if BX_SUPPORT_CET && BX_SUPPORT_VMX
|
||||
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
||||
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
||||
if (vm->shadow_stack_prematurely_busy)
|
||||
BX_PANIC(("Shadow stack prematurely busy is left set !"));
|
||||
vm->shadow_stack_prematurely_busy = false; // for safety
|
||||
}
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
|
||||
// check on events which occurred for previous instructions (traps)
|
||||
|
@ -4944,6 +4944,7 @@ public: // for now...
|
||||
BX_SMF void init_secondary_proc_based_vmexec_ctrls(void);
|
||||
BX_SMF void init_tertiary_proc_based_vmexec_ctrls(void);
|
||||
BX_SMF void init_vmexit_ctrls(void);
|
||||
BX_SMF void init_secondary_vmexit_ctrls(void);
|
||||
BX_SMF void init_vmentry_ctrls(void);
|
||||
BX_SMF void init_VMCS(void);
|
||||
BX_SMF bool vmcs_field_supported(Bit32u encoding);
|
||||
@ -4974,7 +4975,7 @@ public: // for now...
|
||||
BX_SMF void VMX_Self_IPI_Virtualization(Bit8u vector);
|
||||
BX_SMF void VMX_Evaluate_Pending_Virtual_Interrupts(void);
|
||||
BX_SMF void VMX_Deliver_Virtual_Interrupt(void);
|
||||
BX_SMF void vmx_page_modification_logging(Bit64u guest_addr, unsigned dirty_update);
|
||||
BX_SMF void vmx_page_modification_logging(Bit64u guest_laddr, Bit64u guest_paddr, unsigned dirty_update);
|
||||
#endif
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
BX_SMF Bit16u VMread16_Shadow(unsigned encoding) BX_CPP_AttrRegparmN(1);
|
||||
|
@ -181,8 +181,6 @@ bxICacheEntry_c* BX_CPU_C::serveICacheMiss(Bit32u eipBiased, bx_phy_address pAdd
|
||||
}
|
||||
}
|
||||
|
||||
//BX_INFO(("commit trace %08x len=%d mask %08x", (Bit32u) entry->pAddr, entry->tlen, pageWriteStampTable.getFineGranularityMapping(entry->pAddr)));
|
||||
|
||||
entry->traceMask |= traceMask;
|
||||
|
||||
pageWriteStampTable.markICacheMask(pAddr, entry->traceMask);
|
||||
|
@ -387,6 +387,12 @@ bool BX_CPP_AttrRegparmN(2) BX_CPU_C::rdmsr(Bit32u index, Bit64u *msr)
|
||||
case BX_MSR_VMX_VMEXIT_CTRLS:
|
||||
val64 = VMX_MSR_VMX_VMEXIT_CTRLS;
|
||||
break;
|
||||
case BX_MSR_VMX_VMEXIT_CTRLS2:
|
||||
if (BX_CPU_THIS_PTR vmx_cap.vmx_vmexit_ctrl2_supported_bits) {
|
||||
val64 = VMX_MSR_VMX_VMEXIT_CTRLS2;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
case BX_MSR_VMX_VMENTRY_CTRLS:
|
||||
val64 = VMX_MSR_VMX_VMENTRY_CTRLS;
|
||||
break;
|
||||
@ -1144,6 +1150,7 @@ bool BX_CPP_AttrRegparmN(2) BX_CPU_C::wrmsr(Bit32u index, Bit64u val_64)
|
||||
case BX_MSR_VMX_PROCBASED_CTRLS2:
|
||||
case BX_MSR_VMX_PROCBASED_CTRLS3:
|
||||
case BX_MSR_VMX_VMEXIT_CTRLS:
|
||||
case BX_MSR_VMX_VMEXIT_CTRLS2:
|
||||
case BX_MSR_VMX_VMENTRY_CTRLS:
|
||||
case BX_MSR_VMX_MISC:
|
||||
case BX_MSR_VMX_CR0_FIXED0:
|
||||
|
@ -124,6 +124,7 @@ enum MSR_Register {
|
||||
BX_MSR_VMX_TRUE_VMENTRY_CTRLS = 0x490,
|
||||
BX_MSR_VMX_VMFUNC = 0x491,
|
||||
BX_MSR_VMX_PROCBASED_CTRLS3 = 0x492,
|
||||
BX_MSR_VMX_VMEXIT_CTRLS2 = 0x493,
|
||||
BX_MSR_IA32_FEATURE_CONTROL = 0x03A,
|
||||
BX_MSR_IA32_SMM_MONITOR_CTL = 0x09B,
|
||||
#endif
|
||||
|
@ -921,8 +921,16 @@ void BX_CPU_C::update_access_dirty_PAE(bx_phy_address *entry_addr, Bit64u *entry
|
||||
}
|
||||
|
||||
// Update A/D bits if needed
|
||||
if (!(entry[leaf] & 0x20) || (write && !(entry[leaf] & 0x40))) {
|
||||
entry[leaf] |= (0x20 | (write<<6)); // Update A and possibly D bits
|
||||
// Specifically, a processor that supports CET will never set the dirty flag in a paging-structure entry in which the R/W flag is clear
|
||||
bool set_dirty = write && !(entry[leaf] & 0x40);
|
||||
if (BX_CPUID_SUPPORT_ISA_EXTENSION(BX_ISA_CET)) {
|
||||
if (set_dirty && !(entry[leaf] & 0x02)) {
|
||||
BX_PANIC(("PAE: asked to set dirty on paging leaf entry with R/W bit clear"));
|
||||
}
|
||||
}
|
||||
if (!(entry[leaf] & 0x20) || set_dirty) {
|
||||
entry[leaf] |= 0x20; // Update A and possibly D bits
|
||||
if (set_dirty) entry[leaf] |= 0x40;
|
||||
write_physical_qword(entry_addr[leaf], entry[leaf], entry_memtype[leaf], AccessReason(BX_PTE_ACCESS + leaf)); // should be done with locked RMW
|
||||
}
|
||||
}
|
||||
@ -1227,8 +1235,16 @@ void BX_CPU_C::update_access_dirty(bx_phy_address *entry_addr, Bit32u *entry, Bx
|
||||
}
|
||||
|
||||
// Update A/D bits if needed
|
||||
if (!(entry[leaf] & 0x20) || (write && !(entry[leaf] & 0x40))) {
|
||||
entry[leaf] |= (0x20 | (write<<6)); // Update A and possibly D bits
|
||||
// Specifically, a processor that supports CET will never set the dirty flag in a paging-structure entry in which the R/W flag is clear
|
||||
bool set_dirty = write && !(entry[leaf] & 0x40);
|
||||
if (BX_CPUID_SUPPORT_ISA_EXTENSION(BX_ISA_CET)) {
|
||||
if (set_dirty && !(entry[leaf] & 0x02)) {
|
||||
BX_PANIC(("Legacy Paging: asked to set dirty on paging leaf entry with R/W bit clear"));
|
||||
}
|
||||
}
|
||||
if (!(entry[leaf] & 0x20) || set_dirty) {
|
||||
entry[leaf] |= 0x20; // Update A and possibly D bits
|
||||
if (set_dirty) entry[leaf] |= 0x40;
|
||||
write_physical_dword(entry_addr[leaf], entry[leaf], entry_memtype[leaf], AccessReason(BX_PTE_ACCESS + leaf)); // should be done with locked RMW
|
||||
}
|
||||
}
|
||||
@ -2089,7 +2105,7 @@ bx_phy_address BX_CPU_C::translate_guest_physical(bx_phy_address guest_paddr, bx
|
||||
// write access and Dirty-bit is not set in the leaf entry
|
||||
unsigned dirty_update = (rw & 1) && !(entry[leaf] & 0x200);
|
||||
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL2_PML_ENABLE))
|
||||
vmx_page_modification_logging(guest_paddr, dirty_update);
|
||||
vmx_page_modification_logging(guest_laddr, guest_paddr, dirty_update);
|
||||
|
||||
update_ept_access_dirty(entry_addr, entry, MEMTYPE(eptptr_memtype), leaf, rw & 1);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2009-2023 Stanislav Shwartsman
|
||||
// Copyright (c) 2009-2024 Stanislav Shwartsman
|
||||
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
@ -398,6 +398,10 @@ bool BX_CPU_C::vmcs_field_supported(Bit32u encoding)
|
||||
case VMCS_64BIT_CONTROL_TERTIARY_VMEXEC_CONTROLS_HI:
|
||||
return BX_CPU_THIS_PTR vmx_cap.vmx_vmexec_ctrl3_supported_bits;
|
||||
|
||||
case VMCS_64BIT_CONTROL_SECONDARY_VMEXIT_CONTROLS:
|
||||
case VMCS_64BIT_CONTROL_SECONDARY_VMEXIT_CONTROLS_HI:
|
||||
return BX_CPU_THIS_PTR vmx_cap.vmx_vmexit_ctrl2_supported_bits;
|
||||
|
||||
case VMCS_64BIT_CONTROL_IA32_SPEC_CTRL_MASK:
|
||||
case VMCS_64BIT_CONTROL_IA32_SPEC_CTRL_MASK_HI:
|
||||
case VMCS_64BIT_CONTROL_IA32_SPEC_CTRL_SHADOW:
|
||||
@ -565,6 +569,7 @@ void BX_CPU_C::init_vmx_capabilities(void)
|
||||
init_tertiary_proc_based_vmexec_ctrls(); // must initialize in reverse order
|
||||
init_secondary_proc_based_vmexec_ctrls();
|
||||
init_primary_proc_based_vmexec_ctrls();
|
||||
init_secondary_vmexit_ctrls(); // must initialize in reverse order
|
||||
init_vmexit_ctrls();
|
||||
init_vmentry_ctrls();
|
||||
}
|
||||
@ -881,6 +886,20 @@ void BX_CPU_C::init_tertiary_proc_based_vmexec_ctrls(void)
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPU_C::init_secondary_vmexit_ctrls(void)
|
||||
{
|
||||
struct bx_VMX_Cap *cap = &BX_CPU_THIS_PTR vmx_cap;
|
||||
|
||||
// secondary vmexit controls
|
||||
// -----------------------------------------------------------
|
||||
// [02] Prematurely busy shadow stack control
|
||||
|
||||
#if BX_SUPPORT_CET
|
||||
if (BX_CPUID_SUPPORT_ISA_EXTENSION(BX_ISA_CET))
|
||||
cap->vmx_vmexit_ctrl2_supported_bits |= VMX_VMEXIT_CTRL2_SHADOW_STACK_BUSY_CTRL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPU_C::init_vmexit_ctrls(void)
|
||||
{
|
||||
struct bx_VMX_Cap *cap = &BX_CPU_THIS_PTR vmx_cap;
|
||||
@ -905,42 +924,46 @@ void BX_CPU_C::init_vmexit_ctrls(void)
|
||||
// [28] Save host CET state on VMEXIT
|
||||
// [29] Save host MSR_IA32_PKRS on VMEXIT
|
||||
// [30] Save guest MSR_PERF_GLOBAL_CTRL on VMEXIT
|
||||
// [31] Activate secondary VMEXIT controls
|
||||
|
||||
cap->vmx_vmexit_ctrl_supported_bits =
|
||||
cap->vmx_vmexit_ctrl1_supported_bits =
|
||||
VMX_VMEXIT_CTRL1_INTA_ON_VMEXIT | VMX_VMEXIT_CTRL1_SAVE_DBG_CTRLS;
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (BX_CPUID_SUPPORT_ISA_EXTENSION(BX_ISA_LONG_MODE))
|
||||
cap->vmx_vmexit_ctrl_supported_bits |= VMX_VMEXIT_CTRL1_HOST_ADDR_SPACE_SIZE;
|
||||
cap->vmx_vmexit_ctrl1_supported_bits |= VMX_VMEXIT_CTRL1_HOST_ADDR_SPACE_SIZE;
|
||||
#endif
|
||||
if (BX_SUPPORT_VMX_EXTENSION(BX_VMX_PERF_GLOBAL_CTRL))
|
||||
cap->vmx_vmexit_ctrl_supported_bits |= VMX_VMEXIT_CTRL1_LOAD_PERF_GLOBAL_CTRL_MSR;
|
||||
cap->vmx_vmexit_ctrl1_supported_bits |= VMX_VMEXIT_CTRL1_LOAD_PERF_GLOBAL_CTRL_MSR;
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (BX_SUPPORT_VMX_EXTENSION(BX_VMX_PAT)) {
|
||||
cap->vmx_vmexit_ctrl_supported_bits |=
|
||||
cap->vmx_vmexit_ctrl1_supported_bits |=
|
||||
VMX_VMEXIT_CTRL1_STORE_PAT_MSR | VMX_VMEXIT_CTRL1_LOAD_PAT_MSR;
|
||||
}
|
||||
if (BX_SUPPORT_VMX_EXTENSION(BX_VMX_EFER)) {
|
||||
cap->vmx_vmexit_ctrl_supported_bits |=
|
||||
cap->vmx_vmexit_ctrl1_supported_bits |=
|
||||
VMX_VMEXIT_CTRL1_STORE_EFER_MSR | VMX_VMEXIT_CTRL1_LOAD_EFER_MSR;
|
||||
}
|
||||
if (BX_SUPPORT_VMX_EXTENSION(BX_VMX_PREEMPTION_TIMER))
|
||||
cap->vmx_vmexit_ctrl_supported_bits |= VMX_VMEXIT_CTRL1_STORE_VMX_PREEMPTION_TIMER;
|
||||
cap->vmx_vmexit_ctrl1_supported_bits |= VMX_VMEXIT_CTRL1_STORE_VMX_PREEMPTION_TIMER;
|
||||
#endif
|
||||
#if BX_SUPPORT_UINTR
|
||||
if (BX_CPUID_SUPPORT_ISA_EXTENSION(BX_ISA_UINTR))
|
||||
cap->vmx_vmexit_ctrl_supported_bits |= VMX_VMEXIT_CTRL1_CLEAR_UINV;
|
||||
cap->vmx_vmexit_ctrl1_supported_bits |= VMX_VMEXIT_CTRL1_CLEAR_UINV;
|
||||
#endif
|
||||
#if BX_SUPPORT_CET
|
||||
if (BX_CPUID_SUPPORT_ISA_EXTENSION(BX_ISA_CET))
|
||||
cap->vmx_vmexit_ctrl_supported_bits |= VMX_VMEXIT_CTRL1_LOAD_HOST_CET_STATE;
|
||||
cap->vmx_vmexit_ctrl1_supported_bits |= VMX_VMEXIT_CTRL1_LOAD_HOST_CET_STATE;
|
||||
#endif
|
||||
#if BX_SUPPORT_PKEYS
|
||||
if (BX_CPUID_SUPPORT_ISA_EXTENSION(BX_ISA_PKS))
|
||||
cap->vmx_vmexit_ctrl_supported_bits |= VMX_VMEXIT_CTRL1_LOAD_HOST_PKRS;
|
||||
cap->vmx_vmexit_ctrl1_supported_bits |= VMX_VMEXIT_CTRL1_LOAD_HOST_PKRS;
|
||||
#endif
|
||||
if (BX_SUPPORT_VMX_EXTENSION(BX_VMX_PERF_GLOBAL_CTRL))
|
||||
cap->vmx_vmexit_ctrl_supported_bits |= VMX_VMEXIT_CTRL1_SAVE_PERF_GLOBAL_CTRL;
|
||||
cap->vmx_vmexit_ctrl1_supported_bits |= VMX_VMEXIT_CTRL1_SAVE_PERF_GLOBAL_CTRL;
|
||||
|
||||
if (cap->vmx_vmexit_ctrl2_supported_bits)
|
||||
cap->vmx_vmexit_ctrl1_supported_bits |= VMX_VMEXIT_CTRL1_ACTIVATE_SECONDARY_CTRLS;
|
||||
}
|
||||
|
||||
void BX_CPU_C::init_vmentry_ctrls(void)
|
||||
|
@ -2,7 +2,7 @@
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2009-2023 Stanislav Shwartsman
|
||||
// Copyright (c) 2009-2024 Stanislav Shwartsman
|
||||
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
@ -198,7 +198,7 @@ void BX_CPU_C::VMexit_ExtInterrupt(void)
|
||||
if (PIN_VMEXIT(VMX_PIN_BASED_VMEXEC_CTRL_EXTERNAL_INTERRUPT_VMEXIT)) {
|
||||
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
||||
|
||||
if (! (vm->vmexit_ctrls & VMX_VMEXIT_CTRL1_INTA_ON_VMEXIT)) {
|
||||
if (! (vm->vmexit_ctrls1 & VMX_VMEXIT_CTRL1_INTA_ON_VMEXIT)) {
|
||||
// interrupt wasn't acknowledged and still pending, interruption info is invalid
|
||||
VMwrite32(VMCS_32BIT_VMEXIT_INTERRUPTION_INFO, 0);
|
||||
VMexit(VMX_VMEXIT_EXTERNAL_INTERRUPT, 0);
|
||||
@ -738,11 +738,16 @@ void BX_CPU_C::Virtualization_Exception(Bit64u qualification, Bit64u guest_physi
|
||||
// - 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
|
||||
// - the EPT violation cause a shadow stack to become prematurely busy
|
||||
|
||||
if (! BX_CPU_THIS_PTR cr0.get_PE() || BX_CPU_THIS_PTR in_event) return;
|
||||
|
||||
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
||||
|
||||
#if BX_SUPPORT_CET
|
||||
if (vm->shadow_stack_prematurely_busy) return;
|
||||
#endif
|
||||
|
||||
BxMemtype ve_info_memtype = BX_MEMTYPE_INVALID;
|
||||
#if BX_SUPPORT_MEMTYPE
|
||||
ve_info_memtype = resolve_memtype(vm->ve_info_addr);
|
||||
@ -769,7 +774,7 @@ void BX_CPU_C::Virtualization_Exception(Bit64u qualification, Bit64u guest_physi
|
||||
exception(BX_VE_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
void BX_CPU_C::vmx_page_modification_logging(Bit64u guest_paddr, unsigned dirty_update)
|
||||
void BX_CPU_C::vmx_page_modification_logging(Bit64u guest_laddr, Bit64u guest_paddr, unsigned dirty_update)
|
||||
{
|
||||
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
||||
|
||||
@ -778,6 +783,9 @@ void BX_CPU_C::vmx_page_modification_logging(Bit64u guest_paddr, unsigned dirty_
|
||||
if (BX_CPU_THIS_PTR nmi_unblocking_iret)
|
||||
vmexit_qualification |= (1 << 12);
|
||||
|
||||
if (vm->vmexit_ctrls2 & VMX_VMEXIT_CTRL2_SHADOW_STACK_BUSY_CTRL) {
|
||||
VMwrite_natural(VMCS_GUEST_LINEAR_ADDR, guest_laddr);
|
||||
}
|
||||
VMexit(VMX_VMEXIT_PML_LOGFULL, vmexit_qualification);
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2009-2023 Stanislav Shwartsman
|
||||
// Copyright (c) 2009-2024 Stanislav Shwartsman
|
||||
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
@ -736,7 +736,7 @@ VMX_error_code BX_CPU_C::VMenterLoadCheckVmControls(void)
|
||||
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: posted interrupts must be enabled together with virtual interrupt delivery"));
|
||||
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
||||
}
|
||||
if (! (vm->vmexit_ctrls & VMX_VMEXIT_CTRL1_INTA_ON_VMEXIT)) {
|
||||
if (! (vm->vmexit_ctrls1 & VMX_VMEXIT_CTRL1_INTA_ON_VMEXIT)) {
|
||||
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: posted interrupts must be enabled together 'ack interrupt on exit'"));
|
||||
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
||||
}
|
||||
@ -887,7 +887,11 @@ VMX_error_code BX_CPU_C::VMenterLoadCheckVmControls(void)
|
||||
// Load VM-exit control fields to VMCS Cache
|
||||
//
|
||||
|
||||
vm->vmexit_ctrls = VMread32(VMCS_32BIT_CONTROL_VMEXIT_CONTROLS);
|
||||
vm->vmexit_ctrls1 = VMread32(VMCS_32BIT_CONTROL_VMEXIT_CONTROLS);
|
||||
if (vm->vmexit_ctrls1 & VMX_VMEXIT_CTRL1_ACTIVATE_SECONDARY_CTRLS)
|
||||
vm->vmexit_ctrls2 = VMread64(VMCS_64BIT_CONTROL_SECONDARY_VMEXIT_CONTROLS);
|
||||
else
|
||||
vm->vmexit_ctrls2 = 0;
|
||||
vm->vmexit_msr_store_cnt = VMread32(VMCS_32BIT_CONTROL_VMEXIT_MSR_STORE_COUNT);
|
||||
vm->vmexit_msr_load_cnt = VMread32(VMCS_32BIT_CONTROL_VMEXIT_MSR_LOAD_COUNT);
|
||||
|
||||
@ -895,17 +899,22 @@ VMX_error_code BX_CPU_C::VMenterLoadCheckVmControls(void)
|
||||
// Check VM-exit control fields
|
||||
//
|
||||
|
||||
if (~vm->vmexit_ctrls & VMX_CHECKS_USE_MSR_VMX_VMEXIT_CTRLS_LO) {
|
||||
if (~vm->vmexit_ctrls1 & VMX_CHECKS_USE_MSR_VMX_VMEXIT_CTRLS_LO) {
|
||||
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: VMX vmexit controls allowed 0-settings"));
|
||||
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
||||
}
|
||||
if (vm->vmexit_ctrls & ~VMX_CHECKS_USE_MSR_VMX_VMEXIT_CTRLS_HI) {
|
||||
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: VMX vmexit controls allowed 1-settings [0x%08x]", vm->vmexit_ctrls & ~VMX_CHECKS_USE_MSR_VMX_VMEXIT_CTRLS_HI));
|
||||
if (vm->vmexit_ctrls1 & ~VMX_CHECKS_USE_MSR_VMX_VMEXIT_CTRLS_HI) {
|
||||
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: VMX vmexit controls allowed 1-settings [0x%08x]", vm->vmexit_ctrls1 & ~VMX_CHECKS_USE_MSR_VMX_VMEXIT_CTRLS_HI));
|
||||
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
||||
}
|
||||
|
||||
if (vm->vmexit_ctrls2 & ~VMX_VMEXIT_CTRL2_SUPPORTED_BITS) {
|
||||
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: VMX vmexit secondary controls allowed 1-settings"));
|
||||
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if ((~vm->pin_vmexec_ctrls & VMX_PIN_BASED_VMEXEC_CTRL_VMX_PREEMPTION_TIMER_VMEXIT) && (vm->vmexit_ctrls & VMX_VMEXIT_CTRL1_STORE_VMX_PREEMPTION_TIMER)) {
|
||||
if ((~vm->pin_vmexec_ctrls & VMX_PIN_BASED_VMEXEC_CTRL_VMX_PREEMPTION_TIMER_VMEXIT) && (vm->vmexit_ctrls1 & VMX_VMEXIT_CTRL1_STORE_VMX_PREEMPTION_TIMER)) {
|
||||
BX_ERROR(("VMFAIL: save_VMX_preemption_timer VMEXIT control is set but VMX_preemption_timer VMEXEC control is clear"));
|
||||
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
||||
}
|
||||
@ -939,6 +948,13 @@ VMX_error_code BX_CPU_C::VMenterLoadCheckVmControls(void)
|
||||
}
|
||||
}
|
||||
|
||||
if (PIN_VMEXIT(VMX_PIN_BASED_VMEXEC_CTRL_PROCESS_POSTED_INTERRUPTS)) {
|
||||
if (! (vm->vmexit_ctrls1 & VMX_VMEXIT_CTRL1_INTA_ON_VMEXIT)) {
|
||||
BX_ERROR(("VMFAIL: VMCS EXEC CTRL: posted interrupts must be enabled together 'ack interrupt on exit'"));
|
||||
return VMXERR_VMENTRY_INVALID_VM_CONTROL_FIELD;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Load VM-entry control fields to VMCS Cache
|
||||
//
|
||||
@ -1095,7 +1111,7 @@ VMX_error_code BX_CPU_C::VMenterLoadCheckHostState(void)
|
||||
// VM Host State Checks Related to Address-Space Size
|
||||
//
|
||||
|
||||
Bit32u vmexit_ctrls = vm->vmexit_ctrls;
|
||||
Bit32u vmexit_ctrls = vm->vmexit_ctrls1;
|
||||
if (vmexit_ctrls & VMX_VMEXIT_CTRL1_HOST_ADDR_SPACE_SIZE) {
|
||||
x86_64_host = true;
|
||||
}
|
||||
@ -2444,7 +2460,7 @@ void BX_CPU_C::VMexitSaveGuestState(Bit32u reason, Bit32u vector)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (vm->vmexit_ctrls & VMX_VMEXIT_CTRL1_SAVE_DBG_CTRLS)
|
||||
if (vm->vmexit_ctrls1 & VMX_VMEXIT_CTRL1_SAVE_DBG_CTRLS)
|
||||
VMwrite_natural(VMCS_GUEST_DR7, BX_CPU_THIS_PTR dr7.get32());
|
||||
|
||||
VMwrite_natural(VMCS_GUEST_RIP, RIP);
|
||||
@ -2521,10 +2537,10 @@ void BX_CPU_C::VMexitSaveGuestState(Bit32u reason, Bit32u vector)
|
||||
VMwrite32(VMCS_32BIT_GUEST_IA32_SYSENTER_CS_MSR, BX_CPU_THIS_PTR msr.sysenter_cs_msr);
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (vm->vmexit_ctrls & VMX_VMEXIT_CTRL1_STORE_PAT_MSR)
|
||||
if (vm->vmexit_ctrls1 & VMX_VMEXIT_CTRL1_STORE_PAT_MSR)
|
||||
VMwrite64(VMCS_64BIT_GUEST_IA32_PAT, BX_CPU_THIS_PTR msr.pat.u64);
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (vm->vmexit_ctrls & VMX_VMEXIT_CTRL1_STORE_EFER_MSR)
|
||||
if (vm->vmexit_ctrls1 & VMX_VMEXIT_CTRL1_STORE_EFER_MSR)
|
||||
VMwrite64(VMCS_64BIT_GUEST_IA32_EFER, BX_CPU_THIS_PTR efer.get32());
|
||||
#endif
|
||||
#endif
|
||||
@ -2606,7 +2622,7 @@ void BX_CPU_C::VMexitSaveGuestState(Bit32u reason, Bit32u vector)
|
||||
BX_CPU_THIS_PTR lapic->deactivate_vmx_preemption_timer();
|
||||
clear_event(BX_EVENT_VMX_PREEMPTION_TIMER_EXPIRED);
|
||||
// Store back to VMCS
|
||||
if (vm->vmexit_ctrls & VMX_VMEXIT_CTRL1_STORE_VMX_PREEMPTION_TIMER)
|
||||
if (vm->vmexit_ctrls1 & VMX_VMEXIT_CTRL1_STORE_VMX_PREEMPTION_TIMER)
|
||||
VMwrite32(VMCS_32BIT_GUEST_PREEMPTION_TIMER_VALUE, BX_CPU_THIS_PTR lapic->read_vmx_preemption_timer());
|
||||
|
||||
if (vm->vmexec_ctrls2 & VMX_VM_EXEC_CTRL2_VIRTUAL_INT_DELIVERY) {
|
||||
@ -2626,7 +2642,7 @@ void BX_CPU_C::VMexitLoadHostState(void)
|
||||
BX_CPU_THIS_PTR tsc_offset = 0;
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
Bit32u vmexit_ctrls = BX_CPU_THIS_PTR vmcs.vmexit_ctrls;
|
||||
Bit32u vmexit_ctrls = BX_CPU_THIS_PTR vmcs.vmexit_ctrls1;
|
||||
if (vmexit_ctrls & VMX_VMEXIT_CTRL1_HOST_ADDR_SPACE_SIZE) {
|
||||
BX_DEBUG(("VMEXIT to x86-64 host"));
|
||||
x86_64_host = true;
|
||||
@ -2837,6 +2853,20 @@ void BX_CPU_C::VMexit(Bit32u reason, Bit64u qualification)
|
||||
// STEP 0: Update VMEXIT reason
|
||||
//
|
||||
|
||||
// Extra vmexit reason bits:
|
||||
// [25] Shadow stack prematurely busy
|
||||
// [26] VMM bus lock detection (not implemented yet)
|
||||
// [27] Enclave mode (not supported)
|
||||
// [28] Pending MTF vmexit (only set by SMM VMEXIT which not implemented)
|
||||
// [29] VmExit from VMX root operation (hannpen only in SMM VMEXIT which not implemented)
|
||||
#if BX_SUPPORT_CET
|
||||
if (vm->vmexit_ctrls2 & VMX_VMEXIT_CTRL2_SHADOW_STACK_BUSY_CTRL) {
|
||||
if (vm->shadow_stack_prematurely_busy)
|
||||
reason |= (1<<25);
|
||||
}
|
||||
vm->shadow_stack_prematurely_busy = false;
|
||||
#endif
|
||||
|
||||
VMwrite32(VMCS_32BIT_VMEXIT_REASON, reason);
|
||||
VMwrite_natural(VMCS_VMEXIT_QUALIFICATION, qualification);
|
||||
|
||||
@ -4184,7 +4214,8 @@ void BX_CPU_C::register_vmx_state(bx_param_c *parent)
|
||||
|
||||
bx_list_c *vmexit_ctrls = new bx_list_c(vmcache, "VMEXIT_CTRLS");
|
||||
|
||||
BXRS_HEX_PARAM_FIELD(vmexit_ctrls, vmexit_ctrls, BX_CPU_THIS_PTR vmcs.vmexit_ctrls);
|
||||
BXRS_HEX_PARAM_FIELD(vmexit_ctrls, vmexit_ctrls, BX_CPU_THIS_PTR vmcs.vmexit_ctrls1);
|
||||
BXRS_HEX_PARAM_FIELD(vmexit_ctrls, vmexit_ctrls2, BX_CPU_THIS_PTR vmcs.vmexit_ctrls2);
|
||||
BXRS_DEC_PARAM_FIELD(vmexit_ctrls, vmexit_msr_store_cnt, BX_CPU_THIS_PTR vmcs.vmexit_msr_store_cnt);
|
||||
BXRS_HEX_PARAM_FIELD(vmexit_ctrls, vmexit_msr_store_addr, BX_CPU_THIS_PTR vmcs.vmexit_msr_store_addr);
|
||||
BXRS_DEC_PARAM_FIELD(vmexit_ctrls, vmexit_msr_load_cnt, BX_CPU_THIS_PTR vmcs.vmexit_msr_load_cnt);
|
||||
|
@ -2,7 +2,7 @@
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2009-2023 Stanislav Shwartsman
|
||||
// Copyright (c) 2009-2024 Stanislav Shwartsman
|
||||
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or
|
||||
@ -708,7 +708,8 @@ typedef struct bx_VMX_Cap
|
||||
Bit32u vmx_proc_vmexec_ctrl_supported_bits;
|
||||
Bit32u vmx_vmexec_ctrl2_supported_bits;
|
||||
Bit64u vmx_vmexec_ctrl3_supported_bits;
|
||||
Bit32u vmx_vmexit_ctrl_supported_bits;
|
||||
Bit32u vmx_vmexit_ctrl1_supported_bits;
|
||||
Bit32u vmx_vmexit_ctrl2_supported_bits;
|
||||
Bit32u vmx_vmentry_ctrl_supported_bits;
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
Bit64u vmx_ept_vpid_cap_supported_bits;
|
||||
@ -886,6 +887,10 @@ typedef struct bx_VMCS
|
||||
Bit64u xss_exiting_bitmap;
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_CET
|
||||
bool shadow_stack_prematurely_busy;
|
||||
#endif
|
||||
|
||||
//
|
||||
// VM-Exit Control Fields
|
||||
//
|
||||
@ -907,11 +912,19 @@ typedef struct bx_VMCS
|
||||
#define VMX_VMEXIT_CTRL1_LOAD_HOST_CET_STATE (1 << 28) /* CET */
|
||||
#define VMX_VMEXIT_CTRL1_LOAD_HOST_PKRS (1 << 29) /* Supervisor-Mode Protection Keys */
|
||||
#define VMX_VMEXIT_CTRL1_SAVE_PERF_GLOBAL_CTRL (1 << 30) /* Save IA32_PERF_GLOBAL_CTRL on vmexit (not implemented) */
|
||||
#define VMX_VMEXIT_CTRL1_ACTIVATE_SECONDARY_CTRLS (1 << 31)
|
||||
|
||||
#define VMX_VMEXIT_CTRL1_SUPPORTED_BITS \
|
||||
(BX_CPU_THIS_PTR vmx_cap.vmx_vmexit_ctrl_supported_bits)
|
||||
(BX_CPU_THIS_PTR vmx_cap.vmx_vmexit_ctrl1_supported_bits)
|
||||
|
||||
Bit32u vmexit_ctrls;
|
||||
Bit32u vmexit_ctrls1;
|
||||
|
||||
#define VMX_VMEXIT_CTRL2_SHADOW_STACK_BUSY_CTRL (1 << 2) /* Shadow stack prematurely busy */
|
||||
|
||||
#define VMX_VMEXIT_CTRL2_SUPPORTED_BITS \
|
||||
(BX_CPU_THIS_PTR vmx_cap.vmx_vmexit_ctrl2_supported_bits)
|
||||
|
||||
Bit64u vmexit_ctrls2;
|
||||
|
||||
Bit32u vmexit_msr_store_cnt;
|
||||
bx_phy_address vmexit_msr_store_addr;
|
||||
@ -1266,6 +1279,13 @@ const Bit32u VMX_MSR_VMX_PROCBASED_CTRLS2_LO = 0x00000000;
|
||||
#define VMX_MSR_VMX_PROCBASED_CTRLS3 (VMX_VM_EXEC_CTRL3_SUPPORTED_BITS)
|
||||
|
||||
|
||||
// IA32_VMX_EXIT_CTLS2 MSR (0x493)
|
||||
// ---------------------
|
||||
|
||||
// Allowed 1-settings
|
||||
#define VMX_MSR_VMX_VMEXIT_CTRLS2 (VMX_VMEXIT_CTRL2_SUPPORTED_BITS)
|
||||
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
|
||||
// IA32_VMX_EPT_VPID_CAP MSR (0x48c)
|
||||
|
Loading…
Reference in New Issue
Block a user