aboutsummaryrefslogtreecommitdiff
path: root/accel
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2019-04-02 14:37:51 +0700
committerRichard Henderson <richard.henderson@linaro.org>2019-05-10 07:55:06 -0700
commitda6bbf8513e621a8fc2fd315d77318f36547474d (patch)
treee5e71300053bad1fda664ea1113a46eff43e4fce /accel
parentefb4f3b62c69383a7308d7b739a3193e7c0ccae8 (diff)
downloadqemu-da6bbf8513e621a8fc2fd315d77318f36547474d.zip
qemu-da6bbf8513e621a8fc2fd315d77318f36547474d.tar.gz
qemu-da6bbf8513e621a8fc2fd315d77318f36547474d.tar.bz2
tcg: Add CPUClass::tlb_fill
This hook will replace the (user-only mode specific) handle_mmu_fault hook, and the (system mode specific) tlb_fill function. The handle_mmu_fault hook was written as if there was a valid way to recover from an mmu fault, and had 3 possible return states. In reality, the only valid action is to raise an exception, return to the main loop, and deliver the SIGSEGV to the guest. Note that all of the current implementations of handle_mmu_fault for guests which support linux-user do in fact only ever return 1, which is the signal to return to the main loop. Using the hook for system mode requires that all targets be converted, so for now the hook is (optionally) used only from user-only mode. Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'accel')
-rw-r--r--accel/tcg/user-exec.c39
1 files changed, 14 insertions, 25 deletions
diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c
index 0789984..199f88c 100644
--- a/accel/tcg/user-exec.c
+++ b/accel/tcg/user-exec.c
@@ -65,6 +65,7 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
CPUClass *cc;
int ret;
unsigned long address = (unsigned long)info->si_addr;
+ MMUAccessType access_type;
/* We must handle PC addresses from two different sources:
* a call return address and a signal frame address.
@@ -147,35 +148,23 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
are still valid segv ones */
address = h2g_nocheck(address);
- cc = CPU_GET_CLASS(cpu);
- /* see if it is an MMU fault */
- g_assert(cc->handle_mmu_fault);
- ret = cc->handle_mmu_fault(cpu, address, 0, is_write, MMU_USER_IDX);
-
- if (ret == 0) {
- /* The MMU fault was handled without causing real CPU fault.
- * Retain helper_retaddr for a possible second fault.
- */
- return 1;
- }
-
- /* All other paths lead to cpu_exit; clear helper_retaddr
- * for next execution.
+ /*
+ * There is no way the target can handle this other than raising
+ * an exception. Undo signal and retaddr state prior to longjmp.
*/
+ sigprocmask(SIG_SETMASK, old_set, NULL);
helper_retaddr = 0;
- if (ret < 0) {
- return 0; /* not an MMU fault */
+ cc = CPU_GET_CLASS(cpu);
+ if (cc->tlb_fill) {
+ access_type = is_write ? MMU_DATA_STORE : MMU_DATA_LOAD;
+ cc->tlb_fill(cpu, address, 0, access_type, MMU_USER_IDX, false, pc);
+ g_assert_not_reached();
+ } else {
+ ret = cc->handle_mmu_fault(cpu, address, 0, is_write, MMU_USER_IDX);
+ g_assert(ret > 0);
+ cpu_loop_exit_restore(cpu, pc);
}
-
- /* Now we have a real cpu fault. */
- cpu_restore_state(cpu, pc, true);
-
- sigprocmask(SIG_SETMASK, old_set, NULL);
- cpu_loop_exit(cpu);
-
- /* never comes here */
- return 1;
}
#if defined(__i386__)