implement VMX SUPPORT FOR THE IA32_SPEC_CTRL MSR announced in 319433-052

bugfix: "shadow stack prematurely busy" secondary vmexit control was wrongly mapped into bit2 insetad of bit3
This commit is contained in:
Stanislav Shwartsman 2024-04-27 09:44:32 +03:00
parent c6b7961799
commit 247aca0956
5 changed files with 67 additions and 9 deletions

View File

@ -663,6 +663,18 @@ bool isValidMSR_FixedMTRR(Bit64u fixed_mtrr_val)
}
#endif
bool isValidMSR_IA32_SPEC_CTRL(Bit64u val_64)
{
// [0] - Enable IBRS: Indirect Branch Restricted Speculation
// [1] - Enable STIBP: Single Thread Indirect Branch Predictors
// [2] - Enable SSCB: Speculative Store Bypass Disable
// [63:3] - reserved
if (val_64 & ~(BX_CONST64(0x7)))
return false;
return true;
}
#if BX_CPU_LEVEL >= 5
bool BX_CPP_AttrRegparmN(2) BX_CPU_C::wrmsr(Bit32u index, Bit64u val_64)
{
@ -1091,11 +1103,7 @@ bool BX_CPP_AttrRegparmN(2) BX_CPU_C::wrmsr(Bit32u index, Bit64u val_64)
if (BX_CPU_THIS_PTR in_vmx_guest && vm->vmexec_ctrls3.VIRTUALIZE_IA32_SPEC_CTRL())
val_64 = (BX_CPU_THIS_PTR msr.ia32_spec_ctrl & vm->ia32_spec_ctrl_mask) | (val_64 & ~vm->ia32_spec_ctrl_mask);
#endif
// [0] - Enable IBRS: Indirect Branch Restricted Speculation
// [1] - Enable STIBP: Single Thread Indirect Branch Predictors
// [2] - Enable SSCB: Speculative Store Bypass Disable
// [63:3] - reserved
if (val_64 & ~(BX_CONST64(0x7))) {
if (! isValidMSR_IA32_SPEC_CTRL(val_64)) {
BX_ERROR(("WRMSR: attempt to set reserved bits of IA32_SPEC_CTRL !"));
return false;
}

View File

@ -461,6 +461,12 @@ bool BX_CPU_C::vmcs_field_supported(Bit32u encoding)
return is_cpu_extension_supported(BX_ISA_PKS);
#endif
#if BX_SUPPORT_VMX >= 2
case VMCS_64BIT_GUEST_IA32_SPEC_CTRL:
case VMCS_64BIT_GUEST_IA32_SPEC_CTRL_HI:
return BX_SUPPORT_VMX_EXTENSION(BX_VMX_SPEC_CTRL_VIRTUALIZATION);
#endif
#if BX_SUPPORT_VMX >= 2
/* VMCS 64-bit host state fields */
/* binary 0010_11xx_xxxx_xxx0 */
@ -483,6 +489,12 @@ bool BX_CPU_C::vmcs_field_supported(Bit32u encoding)
return is_cpu_extension_supported(BX_ISA_PKS);
#endif
#if BX_SUPPORT_VMX >= 2
case VMCS_64BIT_HOST_IA32_SPEC_CTRL:
case VMCS_64BIT_HOST_IA32_SPEC_CTRL_HI:
return BX_SUPPORT_VMX_EXTENSION(BX_VMX_SPEC_CTRL_VIRTUALIZATION);
#endif
/* VMCS natural width control fields */
/* binary 0110_00xx_xxxx_xxx0 */
case VMCS_CONTROL_CR0_GUEST_HOST_MASK:
@ -894,8 +906,11 @@ void BX_CPU_C::init_secondary_vmexit_ctrls(void)
// secondary vmexit controls
// -----------------------------------------------------------
// [02] Prematurely busy shadow stack control
// [02] load host MSR_IA32_SPEC_CTRL control
// [03] Prematurely busy shadow stack control
if (BX_SUPPORT_VMX_EXTENSION(BX_VMX_SPEC_CTRL_VIRTUALIZATION))
cap->vmx_vmexit_ctrl2_supported_bits |= VMX_VMEXIT_CTRL2_LOAD_HOST_IA32_SPEC_CTRL;
#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;
@ -987,6 +1002,7 @@ void BX_CPU_C::init_vmentry_ctrls(void)
// [17] Load guest CET state
// [19] Load guest UINV state
// [22] Load guest MSR_IA32_PKRS value
// [24] Load guest MSR_IA32_SPEC_CTRL value
cap->vmx_vmentry_ctrl_supported_bits = VMX_VMENTRY_CTRL1_LOAD_DBG_CTRLS |
VMX_VMENTRY_CTRL1_SMM_ENTER |
@ -1016,6 +1032,8 @@ void BX_CPU_C::init_vmentry_ctrls(void)
if (BX_CPUID_SUPPORT_ISA_EXTENSION(BX_ISA_PKS))
cap->vmx_vmentry_ctrl_supported_bits |= VMX_VMENTRY_CTRL1_LOAD_GUEST_PKRS;
#endif
if (BX_SUPPORT_VMX_EXTENSION(BX_VMX_SPEC_CTRL_VIRTUALIZATION))
cap->vmx_vmexit_ctrl2_supported_bits |= VMX_VMENTRY_CTRL1_LOAD_GUEST_IA32_SPEC_CTRL;
}
#endif // BX_SUPPORT_VMX

View File

@ -40,6 +40,7 @@ extern VMCS_Mapping vmcs_map;
#if BX_SUPPORT_VMX >= 2
extern bool isValidMSR_PAT(Bit64u pat_msr);
extern bool isValidMSR_IA32_SPEC_CTRL(Bit64u val_64);
#endif
#if BX_SUPPORT_CET
@ -1234,6 +1235,14 @@ VMX_error_code BX_CPU_C::VMenterLoadCheckHostState(void)
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
}
}
if (vm->vmexit_ctrls2.LOAD_HOST_IA32_SPEC_CTRL()) {
host_state->ia32_spec_ctrl_msr = VMread64(VMCS_64BIT_HOST_IA32_SPEC_CTRL);
if (! isValidMSR_IA32_SPEC_CTRL(host_state->ia32_spec_ctrl_msr)) {
BX_ERROR(("VMFAIL: invalid value in host IA32_SPEC_CTRL_MSR"));
return VMXERR_VMENTRY_INVALID_VM_HOST_STATE_FIELD;
}
}
#endif
host_state->rsp = (bx_address) VMread_natural(VMCS_HOST_RSP);
@ -1843,6 +1852,14 @@ Bit32u BX_CPU_C::VMenterLoadCheckGuestState(Bit64u *qualification)
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
}
}
if (vm->vmentry_ctrls.LOAD_GUEST_IA32_SPEC_CTRL()) {
guest.ia32_spec_ctrl_msr = VMread64(VMCS_64BIT_GUEST_IA32_SPEC_CTRL);
if (! isValidMSR_IA32_SPEC_CTRL(guest.ia32_spec_ctrl_msr)) {
BX_ERROR(("VMFAIL: invalid value in guest MSR_IA32_SPEC_CTRL"));
return VMX_VMEXIT_VMENTRY_FAILURE_GUEST_STATE;
}
}
#endif
guest.rip = VMread_natural(VMCS_GUEST_RIP);
@ -2158,6 +2175,10 @@ Bit32u BX_CPU_C::VMenterLoadCheckGuestState(Bit64u *qualification)
if (vm->vmentry_ctrls.LOAD_PAT_MSR()) {
BX_CPU_THIS_PTR msr.pat = guest.pat_msr;
}
if (vm->vmentry_ctrls.LOAD_GUEST_IA32_SPEC_CTRL()) {
BX_CPU_THIS_PTR msr.ia32_spec_ctrl = guest.ia32_spec_ctrl_msr;
}
#endif
#if BX_SUPPORT_VMX >= 2
@ -2671,6 +2692,9 @@ void BX_CPU_C::VMexitLoadHostState(void)
if (vm->vmexit_ctrls1.LOAD_PAT_MSR()) {
BX_CPU_THIS_PTR msr.pat = host_state->pat_msr;
}
if (vm->vmexit_ctrls2.LOAD_HOST_IA32_SPEC_CTRL()) {
BX_CPU_THIS_PTR msr.ia32_spec_ctrl = host_state->ia32_spec_ctrl_msr;
}
#endif
// CS selector loaded from VMCS
@ -4248,6 +4272,7 @@ void BX_CPU_C::register_vmx_state(bx_param_c *parent)
#if BX_SUPPORT_X86_64
BXRS_HEX_PARAM_FIELD(host, efer_msr, vm->host_state.efer_msr);
#endif
BXRS_HEX_PARAM_FIELD(host, ia32_spec_ctrl_msr, vm->host_state.ia32_spec_ctrl_msr);
#endif
#if BX_SUPPORT_CET
BXRS_HEX_PARAM_FIELD(host, ia32_s_cet_msr, vm->host_state.msr_ia32_s_cet);

