From ae91cdabf60b97d3205de3aa55954dd4f5903845 Mon Sep 17 00:00:00 2001 From: Jonathan Neuschäfer Date: Fri, 21 Sep 2018 18:57:04 +0200 Subject: arch/riscv: Advance the PC after handling misaligned load/store MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After emulating an instruction in the misaligned load/store handler, we need to increment the program counter by the size of instruction. Otherwise the same instruction is executed (and emulated) again and again. While were at it: Also return early in the unlikely case that the faulting instruction is not 16 or 32 bits long, and be more explicit about the return values of fetch_*bit_instruction. Tested by Philipp Hug, using the linuxcheck payload. Fixes: cda59b56ba ("riscv: update misaligned memory access exception handling") Change-Id: Ie2dc0083835809971143cd6ab89fe4f7acd2a845 Signed-off-by: Jonathan Neuschäfer Reviewed-on: https://review.coreboot.org/28617 Tested-by: build bot (Jenkins) Reviewed-by: Philipp Hug Reviewed-by: Ronald G. Minnich --- src/arch/riscv/misaligned.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'src/arch') diff --git a/src/arch/riscv/misaligned.c b/src/arch/riscv/misaligned.c index cb045b8323..ba96102839 100644 --- a/src/arch/riscv/misaligned.c +++ b/src/arch/riscv/misaligned.c @@ -146,17 +146,18 @@ static struct memory_instruction_info *match_instruction(uintptr_t insn) } -static int fetch_16bit_instruction(uintptr_t vaddr, uintptr_t *insn) +static int 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 0; } return -1; } -static int fetch_32bit_instruction(uintptr_t vaddr, uintptr_t *insn) +static int 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 + 2); @@ -164,6 +165,7 @@ static int fetch_32bit_instruction(uintptr_t vaddr, uintptr_t *insn) if ((EXTRACT_FIELD(ins, 0x3) == 3) && (EXTRACT_FIELD(ins, 0x1c) != 0x7)) { *insn = ins; + *size = 4; return 0; } return -1; @@ -174,11 +176,15 @@ void handle_misaligned(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)) - if (fetch_32bit_instruction(tf->epc, &insn)) + 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); @@ -264,4 +270,7 @@ void handle_misaligned(trapframe *tf) mprv_write_u8(addr, buff.b[i]); } } + + /* return to where we came from */ + write_csr(mepc, read_csr(mepc) + insn_size); } -- cgit v1.2.3