Skip to content

[Bug] hedeleg writes are masked to zero in H-enabled Rocket #3815

Open

Description

@jf-cc727

Bug Description

Official Rocket Chip master with the H extension enabled accepts an HS-mode write of 0x000c0000 to hedeleg, but reads back 0. These are hedeleg bits 18 and 19.

The minimal PoC starts in M-mode, opens a permissive PMP entry so HS-mode can execute from the loaded image, enters HS-mode with mret, writes hedeleg[18:19], reads hedeleg, and fails if those two bits are not preserved.

Core HS-mode sequence:

li   t0, 0x000c0000
csrw hedeleg, t0
csrr s0, hedeleg
and  s0, s0, t0
bne  s0, t0, fail_masked

This is a direct CSR write/readback issue in an H-enabled Rocket configuration. It is not a reset-profile issue and not a BootROM false positive.

Upstream version confirmation: this issue was validated against the official Rocket Chip master line at revision v1.6-819-g55bcad0f5, confirmed at commit 55bcad0f59436de98ea510334121de8546b9e9d7, using freechips.rocketchip.system.HypervisorConfig. No fix revision has been identified yet.

RISC-V Specification Requirement

The RISC-V Privileged ISA, Section 15.1.2. Hypervisor and Virtual Supervisor CSRs, states that HS-mode provides additional CSRs, including hedeleg, to control VS-mode guest behavior.

Section 15.1.2.2. Hypervisor Trap Delegation (hedeleg and hideleg) Registers defines hedeleg as a 64-bit read/write register used to further delegate synchronous traps from HS-mode to VS-mode. The same section says each hedeleg bit is either writable or read-only zero, and Table 2 enumerates the required behavior.

For this PoC, the relevant Table 2 entries are:

Bit Attribute Corresponding exception
18 Writable Software check
19 Writable Hardware error

Reference: RISC-V Privileged ISA v20260120, Hypervisor Trap Delegation Registers

An H-enabled implementation should therefore preserve these two writable bits on readback after HS-mode software writes them.

Steps to Reproduce

Essential source:

li   t0, -1
csrw pmpaddr0, t0
li   t0, 0x1f
csrw pmpcfg0, t0

la   t0, hs_entry
csrw mepc, t0
li   t1, 0x1800
csrc mstatus, t1
li   t1, 0x0800
csrs mstatus, t1
mret

hs_entry:
  li   t0, 0x000c0000
  csrw hedeleg, t0
  csrr s0, hedeleg
  and  s0, s0, t0
  bne  s0, t0, fail_masked

Expected Result

After HS-mode writes 0x000c0000 to hedeleg, bits 18 and 19 should read back as set:

hedeleg & 0x000c0000 == 0x000c0000

Actual Result

Official Rocket Chip HypervisorConfig reads back zero for those bits at the failing CSR read:

16552:C0: 75272 [1] pc=[0000000080000050] W[r 5=00000000000c0000][1] ... inst=[000c02b7]
16553:C0: 75273 [1] pc=[0000000080000054] ... R[r 5=00000000000c0000] ... inst=[60229073]
16554:C0: 75278 [1] pc=[0000000080000058] W[r 8=0000000000000000][1] ... inst=[60202473]

So software prepares 0x000c0000, writes hedeleg, and the following csrr hedeleg still returns zero.

The PoC reaches fail_masked and exits with code 61:

*** FAILED *** (tohost = 61)
*** FAILED *** via dtm (code = 61, seed 1) after 97394 cycles

RK-2.zip

Activity

  1. hiSandog commented on Jul 11, 2026

    @hiSandog

    A directed CSR test could cover both writable and unsupported hedeleg bits, rather than only checking one nonzero write. Writing all ones and checking the architectural mask, followed by a mixed pattern, would catch both the current zero-mask failure and accidental exposure of reserved bits.

  2. jf-cc727 commented on Jul 11, 2026

    @jf-cc727
    Author

    Thanks, that makes sense. I added a supplemental directed CSR mask test for hedeleg. The test writes all ones and then a mixed pattern, checking both the required-writable bits and the required-zero bits from the architectural mask. The result still shows the current zero-mask failure: both the all-ones write and the mixed-pattern write miss hedeleg[18:19] (missing mask 0x000c0000). The required-zero bits checked by the test remained zero, so this run confirms the writable-bit failure without showing accidental exposure of reserved/unsupported bits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions