arch/riscv: Fix unaligned memory access emulation

Change-Id: I06c6493355f25f3780f75e345c517b434912696f
Signed-off-by: Jonathan Neuschäfer <j.neuschaefer@gmx.net>
Reviewed-on: https://review.coreboot.org/16261
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
This commit is contained in:
Jonathan Neuschäfer 2016-08-22 19:37:15 +02:00 committed by Ronald G. Minnich
parent 85b1aadcc1
commit b6648cd888
1 changed files with 20 additions and 12 deletions

View File

@ -14,10 +14,11 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <console/console.h>
#include <arch/exception.h> #include <arch/exception.h>
#include <console/console.h>
#include <spike_util.h> #include <spike_util.h>
#include <string.h> #include <string.h>
#include <vm.h>
#define HART_ID 0 #define HART_ID 0
#define CONSOLE_PUT 1 #define CONSOLE_PUT 1
@ -171,14 +172,16 @@ void trap_handler(trapframe *tf) {
die("Can't recover from trap. Halting.\n"); die("Can't recover from trap. Halting.\n");
} }
static uint32_t fetch_instruction(uintptr_t vaddr) {
printk(BIOS_SPEW, "fetching instruction at 0x%016zx\n", (size_t)vaddr);
return mprv_read_u32((uint32_t *) vaddr);
}
void handle_misaligned_load(trapframe *tf) { void handle_misaligned_load(trapframe *tf) {
printk(BIOS_DEBUG, "Trapframe ptr: %p\n", tf); printk(BIOS_DEBUG, "Trapframe ptr: %p\n", tf);
printk(BIOS_DEBUG, "Stored sp: %p\n", (void*) tf->gpr[2]); printk(BIOS_DEBUG, "Stored sp: %p\n", (void*) tf->gpr[2]);
insn_t faultingInstruction = 0;
uintptr_t faultingInstructionAddr = tf->epc; uintptr_t faultingInstructionAddr = tf->epc;
asm("move t0, %0" : /* No outputs */ : "r"(faultingInstructionAddr)); insn_t faultingInstruction = fetch_instruction(faultingInstructionAddr);
asm("lw t0, 0(t0)");
asm("move %0, t0" : "=r"(faultingInstruction));
printk(BIOS_DEBUG, "Faulting instruction: 0x%x\n", faultingInstruction); printk(BIOS_DEBUG, "Faulting instruction: 0x%x\n", faultingInstruction);
insn_t widthMask = 0x7000; insn_t widthMask = 0x7000;
insn_t memWidth = (faultingInstruction & widthMask) >> 12; insn_t memWidth = (faultingInstruction & widthMask) >> 12;
@ -188,7 +191,12 @@ void handle_misaligned_load(trapframe *tf) {
if (memWidth == 3) { if (memWidth == 3) {
// load double, handle the issue // load double, handle the issue
void* badAddress = (void*) tf->badvaddr; void* badAddress = (void*) tf->badvaddr;
memcpy(&(tf->gpr[destRegister]), badAddress, 8); uint64_t value = 0;
for (int i = 0; i < 8; i++) {
value <<= 8;
value += mprv_read_u8(badAddress+i);
}
tf->gpr[destRegister] = value;
} else { } else {
// panic, this should not have happened // panic, this should not have happened
printk(BIOS_DEBUG, "Code should not reach this path, misaligned on a non-64 bit store/load\n"); printk(BIOS_DEBUG, "Code should not reach this path, misaligned on a non-64 bit store/load\n");
@ -203,11 +211,8 @@ void handle_misaligned_load(trapframe *tf) {
void handle_misaligned_store(trapframe *tf) { void handle_misaligned_store(trapframe *tf) {
printk(BIOS_DEBUG, "Trapframe ptr: %p\n", tf); printk(BIOS_DEBUG, "Trapframe ptr: %p\n", tf);
printk(BIOS_DEBUG, "Stored sp: %p\n", (void*) tf->gpr[2]); printk(BIOS_DEBUG, "Stored sp: %p\n", (void*) tf->gpr[2]);
insn_t faultingInstruction = 0;
uintptr_t faultingInstructionAddr = tf->epc; uintptr_t faultingInstructionAddr = tf->epc;
asm("move t0, %0" : /* No outputs */ : "r"(faultingInstructionAddr)); insn_t faultingInstruction = fetch_instruction(faultingInstructionAddr);
asm("lw t0, 0(t0)");
asm("move %0, t0" : "=r"(faultingInstruction));
printk(BIOS_DEBUG, "Faulting instruction: 0x%x\n", faultingInstruction); printk(BIOS_DEBUG, "Faulting instruction: 0x%x\n", faultingInstruction);
insn_t widthMask = 0x7000; insn_t widthMask = 0x7000;
insn_t memWidth = (faultingInstruction & widthMask) >> 12; insn_t memWidth = (faultingInstruction & widthMask) >> 12;
@ -217,8 +222,11 @@ void handle_misaligned_store(trapframe *tf) {
if (memWidth == 3) { if (memWidth == 3) {
// store double, handle the issue // store double, handle the issue
void* badAddress = (void*) tf->badvaddr; void* badAddress = (void*) tf->badvaddr;
long valueToStore = tf->gpr[srcRegister]; uint64_t value = tf->gpr[srcRegister];
memcpy(badAddress, &valueToStore, 8); for (int i = 0; i < 8; i++) {
mprv_write_u8(badAddress+i, value);
value >>= 8;
}
} else { } else {
// panic, this should not have happened // panic, this should not have happened
printk(BIOS_DEBUG, "Code should not reach this path, misaligned on a non-64 bit store/load\n"); printk(BIOS_DEBUG, "Code should not reach this path, misaligned on a non-64 bit store/load\n");