Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal to simplify (and fix) Zcheri_legacy #39

Closed
sorear opened this issue Jan 24, 2024 · 4 comments
Closed

Proposal to simplify (and fix) Zcheri_legacy #39

sorear opened this issue Jan 24, 2024 · 4 comments
Labels
question Further information is requested

Comments

@sorear
Copy link
Contributor

sorear commented Jan 24, 2024

Zcheri_legacy, to my understanding, serves two purposes:

  1. Allowing capability-naive software stacks to run on capability-capable hardware.
  2. Supporting the execution of hybrid software.

I argue that, as currently defined, it doesn't really work for either case.

  1. Legacy mode indeed allows valid instructions to execute in the same way they would without Zcheri_purecap. However, stacks will include untrusted code, which can compromise a naive supervisor by modifying ddc prior to a trap. Zcheri_legacy has no mechanism to prevent untrusted code from modifying ddc other than lowering XLEN, which affects the naive code that can be run.

  2. Since ISAv9's [LS][TYPE].CAP instructions are not supported in Zcheri_purecap, the only way to access data through a capability in Legacy mode is to perform a csrrw on ddc between each memory access. This is highly likely to be a serializing instruction.

    Not a dealbreaker, except that Zcheri_mode is Pareto-better. It's shorter - 2 bytes for C.CMODESWITCH instead of 4 for CSRRW, and can be omitted entirely between accesses to different capabilities. It can be made faster easily - CMODESWITCH affects no state other than pcc, allowing it to be executed during decode in typical implementations without a pipeline bubble. It's simpler to compile, since there is no need to allocate the ddc register. It simplifies the hardware - assuming Capability mode execution in higher privileges, there is no need for the mtdc, dddc, stdc, or pcc registers, only add one instruction and it doesn't even need backend handling.

We could, in principle, address problem 1 by adding a second bit to xenvcfg which functions the same as lowering XLEN, but that isn't a simplification and doesn't address problem 2. Instead, let's simplify Zcheri_legacy by focusing exclusively on use case 1, and leaving use case 2 to Zcheri_mode. The intent is that new-Zcheri_legacy + Zcheri_mode will be simpler and faster in all cases than old-Zcheri_legacy alone.


Define three execution modes.

In Legacy mode, all instructions defined by Zcheri_purecap are "reserved" in the language of the base ISA spec and cause an illegal-instruction exception if Sstrict is claimed. All instructions not defined by Zcheri_purecap function as described for Legacy mode, using ddc instead of explicit argument capabilities to authorize access. No capability-related state is accessible except for the implicit use of ddc.

Legacy mode is forced if XLEN < XLENMAX or if the effective CME = 0. It serves the purpose of allowing legacy code to run securely, and combines the current "Legacy mode" and "disable most CHERI features" mode.

In Capability mode, all instructions defined by Zcheri_purecap function as described therein.

Capability mode is used if Legacy mode is not forced and pcc.M = 0 (see #34). This is the only mode possible in the absence of the Zcheri_legacy extension.

In Semi-legacy mode, all instructions defined by Zcheri_purecap function as described (for Semi-legacy mode if applicable), and all other instructions function as described for Legacy mode.

Semi-legacy mode is used if Legacy mode is not forced and pcc.M = 1. Naturally, this is only possible with the Zcheri_mode extension. Hybrid software will use Semi-legacy mode and Capability mode.

Delete the JALR.CAP instruction - it's no longer possible to execute in any mode. Also delete JALR.PCC, the last remnant of the mode-independent instructions, I don't think it still serves a purpose.

Delete the pcc CSR; it's not accessible in Legacy mode and in the other modes you can use auipcc possibly after a cmodeswitch.

Delete mtpc and stpc; you can handle saves and restores by running the trap handler in Capability mode and using the existing mscratchc/sscratchc.

Delete dddc; debug mode always executes in Capability mode (since DXLEN = XLENMAX and dpc.M = 0), so ddc doesn't affect debug execution and can be read and written like any other CSR from debug mode. Delete the clauses that alter ddc and dddc on entry and exit from debug mode for the same reason.

Since there is now a clear separation between capability and non-capability execution, the width of csrrw instructions can be inferred from the execution mode. Reading a capability CSR in Legacy mode or Semi-Legacy mode reads the CSR value then writes XLEN bits from the address of the capability to the destination register, sign-extended to XLENMAX bits. Writing a capability CSR in Legacy mode or Semi-Legacy mode, or using a bitwise instruction, combines the old value and new address (sign-extended from XLEN to XLENMAX bits) using a CSETADDR operation before following the write behavior of the capability CSR.

With the CSR width determined by the execution mode, it is no longer necessary to determine it using an alias. Delete the names (but not the registers) mscratchc, mepcc, mtvecc, sscratchc, sepcc, stvecc, dpcc, dscratch0c, dscratch1c, jvtc. Do not allocate aliases vsscratchc, vsepcc, vstvecc.

While not the primary goal, eliminating 17 CSR names reclaims 0.5% of the non-custom CSR space.

@tariqkurd-repo tariqkurd-repo added the question Further information is requested label Jan 25, 2024
tariqkurd-repo added a commit that referenced this issue Feb 20, 2024
#81)

A CHERI mode enable for M-mode allows Zcheri_legacy to run full legacy
software stacks, including firmware soon after reset.

This also removes the behavioral difference between Zcheri_legacy and
Zcheri_mode in terms of the instruction set in effect after reset,
making Zcheri_mode a true extension of Zcheri_legacy.

CHERI register access disables for S-mode and U-mode allow Zcheri_legacy
to prevent cross-domain interference and covert channels within a legacy
environment.

These two are the strictly additive part of #39.

---------

Signed-off-by: Tariq Kurd <[email protected]>
Co-authored-by: Tariq Kurd <[email protected]>
@sorear
Copy link
Contributor Author

sorear commented Feb 25, 2024

Everything here was addressed by #113 or #81 or will be addressed by #130.

@tariqkurd-repo
Copy link
Collaborator

is there anything else to be addressed with this issue?

@arichardson
Copy link
Collaborator

Many of these changes have been made, bt I think the one open is whether we really need the *tdc CSRs.

@andresag01
Copy link
Collaborator

I agree with @arichardson, most of the proposed changes here were adopted in CHERI RISC-V already. Also, there has been no activity in this ticket for a while, so I will close it. Please open a new ticket if you'd like to propose further changes to the spec. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants