If L1 allows L2 to modify CR4.OSXSAVE, then L0 kvm recalculates the guest's CPUID.01H:ECX.OSXSAVE bit when the L2 guest changes CR4.OSXSAVE via MOV-to-CR4. Verify that kvm also recalculates this CPUID bit when loading L1's CR4 from the "host CR4" field of the VMCS12. Signed-off-by: Jim Mattson <jmattson@xxxxxxxxxx> Reviewed-by: Ricardo Koller <ricarkol@xxxxxxxxxx> Reviewed-by: Peter Shier <pshier@xxxxxxxxxx> --- lib/x86/processor.h | 52 +++++++++++++++++++++++++-------------------- x86/vmx_tests.c | 34 +++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 23 deletions(-) diff --git a/lib/x86/processor.h b/lib/x86/processor.h index c2c487c..79ebbd1 100644 --- a/lib/x86/processor.h +++ b/lib/x86/processor.h @@ -26,30 +26,31 @@ #define PF_VECTOR 14 #define AC_VECTOR 17 -#define X86_CR0_PE 0x00000001 -#define X86_CR0_MP 0x00000002 -#define X86_CR0_EM 0x00000004 -#define X86_CR0_TS 0x00000008 -#define X86_CR0_WP 0x00010000 -#define X86_CR0_AM 0x00040000 -#define X86_CR0_NW 0x20000000 -#define X86_CR0_CD 0x40000000 -#define X86_CR0_PG 0x80000000 +#define X86_CR0_PE 0x00000001 +#define X86_CR0_MP 0x00000002 +#define X86_CR0_EM 0x00000004 +#define X86_CR0_TS 0x00000008 +#define X86_CR0_WP 0x00010000 +#define X86_CR0_AM 0x00040000 +#define X86_CR0_NW 0x20000000 +#define X86_CR0_CD 0x40000000 +#define X86_CR0_PG 0x80000000 #define X86_CR3_PCID_MASK 0x00000fff -#define X86_CR4_TSD 0x00000004 -#define X86_CR4_DE 0x00000008 -#define X86_CR4_PSE 0x00000010 -#define X86_CR4_PAE 0x00000020 -#define X86_CR4_MCE 0x00000040 -#define X86_CR4_PGE 0x00000080 -#define X86_CR4_PCE 0x00000100 -#define X86_CR4_UMIP 0x00000800 -#define X86_CR4_LA57 0x00001000 -#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 +#define X86_CR4_TSD 0x00000004 +#define X86_CR4_DE 0x00000008 +#define X86_CR4_PSE 0x00000010 +#define X86_CR4_PAE 0x00000020 +#define X86_CR4_MCE 0x00000040 +#define X86_CR4_PGE 0x00000080 +#define X86_CR4_PCE 0x00000100 +#define X86_CR4_UMIP 0x00000800 +#define X86_CR4_LA57 0x00001000 +#define X86_CR4_VMXE 0x00002000 +#define X86_CR4_PCIDE 0x00020000 +#define X86_CR4_OSXSAVE 0x00040000 +#define X86_CR4_SMEP 0x00100000 +#define X86_CR4_SMAP 0x00200000 +#define X86_CR4_PKE 0x00400000 #define X86_EFLAGS_CF 0x00000001 #define X86_EFLAGS_FIXED 0x00000002 @@ -609,4 +610,9 @@ static inline int cpu_has_efer_nx(void) return !!(this_cpu_has(X86_FEATURE_NX)); } +static inline bool cpuid_osxsave(void) +{ + return cpuid(1).c & (1 << (X86_FEATURE_OSXSAVE % 32)); +} + #endif diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index d2084ae..301ca85 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -8416,6 +8416,39 @@ static void vmx_cr_load_test(void) TEST_ASSERT(!write_cr4_checking(orig_cr4)); } +static void vmx_cr4_osxsave_test_guest(void) +{ + write_cr4(read_cr4() & ~X86_CR4_OSXSAVE); +} + +/* + * Ensure that kvm recalculates the L1 guest's CPUID.01H:ECX.OSXSAVE + * after VM-exit from an L2 guest that sets CR4.OSXSAVE to a different + * value than in L1. + */ +static void vmx_cr4_osxsave_test(void) +{ + if (!this_cpu_has(X86_FEATURE_XSAVE)) { + report_skip("XSAVE not detected"); + return; + } + + if (!(read_cr4() & X86_CR4_OSXSAVE)) { + unsigned long cr4 = read_cr4() | X86_CR4_OSXSAVE; + + write_cr4(cr4); + vmcs_write(GUEST_CR4, cr4); + vmcs_write(HOST_CR4, cr4); + } + + TEST_ASSERT(cpuid_osxsave()); + + test_set_guest(vmx_cr4_osxsave_test_guest); + enter_guest(); + + TEST_ASSERT(cpuid_osxsave()); +} + static void vmx_nm_test_guest(void) { write_cr0(read_cr0() | X86_CR0_TS); @@ -10496,6 +10529,7 @@ struct vmx_test vmx_tests[] = { TEST(vmx_vmcs_shadow_test), /* Regression tests */ TEST(vmx_cr_load_test), + TEST(vmx_cr4_osxsave_test), TEST(vmx_nm_test), TEST(vmx_db_test), TEST(vmx_nmi_window_test), -- 2.29.1.341.ge80a0c044ae-goog