A stack based memory access should generate a #SS(0) exception but QEMU/TCG as of now (7.2) makes all exceptions based on a non-canonical address generate a #GP(0) instead (issue linked below). Add a test that will succeed when run under KVM but fail when using TCG. Link: https://gitlab.com/qemu-project/qemu/-/issues/928 Signed-off-by: Mathias Krause <minipli@xxxxxxxxxxxxxx> --- The non-canonical jump test is, apparently, broken under TCG as well. It "succeeds," as in changing RIP and thereby creating a #GP loop. I therefore put the new test in front of it to allow it to run. x86/emulator64.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/x86/emulator64.c b/x86/emulator64.c index 7f55d388c597..df2cd2c85308 100644 --- a/x86/emulator64.c +++ b/x86/emulator64.c @@ -2,10 +2,12 @@ #define GS_BASE 0x400000 static unsigned long rip_advance; +static struct ex_regs last_ex_regs; static void advance_rip_and_note_exception(struct ex_regs *regs) { ++exceptions; + last_ex_regs = *regs; regs->rip += rip_advance; } @@ -347,6 +349,55 @@ static void test_jmp_noncanonical(uint64_t *mem) handle_exception(GP_VECTOR, old); } +static void test_reg_noncanonical(void) +{ + extern char nc_rsp_start, nc_rsp_end, nc_rbp_start, nc_rbp_end; + extern char nc_rax_start, nc_rax_end; + handler old_ss, old_gp; + + old_ss = handle_exception(SS_VECTOR, advance_rip_and_note_exception); + old_gp = handle_exception(GP_VECTOR, advance_rip_and_note_exception); + + /* RAX based, should #GP(0) */ + exceptions = 0; + rip_advance = &nc_rax_end - &nc_rax_start; + asm volatile("nc_rax_start: orq $0, (%[msb]); nc_rax_end:\n\t" + : : [msb]"a"(1ul << 63)); + report(exceptions == 1 + && last_ex_regs.vector == GP_VECTOR + && last_ex_regs.error_code == 0, + "non-canonical memory access, should %s(0), got %s(%lu)", + exception_mnemonic(GP_VECTOR), + exception_mnemonic(last_ex_regs.vector), last_ex_regs.error_code); + + /* RSP based, should #SS(0) */ + exceptions = 0; + rip_advance = &nc_rsp_end - &nc_rsp_start; + asm volatile("nc_rsp_start: orq $0, (%%rsp,%[msb],1); nc_rsp_end:\n\t" + : : [msb]"r"(1ul << 63)); + report(exceptions == 1 + && last_ex_regs.vector == SS_VECTOR + && last_ex_regs.error_code == 0, + "non-canonical rsp-based access, should %s(0), got %s(%lu)", + exception_mnemonic(SS_VECTOR), + exception_mnemonic(last_ex_regs.vector), last_ex_regs.error_code); + + /* RBP based, should #SS(0) */ + exceptions = 0; + rip_advance = &nc_rbp_end - &nc_rbp_start; + asm volatile("nc_rbp_start: orq $0, (%%rbp,%[msb],1); nc_rbp_end:\n\t" + : : [msb]"r"(1ul << 63)); + report(exceptions == 1 + && last_ex_regs.vector == SS_VECTOR + && last_ex_regs.error_code == 0, + "non-canonical rbp-based access, should %s(0), got %s(%lu)", + exception_mnemonic(SS_VECTOR), + exception_mnemonic(last_ex_regs.vector), last_ex_regs.error_code); + + handle_exception(SS_VECTOR, old_ss); + handle_exception(GP_VECTOR, old_gp); +} + static void test_movabs(uint64_t *mem) { /* mov $0x9090909090909090, %rcx */ @@ -460,5 +511,6 @@ static void test_emulator_64(void *mem) test_push16(mem); + test_reg_noncanonical(); test_jmp_noncanonical(mem); } -- 2.39.1