[PATCH] x86: Add test for TPR threshold and vTPR check on VM-entry

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

 



This test checks that a nested VM-entry fails if the "use TPR shadow"
VM-execution control is set, the "virtual-interrupt delivery"
VM-execution control is clear, "virtualize APIC accesses" is clear and
bits 3:0 of TPR threshold is greater than bits 7:4 of vTPR.

Signed-off-by: Krish Sadhukhan <krish.sadhukhan@xxxxxxxxxx>
Signed-off-by: Jim Mattson <jmattson@xxxxxxxxxx>
---
 x86/vmx.h       |   1 +
 x86/vmx_tests.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 106 insertions(+), 18 deletions(-)

diff --git a/x86/vmx.h b/x86/vmx.h
index f0b8776..bdcaac0 100644
--- a/x86/vmx.h
+++ b/x86/vmx.h
@@ -388,6 +388,7 @@ enum Ctrl0 {
 };
 
 enum Ctrl1 {
+	CPU_VIRT_APIC_ACCESSES	= 1ul << 0,
 	CPU_EPT			= 1ul << 1,
 	CPU_DESC_TABLE		= 1ul << 2,
 	CPU_RDTSCP		= 1ul << 3,
diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c
index e8c97f2..6c10281 100644
--- a/x86/vmx_tests.c
+++ b/x86/vmx_tests.c
@@ -3476,18 +3476,58 @@ static void test_apic_virt_addr(void)
 				 "virtual-APIC address", "Use TPR shadow", true);
 }
 
