Instruction tests of VMX should not be executed if the feature is unsupported by the CPU. Even if the execution controls allow to trap exits on the feature, the feature might be disabled, for example through IA32_MISC_ENABLES. Therefore, checking that the feature is supported through CPUID is needed. Introduce a general mechanism to check that a feature is supported and use it for monitor/mwait. Signed-off-by: Nadav Amit <nadav.amit@xxxxxxxxx> --- x86/vmx_tests.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index cade812..bdff938 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -842,6 +842,17 @@ extern void insn_rdseed(void); u32 cur_insn; u64 cr3; +#define X86_FEATURE_MONITOR (1 << 3) +#define X86_FEATURE_MCE (1 << 7) +#define X86_FEATURE_PCID (1 << 17) + +typedef bool (*supported_fn)(void); + +static bool monitor_supported(void) +{ + return cpuid(1).c & X86_FEATURE_MONITOR; +} + struct insn_table { const char *name; u32 flag; @@ -853,6 +864,8 @@ struct insn_table { // Use FIELD_EXIT_QUAL and FIELD_INSN_INFO to define // which field need to be tested, reason is always tested u32 test_field; + const supported_fn supported_fn; + u8 disabled; }; /* @@ -868,7 +881,7 @@ static struct insn_table insn_table[] = { {"HLT", CPU_HLT, insn_hlt, INSN_CPU0, 12, 0, 0, 0}, {"INVLPG", CPU_INVLPG, insn_invlpg, INSN_CPU0, 14, 0x12345678, 0, FIELD_EXIT_QUAL}, - {"MWAIT", CPU_MWAIT, insn_mwait, INSN_CPU0, 36, 0, 0, 0}, + {"MWAIT", CPU_MWAIT, insn_mwait, INSN_CPU0, 36, 0, 0, 0, &monitor_supported}, {"RDPMC", CPU_RDPMC, insn_rdpmc, INSN_CPU0, 15, 0, 0, 0}, {"RDTSC", CPU_RDTSC, insn_rdtsc, INSN_CPU0, 16, 0, 0, 0}, {"CR3 load", CPU_CR3_LOAD, insn_cr3_load, INSN_CPU0, 28, 0x3, 0, @@ -881,7 +894,7 @@ static struct insn_table insn_table[] = { {"CR8 store", CPU_CR8_STORE, insn_cr8_store, INSN_CPU0, 28, 0x18, 0, FIELD_EXIT_QUAL}, #endif - {"MONITOR", CPU_MONITOR, insn_monitor, INSN_CPU0, 39, 0, 0, 0}, + {"MONITOR", CPU_MONITOR, insn_monitor, INSN_CPU0, 39, 0, 0, 0, &monitor_supported}, {"PAUSE", CPU_PAUSE, insn_pause, INSN_CPU0, 40, 0, 0, 0}, // Flags for Secondary Processor-Based VM-Execution Controls {"WBINVD", CPU_WBINVD, insn_wbinvd, INSN_CPU1, 54, 0, 0, 0}, @@ -904,13 +917,19 @@ static struct insn_table insn_table[] = { static int insn_intercept_init(struct vmcs *vmcs) { - u32 ctrl_cpu; + u32 ctrl_cpu, cur_insn; ctrl_cpu = ctrl_cpu_rev[0].set | CPU_SECONDARY; ctrl_cpu &= ctrl_cpu_rev[0].clr; vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu); vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu_rev[1].set); cr3 = read_cr3(); + + for (cur_insn = 0; insn_table[cur_insn].name != NULL; cur_insn++) { + if (insn_table[cur_insn].supported_fn == NULL) + continue; + insn_table[cur_insn].disabled = !insn_table[cur_insn].supported_fn(); + } return VMX_TEST_START; } @@ -928,6 +947,12 @@ static void insn_intercept_main(void) continue; } + if (insn_table[cur_insn].disabled) { + printf("\tFeature required for %s is not supported.\n", + insn_table[cur_insn].name); + continue; + } + if ((insn_table[cur_insn].type == INSN_CPU0 && !(ctrl_cpu_rev[0].set & insn_table[cur_insn].flag)) || (insn_table[cur_insn].type == INSN_CPU1 && @@ -6841,9 +6866,6 @@ static void vmentry_movss_shadow_test(void) vmcs_write(GUEST_RFLAGS, X86_EFLAGS_FIXED); } -#define X86_FEATURE_PCID (1 << 17) -#define X86_FEATURE_MCE (1 << 7) - static int write_cr4_checking(unsigned long val) { asm volatile(ASM_TRY("1f") -- 2.17.1