[otp_ctrl] Make LC partition unreadable and reduce LC cnt to 16 strokes
Signed-off-by: Michael Schaffner <msf@opentitan.org>
diff --git a/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv b/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv
index 4f4ea6a..1f024c0 100644
--- a/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv
+++ b/hw/ip/lc_ctrl/rtl/lc_ctrl_pkg.sv
@@ -13,7 +13,7 @@
parameter int LcTokenWidth = 128;
parameter int NumLcStateValues = 12;
parameter int LcStateWidth = NumLcStateValues * LcValueWidth;
- parameter int NumLcCountValues = 32;
+ parameter int NumLcCountValues = 16;
parameter int LcCountWidth = NumLcCountValues * LcValueWidth;
typedef enum logic [LcValueWidth-1:0] {
diff --git a/hw/ip/otp_ctrl/data/otp_ctrl_mmap.hjson b/hw/ip/otp_ctrl/data/otp_ctrl_mmap.hjson
index e45bc66..9ec6881 100644
--- a/hw/ip/otp_ctrl/data/otp_ctrl_mmap.hjson
+++ b/hw/ip/otp_ctrl/data/otp_ctrl_mmap.hjson
@@ -69,7 +69,7 @@
{
name: "HW_CFG",
variant: "Buffered",
- size: "176", // in bytes
+ size: "208", // in bytes
secret: "False",
sw_digest: "False",
hw_digest: "True",
@@ -79,7 +79,7 @@
items: [
{
name: "HW_CFG_CONTENT",
- size: "168"
+ size: "200"
}
],
desc: '''Hardware configuration bits used to hardwire
@@ -168,7 +168,7 @@
{
name: "LIFE_CYCLE",
variant: "LifeCycle",
- size: "88", // in bytes
+ size: "56", // in bytes
secret: "False",
sw_digest: "False",
hw_digest: "False",
@@ -182,12 +182,21 @@
}
{
name: "LC_TRANSITION_CNT",
- size: "64"
+ size: "32"
}
],
- desc: '''Life-cycle related bits. Note, this
+ desc: '''Life-cycle related bits. This
partition cannot be locked as the life cycle
state needs to be able to advance to RMA in-field.
+ Note that while this partition is not marked secret
+ (i.e. it is not scrambled) it is not readable
+ nor writeable via the DAI. Only the LC controller
+ can access this partition, and even via the LC
+ controller it is not possible to read the
+ raw manufacturing life cycle state in encoded form,
+ since that encoding is considered a netlist secret.
+ The LC controller only exposes a decoded version of
+ this state.
'''
}
]
diff --git a/hw/ip/otp_ctrl/doc/_index.md b/hw/ip/otp_ctrl/doc/_index.md
index 606d07c..82d8eb9 100644
--- a/hw/ip/otp_ctrl/doc/_index.md
+++ b/hw/ip/otp_ctrl/doc/_index.md
@@ -167,11 +167,12 @@
### Life Cycle Partition
The life cycle partition cannot be locked and will therefore not contain a stored digest.
+Note however that only the life cycle controller has access to this partition, i.e., the DAI cannot read nor write from/to the life cycle partition.
## Secret vs Non-Secret Partitions
Non-secret OTP partitions hold data that can be public; or data that has no impact on security.
-For example, the current value of lock bits, life cycle state or clock calibration value.
+For example, the current value of lock bits or clock calibration values.
These values are stored in OTP as plaintext.
Secret partitions contain data that are critical to security, for example FLASH scrambling keys, device root secret and unlock tokens.
@@ -390,22 +391,25 @@
##### State Transitions
-In order to perform life cycle state transitions, the life cycle controller can present the **incremental** value of the life cycle state and counter with respect to the current status via the programming interface as shown below:
+In order to perform life cycle state transitions, the life cycle controller can present the new value of the life cycle state and counter via the programming interface as shown below:
{{< wavejson >}}
{signal: [
- {name: 'clk_i', wave: 'p.......'},
- {name: 'lc_otp_program_i.req', wave: '01.|..0.'},
- {name: 'lc_otp_program_i.state_delta', wave: '03.|..0.'},
- {name: 'lc_otp_program_i.count_delta', wave: '03.|..0.'},
- {name: 'lc_otp_program_o.ack', wave: '0..|.10.'},
- {name: 'lc_otp_program_o.err', wave: '0..|.40.'},
+ {name: 'clk_i', wave: 'p.......'},
+ {name: 'lc_otp_program_i.req', wave: '01.|..0.'},
+ {name: 'lc_otp_program_i.state', wave: '03.|..0.'},
+ {name: 'lc_otp_program_i.count', wave: '03.|..0.'},
+ {name: 'lc_otp_program_o.ack', wave: '0..|.10.'},
+ {name: 'lc_otp_program_o.err', wave: '0..|.40.'},
]}
{{< /wavejson >}}
-Note that the request must remain asserted until the life cycle controller has responded.
+The request must remain asserted until the life cycle controller has responded.
An error is fatal and indicates that the OTP programming operation has failed.
+Note that the new state must not clear any bits that have already been programmed to OTP - i.e., the new state must be incrementally programmable on top of the previous state.
+There are hence some implications on the life cycle encoding due to the ECC employed, see [life cycle state encoding]({{< relref "hw/ip/lc_ctrl/doc/_index.md#life-cycle-manufacturing-state-encodings" >}}) for details.
+
##### Token Hashing
The OTP controller implements a [PRESENT-based one-way function]({{< relref "#scrambling-datapath" >}}) on 128bit to compute the partition digests.
@@ -881,7 +885,7 @@
0x1 | MacroError | no | x | x | x | x | Returned if the OTP macro command was invalid or did not complete successfully due to a macro malfunction.
0x2 | MacroEccCorrError | yes | x | - | x | x | A correctable ECC error has occurred during a read operation in the OTP macro.
0x3 | MacroEccUncorrError | no | x | - | x | x | An uncorrectable ECC error has occurred during a read operation in the OTP macro.
-0x4 | MacroWriteBlankError | yes | x | x | x | x | This error is returned if a write operation attempted to overwrite an already programmed location.
+0x4 | MacroWriteBlankError | yes | x | x | x | x | This error is returned if a write operation attempted to clear an already programmed bit location.
0x5 | AccessError | yes | x | - | x | - | An access error has occurred (e.g. write to write-locked region, or read to a read-locked region).
0x6 | CheckFailError | no | - | - | x | x | An unrecoverable ECC, integrity or consistency error has been detected.
0x7 | FsmStateError | no | x | x | x | x | The FSM has been glitched into an invalid state, or escalation has been triggered and the FSM has been moved into a terminal error state.
diff --git a/hw/ip/otp_ctrl/rtl/otp_ctrl.sv b/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
index f60400b..8d9a348 100644
--- a/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
+++ b/hw/ip/otp_ctrl/rtl/otp_ctrl.sv
@@ -250,8 +250,10 @@
always_comb begin : p_access_control
// Default (this will be overridden by partition-internal settings).
part_access_csrs = {{32'(2*NumPart)}{Unlocked}};
- // Permanently lock DAI write access to the life cycle partition
+ // Permanently lock DAI write and read access to the life cycle partition.
+ // The LC partition can only be read from and written to via the LC controller.
part_access_csrs[LifeCycleIdx].write_lock = Locked;
+ part_access_csrs[LifeCycleIdx].read_lock = Locked;
// Propagate CSR read enables down to the SW_CFG partitions.
if (!reg2hw.creator_sw_cfg_read_lock) part_access_csrs[CreatorSwCfgIdx].read_lock = Locked;