Skip to contentSkip to conversation

x86: Add control register pinning tests

PATCH New John Andersen 1 participant 1 message Jun 18, 2020 KVM

lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 x86: Add control register pinning tests

Paravirutalized control register pinning adds MSRs guests can use to discover which bits in CR0/4 they may pin, and MSRs for activating pinning for any of those bits.

We check that the bits allowed to be pinned for CR4 are UMIP, SMEP, and SMAP. Only WP should be allowed to be pinned in CR0.

We turn on all of the allowed bits, pin them, then attempt to disable them. We verify that the attempt to disable was unsuccessful, and that it generated a general protection fault.

For nested, we check that for when pinning enabled in L1, changing HOST_CR0/4 will not result in the un-setting of pinned bits. The VMX CR pinning tests is it's own test so that the pinning doesn't potentially affect other tests within the same .flat testing VM.

---
 x86/Makefile.common |   3 +-
 lib/x86/desc.h      |   1 +
 lib/x86/msr.h       |   8 ++
 lib/x86/processor.h |   6 ++
 lib/x86/desc.c      |   8 ++
 x86/cr_pin_high.c   | 213 ++++++++++++++++++++++++++++++++++++++++++++
 x86/cr_pin_low.c    |  65 ++++++++++++++
 x86/pcid.c          |   8 --
 x86/vmx_tests.c     | 144 ++++++++++++++++++++++++++++++
 x86/unittests.cfg   |  16 +++-
 10 files changed, 462 insertions(+), 10 deletions(-)
 create mode 100644 x86/cr_pin_high.c
 create mode 100644 x86/cr_pin_low.c
x86/Makefile.common +2 -1
index ab67ca0..bab7fe2 100644
@@ -58,7 +58,8 @@ tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \
                $(TEST_DIR)/init.flat $(TEST_DIR)/smap.flat \
                $(TEST_DIR)/hyperv_synic.flat $(TEST_DIR)/hyperv_stimer.flat \
                $(TEST_DIR)/hyperv_connections.flat \
-               $(TEST_DIR)/umip.flat $(TEST_DIR)/tsx-ctrl.flat
+               $(TEST_DIR)/umip.flat $(TEST_DIR)/tsx-ctrl.flat \
+               $(TEST_DIR)/cr_pin_low.flat $(TEST_DIR)/cr_pin_high.flat
 
 test_cases: $(tests-common) $(tests)
 
lib/x86/desc.h +1 -0
index 0fe5cbf..9fb921c 100644
@@ -211,6 +211,7 @@ extern tss64_t tss;
 #endif
 
 unsigned exception_vector(void);
+int write_cr0_checking(unsigned long val);
 int write_cr4_checking(unsigned long val);
 unsigned exception_error_code(void);
 bool exception_rflags_rf(void);
lib/x86/msr.h +8 -0
index 6ef5502..13152a3 100644
@@ -431,4 +431,12 @@
 #define MSR_VM_IGNNE                    0xc0010115
 #define MSR_VM_HSAVE_PA                 0xc0010117
 
+/* KVM MSRs */
+#define MSR_KVM_CR0_PIN_ALLOWED		0x4b564d08
+#define MSR_KVM_CR4_PIN_ALLOWED		0x4b564d09
+#define MSR_KVM_CR0_PINNED_LOW		0x4b564d0a
+#define MSR_KVM_CR0_PINNED_HIGH		0x4b564d0b
+#define MSR_KVM_CR4_PINNED_LOW		0x4b564d0c
+#define MSR_KVM_CR4_PINNED_HIGH		0x4b564d0d
+
 #endif /* _ASM_X86_MSR_INDEX_H */
lib/x86/processor.h +6 -0
index 6e0811e..5bfd296 100644
@@ -146,6 +146,7 @@ static inline u8 cpuid_maxphyaddr(void)
 #define	X86_FEATURE_SMEP	        (CPUID(0x7, 0, EBX, 7))
 #define	X86_FEATURE_INVPCID		(CPUID(0x7, 0, EBX, 10))
 #define	X86_FEATURE_RTM			(CPUID(0x7, 0, EBX, 11))
