Skip to content

[Bug] 2KB PMP regions are enforced inconsistently in TOR mode #60

Description

@KnightGOKU

Summary

OpenC910 exposes a 2KB PMP granularity through pmpaddr readback, but a locked 2KB TOR deny region is not enforced. The minimal testcase installs a TOR deny region for [0x60000, 0x60800) and then executes a single lw from 0x60400, which is inside that denied range.

This is different from the previously reported NA4 bypass: this testcase does not use NA4, and it does not rely on a lower-priority NAPOT allow entry.
It only tests whether a 2KB TOR deny region is enforced after PMP CSR readback advertises a 2KB grain.

Expected result:

  • the load from 0x60400 raises mcause = 5 (load access fault)
  • the testcase prints TRAP

Actual result on OpenC910:

  • the load retires successfully
  • the testcase prints BUG

Test Case

The testcase first probes PMP granularity by writing all ones to pmpaddr0 while pmpcfg0=0. OpenC910 reads back low bits indicating a 2KB grain. It then programs:

  • PMP0: TOR lower bound 0x60000
  • PMP1: locked no-access TOR upper bound 0x60800
  • access: lw from 0x60400
.include "openc910_min_common.inc"

.equ TARGET_BASE, 0x60000
.equ TARGET_ADDR, 0x60400
.equ TOR_TOP_2K,  0x60800
.equ TOR_TOP_4K,  0x61000
.equ PMPCFG_TOR_DENY_L_ENTRY1, 0x8800

.text
.align 6
.global main
main:
  la    t0, trap_handler
  csrw  mtvec, t0

  # Probe pmpaddr granularity. Low 10 bits should read as 0x200,
  # which advertises a 2KB PMP grain.
  csrw  pmpcfg0, zero
  li    t0, -1
  csrw  pmpaddr0, t0
  csrr  t1, pmpaddr0
  li    t2, 0x3ff
  and   t1, t1, t2
  li    t2, 0x200
  bne   t1, t2, setup_failed

  # Initialize the target word while PMP is off.
  li    t0, TARGET_ADDR
  li    t1, 0x11223344
  sw    t1, 0(t0)
  fence

  # PMP0 is the TOR lower bound.
  li    t0, TARGET_BASE
  srli  t0, t0, 2
  csrw  pmpaddr0, t0

  # PMP1 is the locked no-access TOR entry.
  li    t0, TOR_TOP_2K
  srli  t0, t0, 2
  csrw  pmpaddr1, t0
  li    t0, PMPCFG_TOR_DENY_L_ENTRY1
  csrw  pmpcfg0, t0
  fence

  # This load is inside [0x60000, 0x60800), so it should trap.
  li    t0, TARGET_ADDR
  lw    t1, 0(t0)

  la    a0, msg_bug
  jal   ra, oracle_puts
1:
  j     1b

trap_handler:
  csrr  t0, mcause
  li    t1, 5
  beq   t0, t1, expected_trap

  la    a0, msg_wrong
  jal   ra, oracle_puts
2:
  j     2b

expected_trap:
  la    a0, msg_trap
  jal   ra, oracle_puts
3:
  j     3b

setup_failed:
  la    a0, msg_setup_failed
  jal   ra, oracle_puts
4:
  j     4b

.section .rodata
msg_bug:
  .asciz "BUG\n"
msg_trap:
  .asciz "TRAP\n"
msg_wrong:
  .asciz "WRONG\n"
msg_setup_failed:
  .asciz "SETUP_FAIL\n"

The attached seed has one optional control switch, REGION_4K_CONTROL=1, which changes only the TOR upper bound from 0x60800 to 0x61000. That control prints TRAP, showing that the trap handler and locked PMP deny path work when the TOR region is widened to 4KB.

How to reproduce

Build OpenC910's native Verilator simulator

Run this once:

cd openc910/smart_run
make compile SIM=verilator THREADS=8
make buildVerilator

Compile and run the failing 2KB TOR testcase

/opt/riscv/bin/riscv64-unknown-elf-gcc -c -march=rv64gc_zicsr_zifencei -mabi=lp64d -O2 openc910_min_crt0.S -o openc910_min_crt0.o
/opt/riscv/bin/riscv64-unknown-elf-gcc -c -march=rv64gc_zicsr_zifencei -mabi=lp64d -O2 -I. -DREGION_4K_CONTROL=0 seeds/openc910_tor_2kb_grain_bypass_min.S -o openc910_tor_2kb_grain_bypass_min.o
/opt/riscv/bin/riscv64-unknown-elf-gcc -nostdlib -nostartfiles -march=rv64gc_zicsr_zifencei -mabi=lp64d -T openc910_min_linker.ld openc910_min_crt0.o openc910_tor_2kb_grain_bypass_min.o -o openc910_tor_2kb_grain_bypass_min.elf
/opt/riscv/bin/riscv64-unknown-elf-objcopy -O srec openc910_tor_2kb_grain_bypass_min.elf openc910_tor_2kb_grain_bypass_min_inst.hex -j .text* -j .rodata* -j .eh_frame*
/opt/riscv/bin/riscv64-unknown-elf-objcopy -O srec openc910_tor_2kb_grain_bypass_min.elf openc910_tor_2kb_grain_bypass_min_data.hex -j .data* -j .bss -j .sbss -j .COMMON
../tests/bin/Srec2vmem openc910_tor_2kb_grain_bypass_min_inst.hex inst.pat
../tests/bin/Srec2vmem openc910_tor_2kb_grain_bypass_min_data.hex data.pat
./obj_dir/Vtop

Observed failing output:

  • BUG

Meaning:

  • BUG = the load from the locked 2KB TOR deny region retired successfully
  • TRAP = correct behavior; the load raised mcause = 5
  • WRONG = some unexpected trap happened, but not the expected load access fault
  • SETUP_FAIL = the PMP granularity readback check did not observe the expected 2KB grain

test.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions