[rtl] RRAM otp hw plug#30412
Conversation
43435b1 to
cb9246e
Compare
vogelpi
left a comment
There was a problem hiding this comment.
Thanks @gautschimi this matches the original PR which I reviewed in depth + the requested comments. These are very valuable, thanks for adding them.
I mostly have some questions. We can also discuss in person if preferred.
I would appreciate if also @andrea-caforio and @elliotb-lowrisc could review this PR as they have experience with OTP_CTRL and @andrea-caforio for example implemented the zeroization feature originally.
| intg_addr_d = OtpIntgStartAddr + (otp_byte_addr >> vbits(OtpIntgDataWidth/8)); | ||
| intg_ind_d = otp_byte_addr[vbits(OtpIntgDataWidth/8) +: OtpIntgIndWidth]; |
There was a problem hiding this comment.
Historically, some OTP partitions did not have integrity because it was truly OTP. One example are the strike counters in Darjeeling to prevent firmware rollback. Software then implemented some form of integrity itself (e.g. by using multiple bits to increment the counter by one).
I think now that the OTP behavior is logically emulated using RSW, we can only apply this to the data part of the emulated OTP and leave the additional integrity part without RSW. This would mean we can use the additional integrity for all OTP partitions, thereby reducing hardware design and verification complexity, as well as software complexity (since software won't have to take care of integrity for strike counters etc.). What is your view on this?
There was a problem hiding this comment.
Are you suggesting to include the integrity in all cases and remove the case differentiation?
There was a problem hiding this comment.
ah you are talking about software. Yes we could have hardware integrity for all partitions and get rid of the extra software integrity.
| wvalid_o = 1'b1; | ||
| end | ||
| if (done_i) begin | ||
| if (mubi4_test_true_strict(mubi4_or_hi(zer_en_q, intg_en_q))) begin |
There was a problem hiding this comment.
My understanding is that test_true_strict() is okay here because if with a single bit flip in intg_en_q or zer_en_q one would manage to bypass the integrity update, this would result in integrity errors down the line. Does this makes sense? Is it worth documenting this?
There was a problem hiding this comment.
This is the intention indeed. I can add a comment in the code
| end | ||
| if (done_i) begin | ||
| if (mubi4_test_true_strict(mubi4_or_hi(zer_en_q, intg_en_q))) begin | ||
| state_d = StReqIntgWords; |
There was a problem hiding this comment.
Does this mean we read the integrity words before we have confirmed the write went though? Shouldn't we first wait for the write to conclude before starting with the integrity?
There was a problem hiding this comment.
both pages need to be read, updated and written. It was easier to first modify the integrity page, but it could also be done the other way round.
| if (rmw_en) begin | ||
| for (int k = 0; k <= otp_size_q; k++) begin | ||
| rram_word_d[(otp_off_q + k)*OtpWidth +: OtpWidth] = wdata_mod[k]; | ||
| if (mubi4_test_false_strict(zer_en_q)) begin | ||
| // Inconsistent write data. Detect if operation tried to clear a bit to zero. | ||
| if ((otp_wdata_q[k] & rdata[k]) != rdata[k]) begin | ||
| wdata_inconsistent = 1'b1; | ||
| end | ||
| end | ||
| end | ||
| end else if (intg_update) begin | ||
| rram_word_d[intg_ind_q*OtpIntgWidth +: OtpIntgWidth] = intg_q; | ||
| end else if (clr_buf) begin | ||
| rram_word_d = '0; | ||
| end else if (rvalid_i && rready_o) begin | ||
| if (data_err) begin | ||
| rram_word_d[bus_cnt_q*BusWidth +: BusWidth] = '1; | ||
| end else begin | ||
| rram_word_d[bus_cnt_q*BusWidth +: BusWidth] = rdata_i[BusWidth-1:0]; | ||
| end | ||
| end | ||
| end |
There was a problem hiding this comment.
This block of code effectively defines what is going to be written to the RRAM macro or returned to OTP_CTRL. The hardening is not ideal right now (multiple single-bit control signals are evaluated such as rmw_en, intg_update, data_err, clr_buf). But properly hardening that is going to be challenging because it's effectively a big multiplexer.
We need to reason why this is sufficient and document that. For example if we can say that for every OTP write operation, a read back is done afterwards to confirm the intended write went through, this is fine. Otherwise we have to come up with a smart countermeasure overarching this multiplexers, see https://opentitan.org/book/doc/security/implementation_guidelines/hardware/#recommendation-3-fault-injection-countermeasures for ideas. For example for a write operation, we could load the buffer with the right value (as we do now) and then re-check that value at the end of the operation is still the same (in StWaitWrite). WDYT?
There was a problem hiding this comment.
Note that RRAM reads are 3 orders of magnitude faster than RRAM writes, so the overhead of read-verify in RRAM is not big, plus it has better coverage than consistency checks within the controller because it also covers inter-RRAM write tampering. I think we should consider read-verify after every RRAM write (regardless of OTP or not).
There was a problem hiding this comment.
I think we could recheck at the end of the StWaitWrite. Or maybe just readback the written words.
There was a problem hiding this comment.
For all integrity enabled partitions (all but the test partition) we would have integrity mismatches. Tampering with this mux would get detected.
There was a problem hiding this comment.
Ok I think, we can store a local copy of the address and read back the data to confirm it has been properly written. I will add this
There was a problem hiding this comment.
ok I have added the read-back for all write operations.
In the beginning of the operation we store two addresses: addr_q (address of the OTP data word), addr_intg_q (address of the integrity word).
We then read the data and integrity word, update them with RSM and write them back. In the end of the operation the data word is read again and its integrity is compared to the previously computed integrity word.
Please note: In addition to the implemented read-back otp_ctrl itself performs regular read operations to verify the partition integrity.
elliotb-lowrisc
left a comment
There was a problem hiding this comment.
I think I need a bit more context. Could you write some high-level documentation, perhaps including a graphical or textural breakdown of the partitions/regions/pages and how they relate to the higher-level address spaces (e.g. otp_ctrl partitions) and the underlying RRAM macros?
| All errors except for multi-bit ECC errors (!!FAULT_STATUS.PHY_RELBL_ERR). | ||
| Once set, they remain set until reset. |
There was a problem hiding this comment.
Could you clarify these two lines a bit? I think it is supposed to convey that these are all un-clearable errors except for the multi-bit ECC condition which may or may not be clearable
There was a problem hiding this comment.
This is not related to this PR.
The explanation can be found a bit below in the description of the phy_relbl_err bit:
Note that this error bit can be cleared to allow firmware dealing with multi-bit ECC errors during firmware selection and verification. After passing this stage, it is recommended that firmware classifies the corresponding alert as fatal on the receiver end, i.e, inside the alert handler.
cb9246e to
81aa182
Compare
A first documentation can be found here: and there is also information in the RFC , |
dfc76c9 to
2c58837
Compare
2c58837 to
bcac448
Compare
| wvalid_o = 1'b1; | ||
| end | ||
| if (done_i) begin | ||
| if (mubi4_test_true_strict(zer_en_q)) begin |
There was a problem hiding this comment.
Maybe a dumb question: Up until this point the sequence of operations for writing an integrity protected word or a zeroized word is identical, why do we immediately skip into the read state when writing the zeroized integrity bits but wait for this write to complete in the other case?
There was a problem hiding this comment.
good question. The reason is that the write is a blocking operation. The read will also wait for the write to complete. We could also jump to the wait state and then go to the read, it would be the same
bcac448 to
930c56f
Compare
b89448f to
17c6cbb
Compare
This commit adds the plug between rram_ctrl and otp_ctrl and will replace otp_macro. It converts otp_ctrl transactions to rram read/write operations. The following operations are supported: - Read, ReadRaw - Write, WriteRaw - Init - Zeroize All values are protected with an additional integrity check value that must match (except for ReadRaw/WriteRaw) Signed-off-by: Michael Gautschi <mgautschi@lowrisc.org>
The requests from otp_ctrl to rram_ctrl come from the otp_clk domain (clk_io4) and need to be synchronized to the main clock domain (system clock). Two FIFOs (prim_fifo_async_simple) have been added for the request and response path. Signed-off-by: Michael Gautschi <mgautschi@lowrisc.org>
And fix remaining issues in rram_ctrl_otp and top. rram_ctrl_otp required a waifer for FOR_LOOP_BOUNDS, VAR_INDEX_RANGE, LOOP_VAR_OP. Signed-off-by: Michael Gautschi <mgautschi@lowrisc.org>
After manufacturing the RRAM is unprogrammed and OTP read commands will result in garbage and integrity mismatches if the read path tries to remove the address infection. Addr-infection has been disabled for the full OTP region. Integrity is guaranteed with the separate integrity word stored in the integrity page. Signed-off-by: Michael Gautschi <mgautschi@lowrisc.org>
RRAM write operations are less protected than read operations. Therefore, every OTP write is verified with a subsequent read-back. If the readback does not match the original data, an alert is created. (same behaviour as for an OTP read with integrity) Signed-off-by: Michael Gautschi <mgautschi@lowrisc.org>
17c6cbb to
20dca29
Compare
As per RFC , Earlgrey will be extended with support for RRAM based non-volatile memory.
This 8th PR adds the otp hw module for the RRAM controller.
rram_ctrl_otp.sv: A FSM that performs the read-set-write algorithm and supports all commands issued byotp_ctrl.This PR also adds the DV for this module with a new testcase:dvsim hw/ip/rram_ctrl/dv/rram_ctrl_sim_cfg.hjson -i rram_ctrl_otpThe smoke test is also extended to issue OTP transactions.This PR also enables the lint flow for the full module that was disabled in the first PR (see #30366 (comment))
This PR is based on #30411