Skip to content

Draft: Add support for the CHERI "RV64Y" extension - #3382

Draft
PRugg-Cap wants to merge 8 commits into
openhwgroup:masterfrom
PRugg-Cap:cheri-upstream-pr
Draft

Draft: Add support for the CHERI "RV64Y" extension#3382
PRugg-Cap wants to merge 8 commits into
openhwgroup:masterfrom
PRugg-Cap:cheri-upstream-pr

Conversation

@PRugg-Cap

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.

As discussed, at Capabilities Limited based on initial work at Zero Day Labs, we have been integrating CHERI (the RISC-V Y extension): see https://github.com/riscv/riscv-cheri. This adds "capabilities" in hardware to provide memory safety and compartmentalisation that allows software to protect itself against common security vulnerabilities like buffer overflows.

This is a draft PR with the current state of our changes to get feedback on a path to upstreaming. I have extracted out only the CHERI features from our fork https://github.com/Capabilities-Limited/cheri-cva6, along with the minimal changes required for tests to pass etc. Only the last commit "Add RV64Y support" is relevant for review: other things will be addressed in other PRs. It would be very helpful to get feedback on the code style, if there are any changes that can be extracted out and made upstream separately, and if there are any changes we can make to the CHERI implementation to reduce the diff.

This PR does not introduce CHERI-specific tests. We primarily use TestRIG for this testing. We understand this is a requirement for upstreaming, but the aim of this PR is to establish that we can integrate CHERI without regressing the baseline design. Since RVY is backwards compatible, all the existing tests in this repository we have tried pass, both with and without CHERI enabled in.

A few other notes on limitations:

  • As discussed, this will not be merged until the RISC-V Y extension is ratified.
  • The current implementation is based on version 0.9.4 of the RISC-V Y spec. Updating is a work in progress, but changes are relatively minor.
  • Various further updates and optimisations are planned for the CHERI implementation.
  • We need to pull forward the version of verilator used, and there is an associated workaround: please ignore. We can discuss this closer to ratification if it's still an issue.
  • I've made a change to how debug single-step is implemented. I believe this should be an area saving for non-CHERI but still need to evaluate this. To be discussed in a separate PR.
  • I currently have reverted the big-endian support, as it's a bit of a pain to merge CHERI with those changes. I will of course resolve the conflicts properly prior to upstreaming.

PRugg-Cap and others added 6 commits July 6, 2026 18:41
This reverts commit e7d7ea6.

This is difficult to compose with CHERI, and there are currently
no plans to enable both together.
We will perform the sourcecode integration closer to ratification
and upstreaming.
Some minor fixes to baseline CVA6 we need to get our test flows passing.
We intend to merge these as individual PRs.
Without this, the CHERI changes seem to hit a compiler bug.
The newer Verilator version seems to trigger a different codepath in CI.
This causes the Spike tandem to run, which fails without this change as
Spike doesn't detect scalar crypto in the archstring.
As a workaround for now, patch the subrepo to always enable sclar crypto:
the configurations that test CVA6 with the extension removed don't test
the instructions, so it doesn't matter that it's enabled in Spike.
The existing implementation adds commit logic to detect the first
instruction after resume, then recalculates the architectural next
PC in the CSR register file.
Instead, we can detect the second instruction and use the usual
mechanism to drop it. That way it has a calculated PC the CSR
register file can use to determine the architectural state.
This is useful for CHERI as there would be even more logic to
recalculate the architectural next PC (and PCC).
This adds CHERI support to CVA6, according to version 0.9.4 of the
riscv-cheri spec.

Co-authored-by: joncapltd <Jonathan.Woodruff@capabilitieslimited.co.uk>
Co-authored-by: Alexandre <alexandre@capabilitieslimited.co.uk>
Co-authored-by: Bruno Sa <bruno.vilaca.sa@gmail.com>
Comment thread core/issue_read_operands.sv Outdated
@JeanRochCoulon

Copy link
Copy Markdown
Contributor

Great @PRugg-Cap ! Great step !