-static void try_tpr_threshold(unsigned val)
+static void set_vtpr(unsigned vtpr)
+{
+	*(u32 *)phys_to_virt(vmcs_read(APIC_VIRT_ADDR) + APIC_TASKPRI) = vtpr;
+}
+
+static void try_tpr_threshold_and_vtpr(unsigned threshold, unsigned vtpr)
+{
+	bool valid = true;
+	u32 primary = vmcs_read(CPU_EXEC_CTRL0);
+	u32 secondary = vmcs_read(CPU_EXEC_CTRL1);
+
+	if ((primary & CPU_TPR_SHADOW) &&
+	    (!(primary & CPU_SECONDARY) ||
+	     !(secondary & (CPU_VINTD | CPU_VIRT_APIC_ACCESSES))))
+		valid = (threshold & 0xf) <= ((vtpr >> 4) & 0xf);
+
+	set_vtpr(vtpr);
+	report_prefix_pushf("TPR threshold 0x%x, VTPR.class 0x%x",
+	    threshold, (vtpr >> 4) & 0xf);
+	test_vmx_controls(valid, false);
+	report_prefix_pop();
+}
+
+/*
+ * Test interesting vTPR values for a given TPR threshold.
+ */
+static void test_vtpr_values(unsigned threshold)
+{
+	try_tpr_threshold_and_vtpr(threshold, threshold - 1);
+	try_tpr_threshold_and_vtpr(threshold, threshold);
+	try_tpr_threshold_and_vtpr(threshold, threshold + 1);
+}
+
+static void try_tpr_threshold(unsigned threshold)
 {
 	bool valid = true;
 
-	if ((vmcs_read(CPU_EXEC_CTRL0) & CPU_TPR_SHADOW) &&
-	    !((vmcs_read(CPU_EXEC_CTRL0) & CPU_SECONDARY) &&
-	      (vmcs_read(CPU_EXEC_CTRL1) & CPU_VINTD)))
-		valid = !(val >> 4);
-	report_prefix_pushf("TPR threshold 0x%x", val);
-	vmcs_write(TPR_THRESHOLD, val);
+	u32 primary = vmcs_read(CPU_EXEC_CTRL0);
+	u32 secondary = vmcs_read(CPU_EXEC_CTRL1);
+
+	if ((primary & CPU_TPR_SHADOW) && !((primary & CPU_SECONDARY) &&
+	    (secondary & CPU_VINTD)))
+		valid = !(threshold >> 4);
+
+	set_vtpr(-1);
+	vmcs_write(TPR_THRESHOLD, threshold);
+	report_prefix_pushf("TPR threshold 0x%x, VTPR.class 0xf", threshold);
 	test_vmx_controls(valid, false);
 	report_prefix_pop();
+
+	if (valid)
+		test_vtpr_values(threshold);
 }
 
 /*
@@ -3506,10 +3546,21 @@ static void test_tpr_threshold_values(void)
 }
 
 /*
- * If the "use TPR shadow" VM-execution control is 1 and the
- * "virtual-interrupt delivery" VM-execution control is 0, bits 31:4
- * of the TPR threshold VM-execution control field must be 0.
- * [Intel SDM]
+ * This test covers the following two VM entry checks:
+ *
+ *      i) If the "use TPR shadow" VM-execution control is 1 and the
+ *         "virtual-interrupt delivery" VM-execution control is 0, bits
+ *         31:4 of the TPR threshold VM-execution control field must
+	   be 0.
+ *         [Intel SDM]
+ *
+ *      ii) If the "use TPR shadow" VM-execution control is 1, the
+ *          "virtual-interrupt delivery" VM-execution control is 0
+ *          and the "virtualize APIC accesses" VM-execution control
+ *          is 0, the value of bits 3:0 of the TPR threshold VM-execution
+ *          control field must not be greater than the value of bits
+ *          7:4 of VTPR.
+ *          [Intel SDM]
  */
 static void test_tpr_threshold(void)
 {
@@ -3524,7 +3575,7 @@ static void test_tpr_threshold(void)
 	vmcs_write(APIC_VIRT_ADDR, virt_to_phys(virtual_apic_page));
 
 	vmcs_write(CPU_EXEC_CTRL0, primary & ~(CPU_TPR_SHADOW | CPU_SECONDARY));
-	report_prefix_pushf("Use TPR shadow disabled");
+	report_prefix_pushf("Use TPR shadow disabled, secondary controls disabled");
 	test_tpr_threshold_values();
 	report_prefix_pop();
 	vmcs_write(CPU_EXEC_CTRL0, vmcs_read(CPU_EXEC_CTRL0) | CPU_TPR_SHADOW);
@@ -3532,23 +3583,59 @@ static void test_tpr_threshold(void)
 	test_tpr_threshold_values();
 	report_prefix_pop();
 
-	if ((ctrl_cpu_rev[0].clr & CPU_SECONDARY) &&
-	    (ctrl_cpu_rev[1].clr & CPU_VINTD)) {
-		u32 secondary = vmcs_read(CPU_EXEC_CTRL1);
+	if (!((ctrl_cpu_rev[0].clr & CPU_SECONDARY) &&
+	    (ctrl_cpu_rev[1].clr & (CPU_VINTD  | CPU_VIRT_APIC_ACCESSES))))
+		return;
+
+	u32 secondary = vmcs_read(CPU_EXEC_CTRL1);
 
+	if (ctrl_cpu_rev[1].clr & CPU_VINTD) {
 		vmcs_write(CPU_EXEC_CTRL1, CPU_VINTD);
-		report_prefix_pushf("Use TPR shadow enabled; secondary controls disabled");
+		report_prefix_pushf("Use TPR shadow enabled; secondary controls disabled; virtual-interrupt delivery enabled; virtualize APIC accesses disabled");
 		test_tpr_threshold_values();
 		report_prefix_pop();
+
 		vmcs_write(CPU_EXEC_CTRL0,
 			   vmcs_read(CPU_EXEC_CTRL0) | CPU_SECONDARY);
-		report_prefix_pushf("Use TPR shadow enabled; virtual-interrupt delivery enabled");
+		report_prefix_pushf("Use TPR shadow enabled; secondary controls enabled; virtual-interrupt delivery enabled; virtualize APIC accesses disabled");
+		test_tpr_threshold_values();
+		report_prefix_pop();
+	}
+
+	if (ctrl_cpu_rev[1].clr & CPU_VIRT_APIC_ACCESSES) {
+		vmcs_write(CPU_EXEC_CTRL0,
+			   vmcs_read(CPU_EXEC_CTRL0) & ~CPU_SECONDARY);
+		vmcs_write(CPU_EXEC_CTRL1, CPU_VIRT_APIC_ACCESSES);
+		report_prefix_pushf("Use TPR shadow enabled; secondary controls disabled; virtual-interrupt delivery enabled; virtualize APIC accesses enabled");
 		test_tpr_threshold_values();
 		report_prefix_pop();
 
-		vmcs_write(CPU_EXEC_CTRL1, secondary);
+		vmcs_write(CPU_EXEC_CTRL0,
+			   vmcs_read(CPU_EXEC_CTRL0) | CPU_SECONDARY);
+		report_prefix_pushf("Use TPR shadow enabled; secondary controls enabled; virtual-interrupt delivery enabled; virtualize APIC accesses enabled");
+		test_tpr_threshold_values();
+		report_prefix_pop();
 	}
 
+	if ((ctrl_cpu_rev[1].clr &
+	     (CPU_VINTD | CPU_VIRT_APIC_ACCESSES)) ==
+	    (CPU_VINTD | CPU_VIRT_APIC_ACCESSES)) {
+		vmcs_write(CPU_EXEC_CTRL0,
+			   vmcs_read(CPU_EXEC_CTRL0) & ~CPU_SECONDARY);
+		vmcs_write(CPU_EXEC_CTRL1,
+			   CPU_VINTD | CPU_VIRT_APIC_ACCESSES);
+		report_prefix_pushf("Use TPR shadow enabled; secondary controls disabled; virtual-interrupt delivery enabled; virtualize APIC accesses enabled");
+		test_tpr_threshold_values();
+		report_prefix_pop();
+
+		vmcs_write(CPU_EXEC_CTRL0,
+			   vmcs_read(CPU_EXEC_CTRL0) | CPU_SECONDARY);
+		report_prefix_pushf("Use TPR shadow enabled; secondary controls enabled; virtual-interrupt delivery enabled; virtualize APIC accesses enabled");
+		test_tpr_threshold_values();
+		report_prefix_pop();
+	}
+
+	vmcs_write(CPU_EXEC_CTRL1, secondary);
 	vmcs_write(CPU_EXEC_CTRL0, primary);
 }
 
-- 
2.9.5




[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