From 073c4b74cad5c6aa273caf156b38bec4f6179d54 Mon Sep 17 00:00:00 2001 From: "Takacs, Philipp" Date: Tue, 9 May 2023 14:20:11 +0200 Subject: [PATCH] load_helper only call cpu_loop_exit() when emulation is running The load_helper is sometimes called from register writes. When the load fails check if emulation is running before jump out of the emulated code. --- qemu/accel/tcg/cputlb.c | 38 +++++++++++++++++++++++--------------- tests/unit/test_x86.c | 12 ++++++++++++ 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/qemu/accel/tcg/cputlb.c b/qemu/accel/tcg/cputlb.c index 659faf3f..29c6555b 100644 --- a/qemu/accel/tcg/cputlb.c +++ b/qemu/accel/tcg/cputlb.c @@ -1520,21 +1520,25 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, mr = find_memory_region(uc, paddr); if (mr == NULL) { uc->invalid_error = UC_ERR_MAP; - cpu_exit(uc->cpu); - // XXX(@lazymio): We have to exit early so that the target register won't be overwritten - // because qemu might generate tcg code like: - // qemu_ld_i64 x0,x1,leq,8 sync: 0 dead: 0 1 - // where we don't have a change to recover x0 value - cpu_loop_exit(uc->cpu); + if (!uc->cpu->stopped) { + cpu_exit(uc->cpu); + // XXX(@lazymio): We have to exit early so that the target register won't be overwritten + // because qemu might generate tcg code like: + // qemu_ld_i64 x0,x1,leq,8 sync: 0 dead: 0 1 + // where we don't have a change to recover x0 value + cpu_loop_exit(uc->cpu); + } return 0; } } else { uc->invalid_addr = paddr; uc->invalid_error = error_code; // printf("***** Invalid fetch (unmapped memory) at " TARGET_FMT_lx "\n", addr); - cpu_exit(uc->cpu); - // See comments above - cpu_loop_exit(uc->cpu); + if (!uc->cpu->stopped) { + cpu_exit(uc->cpu); + // See comments above + cpu_loop_exit(uc->cpu); + } return 0; } } @@ -1588,9 +1592,11 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uc->invalid_addr = paddr; uc->invalid_error = UC_ERR_READ_PROT; // printf("***** Invalid memory read (non-readable) at " TARGET_FMT_lx "\n", addr); - cpu_exit(uc->cpu); - // See comments above - cpu_loop_exit(uc->cpu); + if (!uc->cpu->stopped) { + cpu_exit(uc->cpu); + // See comments above + cpu_loop_exit(uc->cpu); + } return 0; } } @@ -1618,9 +1624,11 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uc->invalid_addr = paddr; uc->invalid_error = UC_ERR_FETCH_PROT; // printf("***** Invalid fetch (non-executable) at " TARGET_FMT_lx "\n", addr); - cpu_exit(uc->cpu); - // See comments above - cpu_loop_exit(uc->cpu); + if (!uc->cpu->stopped) { + cpu_exit(uc->cpu); + // See comments above + cpu_loop_exit(uc->cpu); + } return 0; } } diff --git a/tests/unit/test_x86.c b/tests/unit/test_x86.c index e1cc9a5c..61625e82 100644 --- a/tests/unit/test_x86.c +++ b/tests/unit/test_x86.c @@ -1415,6 +1415,17 @@ static void test_x86_vtlb(void) OK(uc_close(uc)); } +static void test_x86_segmentation() +{ + uc_engine *uc; + uint64_t fs = 0x53; + uc_x86_mmr gdtr = { 0, 0xfffff8076d962000, 0x57, 0 }; + + OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc)); + OK(uc_reg_write(uc, UC_X86_REG_GDTR, &gdtr)); + uc_assert_err(UC_ERR_EXCEPTION, uc_reg_write(uc, UC_X86_REG_FS, &fs)); +} + TEST_LIST = { {"test_x86_in", test_x86_in}, @@ -1461,4 +1472,5 @@ TEST_LIST = { {"test_x86_16_incorrect_ip", test_x86_16_incorrect_ip}, {"test_x86_mmu", test_x86_mmu}, {"test_x86_vtlb", test_x86_vtlb}, + {"test_x86_segmentation", test_x86_segmentation}, {NULL, NULL}};