@cainria cainria left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really partial review with a few questions for both the author and the project maintainers.

Comment on lines +32 to +37
localparam XLEN = cva6_config_pkg::CVA6ConfigXlen;
localparam CheriPresent = cva6_config_pkg::CVA6ConfigRVZcheripurecap;
localparam CLEN = CheriPresent ? 2 * XLEN : XLEN;
localparam REGLEN = CheriPresent ? $bits(cva6_cheri_pkg::cap_reg_t) : XLEN;
localparam logic [REGLEN-1:0] REG_NULL = CheriPresent ? cva6_cheri_pkg::REG_NULL_CAP : '0;
localparam logic [REGLEN-1:0] REG_ROOT = CheriPresent ? cva6_cheri_pkg::REG_ROOT_CAP : '0;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you considered using the config structure instead?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice. The problem is that I want to introduce the functions reg_to_x and x_to_reg, which need to take a REGLEN and return an XLEN, and vice versa. That means they can't be taken from the config struct, as they have to be more static. CVA6Cfg.CLEN and CVA6Cfg.REGLEN are used elsewhere where they can be.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm misunderstanding something about how the types can be used, do let me know though!

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is indeed a limitation of the language (it lacks generic types).

What I recommend in this case:

  • If the function is called only in one module (not the case here), move the function into this module. This is what we did for mult functions.
  • Otherwise, create a module instead of a function to allow a generic interface. But SystemVerilog does not allow to instantiate modules with call syntax so it might not be handy…

I would still be in favor of the component approach to not break the configuration effort.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, okay, these functions were introduced to reduce diff and avoid lots of:

