aboutsummaryrefslogtreecommitdiff
path: root/machine
diff options
context:
space:
mode:
authorAndrew Waterman <andrew@sifive.com>2017-10-23 23:38:41 -0700
committerAndrew Waterman <andrew@sifive.com>2017-10-23 23:38:41 -0700
commit18087efa98d77918d55127c3d7745cd6d6d9d77b (patch)
tree8506d286ac435342ccb4b6d8fad88aa08facbebb /machine
parent4c64de3213e7a08e4097970b26a14ad835cabfab (diff)
downloadriscv-pk-18087efa98d77918d55127c3d7745cd6d6d9d77b.zip
riscv-pk-18087efa98d77918d55127c3d7745cd6d6d9d77b.tar.gz
riscv-pk-18087efa98d77918d55127c3d7745cd6d6d9d77b.tar.bz2
Make 4-byte aligned instruction-emulation loads atomic
Per the Unix-class platform spec
Diffstat (limited to 'machine')
-rw-r--r--machine/unprivileged_memory.h15
1 files changed, 12 insertions, 3 deletions
diff --git a/machine/unprivileged_memory.h b/machine/unprivileged_memory.h
index 787f5f8..5cf2727 100644
--- a/machine/unprivileged_memory.h
+++ b/machine/unprivileged_memory.h
@@ -76,16 +76,25 @@ static uintptr_t __attribute__((always_inline)) get_insn(uintptr_t mepc, uintptr
#else
uintptr_t rvc_mask = 3, 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"
+ "sll %[insn], %[insn], %[xlen_minus_16]\n"
+ "srl %[insn], %[insn], %[xlen_minus_16]\n"
+ "j 2f\n"
+ "1:\n"
"lhu %[insn], (%[addr])\n"
"and %[tmp], %[insn], %[rvc_mask]\n"
- "bne %[tmp], %[rvc_mask], 1f\n"
+ "bne %[tmp], %[rvc_mask], 2f\n"
"lhu %[tmp], 2(%[addr])\n"
"sll %[tmp], %[tmp], 16\n"
"add %[insn], %[insn], %[tmp]\n"
- "1: csrw mstatus, %[mstatus]"
+ "2: csrw mstatus, %[mstatus]"
: [mstatus] "+&r" (__mstatus), [insn] "=&r" (val), [tmp] "=&r" (tmp)
: [mprv] "r" (MSTATUS_MPRV | MSTATUS_MXR), [addr] "r" (__mepc),
- [rvc_mask] "r" (rvc_mask));
+ [rvc_mask] "r" (rvc_mask), [xlen_minus_16] "i" (__riscv_xlen - 16));
#endif
*mstatus = __mstatus;
return val;