From: Michal Luczaj <mhal@xxxxxxx> Verify that code breakpoints (#DBs) are suppressed on Intel CPUs when MOV/POP SS blocking is active, and that #DBs are _not_ suppressed on AMD CPUs. If forced emulation is available, verify that KVM correctly emulates both the MOV/POP SS shadow and the resulting interaction with code breakpoints. Note, properly testing forced emulation on Intel requires instructing KVM to clear RFLAGS.RF prior to emulating. Ideally this test would go in debug.c, but POP SS is disallowed in 64-bit mode and "debug" is a 64-bit only test. Alternatively, the debug test could temporarily transition to 32-bit mode, but that relies on the stack and code being addressable in 32-bit mode, which may not always hold true. Signed-off-by: Michal Luczaj <mhal@xxxxxxx> Co-developed-by: Sean Christopherson <seanjc@xxxxxxxxxx> Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx> --- x86/emulator.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/x86/emulator.c b/x86/emulator.c index f91f6e7..a92fc19 100644 --- a/x86/emulator.c +++ b/x86/emulator.c @@ -716,6 +716,79 @@ static void test_illegal_movbe(void) "Wanted #UD on MOVBE with /reg, got vector = %u", vector); } +#ifdef __x86_64__ +#define RIP_RELATIVE "(%%rip)" +#else +#define RIP_RELATIVE "" +#endif + +static void handle_db(struct ex_regs *regs) +{ + ++exceptions; + regs->rflags |= X86_EFLAGS_RF; +} + +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; + + write_dr7(DR7_FIXED_1 | + DR7_GLOBAL_ENABLE_DRx(0) | + DR7_EXECUTE_DRx(0) | + DR7_LEN_1_DRx(0)); + +#define MOV_POP_SS_DB(desc, fep1, fep2, insn, store_ss, load_ss) \ +({ \ + unsigned long r; \ + \ + exceptions = 0; \ + asm volatile("lea 1f " RIP_RELATIVE ", %0\n\t" \ + "mov %0, %%dr0\n\t" \ + store_ss \ + fep1 load_ss \ + fep2 "1: xor %0, %0\n\t" \ + "2:" \ + : "=r" (r) \ + : \ + : "memory"); \ + report(exceptions == nr_expected && !r, \ + desc ": #DB %s after " insn " SS", \ + nr_expected ? "occurred" : "suppressed"); \ +}) + +#define MOV_SS_DB(desc, fep1, fep2) \ + MOV_POP_SS_DB(desc, fep1, fep2, "MOV", \ + "mov %%ss, %0\n\t", "mov %0, %%ss\n\t") + + MOV_SS_DB("no fep", "", ""); + if (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); + } + +/* PUSH/POP SS are invalid in 64-bit mode. */ +#ifndef __x86_64__ +#define POP_SS_DB(desc, fep1, fep2) \ + MOV_POP_SS_DB(desc, fep1, fep2, "POP", \ + "push %%ss\n\t", "pop %%ss\n\t") + + POP_SS_DB("no fep", "", ""); + if (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); + } +#endif + + write_dr7(DR7_FIXED_1); + + handle_exception(DB_VECTOR, old_db_handler); +} + int main(void) { void *mem; @@ -762,6 +835,7 @@ int main(void) test_string_io_mmio(mem); test_illegal_movbe(); + test_mov_pop_ss_code_db(); #ifdef __x86_64__ test_emulator_64(mem); -- 2.37.2.672.g94769d06f0-goog