nVMX: Test vmentry of unrestricted (PG=0/PE=1) nested guest
According to section "UNRESTRICTED GUESTS" in SDM vol 3c, if the
"unrestricted guest" secondary VM-execution control is set, guests can run
in unpaged protected mode or in real mode. This patch tests vmentry of an
unrestricted guest in unpaged protected mode.
Signed-off-by: Jim Mattson <jmattson@google.com>
Signed-off-by: Krish Sadhukhan <krish.sadhukhan@oracle.com>
Message-Id: <20200921081027.23047-4-krish.sadhukhan@oracle.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
diff --git a/x86/vmx.c b/x86/vmx.c
index 07415b4..1a84a74 100644
--- a/x86/vmx.c
+++ b/x86/vmx.c
@@ -1699,7 +1699,7 @@
}
/* This function can only be called in guest */
-static void __attribute__((__used__)) hypercall(u32 hypercall_no)
+void __attribute__((__used__)) hypercall(u32 hypercall_no)
{
u64 val = 0;
val = (hypercall_no & HYPERCALL_MASK) | HYPERCALL_BIT;
diff --git a/x86/vmx.h b/x86/vmx.h
index d1c2436..e29301e 100644
--- a/x86/vmx.h
+++ b/x86/vmx.h
@@ -895,6 +895,7 @@
void __enter_guest(u8 abort_flag, struct vmentry_result *result);
void enter_guest(void);
void enter_guest_with_bad_controls(void);
+void hypercall(u32 hypercall_no);
typedef void (*test_guest_func)(void);
typedef void (*test_teardown_func)(void *data);
diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
index 2b6e47b..d2084ae 100644
--- a/x86/vmx_tests.c
+++ b/x86/vmx_tests.c
@@ -8229,6 +8229,53 @@
enter_guest();
}
+extern void unrestricted_guest_main(void);
+asm (".code32\n"
+ "unrestricted_guest_main:\n"
+ "vmcall\n"
+ "nop\n"
+ "mov $1, %edi\n"
+ "call hypercall\n"
+ ".code64\n");
+
+static void setup_unrestricted_guest(void)
+{
+ vmcs_write(GUEST_CR0, vmcs_read(GUEST_CR0) & ~(X86_CR0_PG));
+ vmcs_write(ENT_CONTROLS, vmcs_read(ENT_CONTROLS) & ~ENT_GUEST_64);
+ vmcs_write(GUEST_EFER, vmcs_read(GUEST_EFER) & ~EFER_LMA);
+ vmcs_write(GUEST_RIP, virt_to_phys(unrestricted_guest_main));
+}
+
+static void unsetup_unrestricted_guest(void)
+{
+ vmcs_write(GUEST_CR0, vmcs_read(GUEST_CR0) | X86_CR0_PG);
+ vmcs_write(ENT_CONTROLS, vmcs_read(ENT_CONTROLS) | ENT_GUEST_64);
+ vmcs_write(GUEST_EFER, vmcs_read(GUEST_EFER) | EFER_LMA);
+ vmcs_write(GUEST_RIP, (u64) phys_to_virt(vmcs_read(GUEST_RIP)));
+ vmcs_write(GUEST_RSP, (u64) phys_to_virt(vmcs_read(GUEST_RSP)));
+}
+
+/*
+ * If "unrestricted guest" secondary VM-execution control is set, guests
+ * can run in unpaged protected mode.
+ */
+static void vmentry_unrestricted_guest_test(void)
+{
+ test_set_guest(unrestricted_guest_main);
+ setup_unrestricted_guest();
+ if (setup_ept(false))
+ test_skip("EPT not supported");
+ vmcs_write(CPU_EXEC_CTRL1, vmcs_read(CPU_EXEC_CTRL1) | CPU_URG);
+ test_guest_state("Unrestricted guest test", false, CPU_URG, "CPU_URG");
+
+ /*
+ * Let the guest finish execution as a regular guest
+ */
+ unsetup_unrestricted_guest();
+ vmcs_write(CPU_EXEC_CTRL1, vmcs_read(CPU_EXEC_CTRL1) & ~CPU_URG);
+ enter_guest();
+}
+
static bool valid_vmcs_for_vmentry(void)
{
struct vmcs *current_vmcs = NULL;
@@ -10434,6 +10481,7 @@
TEST(vmx_host_state_area_test),
TEST(vmx_guest_state_area_test),
TEST(vmentry_movss_shadow_test),
+ TEST(vmentry_unrestricted_guest_test),
/* APICv tests */
TEST(vmx_eoi_bitmap_ioapic_scan_test),
TEST(vmx_hlt_with_rvi_test),