diff --git a/include/sbi/riscv_encoding.h b/include/sbi/riscv_encoding.h index e1d0b46..8bcd66a 100644 --- a/include/sbi/riscv_encoding.h +++ b/include/sbi/riscv_encoding.h @@ -625,6 +625,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 9af3d24..fb67c28 100644 --- a/lib/sbi/sbi_illegal_insn.c +++ b/lib/sbi/sbi_illegal_insn.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -31,6 +32,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; @@ -83,7 +95,7 @@ static 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 */