..to verify KVM performs the appropriate consistency checks for loading IA32_PERF_GLOBAL_CONTROL as part of running a nested guest. According to section "Checking and Loading Guest State" in Intel SDM vol 3C, the following check is performed on vmentry: 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. Signed-off-by: Krish Sadhukhan <krish.sadhukhan@xxxxxxxxxx> Reviewed-by: Karl Heubaum <karl.heubaum@xxxxxxxxxx> --- x86/vmx_tests.c | 82 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 11 deletions(-) diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index a339bb3..65772ce 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -5031,29 +5031,69 @@ static void test_perf_global_ctl(u32 field, const char * field_name, u64 perf_global_saved = vmcs_read(field); u64 i, val; + if (field == GUEST_PERF_GLOBAL_CTRL) { + vmx_set_test_stage(1); + test_set_guest(guest_state_test_main); + } + 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(); + if (field == HOST_PERF_GLOBAL_CTRL) { + 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(); + } else { // GUEST_PERF_GLOBAL_CTRL + enter_guest(); + report_guest_state_test("ENT_LOAD_PERF disabled", + VMX_VMCALL, val, + "GUEST_PERF_GLOBAL_CTRL"); + } } 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); + if (field == HOST_PERF_GLOBAL_CTRL) { + 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(); + } else { // GUEST_PERF_GLOBAL_CTRL + enter_guest(); + if (PERF_GLOBAL_CTRL_VALID_BITS & (1ull << i)) { + report_guest_state_test("ENT_LOAD_PERF enabled", + VMX_FAIL_STATE | + VMX_ENTRY_FAILURE, + val, + "GUEST_PERF_GLOBAL_CTRL"); + } else { + report_guest_state_test("ENT_LOAD_PERF enabled", + VMX_VMCALL, + val, + "GUEST_PERF_GLOBAL_CTRL"); + } + } + } + + if (field == GUEST_PERF_GLOBAL_CTRL) { + /* + * Let the guest finish execution + */ + vmx_set_test_stage(2); + vmcs_write(field, perf_global_saved); + enter_guest(); } vmcs_write(ctrl_field, ctrl_saved); @@ -5079,6 +5119,25 @@ static void test_host_perf_global_ctl(void) EXI_CONTROLS, EXI_LOAD_PERF); } +/* + * If the "load IA32_PERF_GLOBAL_CTRL" VM-entry 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_guest_perf_global_ctl(void) +{ + if (!(ctrl_exit_rev.clr & ENT_LOAD_PERF)) { + printf("\"load IA32_PERF_GLOBAL_CTRL\" VM-entry control not " + "supported\n"); + return; + } + + test_perf_global_ctl(GUEST_PERF_GLOBAL_CTRL, "GUEST_PERF_GLOBAL_CTRL", + ENT_CONTROLS, ENT_LOAD_PERF); +} + /* * PAT values higher than 8 are uninteresting since they're likely lumped * in with "8". We only test values above 8 one bit at a time, @@ -5243,6 +5302,7 @@ static void test_load_guest_pat(void) */ static void vmx_guest_state_area_test(void) { + test_guest_perf_global_ctl(); test_load_guest_pat(); } -- 2.20.1