diff options
author | Samuel Holland <samuel@sholland.org> | 2022-05-29 21:25:30 +0300 |
---|---|---|
committer | Anup Patel <anup@brainfault.org> | 2022-06-01 14:50:20 +0300 |
commit | cb8271c8e43e3c317436b7377c4fa0ac669f8fb5 (patch) | |
tree | 7315f93406b3ba854e4d10660f960cdeacc0cc36 | |
parent | ff65bfec4e4fdef31de0871d03f58ca020d6ada2 (diff) | |
download | opensbi-cb8271c8e43e3c317436b7377c4fa0ac669f8fb5.tar.xz |
lib: sbi_illegal_insn: Add emulation for fence.tso
While OpenC906 appears to properly decode `fence.tso` as a fence
instruction[1], the version of the C906 taped out in the Allwinner D1
does not, and raises illegal instruction.
Handle this errata by emulating `fence.tso` as `fence rw, rw`.
[1]: https://github.com/T-head-Semi/openc906/blob/30827e7f/C906_RTL_FACTORY/gen_rtl/idu/rtl/aq_idu_id_decd.v#L2097
Signed-off-by: Samuel Holland <samuel@sholland.org>
Reviewed-by: Anup Patel <anup@brainfault.org>
-rw-r--r-- | include/sbi/riscv_encoding.h | 3 | ||||
-rw-r--r-- | lib/sbi/sbi_illegal_insn.c | 14 |
2 files changed, 16 insertions, 1 deletions
diff --git a/include/sbi/riscv_encoding.h b/include/sbi/riscv_encoding.h index 7cfbace..a164768 100644 --- a/include/sbi/riscv_encoding.h +++ b/include/sbi/riscv_encoding.h @@ -838,6 +838,9 @@ #define INSN_MASK_WFI 0xffffff00 #define INSN_MATCH_WFI 0x10500000 +#define INSN_MASK_FENCE_TSO 0xffffffff +#define INSN_MATCH_FENCE_TSO 0x8330000f + #define INSN_16BIT_MASK 0x3 #define INSN_32BIT_MASK 0x1c diff --git a/lib/sbi/sbi_illegal_insn.c b/lib/sbi/sbi_illegal_insn.c index 386b48a..84c04f8 100644 --- a/lib/sbi/sbi_illegal_insn.c +++ b/lib/sbi/sbi_illegal_insn.c @@ -8,6 +8,7 @@ */ #include <sbi/riscv_asm.h> +#include <sbi/riscv_barrier.h> #include <sbi/riscv_encoding.h> #include <sbi/sbi_bitops.h> #include <sbi/sbi_emulate_csr.h> @@ -33,6 +34,17 @@ static int truly_illegal_insn(ulong insn, struct sbi_trap_regs *regs) return sbi_trap_redirect(regs, &trap); } +static int misc_mem_opcode_insn(ulong insn, struct sbi_trap_regs *regs) +{ + /* Errata workaround: emulate `fence.tso` as `fence rw, rw`. */ + if ((insn & INSN_MASK_FENCE_TSO) == INSN_MATCH_FENCE_TSO) { + smp_mb(); + return 0; + } + + return truly_illegal_insn(insn, regs); +} + static int system_opcode_insn(ulong insn, struct sbi_trap_regs *regs) { int do_write, rs1_num = (insn >> 15) & 0x1f; @@ -92,7 +104,7 @@ static const illegal_insn_func illegal_insn_table[32] = { truly_illegal_insn, /* 0 */ truly_illegal_insn, /* 1 */ truly_illegal_insn, /* 2 */ - truly_illegal_insn, /* 3 */ + misc_mem_opcode_insn, /* 3 */ truly_illegal_insn, /* 4 */ truly_illegal_insn, /* 5 */ truly_illegal_insn, /* 6 */ |