Skip to content

Misaligned Sv39 1 GiB superpage leaf is accepted instead of raising load page fault #265

Description

@jf-cc727

Bug Description

NutShell accepts a root-level Sv39 leaf PTE for a 1 GiB mapping even when the lower PPN fields are nonzero. A compliant implementation must treat this as a misaligned superpage and raise a page-fault exception corresponding to the original access type.

In the supplied test program, the test intentionally sets PTE bit 10 (PPN[0] bit 0) in a root-level leaf and then constructs virtual address 0x40002000 so that the malformed 1 GiB mapping aliases the test word at bad_data. Spike raises a precise Load page fault (mcause=13), while NutShell completes the load and returns 0x1122334455667788.

RISC-V Specification Requirement

The Sv39 virtual-address translation algorithm is explicit: after a leaf PTE is found, if the current level represents a superpage and the lower PPN fields are not all zero, the implementation must raise a page-fault exception corresponding to the original access type.

Reference: https://docs.riscv.org/reference/isa/v20260120/priv/supervisor.html#_virtual_address_translation_process

Because the original access in this test program is a load, the required architectural exception is Load page fault (mcause=13), not successful completion of the load.

Steps to Reproduce

  1. Run the supplied poc/program.elf under difftest.
  2. M-mode installs a root-level Sv39 leaf in root_pt[1] and deliberately sets a nonzero lower PPN bit, making the 1 GiB superpage leaf misaligned.
  3. The test enables Sv39 with S-mode effective privilege, constructs a VA whose low 30 bits alias bad_data, and executes the faulting load.

Essential setup:

/* root_pt[1] is a malformed 1 GiB leaf: PPN[0] bit 0 is forced to 1. */
la   t0, root_pt
la   t1, bad_data
srli t1, t1, 12
slli t1, t1, 10
ori  t1, t1, PTE_RAD
li   t2, (1 << 10)
or   t1, t1, t2
sd   t1, 8(t0)

/* Build a VPN[2]=1 VA whose low 30 bits alias bad_data. */
la   t0, bad_data
li   t1, 0x3fffffff
and  a0, t0, t1
li   t1, 0x40000000
or   a0, a0, t1
ld   t2, 0(a0)

Expected Result

  • The load does not complete.
  • mcause = 13 (Load page fault).
  • mepc = load_site (0x8000009c in this build).
  • mtval = 0x40002000.
  • The destination register does not receive the value stored at bad_data through the malformed mapping.

Actual Result

NutShell commits the load and returns the value stored at bad_data, while Spike takes the page fault:

[31] commit pc 000000008000009c ... data 1122334455667788 ... ld      t2, 0(a0) <--
pc: 0x00000000800000f0 ... mcause: 0x000000000000000d mepc: 0x000000008000009c
mtval: 0x0000000040002000 ...
t2 different ... right = 0x0000000000000400, wrong = 0x1122334455667788
mtval different ... right = 0x0000000040002000, wrong = 0x0000000000000000
mcause different ... right = 0x000000000000000d, wrong = 0x0000000000000000
Image

NS-6.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    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