@@ -4995,6 +4995,63 @@ static void test_sysenter_field(u32 field, const char *name)
vmcs_write(field, addr_saved);
}
+#define PERF_GLOBAL_CTRL_VALID_BITS 0x0000000700000003
+
+static void test_perf_global_ctl(u32 field, const char * field_name,
+ u32 ctrl_field, u64 ctrl_bit)
+{
+ u32 ctrl_saved = vmcs_read(ctrl_field);
+ u64 perf_global_saved = vmcs_read(field);
+ u64 i, val;
+
+ vmcs_write(ctrl_field, ctrl_saved & ~ctrl_bit);
+ for (i = 0; i < 64; i++) {
+ val = 1ull << i;
+ vmcs_write(field, val);
+ report_prefix_pushf("\"load IA32_PERF_GLOBAL_CTRL\" "
+ "VM-exit control is off, HOST_PERF_GLOBAL_CTRL %lx", val);
+ test_vmx_vmlaunch(0, false);
+ report_prefix_pop();
+ }
+
+ vmcs_write(ctrl_field, ctrl_saved | ctrl_bit);
+ for (i = 0; i < 64; i++) {
+ val = 1ull << i;
+ vmcs_write(field, val);
+ report_prefix_pushf("\"load IA32_PERF_GLOBAL_CTRL\" "
+ "VM-exit control is on, HOST_PERF_GLOBAL_CTRL %lx", val);
+ if (PERF_GLOBAL_CTRL_VALID_BITS & (1ull << i)) {
+ test_vmx_vmlaunch(0, false);
+ } else {
+ test_vmx_vmlaunch(VMXERR_ENTRY_INVALID_HOST_STATE_FIELD,
+ false);
+ }
+ report_prefix_pop();
+ }
+
+ vmcs_write(ctrl_field, ctrl_saved);
+ vmcs_write(field, perf_global_saved);
+}
+
+/*
+ * If the "load IA32_PERF_GLOBAL_CTRL" VM-exit control is 1, bits reserved
+ * in the IA32_PERF_GLOBAL_CTRL MSR must be 0 in the field for that
+ * register.
+ *
+ * [Intel SDM]
+ */
+static void test_host_perf_global_ctl(void)
+{
+ if (!(ctrl_exit_rev.clr & EXI_LOAD_PERF)) {
+ printf("\"load IA32_PERF_GLOBAL_CTRL\" VM-exit control not "
+ "supported\n");
+ return;
+ }
+
+ test_perf_global_ctl(HOST_PERF_GLOBAL_CTRL, "HOST_PERF_GLOBAL_CTRL",
+ EXI_CONTROLS, EXI_LOAD_PERF);
+}
+
/*
* Check that the virtual CPU checks the VMX Host State Area as
* documented in the Intel SDM.
@@ -5010,6 +5067,8 @@ static void vmx_host_state_area_test(void)
test_sysenter_field(HOST_SYSENTER_ESP, "HOST_SYSENTER_ESP");
test_sysenter_field(HOST_SYSENTER_EIP, "HOST_SYSENTER_EIP");
+
+ test_host_perf_global_ctl();
}
static bool valid_vmcs_for_vmentry(void)