mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-17 07:02:03 -06:00
tcg: Release mmap_lock on translation fault
Turn helper_retaddr into a multi-state flag that may now also indicate when we're performing a read on behalf of the translator. In this case, release the mmap_lock before the longjmp back to the main cpu loop, and thereby avoid a failing assert therein. Fixes: https://bugs.launchpad.net/qemu/+bug/1832353 Tested-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Alex Bennée <alex.bennee@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
parent
2fbb2353ce
commit
52ba13f042
2 changed files with 63 additions and 23 deletions
|
@ -64,27 +64,56 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
|
||||||
CPUState *cpu = current_cpu;
|
CPUState *cpu = current_cpu;
|
||||||
CPUClass *cc;
|
CPUClass *cc;
|
||||||
unsigned long address = (unsigned long)info->si_addr;
|
unsigned long address = (unsigned long)info->si_addr;
|
||||||
MMUAccessType access_type;
|
MMUAccessType access_type = is_write ? MMU_DATA_STORE : MMU_DATA_LOAD;
|
||||||
|
|
||||||
/* We must handle PC addresses from two different sources:
|
switch (helper_retaddr) {
|
||||||
* a call return address and a signal frame address.
|
default:
|
||||||
*
|
/*
|
||||||
* Within cpu_restore_state_from_tb we assume the former and adjust
|
* Fault during host memory operation within a helper function.
|
||||||
* the address by -GETPC_ADJ so that the address is within the call
|
* The helper's host return address, saved here, gives us a
|
||||||
* insn so that addr does not accidentally match the beginning of the
|
* pointer into the generated code that will unwind to the
|
||||||
* next guest insn.
|
* correct guest pc.
|
||||||
*
|
*/
|
||||||
* However, when the PC comes from the signal frame, it points to
|
|
||||||
* the actual faulting host insn and not a call insn. Subtracting
|
|
||||||
* GETPC_ADJ in that case may accidentally match the previous guest insn.
|
|
||||||
*
|
|
||||||
* So for the later case, adjust forward to compensate for what
|
|
||||||
* will be done later by cpu_restore_state_from_tb.
|
|
||||||
*/
|
|
||||||
if (helper_retaddr) {
|
|
||||||
pc = helper_retaddr;
|
pc = helper_retaddr;
|
||||||
} else {
|
break;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
/*
|
||||||
|
* Fault during host memory operation within generated code.
|
||||||
|
* (Or, a unrelated bug within qemu, but we can't tell from here).
|
||||||
|
*
|
||||||
|
* We take the host pc from the signal frame. However, we cannot
|
||||||
|
* use that value directly. Within cpu_restore_state_from_tb, we
|
||||||
|
* assume PC comes from GETPC(), as used by the helper functions,
|
||||||
|
* so we adjust the address by -GETPC_ADJ to form an address that
|
||||||
|
* is within the call insn, so that the address does not accidentially
|
||||||
|
* match the beginning of the next guest insn. However, when the
|
||||||
|
* pc comes from the signal frame it points to the actual faulting
|
||||||
|
* host memory insn and not the return from a call insn.
|
||||||
|
*
|
||||||
|
* Therefore, adjust to compensate for what will be done later
|
||||||
|
* by cpu_restore_state_from_tb.
|
||||||
|
*/
|
||||||
pc += GETPC_ADJ;
|
pc += GETPC_ADJ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
/*
|
||||||
|
* Fault during host read for translation, or loosely, "execution".
|
||||||
|
*
|
||||||
|
* The guest pc is already pointing to the start of the TB for which
|
||||||
|
* code is being generated. If the guest translator manages the
|
||||||
|
* page crossings correctly, this is exactly the correct address
|
||||||
|
* (and if the translator doesn't handle page boundaries correctly
|
||||||
|
* there's little we can do about that here). Therefore, do not
|
||||||
|
* trigger the unwinder.
|
||||||
|
*
|
||||||
|
* Like tb_gen_code, release the memory lock before cpu_loop_exit.
|
||||||
|
*/
|
||||||
|
pc = 0;
|
||||||
|
access_type = MMU_INST_FETCH;
|
||||||
|
mmap_unlock();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For synchronous signals we expect to be coming from the vCPU
|
/* For synchronous signals we expect to be coming from the vCPU
|
||||||
|
@ -155,7 +184,6 @@ static inline int handle_cpu_signal(uintptr_t pc, siginfo_t *info,
|
||||||
clear_helper_retaddr();
|
clear_helper_retaddr();
|
||||||
|
|
||||||
cc = CPU_GET_CLASS(cpu);
|
cc = CPU_GET_CLASS(cpu);
|
||||||
access_type = is_write ? MMU_DATA_STORE : MMU_DATA_LOAD;
|
|
||||||
cc->tlb_fill(cpu, address, 0, access_type, MMU_USER_IDX, false, pc);
|
cc->tlb_fill(cpu, address, 0, access_type, MMU_USER_IDX, false, pc);
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,12 +64,18 @@
|
||||||
static inline RES_TYPE
|
static inline RES_TYPE
|
||||||
glue(glue(cpu_ld, USUFFIX), MEMSUFFIX)(CPUArchState *env, abi_ptr ptr)
|
glue(glue(cpu_ld, USUFFIX), MEMSUFFIX)(CPUArchState *env, abi_ptr ptr)
|
||||||
{
|
{
|
||||||
#if !defined(CODE_ACCESS)
|
#ifdef CODE_ACCESS
|
||||||
|
RES_TYPE ret;
|
||||||
|
set_helper_retaddr(1);
|
||||||
|
ret = glue(glue(ld, USUFFIX), _p)(g2h(ptr));
|
||||||
|
clear_helper_retaddr();
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
trace_guest_mem_before_exec(
|
trace_guest_mem_before_exec(
|
||||||
env_cpu(env), ptr,
|
env_cpu(env), ptr,
|
||||||
trace_mem_build_info(SHIFT, false, MO_TE, false));
|
trace_mem_build_info(SHIFT, false, MO_TE, false));
|
||||||
#endif
|
|
||||||
return glue(glue(ld, USUFFIX), _p)(g2h(ptr));
|
return glue(glue(ld, USUFFIX), _p)(g2h(ptr));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CODE_ACCESS
|
#ifndef CODE_ACCESS
|
||||||
|
@ -90,12 +96,18 @@ glue(glue(glue(cpu_ld, USUFFIX), MEMSUFFIX), _ra)(CPUArchState *env,
|
||||||
static inline int
|
static inline int
|
||||||
glue(glue(cpu_lds, SUFFIX), MEMSUFFIX)(CPUArchState *env, abi_ptr ptr)
|
glue(glue(cpu_lds, SUFFIX), MEMSUFFIX)(CPUArchState *env, abi_ptr ptr)
|
||||||
{
|
{
|
||||||
#if !defined(CODE_ACCESS)
|
#ifdef CODE_ACCESS
|
||||||
|
int ret;
|
||||||
|
set_helper_retaddr(1);
|
||||||
|
ret = glue(glue(lds, SUFFIX), _p)(g2h(ptr));
|
||||||
|
clear_helper_retaddr();
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
trace_guest_mem_before_exec(
|
trace_guest_mem_before_exec(
|
||||||
env_cpu(env), ptr,
|
env_cpu(env), ptr,
|
||||||
trace_mem_build_info(SHIFT, true, MO_TE, false));
|
trace_mem_build_info(SHIFT, true, MO_TE, false));
|
||||||
#endif
|
|
||||||
return glue(glue(lds, SUFFIX), _p)(g2h(ptr));
|
return glue(glue(lds, SUFFIX), _p)(g2h(ptr));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CODE_ACCESS
|
#ifndef CODE_ACCESS
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue