Hazard3/test/sim/sw_testcases/umode_wfi.c

78 lines
2.0 KiB
C
Raw Normal View History

#include "tb_cxxrtl_io.h"
#include "hazard3_csr.h"
// Check that U-mode execution of a wfi causes an illegal opcode exception if
// and only if the mstatus timeout wait bit is set.
/*EXPECTED-OUTPUT***************************************************************
Do WFI with TW=0:
mcause = 8 // = ecall, meaning normal exit. The test also checks mepc.
Do WFI with TW=1:
mstatus = 00200000 // Check TW write is reflected in readback
mcause = 2 // = illegal instruction. The test also checks mepc.
*******************************************************************************/
// Naked so the address can be checked
void __attribute__((naked)) do_wfi() {
asm (
"wfi\n"
"ret\n"
);;
}
void __attribute__((naked)) do_ecall() {
asm ("ecall");
}
// /!\ Unconventional control flow ahead
// Call function in U mode, from M mode. Catch exception, or break back to M
// mode if the function returned normally (via dummy ecall), and then return.
static inline void umode_call_and_catch(void (*f)(void)) {
clear_csr(mstatus, 0x1800u);
write_csr(mepc, f);
uint32_t mtvec_save = read_csr(mtvec);
asm (
" la ra, 1f\n"
" csrw mtvec, ra\n"
" la ra, do_ecall\n"
" mret\n"
// Note mtvec requires 4-byte alignment.
".p2align 2\n"
"1:\n"
: : : "ra"
);
write_csr(mtvec, mtvec_save);
}
int main() {
// Ensure WFI doesn't block by enabling timer IRQ but leaving IRQs globally disabled.
set_csr(mie, -1u);
// Give U mode RWX permission on all of memory.
write_csr(pmpcfg0, 0x1fu);
write_csr(pmpaddr0, -1u);
tb_puts("Do WFI with TW=0:\n");
umode_call_and_catch(&do_wfi);
tb_printf("mcause = %u\n", read_csr(mcause));
if (read_csr(mepc) != (uint32_t)&do_ecall) {
tb_puts("Non-normal return detected\n");
return -1;
}
tb_puts("Do WFI with TW=1:\n");
set_csr(mstatus, 1u << 21);
tb_printf("mstatus = %08x\n", read_csr(mstatus));
umode_call_and_catch(&do_wfi);
tb_printf("mcause = %u\n", read_csr(mcause));
if (read_csr(mepc) != (uint32_t)&do_wfi) {
tb_puts("mepc doesn't point to wfi\n");
return -1;
}
return 0;
}