diff options
Diffstat (limited to 'src/arch')
-rw-r--r-- | src/arch/riscv/Makefile.mk | 1 | ||||
-rw-r--r-- | src/arch/riscv/include/arch/exception.h | 1 | ||||
-rw-r--r-- | src/arch/riscv/misaligned.c | 260 | ||||
-rw-r--r-- | src/arch/riscv/trap_handler.c | 3 | ||||
-rw-r--r-- | src/arch/riscv/virtual_memory.c | 4 |
5 files changed, 4 insertions, 265 deletions
diff --git a/src/arch/riscv/Makefile.mk b/src/arch/riscv/Makefile.mk index 1131bd5e3d..d5defea0e7 100644 --- a/src/arch/riscv/Makefile.mk +++ b/src/arch/riscv/Makefile.mk @@ -52,7 +52,6 @@ COMPILER_RT_ramstage = $(shell $(GCC_ramstage) $(simple_riscv_flags) -print-li all-y += trap_util.S all-y += trap_handler.c all-y += fp_asm.S -all-y += misaligned.c all-y += sbi.c all-y += mcall.c all-y += virtual_memory.c diff --git a/src/arch/riscv/include/arch/exception.h b/src/arch/riscv/include/arch/exception.h index e807a3f3c8..2eb575e608 100644 --- a/src/arch/riscv/include/arch/exception.h +++ b/src/arch/riscv/include/arch/exception.h @@ -28,6 +28,5 @@ static inline void exception_init(void) void redirect_trap(void); void default_trap_handler(struct trapframe *tf); void handle_supervisor_call(struct trapframe *tf); -void handle_misaligned(struct trapframe *tf); #endif diff --git a/src/arch/riscv/misaligned.c b/src/arch/riscv/misaligned.c deleted file mode 100644 index 151ed9962a..0000000000 --- a/src/arch/riscv/misaligned.c +++ /dev/null @@ -1,260 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ - -#include <vm.h> -#include <arch/exception.h> -#include <commonlib/helpers.h> -#include <types.h> - -/* these functions are defined in src/arch/riscv/fp_asm.S */ -#if defined(__riscv_flen) -#if __riscv_flen >= 32 -extern void read_f32(int regnum, uint32_t *v); -extern void write_f32(int regnum, uint32_t *v); -#endif // __riscv_flen >= 32 -#if __riscv_flen >= 64 -extern void read_f64(int regnum, uint64_t *v); -extern void write_f64(int regnum, uint64_t *v); -#endif // __riscv_flen >= 64 -#endif // defined(__riscv_flen) - -/* This union makes it easy to read multibyte types by byte operations. */ -union endian_buf { - uint8_t b[8]; - uint16_t h[4]; - uint32_t w[2]; - uint64_t d[1]; - uintptr_t v; -}; - -/* This struct hold info of load/store instruction */ -struct memory_instruction_info { - /* opcode/mask used to identify instruction, - * (instruction_val) & mask == opcode */ - uint32_t opcode; - uint32_t mask; - /* reg_shift/reg_mask/reg_addition used to get register number - * ((instruction_val >> reg_shift) & reg_mask) + reg_addition */ - unsigned int reg_shift; - unsigned int reg_mask; - unsigned int reg_addition; - unsigned int is_fp : 1; /* mark as a float operation */ - unsigned int is_load : 1; /* mark as a load operation */ - unsigned int width : 8; /* Record the memory width of the operation */ - unsigned int sign_extend : 1; /* mark need to be sign extended */ -}; - -static struct memory_instruction_info insn_info[] = { -#if __riscv_xlen == 128 - { 0x00002000, 0x0000e003, 2, 7, 8, 0, 1, 16, 1}, // C.LQ -#else - { 0x00002000, 0x0000e003, 2, 7, 8, 1, 1, 8, 0}, // C.FLD -#endif - { 0x00004000, 0x0000e003, 2, 7, 8, 0, 1, 4, 1}, // C.LW -#if __riscv_xlen == 32 - { 0x00006000, 0x0000e003, 2, 7, 8, 1, 1, 4, 0}, // C.FLW -#else - { 0x00006000, 0x0000e003, 2, 7, 8, 0, 1, 8, 1}, // C.LD -#endif - -#if __riscv_xlen == 128 - { 0x0000a000, 0x0000e003, 2, 7, 8, 0, 0, 16, 0}, // C.SQ -#else - { 0x0000a000, 0x0000e003, 2, 7, 8, 1, 0, 8, 0}, // C.FSD -#endif - { 0x0000c000, 0x0000e003, 2, 7, 8, 0, 0, 4, 0}, // C.SW -#if __riscv_xlen == 32 - { 0x0000e000, 0x0000e003, 2, 7, 8, 1, 0, 4, 0}, // C.FSW -#else - { 0x0000e000, 0x0000e003, 2, 7, 8, 0, 0, 8, 0}, // C.SD -#endif - -#if __riscv_xlen == 128 - { 0x00002002, 0x0000e003, 7, 15, 0, 0, 1, 16, 1}, // C.LQSP -#else - { 0x00002002, 0x0000e003, 7, 15, 0, 1, 1, 8, 0}, // C.FLDSP -#endif - { 0x00004002, 0x0000e003, 7, 15, 0, 0, 1, 4, 1}, // C.LWSP -#if __riscv_xlen == 32 - { 0x00006002, 0x0000e003, 7, 15, 0, 1, 1, 4, 0}, // C.FLWSP -#else - { 0x00006002, 0x0000e003, 7, 15, 0, 0, 1, 8, 1}, // C.LDSP -#endif - -#if __riscv_xlen == 128 - { 0x0000a002, 0x0000e003, 2, 15, 0, 0, 0, 16, 0}, // C.SQSP -#else - { 0x0000a002, 0x0000e003, 2, 15, 0, 1, 0, 8, 0}, // C.FSDSP -#endif - { 0x0000c002, 0x0000e003, 2, 15, 0, 0, 0, 4, 0}, // C.SWSP -#if __riscv_xlen == 32 - { 0x0000e002, 0x0000e003, 2, 15, 0, 1, 0, 4, 0}, // C.FSWSP -#else - { 0x0000e002, 0x0000e003, 2, 15, 0, 0, 0, 8, 0}, // C.SDSP -#endif - - { 0x00000003, 0x0000707f, 7, 15, 0, 0, 1, 1, 1}, // LB - { 0x00001003, 0x0000707f, 7, 15, 0, 0, 1, 2, 1}, // LH - { 0x00002003, 0x0000707f, 7, 15, 0, 0, 1, 4, 1}, // LW -#if __riscv_xlen > 32 - { 0x00003003, 0x0000707f, 7, 15, 0, 0, 1, 8, 1}, // LD -#endif - { 0x00004003, 0x0000707f, 7, 15, 0, 0, 1, 1, 0}, // LBU - { 0x00005003, 0x0000707f, 7, 15, 0, 0, 1, 2, 0}, // LHU - { 0x00006003, 0x0000707f, 7, 15, 0, 0, 1, 4, 0}, // LWU - - { 0x00000023, 0x0000707f, 20, 15, 0, 0, 0, 1, 0}, // SB - { 0x00001023, 0x0000707f, 20, 15, 0, 0, 0, 2, 0}, // SH - { 0x00002023, 0x0000707f, 20, 15, 0, 0, 0, 4, 0}, // SW -#if __riscv_xlen > 32 - { 0x00003023, 0x0000707f, 20, 15, 0, 0, 0, 8, 0}, // SD -#endif - -#if defined(__riscv_flen) -#if __riscv_flen >= 32 - { 0x00002007, 0x0000707f, 7, 15, 0, 1, 1, 4, 0}, // FLW - { 0x00003007, 0x0000707f, 7, 15, 0, 1, 1, 8, 0}, // FLD -#endif // __riscv_flen >= 32 - -#if __riscv_flen >= 64 - { 0x00002027, 0x0000707f, 20, 15, 0, 1, 0, 4, 0}, // FSW - { 0x00003027, 0x0000707f, 20, 15, 0, 1, 0, 8, 0}, // FSD -#endif // __riscv_flen >= 64 -#endif // defined(__riscv_flen) -}; - -static struct memory_instruction_info *match_instruction(uintptr_t insn) -{ - int i; - for (i = 0; i < ARRAY_SIZE(insn_info); i++) - if ((insn_info[i].mask & insn) == insn_info[i].opcode) - return &(insn_info[i]); - return NULL; -} - -static enum cb_err fetch_16bit_instruction(uintptr_t vaddr, uintptr_t *insn, int *size) -{ - uint16_t ins = mprv_read_mxr_u16((uint16_t *)vaddr); - if (EXTRACT_FIELD(ins, 0x3) != 3) { - *insn = ins; - *size = 2; - return CB_SUCCESS; - } - return CB_ERR; -} - -static enum cb_err fetch_32bit_instruction(uintptr_t vaddr, uintptr_t *insn, int *size) -{ - uint32_t l = (uint32_t)mprv_read_mxr_u16((uint16_t *)vaddr + 0); - uint32_t h = (uint32_t)mprv_read_mxr_u16((uint16_t *)vaddr + 1); - uint32_t ins = (h << 16) | l; - if ((EXTRACT_FIELD(ins, 0x3) == 3) && - (EXTRACT_FIELD(ins, 0x1c) != 0x7)) { - *insn = ins; - *size = 4; - return CB_SUCCESS; - } - return CB_ERR; -} - -void handle_misaligned(struct trapframe *tf) -{ - uintptr_t insn = 0; - union endian_buf buff; - int insn_size = 0; - - /* try to fetch 16/32 bits instruction */ - if (fetch_16bit_instruction(tf->epc, &insn, &insn_size) < 0) { - if (fetch_32bit_instruction(tf->epc, &insn, &insn_size) < 0) { - redirect_trap(); - return; - } - } - - /* matching instruction */ - struct memory_instruction_info *match = match_instruction(insn); - - if (!match) { - redirect_trap(); - return; - } - - int regnum; - regnum = ((insn >> match->reg_shift) & match->reg_mask); - regnum = regnum + match->reg_addition; - buff.v = 0; - if (match->is_load) { - /* load operation */ - - /* reading from memory by bytes prevents misaligned - * memory access */ - for (int i = 0; i < match->width; i++) { - uint8_t *addr = (uint8_t *)(tf->badvaddr + i); - buff.b[i] = mprv_read_u8(addr); - } - - /* sign extend for signed integer loading */ - if (match->sign_extend) - if (buff.v >> (8 * match->width - 1)) - buff.v |= -1 << (8 * match->width); - - /* write to register */ - if (match->is_fp) { - int done = 0; -#if defined(__riscv_flen) -#if __riscv_flen >= 32 - /* single-precision floating-point */ - if (match->width == 4) { - write_f32(regnum, buff.w); - done = 1; - } -#endif // __riscv_flen >= 32 -#if __riscv_flen >= 64 - /* double-precision floating-point */ - if (match->width == 8) { - write_f64(regnum, buff.d); - done = 1; - } -#endif // __riscv_flen >= 64 -#endif // defined(__riscv_flen) - if (!done) - redirect_trap(); - } else { - tf->gpr[regnum] = buff.v; - } - } else { - /* store operation */ - - /* reading from register */ - if (match->is_fp) { - int done = 0; -#if defined(__riscv_flen) -#if __riscv_flen >= 32 - if (match->width == 4) { - read_f32(regnum, buff.w); - done = 1; - } -#endif // __riscv_flen >= 32 -#if __riscv_flen >= 64 - if (match->width == 8) { - read_f64(regnum, buff.d); - done = 1; - } -#endif // __riscv_flen >= 64 -#endif // defined(__riscv_flen) - if (!done) - redirect_trap(); - } else { - buff.v = tf->gpr[regnum]; - } - - /* writing to memory by bytes prevents misaligned - * memory access */ - for (int i = 0; i < match->width; i++) { - uint8_t *addr = (uint8_t *)(tf->badvaddr + i); - mprv_write_u8(addr, buff.b[i]); - } - } - - /* return to where we came from */ - write_csr(mepc, read_csr(mepc) + insn_size); -} diff --git a/src/arch/riscv/trap_handler.c b/src/arch/riscv/trap_handler.c index f3968bb0a6..2f22ce29e5 100644 --- a/src/arch/riscv/trap_handler.c +++ b/src/arch/riscv/trap_handler.c @@ -119,7 +119,6 @@ void default_trap_handler(struct trapframe *tf) } switch (tf->cause) { - case CAUSE_MISALIGNED_FETCH: case CAUSE_FETCH_ACCESS: case CAUSE_ILLEGAL_INSTRUCTION: case CAUSE_BREAKPOINT: @@ -133,10 +132,10 @@ void default_trap_handler(struct trapframe *tf) case CAUSE_SUPERVISOR_ECALL: handle_sbi(tf); return; + case CAUSE_MISALIGNED_FETCH: case CAUSE_MISALIGNED_LOAD: case CAUSE_MISALIGNED_STORE: print_trap_information(tf); - handle_misaligned(tf); return; default: printk(BIOS_EMERG, "================================\n"); diff --git a/src/arch/riscv/virtual_memory.c b/src/arch/riscv/virtual_memory.c index 43e3d70304..ed2127c152 100644 --- a/src/arch/riscv/virtual_memory.c +++ b/src/arch/riscv/virtual_memory.c @@ -13,8 +13,10 @@ * to M-mode). In practice, this variable has been a lifesaver. It is * still not quite determined which delegation might by unallowed by * the spec so for now we enumerate and set them all. */ -static int delegate = 0 +static u32 delegate = 0 | (1 << CAUSE_MISALIGNED_FETCH) + | (1 << CAUSE_MISALIGNED_STORE) + | (1 << CAUSE_MISALIGNED_LOAD) | (1 << CAUSE_FETCH_ACCESS) | (1 << CAUSE_ILLEGAL_INSTRUCTION) | (1 << CAUSE_BREAKPOINT) |