Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions qemu/accel/tcg/cpu-exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -391,8 +391,8 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret)
env->active_tc.PC = uc->next_pc;
#endif
#if defined(TARGET_RISCV)
CPURISCVState *env = &(RISCV_CPU(uc->cpu)->env);
env->pc += 4;
riscv_cpu_prepare_exception_pc(&(RISCV_CPU(uc->cpu)->env),
cpu->exception_index);
#endif
#if defined(TARGET_SPARC)
CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env);
Expand Down
1 change: 1 addition & 0 deletions qemu/riscv32.h
Original file line number Diff line number Diff line change
Expand Up @@ -1311,6 +1311,7 @@
#define riscv_cpu_do_unaligned_access riscv_cpu_do_unaligned_access_riscv32
#define riscv_cpu_tlb_fill riscv_cpu_tlb_fill_riscv32
#define riscv_cpu_do_interrupt riscv_cpu_do_interrupt_riscv32
#define riscv_cpu_prepare_exception_pc riscv_cpu_prepare_exception_pc_riscv32
#define riscv_get_csr_ops riscv_get_csr_ops_riscv32
#define riscv_set_csr_ops riscv_set_csr_ops_riscv32
#define riscv_csrrw riscv_csrrw_riscv32
Expand Down
1 change: 1 addition & 0 deletions qemu/riscv64.h
Original file line number Diff line number Diff line change
Expand Up @@ -1311,6 +1311,7 @@
#define riscv_cpu_do_unaligned_access riscv_cpu_do_unaligned_access_riscv64
#define riscv_cpu_tlb_fill riscv_cpu_tlb_fill_riscv64
#define riscv_cpu_do_interrupt riscv_cpu_do_interrupt_riscv64
#define riscv_cpu_prepare_exception_pc riscv_cpu_prepare_exception_pc_riscv64
#define riscv_get_csr_ops riscv_get_csr_ops_riscv64
#define riscv_set_csr_ops riscv_set_csr_ops_riscv64
#define riscv_csrrw riscv_csrrw_riscv64
Expand Down
1 change: 1 addition & 0 deletions qemu/target/riscv/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable);
bool riscv_cpu_force_hs_excep_enabled(CPURISCVState *env);
void riscv_cpu_set_force_hs_excep(CPURISCVState *env, bool enable);
int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch);
void riscv_cpu_prepare_exception_pc(CPURISCVState *env, uint32_t cause);
hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
void riscv_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
MMUAccessType access_type, int mmu_idx,
Expand Down
77 changes: 59 additions & 18 deletions qemu/target/riscv/cpu_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,59 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
return true;
}

/*
* Return true if a synchronous exception carries a faulting address in
* env->badaddr (used as the machine trap value, mbadaddr/mtval).
*/
static bool riscv_cpu_exception_has_badaddr(target_ulong cause)
{
switch (cause) {
case RISCV_EXCP_INST_GUEST_PAGE_FAULT:
case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT:
case RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT:
case RISCV_EXCP_INST_ADDR_MIS:
case RISCV_EXCP_INST_ACCESS_FAULT:
case RISCV_EXCP_LOAD_ADDR_MIS:
case RISCV_EXCP_STORE_AMO_ADDR_MIS:
case RISCV_EXCP_LOAD_ACCESS_FAULT:
case RISCV_EXCP_STORE_AMO_ACCESS_FAULT:
case RISCV_EXCP_INST_PAGE_FAULT:
case RISCV_EXCP_LOAD_PAGE_FAULT:
case RISCV_EXCP_STORE_PAGE_FAULT:
return true;
default:
return false;
}
}

/*
* Unicorn helper: prepare the PC for a UC_HOOK_INTR callback. This mirrors
* the state riscv_cpu_do_interrupt would have set up (mbadaddr from badaddr
* for address-bearing exceptions) and advances the PC past the faulting
* instruction. Instruction fetch faults already hold the faulting address
* in env->pc and are left untouched.
*/
void riscv_cpu_prepare_exception_pc(CPURISCVState *env, uint32_t cause)
{
if (riscv_cpu_exception_has_badaddr(cause)) {
env->mbadaddr = env->badaddr;
}

if (cause == RISCV_EXCP_INST_ADDR_MIS ||
cause == RISCV_EXCP_INST_ACCESS_FAULT ||
cause == RISCV_EXCP_INST_PAGE_FAULT) {
return;
}

/*
* Execution-time exception: advance past the faulting instruction.
* RISC-V instructions are 16 or 32 bits, selected by the two
* least-significant bits of the opcode.
*/
uint16_t op = cpu_lduw_code(env, env->pc);
env->pc += ((op & 0x3) == 0x3) ? 4 : 2;
}

/*
* Handle Traps
*
Expand All @@ -844,25 +897,13 @@ void riscv_cpu_do_interrupt(CPUState *cs)

if (!async) {
/* set tval to badaddr for traps with address information */
switch (cause) {
case RISCV_EXCP_INST_GUEST_PAGE_FAULT:
case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT:
case RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT:
force_hs_execp = true;
/* fallthrough */
case RISCV_EXCP_INST_ADDR_MIS:
case RISCV_EXCP_INST_ACCESS_FAULT:
case RISCV_EXCP_LOAD_ADDR_MIS:
case RISCV_EXCP_STORE_AMO_ADDR_MIS:
case RISCV_EXCP_LOAD_ACCESS_FAULT:
case RISCV_EXCP_STORE_AMO_ACCESS_FAULT:
case RISCV_EXCP_INST_PAGE_FAULT:
case RISCV_EXCP_LOAD_PAGE_FAULT:
case RISCV_EXCP_STORE_PAGE_FAULT:
if (riscv_cpu_exception_has_badaddr(cause)) {
tval = env->badaddr;
break;
default:
break;
}
if (cause == RISCV_EXCP_INST_GUEST_PAGE_FAULT ||
cause == RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT ||
cause == RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT) {
force_hs_execp = true;
}
/* ecall is dispatched as one cause so translate based on mode */
if (cause == RISCV_EXCP_U_ECALL) {
Expand Down