From 1f2e2b3b8dd6866d4e8c0e3937bf355464d31c50 Mon Sep 17 00:00:00 2001 From: Marcus Comstedt Date: Tue, 24 Nov 2020 01:05:59 +0100 Subject: Fix emulation of misaligned access on big endian target (#224) --- machine/misaligned_ldst.c | 14 ++++++++++++-- machine/unprivileged_memory.h | 21 ++++++++++++++++++++- 2 files changed, 32 insertions(+), 3 deletions(-) (limited to 'machine') diff --git a/machine/misaligned_ldst.c b/machine/misaligned_ldst.c index a187d25..707de2a 100644 --- a/machine/misaligned_ldst.c +++ b/machine/misaligned_ldst.c @@ -10,6 +10,7 @@ union byte_array { uint8_t bytes[8]; uintptr_t intx; + uint32_t int32; uint64_t int64; }; @@ -75,11 +76,15 @@ void misaligned_load_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc) val.bytes[i] = load_uint8_t((void *)(addr + i), mepc); if (!fp) +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ SET_RD(insn, regs, (intptr_t)val.intx << shift >> shift); +#else + SET_RD(insn, regs, (intptr_t)val.intx >> shift); +#endif else if (len == 8) SET_F64_RD(insn, regs, val.int64); else - SET_F32_RD(insn, regs, val.intx); + SET_F32_RD(insn, regs, val.int32); write_csr(mepc, npc); } @@ -138,8 +143,13 @@ void misaligned_store_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc) } uintptr_t addr = read_csr(mbadaddr); +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + intptr_t offs = (len == 8? 0 : sizeof(val.intx) - len); +#else + intptr_t offs = 0; +#endif for (int i = 0; i < len; i++) - store_uint8_t((void *)(addr + i), val.bytes[i], mepc); + store_uint8_t((void *)(addr + i), val.bytes[offs + i], mepc); write_csr(mepc, npc); } diff --git a/machine/unprivileged_memory.h b/machine/unprivileged_memory.h index fb70baa..b54c601 100644 --- a/machine/unprivileged_memory.h +++ b/machine/unprivileged_memory.h @@ -79,22 +79,37 @@ static uintptr_t __attribute__((always_inline)) get_insn(uintptr_t mepc, uintptr : [mstatus] "+&r" (__mstatus), [insn] "=&r" (val) : [mprv] "r" (__mstatus_adjust), [addr] "r" (__mepc)); #else - uintptr_t rvc_mask = 3, tmp; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + uintptr_t rvc_mask = 3 << 24; +#else + uintptr_t rvc_mask = 3; +#endif + uintptr_t tmp; asm ("csrrs %[mstatus], mstatus, %[mprv]\n" "and %[tmp], %[addr], 2\n" "bnez %[tmp], 1f\n" STR(LWU) " %[insn], (%[addr])\n" "and %[tmp], %[insn], %[rvc_mask]\n" "beq %[tmp], %[rvc_mask], 2f\n" +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ "sll %[insn], %[insn], %[xlen_minus_16]\n" "srl %[insn], %[insn], %[xlen_minus_16]\n" +#else + "srl %[insn], %[insn], 16\n" + "sll %[insn], %[insn], 16\n" +#endif "j 2f\n" "1:\n" "lhu %[insn], (%[addr])\n" +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + "sll %[insn], %[insn], 16\n" +#endif "and %[tmp], %[insn], %[rvc_mask]\n" "bne %[tmp], %[rvc_mask], 2f\n" "lhu %[tmp], 2(%[addr])\n" +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ "sll %[tmp], %[tmp], 16\n" +#endif "add %[insn], %[insn], %[tmp]\n" "2: csrw mstatus, %[mstatus]" : [mstatus] "+&r" (__mstatus), [insn] "=&r" (val), [tmp] "=&r" (tmp) @@ -102,7 +117,11 @@ static uintptr_t __attribute__((always_inline)) get_insn(uintptr_t mepc, uintptr [rvc_mask] "r" (rvc_mask), [xlen_minus_16] "i" (__riscv_xlen - 16)); #endif *mstatus = __mstatus; +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return __builtin_bswap32(val); +#else return val; +#endif } #endif -- cgit v1.1