Writing `mseccfg`=0x1 will jump to `_vectors_start`
Observed Behavior
When write 0x01 to mseccfg(0x747), some unknown behavior happened: ibex jump to _vectors_start. I have tested some values, when we write 0x4 or 0x8, ibex is normal, any other value will jump to _vectors_start. See trace file for more information.
Expected Behavior
Ibex has supported Smepmp extension at PMP Enhancements. I have checked this extension, all mseccfg field, including mseccfg.MML and mseccfg.MMWP are WARL.
Steps to reproduce the issue
#include "simple_system_common.h"
int main(void){
asm volatile("li t0, 0x1");
asm volatile("csrw 0x747, t0");
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");
asm volatile("csrr a0, 0x747");
return 0;
}
Build this test code like "hello_test.c", run build/lowrisc_ibex_ibex_simple_system_0/sim-verilator/Vibex_simple_system --meminit=ram,./PATH/TO/test.elf -c 300
My Environment
- build ibex:
fusesoc --cores-root=. run --target=sim --setup --build \ lowrisc:ibex:ibex_simple_system $(util/ibex_config.py opentitan fusesoc_opts)
EDA tool and version: Verilator 4.210 2021-07-07 rev v4.210
Operating system:
Ubuntu Linux 18.04
Version of the Ibex source code:
- ibex version: 8f4c75c5e
I learned how to view waveform diagrams and discovered that when pc=0x1003cc, an exception occurred, and the program jumped to pc=0x100000, which is the location of _vectors_start.
According to the disassembly information, a write operation to the mseccfg register occurred at pc=0x1003cc, which triggered an exception. This exception violated the rules of the Smepmp extension because "All mseccfg fields defined in this proposal are WARL."
0x1 switches on MML which alters the interpretation of PMPs, maybe you haven't configured PMPs properly so now the instruction memory is unaccessible?
Hi @nbdd0121, thanks for your reply.
Actually, the test case shown in the picture above is a part of another test case. When I set PMP correctly, I want to change msecfg.MML to 0x1, a trap occurred and the mcause is zero. I have tested other values, such 0b110, 0b10, etc. All failed. I think the root cause is mseccfg is not writable in ibex.
Here is the full test code, you can comment csrw 0x747, a0 to test before/after setting pmpcfg.
.section .text
.global mseccfg_test
mseccfg_test:
# Load the address of test_data
la t1, lower_bound # t1 = address of lower_bound
la t2, upper_bound # t2 = address of upper_bound
srli t1, t1, 2 # t1 = lower_bound >> 2
srli t2, t2, 2 # t2 = upper_bound >> 2
csrw pmpaddr0, t1 # Set pmpaddr0 = lower bound
csrw pmpaddr1, t2 # Set pmpaddr1 = upper bound
csrr t0, 0x747 # mseccfg = 0x747
# Test mseccfg before setting pmpcfg0
li a0, 0x01
csrw 0x747, a0
# Configure pmpcfg0 --> pmp1cfg.L = 1, pmp1cfg.A = 1 (TOR mode)
li t3, 0x8800
csrw pmpcfg0, t3
# Test mseccfg after setting pmpcfg0
li a0, 0x01
csrw 0x747, a0
li a0, 0x10
ret
.section .data
lower_bound:
.word 0x12345678
.word 0x00000000
upper_bound:
.word 0x00000000
I think you also need to setup PMP to cover executable code.
Well, you can try this test code:
.section .text
.global mseccfg_test
mseccfg_test:
li t1, 0x00100000 # ram ORIGIN = 0x00100000
li t2, 0x00140000 # stack = 0x00130000
csrw pmpaddr0, t1
csrw pmpaddr1, t2
# Test mseccfg before setting pmpcfg0
li a0, 0x01
csrw 0x747, a0
li t3, 0x8800
csrw pmpcfg0, t3
# Test mseccfg after setting pmpcfg0
li a0, 0x01
csrw 0x747, a0
li a0, 0x10
ret
.section .data
lower_bound:
.word 0x12345678
.word 0x00000000
upper_bound:
.word 0x00000000
Trace file, test.elf, test.dis and sim.fst in test.zip
If you still think there's something to be done, please provide me with the test case that you believe is correct. Thanks.