Cache whether or not forced emulation is availability during setup_idt() so that tests can force emulation (or not) in contexts where taking an exception of any kind will fail. Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx> --- lib/x86/desc.c | 22 ++++++++++++++++++++++ lib/x86/desc.h | 14 +------------- x86/access.c | 2 +- x86/emulator.c | 11 +++++------ x86/emulator64.c | 2 +- x86/la57.c | 2 +- x86/lam.c | 2 +- x86/msr.c | 2 +- x86/pmu.c | 2 +- 9 files changed, 34 insertions(+), 25 deletions(-) diff --git a/lib/x86/desc.c b/lib/x86/desc.c index 5748f900..fca37b9a 100644 --- a/lib/x86/desc.c +++ b/lib/x86/desc.c @@ -298,6 +298,22 @@ static void *idt_handlers[32] = { [21] = &cp_fault, }; +bool is_fep_available; + +static bool __is_fep_available(void) +{ + /* + * Use the non-FEP ASM_TRY() as KVM will inject a #UD on the prefix + * itself if forced emulation is not available. + */ + asm goto(ASM_TRY("%l[fep_unavailable]") + KVM_FEP "nop\n\t" + ::: "memory" : fep_unavailable); + return true; +fep_unavailable: + return false; +} + void setup_idt(void) { int i; @@ -311,6 +327,12 @@ void setup_idt(void) } load_idt(); + + /* + * Detect support for forced emulation *after* loading the IDT, as this + * will #UD if FEP is unavailable. + */ + is_fep_available = __is_fep_available(); } void load_idt(void) diff --git a/lib/x86/desc.h b/lib/x86/desc.h index a1e60e78..68f38f3d 100644 --- a/lib/x86/desc.h +++ b/lib/x86/desc.h @@ -164,19 +164,7 @@ typedef struct __attribute__((packed)) { #define KVM_FEP "ud2; .byte 'k', 'v', 'm';" #define ASM_TRY_FEP(catch) __ASM_TRY(KVM_FEP, catch) -static inline bool is_fep_available(void) -{ - /* - * Use the non-FEP ASM_TRY() as KVM will inject a #UD on the prefix - * itself if forced emulation is not available. - */ - asm goto(ASM_TRY("%l[fep_unavailable]") - KVM_FEP "nop\n\t" - ::: "memory" : fep_unavailable); - return true; -fep_unavailable: - return false; -} +extern bool is_fep_available; typedef struct { unsigned short offset0; diff --git a/x86/access.c b/x86/access.c index f90a72d6..d94910bf 100644 --- a/x86/access.c +++ b/x86/access.c @@ -1232,7 +1232,7 @@ void ac_test_run(int pt_levels, bool force_emulation) ac_pt_env_t pt_env; int i, tests, successes; - if (force_emulation && !is_fep_available()) { + if (force_emulation && !is_fep_available) { report_skip("Forced emulation prefix (FEP) not available\n"); return; } diff --git a/x86/emulator.c b/x86/emulator.c index f8bdc26b..4e1ba12a 100644 --- a/x86/emulator.c +++ b/x86/emulator.c @@ -728,7 +728,6 @@ static void handle_db(struct ex_regs *regs) static void test_mov_pop_ss_code_db(void) { handler old_db_handler = handle_exception(DB_VECTOR, handle_db); - bool fep_available = is_fep_available(); /* On Intel, code #DBs are inhibited when MOV/POP SS blocking is active. */ int nr_expected = is_intel() ? 0 : 1; @@ -761,7 +760,7 @@ static void test_mov_pop_ss_code_db(void) "mov %%ss, %0\n\t", "mov %0, %%ss\n\t") MOV_SS_DB("no fep", "", ""); - if (fep_available) { + if (is_fep_available) { MOV_SS_DB("fep MOV-SS", KVM_FEP, ""); MOV_SS_DB("fep XOR", "", KVM_FEP); MOV_SS_DB("fep MOV-SS/fep XOR", KVM_FEP, KVM_FEP); @@ -774,7 +773,7 @@ static void test_mov_pop_ss_code_db(void) "push %%ss\n\t", "pop %%ss\n\t") POP_SS_DB("no fep", "", ""); - if (fep_available) { + if (is_fep_available) { POP_SS_DB("fep POP-SS", KVM_FEP, ""); POP_SS_DB("fep XOR", "", KVM_FEP); POP_SS_DB("fep POP-SS/fep XOR", KVM_FEP, KVM_FEP); @@ -791,8 +790,8 @@ int main(void) void *mem; void *cross_mem; - if (!is_fep_available()) - report_skip("Skipping tests the require forced emulation, " + if (!is_fep_available) + report_skip("Skipping tests that require forced emulation, " "use kvm.force_emulation_prefix=1 to enable"); setup_vm(); @@ -821,7 +820,7 @@ int main(void) //test_lldt(mem); test_ltr(mem); - if (is_fep_available()) { + if (is_fep_available) { test_smsw_reg(mem); test_nop(mem); test_mov_dr(mem); diff --git a/x86/emulator64.c b/x86/emulator64.c index 5d1bb0f0..138903af 100644 --- a/x86/emulator64.c +++ b/x86/emulator64.c @@ -478,7 +478,7 @@ static void test_emulator_64(void *mem) test_sreg(mem); test_cmov(mem); - if (is_fep_available()) { + if (is_fep_available) { test_mmx_movq_mf(mem); test_movabs(mem); test_user_load_dpl0_seg(); diff --git a/x86/la57.c b/x86/la57.c index 41764110..d93e286c 100644 --- a/x86/la57.c +++ b/x86/la57.c @@ -313,7 +313,7 @@ static void test_canonical_checks(void) { __test_canonical_checks(false); - if (is_fep_available()) + if (is_fep_available) __test_canonical_checks(true); else report_skip("Force emulation prefix not enabled"); diff --git a/x86/lam.c b/x86/lam.c index a1c98949..8ad68178 100644 --- a/x86/lam.c +++ b/x86/lam.c @@ -184,7 +184,7 @@ static void __test_lam_sup(void *vaddr, void *vaddr_mmio) test_ptr(vaddr_mmio, true); test_invpcid(vaddr); test_invlpg(vaddr, false); - if (is_fep_available()) + if (is_fep_available) test_invlpg(vaddr, true); } diff --git a/x86/msr.c b/x86/msr.c index e21ff0ac..f582a584 100644 --- a/x86/msr.c +++ b/x86/msr.c @@ -313,7 +313,7 @@ static void test_cmd_msrs(void) test_wrmsr_fault(MSR_IA32_FLUSH_CMD, "FLUSH_CMD", L1D_FLUSH); } - if (is_fep_available()) { + if (is_fep_available) { for (i = 1; i < 64; i++) test_wrmsr_fep_fault(MSR_IA32_FLUSH_CMD, "FLUSH_CMD", BIT_ULL(i)); } diff --git a/x86/pmu.c b/x86/pmu.c index 8cf26b12..b794b7d8 100644 --- a/x86/pmu.c +++ b/x86/pmu.c @@ -823,7 +823,7 @@ static void warm_up(void) static void check_counters(void) { - if (is_fep_available()) + if (is_fep_available) check_emulated_instr(); warm_up(); -- 2.49.0.1266.g31b7d2e469-goog