if (CheriPresent) begin
  a_reg = {{REGLEN-XLEN}{1'b0}, a};
end else begin
  a_reg = a;
end

If we need a module instantiation, then it's probably better to just go back to that.
There are currently 46 calls to these functions throughout the codebase.
I'll contemplate if there's a tidier way. Any chance you could elaborate on how the current approach breaks the configuration effort, so that I can understand the constraints?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe

a_reg = CVA6Cfg.CheriEn ? {{REGLEN-XLEN}{1'b0}, a} : a;

To put it short, we would like to be able to instantiate simultaneously 2 ariane cores with Cheri enabled and different XLEN.
Having values in the package instead of the config struct prevents us from doing that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we had that form in some cases as well. The zero replicate does seem to generate warning in some cases though. Okay, thanks for the summary of the goal: I'll contemplate how to proceed.

end
// 8-bytes size
3'b011: begin
case (addr[3:0])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would the following shorter code be correct?

if (addr[3:0] <= 16) begin
  return 16'h00ff << addr[3:0];
end

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe so. This mirrors the coding style used in the existing be_gen function just below. We assumed it was expressed this way for a reason, but I guess we should evaluate and possibly change both to be more concise.

Comment thread core/cva6.sv
@@ -1,4 +1,6 @@
// Copyright 2017-2019 ETH Zurich and University of Bologna.
// Copyright 2025 Bruno Sá and Zero-Day Labs.
// Copyright 2025 Capabilities Limited.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this copyright compatible with the CVA6 project?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They're the same as the ETH and Bologna ones just above. All the changes are of course made under the indicated license.

Comment thread .gitmodules
[submodule "core/cache_subsystem/hpdcache"]
path = core/cache_subsystem/hpdcache
url = https://github.com/openhwgroup/cv-hpdcache.git
url = https://github.com/Capabilities-Limited/cv-hpdcache.git

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will need to revert this before merge

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay: we have some non-trivial changes to the HPDCache to add capability tag support, but agreed, we should merge those there then this will become a bump of the existing submodule.

Comment thread .gitmodules
Comment on lines +55 to +57
[submodule "vendor/zero-day/axi_tagcontroller"]
path = vendor/zero-day/axi_tagcontroller
url = https://github.com/Capabilities-Limited/axi_cheri_tagcontroller.git

@cainria cainria Jul 7, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we willing to add a new submodule?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't seem like this is a question for us, but just to give context: the tag controller is needed to provide tagged memory, splitting tags out from the AXI requests coming out of the caches and storing them in a dedicated region of DRAM. It definitely "feels" like its own component, much like the HPDCache. If the question is whether we should vendor instead, then we'd likely be happy with that approach.

PRugg-Cap and others added 2 commits July 7, 2026 21:34
Auto whitespace fix

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Auto whitespace fix

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@PRugg-Cap

Copy link
Copy Markdown
Contributor Author

Verible is now failing because of the IS_XLEN{32,64} checking script. I did cherry-pick in the commit to fix it, but I'll hold off on pushing it for now because that would pollute the diff. We'll get it when we rebase anyway.

Comment on lines +31 to +32
localparam CVA6ConfigRVZcheripurecap = 0;
localparam CVA6ConfigRVZcherihybrid = 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
localparam CVA6ConfigRVZcheripurecap = 0;
localparam CVA6ConfigRVZcherihybrid = 0;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this suggestion because we shouldn't modify deprecated packages, or because we shouldn't have these localparams? If the latter, I can have a go at removing them, but I think we need them statically in some cases.

@JeanRochCoulon JeanRochCoulon Jul 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These config packages are not all deprecated, we need to maintain them. The localparams are not used, that is why it is better to remove them


config_pkg::cva6_cfg_t cfg;

cfg.XLEN = CVA6Cfg.XLEN;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CLEN means Cheri len, also when Cheri is disable, coding style can be improved.
Maybe this would bring confusion, but defining cfg.XLEN as below would remove a lot of line modifications. @PRugg-Cap or @Gchauvon Do you have a better suggestion ?

Suggested change
cfg.XLEN = CVA6Cfg.XLEN;
cfg.XLEN = CheriPresent ? (CVA6Cfg.XLEN * 2) : CVA6Cfg.XLEN;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, not quite. CLEN is "capability len" and stands for the architectural length of a capability (excluding tag). However, it's actually quite rarely used. We still need XLEN, which is the size of the x registers, e.g. throughout the frontend, and in the ALU. This matches what is written in the RISC-V architecture document. The parameter we use more broadly is REGLEN, which is bigger than CLEN because we store some extra microarchitectural partially decompressed metadata in the registers.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did a quick grep of the repository, filtering out submodules etc. After our changes the counts of uses of the different parameters are as follows:
CLEN: 198
REGLEN: 123
XLEN: 1038
If we changed XLEN to be CLEN, then we'd save those 198, but the 1038 XLENs would all have to be "ADDRLEN" or "ARITHLEN" or something, so it would actually make the diff a lot bigger.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Though I was surprised we use CLEN more than REGLEN... The parts of the code I was mostly interacting with were more REGLEN heavy)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though I do take the point that having "CLEN", e.g. on the path from memory into the pipeline, is confusing when CHERI is disabled out. We can consider another option, e.g. something like "MEMLEN" (better name needed!) which is the maximum width of something loaded in from memory in one cycle.

@JeanRochCoulon JeanRochCoulon Jul 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanations. I really prefer MEMLEN. I would be please to get @Gchauvon feedback to grant this modification (Guillaume worked on type strategy among the cva6)

@@ -0,0 +1,183 @@
// Copyright 2021 Thales DIS design services SAS

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using cv32a60x config package as example is better, it does not define useless localparams

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay: I'll give that a go

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

👋 Hi there!

This pull request seems inactive. Need more help or have updates? Feel free to let us know. If there are no updates within the next few days, we'll go ahead and close this PR. 😊

@github-actions github-actions Bot added the Status:Stale Issue or PR is stale and hasn't received any updates. label Aug 8, 2026
@PRugg-Cap

Copy link
Copy Markdown
Contributor Author

Apologies: I'm still hoping to find time to do the type refactor, but hopefully we can leave this open.

@github-actions github-actions Bot removed the Status:Stale Issue or PR is stale and hasn't received any updates. label Aug 11, 2026
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.

3 participants