Fix bad mepc reported after branching to a branch in a no-X address range

This commit is contained in:
Luke Wren 2022-05-27 22:47:04 +01:00
parent cd3125b6e5
commit f2876eb51f
2 changed files with 35 additions and 3 deletions

View File

@ -712,13 +712,13 @@ end
endgenerate
// Be careful not to take branches whose comparisons depend on a load result
wire x_jump_req_if_aligned = !x_stall_on_raw && (
wire x_jump_req_unchecked = !x_stall_on_raw && (
d_branchcond == BCOND_ALWAYS ||
d_branchcond == BCOND_ZERO && !x_branch_cmp ||
d_branchcond == BCOND_NZERO && x_branch_cmp
);
assign x_jump_req = x_jump_req_if_aligned && !x_jump_misaligned;
assign x_jump_req = x_jump_req_unchecked && !x_jump_misaligned && !x_exec_pmp_fail;
// Memory protection
@ -807,8 +807,8 @@ end
wire [W_ADDR-1:0] m_exception_return_addr;
wire [W_EXCEPT-1:0] x_except =
x_jump_req_if_aligned && x_jump_misaligned ? EXCEPT_INSTR_MISALIGN :
x_exec_pmp_fail ? EXCEPT_INSTR_FAULT :
x_jump_req_unchecked && x_jump_misaligned ? EXCEPT_INSTR_MISALIGN :
x_csr_illegal_access ? EXCEPT_INSTR_ILLEGAL :
|EXTENSION_A && x_unaligned_addr && d_memop_is_amo ? EXCEPT_STORE_ALIGN :
|EXTENSION_A && x_amo_phase == 3'h4 && x_unaligned_addr ? EXCEPT_STORE_ALIGN :

View File

@ -6,6 +6,9 @@
// the lowest-numbered matching region. Check that partial region matches
// cause failure no matter the permission, unless there is a lower-numbered
// fully matching region.
//
// Check that jumping to a branch in non-X-permitted memory points mepc at the
// branch, not its target (known corner case)
/*EXPECTED-OUTPUT***************************************************************
@ -27,6 +30,8 @@ Full match under partial match, negative overhang
mcause = 11
Partial match under full match, negative overhang
mcause = 1
Jump to bad jump
OK
*******************************************************************************/
@ -63,6 +68,26 @@ void __attribute__((aligned(4), naked)) do_nops() {
);
}
void __attribute__((naked)) do_jump() {
asm (
"j 1f\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"nop\n"
"1:\n"
"ret\n"
);
}
#define MCAUSE_INSTR_FAULT 1
#define MCAUSE_ECALL 11
@ -175,5 +200,12 @@ int main() {
tb_assert(read_csr(mcause) == MCAUSE_INSTR_FAULT, "Should get instruction fault on partial match\n");
tb_assert(read_csr(mepc) == (uint32_t)&do_nops + 2, "Bad mepc\n");
tb_puts("Jump to bad jump\n");
write_pmpcfg(0, 0);
write_pmpcfg(1, 0);
enter_umode(&do_jump);
tb_assert(read_csr(mepc) == (uint32_t)&do_jump, "Bad mepc\n");
tb_puts("OK\n");
return 0;
}