View File

@ -347,7 +347,7 @@ const Bit64u VMX_VMFUNC_EPTP_SWITCHING_MASK = (BX_CONST64(1) << VMX_VMFUNC_EPTP_
#define VMCS_64BIT_GUEST_IA32_RTIT_CTL_HI 0x00002815
#define VMCS_64BIT_GUEST_IA32_PKRS 0x00002818 /* Supervisor-Mode Protection Keys */
#define VMCS_64BIT_GUEST_IA32_PKRS_HI 0x00002819
#define VMCS_64BIT_GUEST_IA32_SPEC_CTRL 0x0000282E /* MSR_IA32_SPEC_CTRL virtualization (not implemented) */
#define VMCS_64BIT_GUEST_IA32_SPEC_CTRL 0x0000282E /* MSR_IA32_SPEC_CTRL virtualization */
#define VMCS_64BIT_GUEST_IA32_SPEC_CTRL_HI 0x0000282F
#define VMCS_64BIT_GUEST_DEADLINE 0x00002830 /* APIC timer virtualization (not implemented) */
#define VMCS_64BIT_GUEST_DEADLINE_HI 0x00002831
@ -362,7 +362,7 @@ const Bit64u VMX_VMFUNC_EPTP_SWITCHING_MASK = (BX_CONST64(1) << VMX_VMFUNC_EPTP_
#define VMCS_64BIT_HOST_IA32_PERF_GLOBAL_CTRL_HI 0x00002C05
#define VMCS_64BIT_HOST_IA32_PKRS 0x00002C06 /* Supervisor-Mode Protection Keys */
#define VMCS_64BIT_HOST_IA32_PKRS_HI 0x00002C07
#define VMCS_64BIT_HOST_IA32_SPEC_CTRL 0x00002C1A /* MSR_IA32_SPEC_CTRL virtualization (not implemented) */
#define VMCS_64BIT_HOST_IA32_SPEC_CTRL 0x00002C1A /* MSR_IA32_SPEC_CTRL virtualization */
#define VMCS_64BIT_HOST_IA32_SPEC_CTRL_HI 0x00002C1B
/* VMCS 32_bit control fields */
@ -652,6 +652,8 @@ typedef struct bx_VMCS_GUEST_STATE
Bit64u pdptr[4];
#endif
Bit64u ia32_spec_ctrl_msr;
#if BX_SUPPORT_CET
Bit64u msr_ia32_s_cet;
bx_address ssp;
@ -696,6 +698,7 @@ typedef struct bx_VMCS_HOST_STATE
Bit64u efer_msr;
#endif
Bit64u pat_msr;
Bit64u ia32_spec_ctrl_msr;
#endif
#if BX_SUPPORT_CET

View File

@ -239,6 +239,7 @@ public:
#define VMX_VMENTRY_CTRL1_LOAD_GUEST_CET_STATE (1 << 20) /* CET */
#define VMX_VMENTRY_CTRL1_LOAD_GUEST_LBR_CTRL (1 << 21) // not implemented
#define VMX_VMENTRY_CTRL1_LOAD_GUEST_PKRS (1 << 22) /* Supervisor-Mode Protection Keys */
#define VMX_VMENTRY_CTRL1_LOAD_GUEST_IA32_SPEC_CTRL (1 << 24)
bool LOAD_DBG_CTRLS() const { return vmentry_ctrls & VMX_VMENTRY_CTRL1_LOAD_DBG_CTRLS; }
bool X86_64_GUEST() const { return vmentry_ctrls & VMX_VMENTRY_CTRL1_X86_64_GUEST; }
@ -254,6 +255,7 @@ public:
bool LOAD_GUEST_CET_STATE() const { return vmentry_ctrls & VMX_VMENTRY_CTRL1_LOAD_GUEST_CET_STATE; }
bool LOAD_GUEST_LBR() const { return vmentry_ctrls & VMX_VMENTRY_CTRL1_LOAD_GUEST_LBR_CTRL; }
bool LOAD_GUEST_PKRS() const { return vmentry_ctrls & VMX_VMENTRY_CTRL1_LOAD_GUEST_PKRS; }
bool LOAD_GUEST_IA32_SPEC_CTRL() const { return vmentry_ctrls & VMX_VMENTRY_CTRL1_LOAD_GUEST_IA32_SPEC_CTRL; }
bool query_any(Bit32u mask) const { return (vmentry_ctrls & mask) != 0; }
bool query_all(Bit32u mask) const { return (vmentry_ctrls & mask) == mask; }
@ -326,8 +328,10 @@ private:
public:
BxVmexit2Controls(Bit64u ctrls = 0): vmexit2_ctrls(ctrls) {}
#define VMX_VMEXIT_CTRL2_SHADOW_STACK_BUSY_CTRL (1 << 2) /* Shadow stack prematurely busy */
#define VMX_VMEXIT_CTRL2_LOAD_HOST_IA32_SPEC_CTRL (1 << 2)
#define VMX_VMEXIT_CTRL2_SHADOW_STACK_BUSY_CTRL (1 << 3) /* Shadow stack prematurely busy */
bool LOAD_HOST_IA32_SPEC_CTRL() const { return vmexit2_ctrls & VMX_VMEXIT_CTRL2_LOAD_HOST_IA32_SPEC_CTRL; }
bool SHADOW_STACK_PREMATURELY_BUSY_CTRL() const { return vmexit2_ctrls & VMX_VMEXIT_CTRL2_SHADOW_STACK_BUSY_CTRL; }
bool query_any(Bit64u mask) const { return (vmexit2_ctrls & mask) != 0; }