Browse Source

Fix emulation of misaligned access on big endian target (#224)

pull/228/head
Marcus Comstedt 5 years ago
committed by GitHub
parent
commit
1f2e2b3b8d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 14
      machine/misaligned_ldst.c
  2. 21
      machine/unprivileged_memory.h

14
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);
}

21
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

Loading…
Cancel
Save