+#define	X86_FEATURE_SMEP		(CPUID(0x7, 0, EBX, 7))
 #define	X86_FEATURE_SMAP		(CPUID(0x7, 0, EBX, 20))
 #define	X86_FEATURE_PCOMMIT		(CPUID(0x7, 0, EBX, 22))
 #define	X86_FEATURE_CLFLUSHOPT		(CPUID(0x7, 0, EBX, 23))
@@ -168,6 +169,11 @@ static inline u8 cpuid_maxphyaddr(void)
 #define	X86_FEATURE_NPT			(CPUID(0x8000000A, 0, EDX, 0))
 #define	X86_FEATURE_NRIPS		(CPUID(0x8000000A, 0, EDX, 3))
 
+/*
+ * KVM CPUID features
+ */
+#define	X86_FEATURE_CR_PIN		(CPUID(0x40000001, 0, EAX, 15))
+
 
 static inline bool this_cpu_has(u64 feature)
 {
lib/x86/desc.c +8 -0
index 451f504..6cf4fac 100644
@@ -251,6 +251,14 @@ unsigned exception_vector(void)
     return vector;
 }
 
+int write_cr0_checking(unsigned long val)
+{
+    asm volatile(ASM_TRY("1f")
+		 "mov %0, %%cr0\n\t"
+		 "1:" : : "r" (val));
+    return exception_vector();
+}
+
 int write_cr4_checking(unsigned long val)
 {
     asm volatile(ASM_TRY("1f")
x86/cr_pin_high.c new file +213 -0

213 lines not on this page · raw message

x86/cr_pin_low.c new file +65 -0

65 lines not on this page · raw message

x86/pcid.c +0 -8
index a8dc8cb..5688699 100644
@@ -10,14 +10,6 @@ struct invpcid_desc {
     unsigned long addr : 64;
 };
 
-static int write_cr0_checking(unsigned long val)
-{
-    asm volatile(ASM_TRY("1f")
-                 "mov %0, %%cr0\n\t"
-                 "1:": : "r" (val));
-    return exception_vector();
-}
-
 static int invpcid_checking(unsigned long type, void *desc)
 {
     asm volatile (ASM_TRY("1f")
x86/vmx_tests.c +144 -0

156 lines not on this page · raw message

x86/unittests.cfg +15 -1
index 504e04e..708bca4 100644
@@ -245,9 +245,17 @@ arch = x86_64
 file = umip.flat
 extra_params = -cpu qemu64,+umip
 
+[cr_pin_low]
+file = cr_pin_low.flat
+extra_params = -cpu qemu64,+umip,+smap,+smep
+
+[cr_pin_high]
+file = cr_pin_high.flat
+extra_params = -cpu qemu64,+umip,+smap,+smep
+
 [vmx]
 file = vmx.flat
-extra_params = -cpu host,+vmx -append "-exit_monitor_from_l2_test -ept_access* -vmx_smp* -vmx_vmcs_shadow_test -atomic_switch_overflow_msrs_test -vmx_init_signal_test -vmx_apic_passthrough_tpr_threshold_test"
+extra_params = -cpu host,+vmx -append "-exit_monitor_from_l2_test -ept_access* -vmx_smp* -vmx_vmcs_shadow_test -atomic_switch_overflow_msrs_test -vmx_init_signal_test -vmx_apic_passthrough_tpr_threshold_test -vmx_cr_pin_test"
 arch = x86_64
 groups = vmx
 
@@ -306,6 +314,12 @@ extra_params = -cpu host,+vmx -append vmx_vmcs_shadow_test
 arch = x86_64
 groups = vmx
 
+[vmx_cr_pin_test]
+file = vmx.flat
+extra_params = -cpu host,+vmx -append vmx_cr_pin_test
+arch = x86_64
+groups = vmx
+
 [debug]
 file = debug.flat
 arch = x86_64
Signature · 1 line
2.21.0