diff mbox

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

Message ID 20171130003755.25658-2-krish.sadhukhan@oracle.com (mailing list archive)
State New, archived
Headers show

Commit Message

Krish Sadhukhan Nov. 30, 2017, 12:37 a.m. UTC
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@oracle.com>
Signed-off-by: Jim Mattson <jmattson@google.com>
---
 x86/vmx.h       |   1 +
 x86/vmx_tests.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 106 insertions(+), 18 deletions(-)

Comments

Paolo Bonzini Dec. 14, 2017, 11:46 a.m. UTC | #1
On 30/11/2017 01:37, Krish Sadhukhan wrote:
> 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@oracle.com>
> Signed-off-by: Jim Mattson <jmattson@google.com>
> ---
>  x86/vmx.h       |   1 +
>  x86/vmx_tests.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++---------
>  2 files changed, 106 insertions(+), 18 deletions(-)

Thanks, queued.  However I haven't pushed it yet because VMX tests are
currently broken (my fault).

Thanks,

Paolo

> 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);
>  }
>  
>
diff mbox

Patch

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);
 }