According to section "Checks on VMX Controls" in Intel SDM vol 3C, the following checks are performed on vmentry of L2 guests: - The CR0 field must not set any bit to a value not supported in VMX operation. - The CR4 field must not set any bit to a value not supported in VMX operation. - On processors that support Intel 64 architecture, the CR3 field must be such that bits 63:52 and bits in the range 51:32 beyond the processor’s physical-address width must be 0. Signed-off-by: Krish Sadhukhan <krish.sadhukhan@xxxxxxxxxx> Reviewed-by: Liam Merwick <liam.merwick@xxxxxxxxxx> --- lib/x86/processor.h | 1 + x86/vmx_tests.c | 77 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/lib/x86/processor.h b/lib/x86/processor.h index 15237a5..916e67d 100644 --- a/lib/x86/processor.h +++ b/lib/x86/processor.h @@ -40,6 +40,7 @@ #define X86_CR4_UMIP 0x00000800 #define X86_CR4_VMXE 0x00002000 #define X86_CR4_PCIDE 0x00020000 +#define X86_CR4_SMEP 0x00100000 #define X86_CR4_SMAP 0x00200000 #define X86_CR4_PKE 0x00400000 diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index 66a87f6..7af0430 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -4995,6 +4995,81 @@ static void test_sysenter_field(u32 field, const char *name) vmcs_write(field, addr_saved); } +static void test_ctl_reg(const char *cr_name, u64 cr, u64 fixed0, u64 fixed1) +{ + u64 val; + u64 cr_saved = vmcs_read(cr); + + val = fixed0 & fixed1; + if (cr == HOST_CR4) + val |= X86_CR4_PAE; + vmcs_write(cr, val); + report_prefix_pushf("%s %lx", cr_name, val); + test_vmx_vmlaunch(0, false); + report_prefix_pop(); + + val = fixed0 | fixed1; + vmcs_write(cr, val); + report_prefix_pushf("%s %lx", cr_name, val); + test_vmx_vmlaunch(0, false); + report_prefix_pop(); + + val = fixed0 ^ fixed1; + vmcs_write(cr, val); + report_prefix_pushf("%s %lx", cr_name, val); + test_vmx_vmlaunch(VMXERR_ENTRY_INVALID_HOST_STATE_FIELD, false); + report_prefix_pop(); + + val = fixed0 & (fixed1 << 1); + vmcs_write(cr, val); + report_prefix_pushf("%s %lx", cr_name, val); + test_vmx_vmlaunch(VMXERR_ENTRY_INVALID_HOST_STATE_FIELD, false); + report_prefix_pop(); + + vmcs_write(cr, cr_saved); +} + +/* + * 1. The CR0 field must not set any bit to a value not supported in VMX + * operation. + * 2. The CR4 field must not set any bit to a value not supported in VMX + * operation. + * 3. On processors that support Intel 64 architecture, the CR3 field must + * be such that bits 63:52 and bits in the range 51:32 beyond the + * processor’s physical-address width must be 0. + * + * [Intel SDM] + */ +static void test_host_ctl_regs(void) +{ + u64 fixed0, fixed1, cr3, cr3_saved; + int i; + + /* Test CR0 */ + fixed0 = rdmsr(MSR_IA32_VMX_CR0_FIXED0); + fixed1 = rdmsr(MSR_IA32_VMX_CR0_FIXED1); + test_ctl_reg("HOST_CR0", HOST_CR0, fixed0, fixed1); + + /* Test CR4 */ + fixed0 = rdmsr(MSR_IA32_VMX_CR4_FIXED0); + fixed1 = rdmsr(MSR_IA32_VMX_CR4_FIXED1) & + ~(X86_CR4_SMEP | X86_CR4_SMAP); + test_ctl_reg("HOST_CR4", HOST_CR4, fixed0, fixed1); + + /* Test CR3 */ + cr3_saved = vmcs_read(HOST_CR3); + for (i = cpuid_maxphyaddr(); i < 64; i++) { + cr3 = cr3_saved | (1ul << i); + vmcs_write(HOST_CR3, cr3); + report_prefix_pushf("HOST_CR3 %lx", cr3); + test_vmx_vmlaunch(VMXERR_ENTRY_INVALID_HOST_STATE_FIELD, + false); + report_prefix_pop(); + } + + vmcs_write(HOST_CR3, cr3_saved); +} + /* * Check that the virtual CPU checks the VMX Host State Area as * documented in the Intel SDM. @@ -5008,6 +5083,8 @@ static void vmx_host_state_area_test(void) */ vmcs_write(GUEST_RFLAGS, 0); + test_host_ctl_regs(); + test_sysenter_field(HOST_SYSENTER_ESP, "HOST_SYSENTER_ESP"); test_sysenter_field(HOST_SYSENTER_EIP, "HOST_SYSENTER_EIP"); } -- 2.17.2