lib: Handle traps when doing unpriv load/store in get_insn()

We can get a page/access trap when doing unpriv load/store in
get_insn() function because on a SMP system Linux swapper running
on HART A can unmap pages from page table used by HART B.

To tackle this we extend get_insn() implementation so that if
we get trap in get_insn() then we redirect it to S-mode as fetch
page/access fault.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
This commit is contained in:
Anup Patel
2019-08-12 11:50:22 +05:30
parent 2e0f3ac758
commit a88e424f6c
4 changed files with 65 additions and 46 deletions

View File

@@ -27,10 +27,14 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
{
union reg_data val;
struct unpriv_trap uptrap;
ulong insn = get_insn(regs->mepc, NULL);
ulong insn = get_insn(regs->mepc, scratch, &uptrap);
ulong addr = csr_read(CSR_MTVAL);
int i, fp = 0, shift = 0, len = 0;
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
if ((insn & INSN_MASK_LW) == INSN_MATCH_LW) {
len = 4;
shift = 8 * (sizeof(ulong) - len);
@@ -100,11 +104,9 @@ int sbi_misaligned_load_handler(u32 hartid, ulong mcause,
for (i = 0; i < len; i++) {
val.data_bytes[i] = load_u8((void *)(addr + i),
scratch, &uptrap);
if (uptrap.cause) {
sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
return 0;
}
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
}
if (!fp)
@@ -127,10 +129,14 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
{
union reg_data val;
struct unpriv_trap uptrap;
ulong insn = get_insn(regs->mepc, NULL);
ulong insn = get_insn(regs->mepc, scratch, &uptrap);
ulong addr = csr_read(CSR_MTVAL);
int i, len = 0;
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
val.data_ulong = GET_RS2(insn, regs);
if ((insn & INSN_MASK_SW) == INSN_MATCH_SW) {
@@ -190,11 +196,9 @@ int sbi_misaligned_store_handler(u32 hartid, ulong mcause,
for (i = 0; i < len; i++) {
store_u8((void *)(addr + i), val.data_bytes[i],
scratch, &uptrap);
if (uptrap.cause) {
sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
return 0;
}
if (uptrap.cause)
return sbi_trap_redirect(regs, scratch, regs->mepc,
uptrap.cause, uptrap.tval);
}
regs->mepc += INSN_LEN(insn);