target/riscv: throw debug exception before page fault
In the RISC-V privileged ISA section 3.1.15 table 15, it is determined that a debug exception that is triggered from a load/store has a higher priority than a possible fault that this access might trigger. This is not the case ATM as shown in [1]. Adding a breakpoint in an address that deliberately will fault is causing a load page fault instead of a debug exception. The reason is that we're throwing in the page fault as soon as the fault occurs (end of riscv_cpu_tlb_fill(), raise_mmu_exception()), not allowing the installed watchpoints to trigger. Call cpu_check_watchpoint() in the page fault path to search and execute any watchpoints that might exist for the address, never returning back to the fault path. If no watchpoints are found cpu_check_watchpoint() will return and we'll fall-through the regular path to raise_mmu_exception(). [1] https://gitlab.com/qemu-project/qemu/-/issues/2627 Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2627 Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-ID: <20250121170626.1992570-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
parent
3fba76e61c
commit
c86edc5476
@ -27,6 +27,7 @@
|
|||||||
#include "exec/page-protection.h"
|
#include "exec/page-protection.h"
|
||||||
#include "instmap.h"
|
#include "instmap.h"
|
||||||
#include "tcg/tcg-op.h"
|
#include "tcg/tcg-op.h"
|
||||||
|
#include "hw/core/tcg-cpu-ops.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
#include "semihosting/common-semi.h"
|
#include "semihosting/common-semi.h"
|
||||||
#include "system/cpu-timers.h"
|
#include "system/cpu-timers.h"
|
||||||
@ -1697,6 +1698,23 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
|||||||
} else if (probe) {
|
} else if (probe) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
int wp_access = 0;
|
||||||
|
|
||||||
|
if (access_type == MMU_DATA_LOAD) {
|
||||||
|
wp_access |= BP_MEM_READ;
|
||||||
|
} else if (access_type == MMU_DATA_STORE) {
|
||||||
|
wp_access |= BP_MEM_WRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If a watchpoint isn't found for 'addr' this will
|
||||||
|
* be a no-op and we'll resume the mmu_exception path.
|
||||||
|
* Otherwise we'll throw a debug exception and execution
|
||||||
|
* will continue elsewhere.
|
||||||
|
*/
|
||||||
|
cpu_check_watchpoint(cs, address, size, MEMTXATTRS_UNSPECIFIED,
|
||||||
|
wp_access, retaddr);
|
||||||
|
|
||||||
raise_mmu_exception(env, address, access_type, pmp_violation,
|
raise_mmu_exception(env, address, access_type, pmp_violation,
|
||||||
first_stage_error, two_stage_lookup,
|
first_stage_error, two_stage_lookup,
|
||||||
two_stage_indirect_error);
|
two_stage_indirect_error);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user