Skip to content

[rtl,cheriot] Implement CHERIoT ISA - #2475

Draft
SamuelRiedel wants to merge 2 commits into
lowRISC:masterfrom
SamuelRiedel:cheriot/pr
Draft

[rtl,cheriot] Implement CHERIoT ISA #2475
SamuelRiedel wants to merge 2 commits into
lowRISC:masterfrom
SamuelRiedel:cheriot/pr

Conversation

@SamuelRiedel

Copy link
Copy Markdown
Contributor

No description provided.

This commit takes the entire cheriot-ibex development since it forked
from lowrisc/ibex (from bdf2f2b)

This commit was ported from https://github.com/microsoft/cheriot-ibex

Co-authored-by: Kunyan Liu <kunyanliu@microsoft.com>

Signed-off-by: Samuel Riedel <sriedel@lowrisc.org>
Signed-off-by: Samuel Riedel <sriedel@lowrisc.org>

@andreaskurth andreaskurth left a comment

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 @SamuelRiedel for this work! As agreed, the first commit imports the Microsoft's CHERIoT implementation, which is based on an earlier fork of Ibex, and rebases it onto the current Ibex, and the second commit reimplements the CHERIoT ISA in a way that fits Ibex's architecture and design very neatly. This two-commit approach makes code provenance and differences explicit, which is important.

I checked your CHERIoT ISA implementation against the v1.0 spec (chapter 9 Sail listings, the §8 encoding tables, and §7.13) and the approved OpenTitan RFC and am convinced that many/most aspects are correct - nice!

One item needs changing in this PR, I think: The register file doesn't seem to implement the RFC's shared 16x65-bit arrangement.

The remaining comments are functional and conformance gaps, and some of them I think are major, but none of them blocks this PR -> follow-up issues.


assign rf_reg[i] = rf_reg_q;

if (BaseIsa == BaseIsaRV32IorCHERIoT) begin : g_rf_cap_flops

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.

This gives 32 entries of 32-bit data plus a 35-bit capability, whereas the approved RFC proposes a single 16x65-bit file where each entry serves two 32-bit GPRs in base-ISA mode, right?

As implemented, the capability flops of entries 16-31 can never hold a non-zero value: CHERIoT masks register addresses to 4 bits in ibex_decoder, and base-ISA mode always writes NULL_CAP. So that's ~560 permanently-zero flops, and synthesis probably will have a hard time optimizing them away because rf_wcap_a_i isn't a constant.

Could we implement the shared 16x65 arrangement here, or is there a reason it doesn't work that we should write down? I'd rather resolve this one in this PR than defer it.

instr_o = {{15 {instr_i[12]}}, instr_i[6:2], instr_i[11:7], {OPCODE_LUI}};

