riscv-qemu
riscv-qemu copied to clipboard
Don't generate exceptions for CSR access in gdbstub.c
Currently the csr_read_helper
and csr_write_helper
TCG CSR helper function in target/riscv/op_helper.c
are the only way to access CSR and they can generate illegal instruction exceptions. i.e. call longjump. We are calling these in gdbstub.c but we really shouldn't be calling functions with this behaviour as a longjmp called outside of a setjump context has undefined behaviour.
The csr_read_helper and csr_write_helper need to be split into front-end wrappers and back-end access functions, with the back-end functions indicating the presence of a CSR (which can be used both for debug access to CSRs and by the front-end helpers used by TCG). This is required because we can't call helpers that may call longjump from the GDB interface in target/riscv/gdbstub.c
Currently CSR read and write is implemented in the helpers that are called directly by TCG:
-
target_ulong csr_read_helper(CPURISCVState *env, target_ulong csrno)
-
void csr_write_helper(CPURISCVState *env, target_ulong val_to_write, target_ulong csrno)
We need to split the helpers into wrappers and create generic CSR access functions that don't generate exceptions, rather indicate presence via their return code. The helpers will then call the CSR access functions, and generate exceptions based on precense. e.g. a return code of -1 can indicate an illegal access. gdbstub.c can could return -1 or (0xffffffff for RV32 or 0xffffffffffffffff for RV64). In the GDB stub we have no way to indicate whether a CSR register exists as the entire 12-bit range is defined, however we can return -1 as a sentinel. The access functions however can distinguish illegal accesses (return -1) from successful accesses (return 0) for CSRs that are fully present or hardwired to zero.
We could add these two methods, perhaps with interfaces in target/riscv/cpu.h
and implementation in target/riscv/csr.c
-
int riscv_csr_read(CPURISCVState *env, target_ulong *val_to_read, target_ulong csrno)
-
int riscv_csr_write(CPURISCVState *env, target_ulong val_to_write, target_ulong csrno)