#include "emulation.h" #include "fp_emulation.h" #include "config.h" #include "unprivileged_memory.h" #include "mtrap.h" #include void illegal_insn_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc) { asm (".pushsection .rodata\n" "illegal_insn_trap_table:\n" " .word truly_illegal_insn\n" #if !defined(__riscv_hard_float) && defined(PK_ENABLE_FP_EMULATION) " .word emulate_float_load\n" #else " .word truly_illegal_insn\n" #endif " .word truly_illegal_insn\n" " .word truly_illegal_insn\n" " .word truly_illegal_insn\n" " .word truly_illegal_insn\n" " .word truly_illegal_insn\n" " .word truly_illegal_insn\n" " .word truly_illegal_insn\n" #if !defined(__riscv_hard_float) && defined(PK_ENABLE_FP_EMULATION) " .word emulate_float_store\n" #else " .word truly_illegal_insn\n" #endif " .word truly_illegal_insn\n" " .word truly_illegal_insn\n" #if !defined(__riscv_muldiv) " .word emulate_mul_div\n" #else " .word truly_illegal_insn\n" #endif " .word truly_illegal_insn\n" #if !defined(__riscv_muldiv) && defined(__riscv64) " .word emulate_mul_div32\n" #else " .word truly_illegal_insn\n" #endif " .word truly_illegal_insn\n" #ifdef PK_ENABLE_FP_EMULATION " .word emulate_fmadd\n" " .word emulate_fmadd\n" " .word emulate_fmadd\n" " .word emulate_fmadd\n" " .word emulate_fp\n" #else " .word truly_illegal_insn\n" " .word truly_illegal_insn\n" " .word truly_illegal_insn\n" " .word truly_illegal_insn\n" " .word truly_illegal_insn\n" #endif " .word truly_illegal_insn\n" " .word truly_illegal_insn\n" " .word truly_illegal_insn\n" " .word truly_illegal_insn\n" " .word truly_illegal_insn\n" " .word truly_illegal_insn\n" " .word truly_illegal_insn\n" " .word emulate_system\n" " .word truly_illegal_insn\n" " .word truly_illegal_insn\n" " .word truly_illegal_insn\n" " .popsection"); uintptr_t mstatus; insn_t insn = get_insn(mepc, &mstatus); if (unlikely((insn & 3) != 3)) return truly_illegal_insn(regs, mcause, mepc, mstatus, insn); write_csr(mepc, mepc + 4); extern int32_t illegal_insn_trap_table[]; int32_t* pf = (void*)illegal_insn_trap_table + (insn & 0x7c); emulation_func f = (emulation_func)(uintptr_t)*pf; f(regs, mcause, mepc, mstatus, insn); } void __attribute__((noinline)) truly_illegal_insn(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc, uintptr_t mstatus, insn_t insn) { redirect_trap(mepc, mstatus); } static inline int emulate_read_csr(int num, uintptr_t mstatus, uintptr_t* result) { switch (num) { case CSR_TIME: *result = read_csr(mtime) + HLS()->utime_delta; return 0; case CSR_CYCLE: *result = read_csr(mcycle) + HLS()->ucycle_delta; return 0; case CSR_INSTRET: *result = read_csr(minstret) + HLS()->uinstret_delta; return 0; case CSR_STIME: *result = read_csr(mtime) + HLS()->stime_delta; return 0; case CSR_SCYCLE: *result = read_csr(mcycle) + HLS()->scycle_delta; return 0; case CSR_SINSTRET: *result = read_csr(minstret) + HLS()->sinstret_delta; return 0; #ifdef __riscv32 case CSR_TIMEH: *result = (((uint64_t)read_csr(mtimeh) << 32) + read_csr(mtime) + HLS()->stime_delta) >> 32; return 0; case CSR_CYCLEH: *result = (((uint64_t)read_csr(mcycleh) << 32) + read_csr(mcycle) + HLS()->scycle_delta) >> 32; return 0; case CSR_INSTRETH: *result = (((uint64_t)read_csr(minstreth) << 32) + read_csr(minstret) + HLS()->sinstret_delta) >> 32; return 0; #endif #if !defined(__riscv_hard_float) && defined(PK_ENABLE_FP_EMULATION) case CSR_FRM: if ((mstatus & MSTATUS_FS) == 0) break; *result = GET_FRM(); return 0; case CSR_FFLAGS: if ((mstatus & MSTATUS_FS) == 0) break; *result = GET_FFLAGS(); return 0; case CSR_FCSR: if ((mstatus & MSTATUS_FS) == 0) break; *result = GET_FCSR(); return 0; #endif } return -1; } static inline int emulate_write_csr(int num, uintptr_t value, uintptr_t mstatus) { switch (num) { #if !defined(__riscv_hard_float) && defined(PK_ENABLE_FP_EMULATION) case CSR_FRM: SET_FRM(value); return 0; case CSR_FFLAGS: SET_FFLAGS(value); return 0; case CSR_FCSR: SET_FCSR(value); return 0; #endif } return -1; } DECLARE_EMULATION_FUNC(emulate_system) { int rs1_num = (insn >> 15) & 0x1f; uintptr_t rs1_val = GET_RS1(insn, regs); int csr_num = (uint32_t)insn >> 20; uintptr_t csr_val, new_csr_val; if (emulate_read_csr(csr_num, mstatus, &csr_val)) return truly_illegal_insn(regs, mcause, mepc, mstatus, insn); int do_write = rs1_num; switch (GET_RM(insn)) { case 0: return truly_illegal_insn(regs, mcause, mepc, mstatus, insn); case 1: new_csr_val = rs1_val; do_write = 1; break; case 2: new_csr_val = csr_val | rs1_val; break; case 3: new_csr_val = csr_val & ~rs1_val; break; case 4: return truly_illegal_insn(regs, mcause, mepc, mstatus, insn); case 5: new_csr_val = rs1_num; do_write = 1; break; case 6: new_csr_val = csr_val | rs1_num; break; case 7: new_csr_val = csr_val & ~rs1_num; break; } if (do_write && emulate_write_csr(csr_num, new_csr_val, mstatus)) return truly_illegal_insn(regs, mcause, mepc, mstatus, insn); SET_RD(insn, regs, csr_val); }