if (instr_i[11:7] == 5'h02) begin
// c.incaddr16csp -> cincoffsetimm csp, csp, nzimm

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.

This remap (and c.incaddr4cspn above) is needed because a plain addi writes a NULL capability in CHERIoT mode. Doesn't Zcmp need the same treatment?

cm.push/cm.pop expand via cm_sp_addi() to addi x2, x2, imm, which would clear csp's tag and bounds; cm_push_store_reg()/cm_pop_load_reg() use sw/lw, so cra's backward sentry is lost in memory and the jalr x0, 0(x1) from cm_ret_ra() then takes a tag violation (cd = cnull, cs1 = cra requires a tagged backward sentry). cm.mvsa01/cm.mva01s similarly clear tags on argument registers. The opentitan config enables RV32ZcaZcbZcmp together with BaseIsaRV32IorCHERIoT, so this is reachable.

Could we either expand these to CHERIoT equivalents? Or is Zcmp incompatible with CHERIoT? Follow-up issue is fine with me, not a blocker for this PR.

Comment thread rtl/ibex_cs_registers.sv
end else if ((cheriot_enable_i == IbexMuBiOn) && csr_save_cause_i && ~debug_csr_save_i &&
~debug_mode_i) begin
mepc_cap <= pcc_exc_cap;
end else if ((cheriot_enable_i == IbexMuBiOn) && mepc_en) begin // legacy cssrw; NMI recover

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.

On mret out of an NMI, mepc_en is asserted from the nmi_mode_i restore path, so this sets mepc_cap to NULL_CAP. mstack only saves the 32-bit mepc, not the capability.

Doesn't that make the interrupted handler's own mret install an untagged PCC and take a CHERI tag violation, i.e. turn a recoverable NMI into an unrecoverable one in CHERIoT mode? Would stacking the capability alongside mstack_epc_q be the fix?

Follow-up issue is fine, not a blocker.

Comment thread rtl/ibex_cheriot_ex.sv
perm_vio_vec[PVIO_EX] = ~rf_fullcap_a.perms.EX;
end else if (cheriot_operator_i.CCSR_RW) begin
perm_vio_vec[PVIO_ASR] = ~pcc_cap_i.perms.SR;
illegal_scr_addr = ~debug_mode_i & (csr_addr_o < 27);

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.

CSpecialRW's Sail treats only SCRs 28-31 as existing and calls handle_illegal() for everything else. Two deviations here:

  • < 27 still admits SCR 27 (ZTOPC). Since ztop_rdata_i/ztop_rcap_i are tied to zero in ibex_core.sv and there is no write path, cspecialrw cd, 27, cs1 silently reads 0 and drops the write instead of trapping.
  • The ~debug_mode_i gate makes SCRs 0-23 legal in debug mode too, where they also read 0 via the default arm of the SCR read mux.

Should this become < 28, with an explicit allowance for the debug SCRs 24-26 only? Follow-up issue is fine, not a blocker.

Comment thread rtl/ibex_cs_registers.sv
// mepc: exception program counter
CSR_MEPC: mepc_en = 1'b1;
// disabled for pure cap mode (only allow cap writes)
CSR_MEPC: mepc_en = ~(BaseIsa == BaseIsaRV32IorCHERIoT)

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.

§7.10 says that accessing the replaced RISC-V CSRs (mtvec, mepc) via the CSR* instructions should raise a Reserved Instruction exception in CHERIoT mode.

Here, and for CSR_MTVEC a few lines below, the write is silently dropped instead, and the corresponding reads in the read mux still succeed. So software can csrw mtvec, x and get no indication that it had no effect. Should these two be forced into illegal_csr when cheriot_enable_i == IbexMuBiOn?

Follow-up issue is fine, not a blocker.

Comment thread rtl/ibex_cheriot_pkg.sv
parameter perms_t PERM_SEA_IMSK = '{default:0}; // Sealing

// Decode the 6-bit compressed permission encoding to the full 12-bit permissions field.
function automatic perms_t cheriot_expand_perms(cperms_t cperms);

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.

perms is only assigned inside the if/else-if chain, with no final else. The six branches do cover all 64 cperms encodings today, so this is functionally correct, but an unconditional perms = '0; (or a default) up front would keep it X-free if the chain is ever edited. Follow-up is fine.

Comment thread rtl/ibex_cheriot_pkg.sv
// Update a capability's address and recompute correction fields. Invalidate the tag if not
// representable.
// chktop/chkbase enable explicit top33/base32 bounds checks used for PCC updates.
function automatic decoded_cap_t cheriot_set_address(decoded_cap_t in_cap, logic [31:0] newptr,

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.

chktop/chkbase are 0 at all three call sites (set_address_comb twice and cheriot_pcc_to_mepc), so ptr_below_top and the two extra terms in the condition below are dead. Drop the two arguments?

Comment thread rtl/ibex_cheriot_ex.sv
end else if (cheriot_setaddr_sel_i == SETADDR_RFA_ARITH) begin
tfcap1 = rf_fullcap_a;
taddr1 = addr_result;
end else if ((cheriot_setaddr_sel_i == SETADDR_SCR) && scr_legalization) begin

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.

This branch looks redundant. MTCC/MEPCC legalization only clears low address bits, and the rf_rdata_a[1:0] != 2'b00 / rf_rdata_a[0] != 1'b0 checks in main_ex already clear the tag in exactly the cases where the address changes, so setaddr1_outcap's representability result is always overridden by trcap.valid = rf_fullcap_a.valid, and the recomputed cap_cor is identical to the input.

Can SETADDR_SCR and scr_legalization be dropped entirely?

Comment thread rtl/ibex_if_stage.sv
unique case (exc_pc_mux_i)
EXC_PC_EXC: exc_pc = { csr_mtvec_i[31:8], 8'h00 };
EXC_PC_IRQ: exc_pc = { csr_mtvec_i[31:8], 1'b0, irq_vec, 2'b00 };
EXC_PC_EXC: exc_pc = ((BaseIsa == BaseIsaRV32IorCHERIoT)

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.

csr_mtvec_i[0] is initialised from csr_mtvec_init_i at boot, so a core that boots in base-ISA mode has it set. After a runtime switch to CHERIoT mode, exceptions would then be vectored here until software writes MTCC, even though CHERIoT supports direct mode only.

Should the direct-mode selection depend on cheriot_enable_i alone rather than also on ~csr_mtvec_i[0]? Follow-up issue is fine.

Comment thread rtl/ibex_cheriot_pkg.sv
} perms_t;

// Sealing types (spec v1.0, chapter 7.13.2)
parameter otype_t OTYPE_UNSEALED = 3'd0;

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.

otype 1 (interrupt-inheriting forward sentry) isn't named here, so ibex_cheriot_ex ends up comparing against the bare literal 3'h1 in the CJALR otype checks. Add an OTYPE_SENTRY_INHERIT = 3'd1 for symmetry with the other four?

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.

2 participants