Skip to content

I3C Provisioned ID CSRs (STBY_CR_DEVICE_PID_LO / STBY_CR_VIRTUAL_DEVICE_PID_LO) are unlocked RW with hardcoded reset values — no immutability or fuse-source path #215

Description

@RaunakGu

Summary

The 48-bit I3C Provisioned ID (PID) registers in the standby-controller CSR block are plain read/write storage flops with no hardware lock, no fuse/OTP source, and no write-enable qualifier. Any agent able to write the CSR/AXI interface (i.e. MCU firmware) can overwrite the PID to an arbitrary value at any time. Combined with hardcoded FUTUREFIX test reset values, a device's I3C identity is today neither unique-per-device nor protected against modification by local firmware.

Raising this to understand the intended design: is the PID meant to be fuse-fed, provisioned-then-locked, or is identity integrity expected to be enforced by the integrator outside i3c-core?

Affected registers

Register Offset Target
I3C_EC.StdbyCtrlMode.STBY_CR_DEVICE_PID_LO.PID_LO 0x19c main
I3C_EC.StdbyCtrlMode.STBY_CR_VIRTUAL_DEVICE_PID_LO.PID_LO 0x1a4 virtual
STBY_CR_DEVICE_CHAR.PID_HI 0x198 main (PID_HI)
STBY_CR_VIRTUAL_DEVICE_CHAR.PID_HI 0x190 virtual (PID_HI)

Evidence (RTL)

RDL field — hw = r; sw = rw, reset = test constant, flagged FUTUREFIX (src/rdl/standby_controller_mode.rdl):

field { name = "PID_LO"; hw = r; sw = rw;
        reset = 32'h005A00A5; // FUTUREFIX: was `pid_lo_reset`
} PID_LO[31:0];

Generated CSR write logic — the only gate on the write is "register addressed + is-write"; no lock/enable term (src/csr/I3CCSR.sv:7363-7385):

if(decoded_reg_strb...STBY_CR_DEVICE_PID_LO && decoded_req_is_wr) begin // SW write
    next_c = (old & ~wr_biten) | (wr_data & wr_biten);
    load_next_c = '1;
end
// ...
if(~rst_ni) field_storage...PID_LO.value <= 32'h5a00a5;   // power-on default only
else if(load_next) field_storage...PID_LO.value <= next_c; // accepts ANY sw write

Confirmed absent across the entire i3c-core RTL for these fields:

  • no swwe / swwel / .wel software-write-enable or write-lock
  • no lifecycle / LC-state gate on the write
  • no hwif_in load path (no fuse/OTP autoload — hw=r only consumes the value for ENTDAA)
  • no lock / otp / fuse signal touching PID or device-char fields

The virtual-target field (src/csr/I3CCSR.sv:7724-7746) is identical (reset 0x5a10a5).

ROM does not program these either — rom/src/i3c.rs I3c::configure() sets static address, ENTDAA/SETDASA enable, timing, queues, recovery FIFO, and PHY enable, but never writes PID_LO / PID_HI / device-char. Shipping parts therefore retain the RTL reset constant.

Observations

  1. Mutable by local firmware. The reset value is a power-on default, not an immutability guarantee; compromised/rogue MCU firmware can rewrite the PID (e.g. to clone or spoof an identity). The external I3C bus side is read-only toward these fields, so the exposure is specifically local CSR/AXI writes.
  2. Not unique per device. With no fuse source wired in, every device defaults to the same 0x005A00A5 (main) / 0x005A10A5 (virtual) PID.
  3. Applies to both targets the core exposes (main + virtual).

Possible directions (for discussion)

  • Fuse-sourced: drive PID_LO / PID_HI from OTP via a hwif_in autoload and make the field sw = r.
  • Sticky write-once lock: add a swwel-gated lock bit that clears only on cold reset (program-once, then RO).
  • Lifecycle-gated write: allow writes only in a manufacturing/provisioning LC phase, disabled in production.
  • Replace/zero the FUTUREFIX reset constants so an unprovisioned part is detectable rather than shipping a fixed value.

Questions

  1. What is the intended provisioning model for the I3C PID — fuse-fed, provisioned-then-locked, or ROM-programmed each boot from a trusted source? The current RTL supports none of these as a protected path.
  2. Is identity immutability expected to be enforced inside i3c-core, or is the integrator expected to add it externally (e.g. a wrapper/AXI access filter gating the CSR region)?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions