Code of Conduct
CVA6 commit affected
81245a4
Bug Description
With vsatp.MODE=Bare and Sv39x4 G-stage translation enabled, a VS-mode instruction fetch at guest physical address 0xC0000000 encounters an invalid G-stage root PTE. The expected exception is an instruction guest-page fault (mcause=20). In the full CVA6 ariane_testharness, a later PMP check can instead make the same fetch report an instruction access fault (mcause=1).
The G-stage table and the faulting fetch are identical in both runs. Only the second PMP entry changes:
- Fault-path address permitted: observed mepc=0xC0000000 and mcause=20 (instruction guest-page fault).
- Fault-path address denied: observed mepc=0xC0000000 and mcause=1 (instruction access fault).
The expected cause is 20 in both runs. The RISC-V H-extension exception-priority table gives an instruction guest-page fault during address translation priority over an instruction access fault associated with the final physical access. A failed G-stage translation has not produced a valid final translated physical address.
To reproduce in the RVH-enabled cv64a6_imafdch_sv39 configuration:
- Place the program at physical address 0x80000000. Place a zero-initialized, 16 KiB-aligned Sv39x4 G-stage root page table at 0x80004000.
- Set the 64-bit root PTE at 0x80004010 (index 2) to 0x00000000200000DF. This is an executable 1 GiB identity-mapping leaf covering the program. Leave the PTE at 0x80004018 (index 3) invalid, so 0xC0000000 has no G-stage mapping.
- Set vsatp.MODE=Bare, hgatp.MODE=8 and hgatp.PPN=0x80004. Execute hfence.gvma after setting the page table, PMP and hgatp. Route the exception to M-mode; do not delegate cause 20 through medeleg. Set mstatus.MPP=S, mstatus.MPV=1 and mepc to the VS-mode entry point, then execute mret.
- Run two program variants that differ only in the PMP setup below. Have the M-mode trap handler read mcause and mepc.
- Fault-path address denied: pmpaddr0=0x20000FFF; PMP entry 1 disabled; pmpcfg0=0x1F.
- Fault-path address permitted: pmpaddr0=0x20000FFF; pmpaddr1=0x1FF; pmpcfg0=0x1F1F.
PMP entry 0 permits the program and page table at physical addresses 0x80000000–0x80007FFF. The control run additionally permits physical addresses 0x00000000–0x00000FFF through entry 1. Both enabled entries use NAPOT addressing and R/W/X permissions.
The relevant program body is below. The test setup supplies the page-table image, PMP values, vsatp and trap-delegation settings, and linker placement described above.
.option norvc
.section .text
.globl _start
_start:
la t0, trap_handler
csrw mtvec, t0
# Configure PMP for one run using the settings above.
li t0, 0x80004
li t1, 8
slli t1, t1, 60
or t0, t0, t1
csrw hgatp, t0
hfence.gvma
la t0, vs_mode
csrw mepc, t0
csrr t1, mstatus
li t2, ~(3 << 11)
and t1, t1, t2
li t2, (1 << 11) | (1 << 39)
or t1, t1, t2
csrw mstatus, t1
mret
vs_mode:
li t0, 0xC0000000
jr t0
trap_handler:
csrr t1, mcause
csrr t0, mepc
1: j 1b
The full-CPU test observed mepc=0xC0000000 and mcause=1 with only PMP entry 0, versus mepc=0xC0000000 and mcause=20 when entry 1 was also enabled.
Issue #3115 raised the broader possibility of an earlier instruction-fetch exception being overwritten in pmp_data_if.sv. This report supplies a paired full-CPU reproducer for the RVH instruction guest-page-fault case. Issue #3337 covers a related data-side priority error; issue #3428 concerns a different G-stage fetch failure.
Vulnerable Code
At the affected commit, core/pmp/src/pmp_data_if.sv preserves an ordinary instruction page fault but does not preserve an instruction guest-page fault:
if (icache_areq_i.fetch_valid) begin
if (icache_areq_o.fetch_exception.cause != riscv::INSTR_PAGE_FAULT) begin
if (!match_any_execute_region || !pmp_if_allow) begin
icache_areq_o.fetch_exception.cause = riscv::INSTR_ACCESS_FAULT;
icache_areq_o.fetch_exception.valid = 1'b1;
end
end
end
The paired results are consistent with a G-stage guest-page fault reaching this block and being overwritten when PMP denies the fault-path address. A trace of the exception before and after this block would confirm that internal sequence directly.
Suggested fix
Preserve a valid INSTR_GUEST_PAGE_FAULT when applying the final instruction PMP/PMA check, alongside the existing handling of INSTR_PAGE_FAULT. Add a full-CPU regression using the same unmapped guest fetch under both PMP configurations and require mcause=20 in each run.
Code of Conduct
CVA6 commit affected
81245a4
Bug Description
With vsatp.MODE=Bare and Sv39x4 G-stage translation enabled, a VS-mode instruction fetch at guest physical address 0xC0000000 encounters an invalid G-stage root PTE. The expected exception is an instruction guest-page fault (mcause=20). In the full CVA6 ariane_testharness, a later PMP check can instead make the same fetch report an instruction access fault (mcause=1).
The G-stage table and the faulting fetch are identical in both runs. Only the second PMP entry changes:
The expected cause is 20 in both runs. The RISC-V H-extension exception-priority table gives an instruction guest-page fault during address translation priority over an instruction access fault associated with the final physical access. A failed G-stage translation has not produced a valid final translated physical address.
To reproduce in the RVH-enabled cv64a6_imafdch_sv39 configuration:
PMP entry 0 permits the program and page table at physical addresses 0x80000000–0x80007FFF. The control run additionally permits physical addresses 0x00000000–0x00000FFF through entry 1. Both enabled entries use NAPOT addressing and R/W/X permissions.
The relevant program body is below. The test setup supplies the page-table image, PMP values, vsatp and trap-delegation settings, and linker placement described above.
The full-CPU test observed mepc=0xC0000000 and mcause=1 with only PMP entry 0, versus mepc=0xC0000000 and mcause=20 when entry 1 was also enabled.
Issue #3115 raised the broader possibility of an earlier instruction-fetch exception being overwritten in pmp_data_if.sv. This report supplies a paired full-CPU reproducer for the RVH instruction guest-page-fault case. Issue #3337 covers a related data-side priority error; issue #3428 concerns a different G-stage fetch failure.
Vulnerable Code
At the affected commit, core/pmp/src/pmp_data_if.sv preserves an ordinary instruction page fault but does not preserve an instruction guest-page fault:
The paired results are consistent with a G-stage guest-page fault reaching this block and being overwritten when PMP denies the fault-path address. A trace of the exception before and after this block would confirm that internal sequence directly.
Suggested fix
Preserve a valid INSTR_GUEST_PAGE_FAULT when applying the final instruction PMP/PMA check, alongside the existing handling of INSTR_PAGE_FAULT. Add a full-CPU regression using the same unmapped guest fetch under both PMP configurations and require mcause=20 in each run.