[kvm-unit-tests PATCH 3/3] KVM: nVMX: Properly configured unrestricted guest for event injection

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The hardware exception injection test toggles unrestricted guest so that
it can test the case where an event is injected into real mode with and
without an error code (exception error codes don't exist in real mode).
Unrestricted guest has its own requirements, specifically that EPT is
also enabled (since IA32 paging could be disabled).

Unfortunately, the enable_unrestricted_guest() helper fails to ensure
EPT is enabled, which causes all subsequent VMLAUNCH instructions to
fail with "invalid control field".  Use the new added enable_ept() to
configure unrestricted guest.  In addition, assert that unrestricted
guest is disabled at the beginning of the relevant section as things
will likely go sideways if unrestricted guest is already enabled, e.g.
odds are good it was enabled in order to muck with CR0.  This allows
for the removal of disable_unrestricted_guest() entirely.  And finally,
clean up the control fields after finishing the unrestricted guest
section (instead of invoking the defunct disable_unrestricted_guest()).

Note that it's not the unrestricted guest tests that fail, since there
is no "vmlaunch succeeds" variant, rather its the following tests that
expect success that end up failing (because the shoddy enabling of URG
isn't undone).

Fixes: 8d2cdb3 ("x86: Add test for nested VM entry prereqs")
Cc: Marc Orr <marcorr@xxxxxxxxxx>
Signed-off-by: Sean Christopherson <sean.j.christopherson@xxxxxxxxx>
---
 x86/vmx.h       | 18 ------------------
 x86/vmx_tests.c | 32 +++++++++++++++++++++++++++++---
 2 files changed, 29 insertions(+), 21 deletions(-)

diff --git a/x86/vmx.h b/x86/vmx.h
index 8a00f73..bcfaa79 100644
--- a/x86/vmx.h
+++ b/x86/vmx.h
@@ -779,24 +779,6 @@ static inline bool invvpid(unsigned long type, u64 vpid, u64 gla)
 	return ret;
 }
 
-static inline int enable_unrestricted_guest(void)
-{
-	if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY))
-		return -1;
-
-	if (!(ctrl_cpu_rev[1].clr & CPU_URG))
-		return -1;
-
-	vmcs_write(CPU_EXEC_CTRL0, vmcs_read(CPU_EXEC_CTRL0) | CPU_SECONDARY);
-	vmcs_write(CPU_EXEC_CTRL1, vmcs_read(CPU_EXEC_CTRL1) | CPU_URG);
-	return 0;
-}
-
-static inline void disable_unrestricted_guest(void)
-{
-	vmcs_write(CPU_EXEC_CTRL1, vmcs_read(CPU_EXEC_CTRL1) & ~CPU_URG);
-}
-
 const char *exit_reason_description(u64 reason);
 void print_vmexit_info(void);
 void print_vmentry_failure_info(struct vmentry_failure *failure);
diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
index 4cfb55f..ff51185 100644
--- a/x86/vmx_tests.c
+++ b/x86/vmx_tests.c
@@ -1067,6 +1067,21 @@ static int enable_ept(void)
 	return setup_eptp(0, false);
 }
 
+static int enable_unrestricted_guest(void)
+{
+	if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY) ||
+	    !(ctrl_cpu_rev[1].clr & CPU_URG))
+		return 1;
+
+	if (enable_ept())
+		return 1;
+
+	vmcs_write(CPU_EXEC_CTRL0, vmcs_read(CPU_EXEC_CTRL0) | CPU_SECONDARY);
+	vmcs_write(CPU_EXEC_CTRL1, vmcs_read(CPU_EXEC_CTRL1) | CPU_URG);
+
+	return 0;
+}
+
 static void ept_enable_ad_bits(void)
 {
 	eptp |= EPTP_AD_FLAG;
@@ -4081,12 +4096,16 @@ static void test_invalid_event_injection(void)
 	 * (a) the "unrestricted guest" VM-execution control is 0
 	 * (b) CR0.PE is set.
 	 */
+
+	/* Assert that unrestricted guest is disabled or unsupported */
+	assert(!(ctrl_cpu_rev[0].clr & CPU_SECONDARY) ||
+	       !(secondary_save & CPU_URG));
+
 	ent_intr_info = ent_intr_info_base | INTR_TYPE_HARD_EXCEPTION |
 			GP_VECTOR;
 	report_prefix_pushf("%s, VM-entry intr info=0x%x",
 			    "error code <-> (!URG || prot_mode) [-]",
 			    ent_intr_info);
-	disable_unrestricted_guest();
 	vmcs_write(GUEST_CR0, guest_cr0_save & ~X86_CR0_PE & ~X86_CR0_PG);
 	vmcs_write(ENT_INTR_INFO, ent_intr_info);
 	test_vmx_controls(false, false);
@@ -4097,18 +4116,19 @@ static void test_invalid_event_injection(void)
 	report_prefix_pushf("%s, VM-entry intr info=0x%x",
 			    "error code <-> (!URG || prot_mode) [+]",
 			    ent_intr_info);
-	disable_unrestricted_guest();
 	vmcs_write(GUEST_CR0, guest_cr0_save & ~X86_CR0_PE & ~X86_CR0_PG);
 	vmcs_write(ENT_INTR_INFO, ent_intr_info);
 	test_vmx_controls(true, false);
 	report_prefix_pop();
 
+	if (enable_unrestricted_guest())
+		goto skip_unrestricted_guest;
+
 	ent_intr_info = ent_intr_info_base | INTR_INFO_DELIVER_CODE_MASK |
 			INTR_TYPE_HARD_EXCEPTION | GP_VECTOR;
 	report_prefix_pushf("%s, VM-entry intr info=0x%x",
 			    "error code <-> (!URG || prot_mode) [-]",
 			    ent_intr_info);
-	enable_unrestricted_guest();
 	vmcs_write(GUEST_CR0, guest_cr0_save & ~X86_CR0_PE & ~X86_CR0_PG);
 	vmcs_write(ENT_INTR_INFO, ent_intr_info);
 	test_vmx_controls(false, false);
@@ -4124,6 +4144,12 @@ static void test_invalid_event_injection(void)
 	test_vmx_controls(false, false);
 	report_prefix_pop();
 
+	vmcs_write(CPU_EXEC_CTRL1, secondary_save);
+	vmcs_write(CPU_EXEC_CTRL0, primary_save);
+
+skip_unrestricted_guest:
+	vmcs_write(GUEST_CR0, guest_cr0_save);
+
 	/* deliver-error-code is 1 iff the interruption type is HW exception */
 	report_prefix_push("error code <-> HW exception");
 	for (cnt = 0; cnt < 8; cnt++) {
-- 
2.20.1




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux