Skip to content

Fix hgatp unsupported mode writes - #3552

Merged
JeanRochCoulon merged 6 commits into
openhwfoundation:masterfrom
124107157-KV:fix/3495-hgatp-mode-warl
Sep 15, 2026
Merged

JeanRochCoulon merged 6 commits into
openhwfoundation:masterfrom
124107157-KV:fix/3495-hgatp-mode-warl

Conversation

@124107157-KV

@124107157-KV 124107157-KV commented Sep 10, 2026

Copy link
Copy Markdown
Contributor
  • I have searched for similar pull requests
  • I am a human engaging in an interpersonal interaction. During this interaction, my words are my own and are not generated. If relevant, I provide links to my sources.

Description

Fix the WARL handling of hgatp.MODE when software writes an unsupported MODE value.

The current hgatp write path only commits hgatp_d when the written MODE is either Bare (ModeOff) or the virtual-memory mode supported by the selected CVA6 configuration.

When software writes an unsupported MODE value, the assignment to hgatp_d is skipped completely. As a result, the entire write is discarded and the previous PPN and VMID values remain unchanged together with the previous MODE.

This behavior is incorrect for hgatp.

Unlike satp, an hgatp write containing an unsupported MODE value must not cause the entire CSR write to be ignored. The MODE field must be legalized according to its WARL behavior while the remaining writable fields are still allowed to take their legal values.

The fix keeps the currently valid hgatp.MODE when the written MODE is unsupported and then commits the rest of the legalized hgatp value. This allows the newly written PPN and VMID fields to update instead of retaining values from the previous guest.

The existing satp and vsatp behavior is not changed.

Related issue

Fixes #3495

Root cause

The existing CSR_HGATP write handling contains logic equivalent to:

if (hgatp.mode == ModeOff || hgatp.mode == CVA6Cfg.MODE_SV)
  hgatp_d = hgatp;

This means that when the incoming MODE is unsupported, hgatp_d is never updated.

For example:

Initial legal value:

MODE = Sv39x4
PPN  = 0x100

Second write:

MODE = 1
PPN  = 0x200

MODE value 1 is unsupported for this configuration.

Before this fix, the second write is discarded entirely and the CSR remains equivalent to:

MODE = Sv39x4
PPN  = 0x100

The expected WARL behavior is:

MODE = Sv39x4
PPN  = 0x200

The legal MODE is retained while the legal PPN field from the new write is accepted.

Changes

The CSR_HGATP write path in core/csr_regfile.sv is changed so that:

  • supported MODE values continue to be written normally;
  • an unsupported incoming MODE is replaced with the current legal hgatp_q.mode;
  • the resulting legalized hgatp value is always committed to hgatp_d;
  • existing PPN low-bit hardwiring remains unchanged;
  • existing VMID masking remains unchanged;
  • satp and vsatp handling remain unchanged.

A directed regression test is also added to reproduce the bug and verify the corrected WARL behavior.

Regression test

Added:

verif/tests/custom/hgatp_warl/hgatp_mode_warl.S

Testlist:

verif/tests/testlist_hgatp_warl.yaml

Test name:

rv64h-p-hgatp-mode-warl

The regression performs the following sequence:

  1. Write a legal hgatp value with MODE set to Sv39x4 and PPN set to 0x100.

  2. Read back hgatp and verify that the legal write was accepted.

  3. Write hgatp again with unsupported MODE value 1 and PPN set to 0x200.

  4. Read back hgatp.

  5. Verify that MODE remains Sv39x4 while PPN changes to 0x200.

The second check specifically detects the original bug where the complete second write was discarded.

Verification

Target configuration:

cv64a6_imafdch_sv39

The Verilator model was built with:

make verilate target=cv64a6_imafdch_sv39

The post-change Verilator build completed successfully with exit status 0.

Before the fix

The directed regression reproduced the bug:

hgatp_mode_warl.o *** FAILED *** (tohost = 2)

The simulation terminated after approximately 2928 cycles.

The failure occurs at test number 2, which is the unsupported-MODE write/read-back check.

This confirms that the original RTL retains the previous PPN after the unsupported MODE write instead of accepting the new PPN.

After the fix

After rebuilding the Verilator model with the RTL change, the exact same regression passed:

hgatp_mode_warl.o *** SUCCESS *** (tohost = 0)

The post-fix RTL run returned:

RTL_RC=0

This demonstrates the expected transition:

Before fix: FAILED, tohost = 2
After fix:  SUCCESS, tohost = 0

The directed test was also compiled and run against Spike as the reference model to confirm the expected WARL behavior.

Files changed

core/csr_regfile.sv
verif/tests/custom/hgatp_warl/hgatp_mode_warl.S
verif/tests/testlist_hgatp_warl.yaml

Scope

This change is intentionally limited to the hgatp unsupported-MODE WARL handling.

It does not modify the behavior of:

  • satp;
  • vsatp;
  • unrelated CSR handling;
  • MMU translation logic;
  • page-table walking logic.

Limitations

Local directed RTL verification was performed with the cv64a6_imafdch_sv39 configuration.

Broader configuration and regression coverage is expected to be exercised by the CVA6 continuous-integration flow.

Preserve the current hgatp mode when software writes an unsupported
MODE value, while still committing the legalized PPN and VMID fields.

Add a directed regression for the unsupported MODE WARL behavior.
@JeanRochCoulon

Copy link
Copy Markdown
Contributor

@ASintzoff can you approve ?

@JeanRochCoulon
JeanRochCoulon merged commit 81245a4 into openhwfoundation:master Sep 15, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] csr_regfile: a write to hgatp with an unsupported MODE is dropped entirely, so PPN and VMID keep the previous guest's values

2 participants