Software APIs
rram_ctrl.c
1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5#include "sw/device/silicon_creator/lib/drivers/rram_ctrl.h"
6
7#include <assert.h>
8
14#include "sw/device/lib/base/multibits.h"
16#include "sw/device/silicon_creator/lib/drivers/otp.h"
17#include "sw/device/silicon_creator/lib/error.h"
18
19#include "hw/top/otp_ctrl_regs.h"
22
23/**
24 * Base address of the rram_ctrl registers.
25 *
26 * There is no devicetree (`dt_rram_ctrl`) support yet, unlike flash_ctrl,
27 * so the base address is taken directly from the autogenerated top-level
28 * memory map instead of `dt_rram_ctrl_primary_reg_block()`.
29 */
30static inline uint32_t rram_ctrl_core_base(void) {
32}
33
34/**
35 * RRAM transaction parameters.
36 */
37typedef struct transaction_params {
38 /**
39 * Start address of a RRAM transaction. Full byte address; the controller
40 * truncates to the closest word-aligned address.
41 */
42 uint32_t addr;
43 /**
44 * Operation type. Must be one of `RRAM_CTRL_CONTROL_OP_VALUE_*`.
45 */
46 uint32_t op_type;
47 /**
48 * Whether the transaction targets the info partition (true) or the data
49 * partition (false).
50 */
51 bool is_info;
52 /**
53 * Number of 32-bit words.
54 */
55 uint32_t word_count;
56} transaction_params_t;
57
58/**
59 * Starts a RRAM transaction.
60 *
61 * @param params Transaction parameters, see `transaction_params_t`.
62 */
63static void transaction_start(transaction_params_t params) {
64 abs_mmio_write32(rram_ctrl_core_base() + RRAM_CTRL_ADDR_REG_OFFSET,
65 params.addr);
66 uint32_t reg = bitfield_bit32_write(0, RRAM_CTRL_CONTROL_START_BIT, true);
67 reg = bitfield_field32_write(reg, RRAM_CTRL_CONTROL_OP_FIELD, params.op_type);
68 reg = bitfield_bit32_write(reg, RRAM_CTRL_CONTROL_PARTITION_BIT,
69 params.is_info);
70 reg = bitfield_field32_write(reg, RRAM_CTRL_CONTROL_NUM_FIELD,
71 params.word_count - 1);
72 abs_mmio_write32(rram_ctrl_core_base() + RRAM_CTRL_CONTROL_REG_OFFSET, reg);
73}
74
75/**
76 * Copies `word_count` words from the read FIFO to the given buffer.
77 *
78 * @param word_count Number of words to read from the FIFO.
79 * @param[out] data Output buffer.
80 */
81static void fifo_read(size_t word_count, void *data) {
82 size_t i = 0, r = word_count - 1;
83 for (; launder32(i) < word_count && launder32(r) < word_count; ++i, --r) {
84 write_32(
85 abs_mmio_read32(rram_ctrl_core_base() + RRAM_CTRL_RD_FIFO_REG_OFFSET),
86 data);
87 data = (char *)data + sizeof(uint32_t);
88 }
89 HARDENED_CHECK_EQ(i, word_count);
90 HARDENED_CHECK_EQ(r, SIZE_MAX);
91}
92
93/**
94 * Copies `word_count` words from the given buffer to the write FIFO.
95 *
96 * @param word_count Number of words to write to the FIFO.
97 * @param data Input buffer.
98 */
99static void fifo_write(size_t word_count, const void *data) {
100 size_t i = 0, r = word_count - 1;
101 for (; launder32(i) < word_count && launder32(r) < word_count; ++i, --r) {
102 abs_mmio_write32(rram_ctrl_core_base() + RRAM_CTRL_WR_FIFO_REG_OFFSET,
103 read_32(data));
104 data = (const char *)data + sizeof(uint32_t);
105 }
106 HARDENED_CHECK_EQ(i, word_count);
107 HARDENED_CHECK_EQ(r, SIZE_MAX);
108}
109
110/**
111 * Blocks until the current RRAM transaction is complete.
112 *
113 * @param error Error code to return in case of a RRAM controller error.
114 * @return The result of the operation.
115 */
117static rom_error_t wait_for_done(rom_error_t error) {
118 uint32_t op_status;
119 do {
120 op_status =
121 abs_mmio_read32(rram_ctrl_core_base() + RRAM_CTRL_OP_STATUS_REG_OFFSET);
122 } while (!bitfield_bit32_read(op_status, RRAM_CTRL_OP_STATUS_DONE_BIT));
123 abs_mmio_write32(rram_ctrl_core_base() + RRAM_CTRL_OP_STATUS_REG_OFFSET, 0u);
124
125 if (bitfield_bit32_read(op_status, RRAM_CTRL_OP_STATUS_ERR_BIT)) {
126 return error;
127 }
128 return kErrorOk;
129}
130
131/**
132 * RRAM controller write transaction word granularity: `write_aligned()` can
133 * only write a whole number of `kRramWriteGranuleWords`-word granules. All
134 * other addr/word_count combinations go through `write()`'s read-modify-write
135 * of the leading/trailing partial granules, so callers (like `nvm_ctrl.c`)
136 * never have to worry about alignment themselves.
137 */
138enum {
139 kRramWriteGranuleWords = 4,
140 kRramWriteGranuleBytes = kRramWriteGranuleWords * (uint32_t)sizeof(uint32_t),
141};
142static_assert((kRramWriteGranuleBytes & (kRramWriteGranuleBytes - 1)) == 0,
143 "RRAM write granule must be a power of two.");
144
145/**
146 * Reads data from the given partition.
147 *
148 * @param addr Full byte address to read from.
149 * @param is_info Whether to read from the info partition (true) or the data
150 * partition (false).
151 * @param word_count Number of bus words to read.
152 * @param[out] data Output buffer.
153 * @param error Error code to return in case of a RRAM controller error.
154 * @return Result of the operation.
155 */
157static rom_error_t read(uint32_t addr, bool is_info, uint32_t word_count,
158 void *data, rom_error_t error) {
159 transaction_start((transaction_params_t){
160 .addr = addr,
161 .op_type = RRAM_CTRL_CONTROL_OP_VALUE_READ,
162 .is_info = is_info,
163 .word_count = word_count,
164 });
165 fifo_read(word_count, data);
166 return wait_for_done(error);
167}
168
169/**
170 * Writes a `kRramWriteGranuleWords`-aligned, `kRramWriteGranuleWords`-sized
171 * number of words to the given partition.
172 *
173 * RRAM has no equivalent of flash's program-window restriction; writes are
174 * simply chunked to the maximum transaction word count.
175 *
176 * @param addr Full byte address to write to; must be
177 * `kRramWriteGranuleBytes`-aligned.
178 * @param is_info Whether to write to the info partition (true) or the data
179 * partition (false).
180 * @param word_count Number of bus words to write; must be a multiple of
181 * `kRramWriteGranuleWords`.
182 * @param data Data to write.
183 * @param error Error code to return in case of a RRAM controller error.
184 * @return Result of the operation.
185 */
187static rom_error_t write_aligned(uint32_t addr, bool is_info,
188 uint32_t word_count, const void *data,
189 rom_error_t error) {
190 enum {
191 kMaxWordCount = RRAM_CTRL_CONTROL_NUM_MASK + 1,
192 };
193 if (word_count % kRramWriteGranuleWords != 0) {
194 return error;
195 }
196
197 while (word_count > 0) {
198 uint32_t chunk_word_count =
199 word_count < kMaxWordCount ? word_count : kMaxWordCount;
200
201 transaction_start((transaction_params_t){
202 .addr = addr,
203 .op_type = RRAM_CTRL_CONTROL_OP_VALUE_WRITE,
204 .is_info = is_info,
205 .word_count = chunk_word_count,
206 });
207
208 fifo_write(chunk_word_count, data);
209 RETURN_IF_ERROR(wait_for_done(error));
210
211 addr += chunk_word_count * sizeof(uint32_t);
212 data = (const char *)data + chunk_word_count * sizeof(uint32_t);
213 word_count -= chunk_word_count;
214 }
215
216 return kErrorOk;
217}
218
219/**
220 * Read-modify-writes a single `kRramWriteGranuleBytes`-sized,
221 * `kRramWriteGranuleBytes`-aligned granule: reads the granule at
222 * `aligned_addr`, splices in `len` bytes of `data` at byte offset `lead`
223 * within it (`lead + len` must not exceed `kRramWriteGranuleBytes`), and
224 * writes the granule back.
225 */
227static rom_error_t granule_rmw(uint32_t aligned_addr, bool is_info, size_t lead,
228 const void *data, size_t len,
229 rom_error_t write_error,
230 rom_error_t read_error) {
231 uint8_t buf[kRramWriteGranuleBytes];
232 RETURN_IF_ERROR(
233 read(aligned_addr, is_info, kRramWriteGranuleWords, buf, read_error));
234 memcpy(buf + lead, data, len);
235 return write_aligned(aligned_addr, is_info, kRramWriteGranuleWords, buf,
236 write_error);
237}
238
239/**
240 * Writes `word_count` words (need not be a multiple of
241 * `kRramWriteGranuleWords`) to `addr` (need not be
242 * `kRramWriteGranuleBytes`-aligned) in the given partition.
243 *
244 * Handles any size via read-modify-write on only the leading and trailing
245 * partial granules (at most `kRramWriteGranuleBytes` of stack buffer at a
246 * time); the aligned middle portion, if any, is written directly with no
247 * read. Unbounded in `word_count`.
248 *
249 * @param addr Full byte address to write to.
250 * @param is_info Whether to write to the info partition (true) or the data
251 * partition (false).
252 * @param word_count Number of bus words to write.
253 * @param data Data to write.
254 * @param write_error Error code to return in case of a write-transaction
255 * controller error.
256 * @param read_error Error code to return in case of a read-transaction
257 * controller error (only reachable via the RMW path).
258 * @return Result of the operation.
259 */
261static rom_error_t write(uint32_t addr, bool is_info, uint32_t word_count,
262 const void *data, rom_error_t write_error,
263 rom_error_t read_error) {
264 if (word_count == 0) {
265 return kErrorOk;
266 }
267
268 size_t byte_count = (size_t)word_count * sizeof(uint32_t);
269 uint32_t aligned_addr = addr & ~(uint32_t)(kRramWriteGranuleBytes - 1);
270 size_t lead = addr - aligned_addr;
271
272 if (lead == 0 && byte_count % kRramWriteGranuleBytes == 0) {
273 // Already granule-aligned on both ends: no RMW needed.
274 return write_aligned(addr, is_info, word_count, data, write_error);
275 }
276
277 // Leading (possibly partial) granule.
278 size_t first_chunk_len = kRramWriteGranuleBytes - lead;
279 if (first_chunk_len > byte_count) {
280 first_chunk_len = byte_count;
281 }
282 RETURN_IF_ERROR(granule_rmw(aligned_addr, is_info, lead, data,
283 first_chunk_len, write_error, read_error));
284 data = (const char *)data + first_chunk_len;
285 byte_count -= first_chunk_len;
286 aligned_addr += kRramWriteGranuleBytes;
287
288 // Aligned middle portion, written directly with no read.
289 size_t middle_words =
290 (byte_count / kRramWriteGranuleBytes) * kRramWriteGranuleWords;
291 if (middle_words > 0) {
292 RETURN_IF_ERROR(write_aligned(aligned_addr, is_info, (uint32_t)middle_words,
293 data, write_error));
294 size_t middle_bytes = middle_words * sizeof(uint32_t);
295 data = (const char *)data + middle_bytes;
296 byte_count -= middle_bytes;
297 aligned_addr += middle_bytes;
298 }
299
300 // Trailing partial granule.
301 if (byte_count > 0) {
302 RETURN_IF_ERROR(granule_rmw(aligned_addr, is_info, 0, data, byte_count,
303 write_error, read_error));
304 }
305 return kErrorOk;
306}
307
308void rram_ctrl_init(void) {
309 // The linker reserves `_nvm_slot_reserved_bytes` (top_earlgrey_memory.ld)
310 // at the tail of every slot; `kRramCtrlReservedPageCount` (rram_ctrl.h)
311 // must derive from that same 32KiB. Nothing at compile time ties a C
312 // constant to a linker symbol, so check they still agree here instead.
313 extern char _nvm_slot_reserved_bytes[];
315 (uint32_t)_nvm_slot_reserved_bytes,
316 kRramCtrlReservedPageCount * RRAM_CTRL_PARAM_BYTES_PER_PAGE);
317
318 SEC_MMIO_ASSERT_WRITE_INCREMENT(kRramCtrlSecMmioInit,
319 kRramCtrlSecMmioDataDefaultCfgSet);
320
321 // Set `HW_INFO_CFG_OVERRIDE` register if needed. Reuses the same OTP word
322 // and bit layout as flash_ctrl. This must be done before initializing the
323 // rram_ctrl.
324 uint32_t reg_val = RRAM_CTRL_HW_INFO_CFG_OVERRIDE_REG_RESVAL;
325 uint32_t otp_val =
326 otp_read32(OTP_CTRL_PARAM_CREATOR_SW_CFG_NVM_HW_INFO_CFG_OVERRIDE_OFFSET);
327 multi_bit_bool_t scramble_dis = bitfield_field32_read(
328 otp_val, RRAM_CTRL_OTP_FIELD_HW_INFO_CFG_OVERRIDE_SCRAMBLE_DIS);
329 if (scramble_dis == kMultiBitBool4True) {
330 reg_val = bitfield_field32_write(
331 reg_val, RRAM_CTRL_HW_INFO_CFG_OVERRIDE_SCRAMBLE_DIS_FIELD,
332 scramble_dis);
333 }
334 multi_bit_bool_t ecc_dis = bitfield_field32_read(
335 otp_val, RRAM_CTRL_OTP_FIELD_HW_INFO_CFG_OVERRIDE_ECC_DIS);
336 if (ecc_dis == kMultiBitBool4True) {
337 reg_val = bitfield_field32_write(
338 reg_val, RRAM_CTRL_HW_INFO_CFG_OVERRIDE_ECC_DIS_FIELD, ecc_dis);
339 }
340 if (reg_val != RRAM_CTRL_HW_INFO_CFG_OVERRIDE_REG_RESVAL) {
341 sec_mmio_write32(
342 rram_ctrl_core_base() + RRAM_CTRL_HW_INFO_CFG_OVERRIDE_REG_OFFSET,
343 reg_val);
344 }
345
346 // Kick off RRAM controller initialization and wait for completion. Unlike
347 // flash_ctrl, where memory protection only gates the controller's own
348 // transaction-based (FIFO) reads/writes, rram_ctrl's memory protection also
349 // gates the direct read path, so RD_EN must be set for the default region
350 // below before RRAM can be read at all.
351 abs_mmio_write32(rram_ctrl_core_base() + RRAM_CTRL_INIT_REG_OFFSET,
352 bitfield_bit32_write(0, RRAM_CTRL_INIT_VAL_BIT, true));
353 rram_ctrl_status_t status;
354 do {
355 rram_ctrl_status_get(&status);
356 } while (!status.init_done);
357
358 // Configure default scrambling and ECC settings for the data partition.
359 // Reuses the same `CREATOR_SW_CFG_NVM_DATA_DEFAULT_CFG` OTP word and bit
360 // layout as flash_ctrl; the high-endurance field does not apply to RRAM.
361 otp_val =
362 otp_read32(OTP_CTRL_PARAM_CREATOR_SW_CFG_NVM_DATA_DEFAULT_CFG_OFFSET);
363 rram_ctrl_cfg_t data_default_cfg = {
364 .scrambling =
365 bitfield_field32_read(otp_val, RRAM_CTRL_OTP_FIELD_SCRAMBLING),
366 .ecc = bitfield_field32_read(otp_val, RRAM_CTRL_OTP_FIELD_ECC),
367 };
368 rram_ctrl_data_default_cfg_set(data_default_cfg);
369}
370
371void rram_ctrl_disable(void) {
372 // DIS is rw1s with MuBi4 fields, so a write is merged into the current value.
373 // Writing MuBi4True to SW_DIS disables the RRAM, while writing MuBi4False to
374 // LOCAL_ESC_RELBL_ERR leaves that field unchanged.
375 uint32_t reg = bitfield_field32_write(
376 RRAM_CTRL_DIS_REG_RESVAL, RRAM_CTRL_DIS_SW_DIS_FIELD, kMultiBitBool4True);
377 abs_mmio_write32(rram_ctrl_core_base() + RRAM_CTRL_DIS_REG_OFFSET, reg);
378}
379
380void rram_ctrl_status_get(rram_ctrl_status_t *status) {
381 uint32_t reg =
382 abs_mmio_read32(rram_ctrl_core_base() + RRAM_CTRL_STATUS_REG_OFFSET);
383 status->rd_full = bitfield_bit32_read(reg, RRAM_CTRL_STATUS_RD_FULL_BIT);
384 status->rd_empty = bitfield_bit32_read(reg, RRAM_CTRL_STATUS_RD_EMPTY_BIT);
385 status->wr_full = bitfield_bit32_read(reg, RRAM_CTRL_STATUS_WR_FULL_BIT);
386 status->wr_empty = bitfield_bit32_read(reg, RRAM_CTRL_STATUS_WR_EMPTY_BIT);
387 status->init_done = bitfield_bit32_read(reg, RRAM_CTRL_STATUS_INIT_DONE_BIT);
388}
389
390void rram_ctrl_error_code_get(rram_ctrl_error_code_t *error_code) {
391 uint32_t code =
392 abs_mmio_read32(rram_ctrl_core_base() + RRAM_CTRL_ERR_CODE_REG_OFFSET);
393 error_code->op_err = bitfield_bit32_read(code, RRAM_CTRL_ERR_CODE_OP_ERR_BIT);
394 error_code->mp_err = bitfield_bit32_read(code, RRAM_CTRL_ERR_CODE_MP_ERR_BIT);
395 error_code->rd_err = bitfield_bit32_read(code, RRAM_CTRL_ERR_CODE_RD_ERR_BIT);
396 error_code->wr_err = bitfield_bit32_read(code, RRAM_CTRL_ERR_CODE_WR_ERR_BIT);
397}
398
399rom_error_t rram_ctrl_data_read(uint32_t addr, uint32_t word_count,
400 void *data) {
401 return read(addr, /*is_info=*/false, word_count, data,
402 kErrorRramCtrlDataRead);
403}
404
405static uint32_t info_page_addr(const rram_ctrl_info_page_t *info_page,
406 uint32_t offset) {
407 HARDENED_CHECK_EQ(info_page->emulated, false);
408 return info_page->page_id * RRAM_CTRL_PARAM_BYTES_PER_PAGE + offset;
409}
410
411rom_error_t rram_ctrl_info_read(const rram_ctrl_info_page_t *info_page,
412 uint32_t offset, uint32_t word_count,
413 void *data) {
414 return read(info_page_addr(info_page, offset), /*is_info=*/true, word_count,
415 data, kErrorRramCtrlInfoRead);
416}
417
418rom_error_t rram_ctrl_info_read_zeros_on_read_error(
419 const rram_ctrl_info_page_t *info_page, uint32_t offset,
420 uint32_t word_count, void *data) {
421 rom_error_t err = rram_ctrl_info_read(info_page, offset, word_count, data);
422 if (err != kErrorOk) {
423 rram_ctrl_error_code_t rram_ctrl_err_code;
424 rram_ctrl_error_code_get(&rram_ctrl_err_code);
425 if (rram_ctrl_err_code.rd_err) {
426 // If we encountered a read error, return all 0s.
427 memset(data, 0, word_count * sizeof(uint32_t));
428 return kErrorOk;
429 }
430 }
431 return err;
432}
433
434rom_error_t rram_ctrl_data_write(uint32_t addr, uint32_t word_count,
435 const void *data) {
436 return write(addr, /*is_info=*/false, word_count, data,
437 kErrorRramCtrlDataWrite, kErrorRramCtrlDataRead);
438}
439
440rom_error_t rram_ctrl_info_write(const rram_ctrl_info_page_t *info_page,
441 uint32_t offset, uint32_t word_count,
442 const void *data) {
443 return write(info_page_addr(info_page, offset), /*is_info=*/true, word_count,
444 data, kErrorRramCtrlInfoWrite, kErrorRramCtrlInfoRead);
445}
446
447void rram_ctrl_exec_set(uint32_t exec_val) {
448 SEC_MMIO_ASSERT_WRITE_INCREMENT(kRramCtrlSecMmioExecSet, 1);
449 sec_mmio_write32(rram_ctrl_core_base() + RRAM_CTRL_EXEC_REG_OFFSET, exec_val);
450}
451
452void rram_ctrl_data_default_perms_set(rram_ctrl_perms_t perms) {
453 SEC_MMIO_ASSERT_WRITE_INCREMENT(kRramCtrlSecMmioDataDefaultPermsSet, 1);
454
455 // Read first to preserve ECC and scrambling bits.
456 uint32_t reg = sec_mmio_read32(rram_ctrl_core_base() +
457 RRAM_CTRL_DEFAULT_REGION_REG_OFFSET);
458 reg = bitfield_field32_write(reg, RRAM_CTRL_DEFAULT_REGION_RD_EN_FIELD,
459 perms.read);
460 reg = bitfield_field32_write(reg, RRAM_CTRL_DEFAULT_REGION_WR_EN_FIELD,
461 perms.write);
462 sec_mmio_write32(rram_ctrl_core_base() + RRAM_CTRL_DEFAULT_REGION_REG_OFFSET,
463 reg);
464}
465
466void rram_ctrl_info_perms_set(const rram_ctrl_info_page_t *info_page,
467 rram_ctrl_perms_t perms) {
468 HARDENED_CHECK_EQ(info_page->emulated, false);
469 SEC_MMIO_ASSERT_WRITE_INCREMENT(kRramCtrlSecMmioInfoPermsSet, 1);
470
471 uint32_t cfg_offset = RRAM_CTRL_INFO_PAGE_CFG_0_REG_OFFSET +
472 info_page->page_id * sizeof(uint32_t);
473 // Read first to preserve ECC and scrambling bits.
474 uint32_t reg = sec_mmio_read32(rram_ctrl_core_base() + cfg_offset);
475 reg = bitfield_field32_write(reg, RRAM_CTRL_INFO_PAGE_CFG_0_EN_0_FIELD,
476 kMultiBitBool4True);
477 reg = bitfield_field32_write(reg, RRAM_CTRL_INFO_PAGE_CFG_0_RD_EN_0_FIELD,
478 perms.read);
479 reg = bitfield_field32_write(reg, RRAM_CTRL_INFO_PAGE_CFG_0_WR_EN_0_FIELD,
480 perms.write);
481 sec_mmio_write32(rram_ctrl_core_base() + cfg_offset, reg);
482}
483
484void rram_ctrl_data_default_cfg_set(rram_ctrl_cfg_t cfg) {
485 SEC_MMIO_ASSERT_WRITE_INCREMENT(kRramCtrlSecMmioDataDefaultCfgSet, 1);
486
487 // Read first to preserve permission bits.
488 uint32_t reg = sec_mmio_read32(rram_ctrl_core_base() +
489 RRAM_CTRL_DEFAULT_REGION_REG_OFFSET);
490 reg = bitfield_field32_write(reg, RRAM_CTRL_DEFAULT_REGION_SCRAMBLE_EN_FIELD,
491 cfg.scrambling);
492 reg = bitfield_field32_write(reg, RRAM_CTRL_DEFAULT_REGION_ECC_EN_FIELD,
493 cfg.ecc);
494 sec_mmio_write32(rram_ctrl_core_base() + RRAM_CTRL_DEFAULT_REGION_REG_OFFSET,
495 reg);
496}
497
498rram_ctrl_cfg_t rram_ctrl_data_default_cfg_get(void) {
499 const uint32_t default_region = sec_mmio_read32(
500 rram_ctrl_core_base() + RRAM_CTRL_DEFAULT_REGION_REG_OFFSET);
501 return (rram_ctrl_cfg_t){
502 .scrambling = bitfield_field32_read(
503 default_region, RRAM_CTRL_DEFAULT_REGION_SCRAMBLE_EN_FIELD),
504 .ecc = bitfield_field32_read(default_region,
505 RRAM_CTRL_DEFAULT_REGION_ECC_EN_FIELD),
506 };
507}
508
509rram_ctrl_cfg_t rram_ctrl_boot_data_cfg_get(void) {
510 uint32_t otp_val =
511 otp_read32(OTP_CTRL_PARAM_CREATOR_SW_CFG_NVM_INFO_BOOT_DATA_CFG_OFFSET);
512 return (rram_ctrl_cfg_t){
513 .scrambling =
514 bitfield_field32_read(otp_val, RRAM_CTRL_OTP_FIELD_SCRAMBLING),
515 .ecc = bitfield_field32_read(otp_val, RRAM_CTRL_OTP_FIELD_ECC),
516 };
517}
518
519void rram_ctrl_data_region_protect(rram_ctrl_region_index_t region,
520 uint32_t page_offset, uint32_t num_pages,
521 rram_ctrl_perms_t perms, rram_ctrl_cfg_t cfg,
522 hardened_bool_t lock) {
523 const uint32_t kBase = rram_ctrl_core_base();
524 HARDENED_CHECK_GE(region, 0);
525 HARDENED_CHECK_LT(region, RRAM_CTRL_PARAM_NUM_REGIONS);
526 // The hardware has no way to express an empty region
527 // (`rram_ctrl_mp_region_sel.sv` matches `addr <= base + size`, inclusive,
528 // so a zero size would protect exactly one page.
529 HARDENED_CHECK_GE(num_pages, 1);
530 region *= sizeof(uint32_t);
531
532 // Reset the region's configuration via the MP_REGION_CFG_${region}
533 // register. This temporarily disables memory protection for the region.
534 //
535 // We use abs_mmio here because we're going to re-write this value later
536 // and the intermediate REG_RESVAL should not be considered a valid data
537 // pattern in this register when we perform a sec_mmio check.
538 abs_mmio_write32(kBase + RRAM_CTRL_MP_REGION_CFG_0_REG_OFFSET + region,
539 RRAM_CTRL_MP_REGION_CFG_0_REG_RESVAL);
540
541 // Set the region's bounds in the MP_REGION_${region} register.
542 //
543 // `rram_ctrl_mp_region_sel.sv` matches `addr <= base + size` (inclusive),
544 // one page past the exclusive `[page_offset, page_offset + num_pages)`
545 // range this function documents. Write `num_pages - 1` to compensate, so
546 // callers keep using the exclusive convention; safe since `num_pages` is
547 // checked nonzero above.
548 uint32_t mp_region = RRAM_CTRL_MP_REGION_0_REG_RESVAL;
549 mp_region = bitfield_field32_write(
550 mp_region, RRAM_CTRL_MP_REGION_0_BASE_0_FIELD, page_offset);
551 mp_region = bitfield_field32_write(
552 mp_region, RRAM_CTRL_MP_REGION_0_SIZE_0_FIELD, num_pages - 1);
553 sec_mmio_write32(kBase + RRAM_CTRL_MP_REGION_0_REG_OFFSET + region,
554 mp_region);
555
556 // Write the new value of MP_REGION_CFG_${region}.
557 uint32_t mp_region_cfg = RRAM_CTRL_MP_REGION_CFG_0_REG_RESVAL;
558 mp_region_cfg = bitfield_field32_write(
559 mp_region_cfg, RRAM_CTRL_MP_REGION_CFG_0_ECC_EN_0_FIELD, cfg.ecc);
560 mp_region_cfg = bitfield_field32_write(
561 mp_region_cfg, RRAM_CTRL_MP_REGION_CFG_0_SCRAMBLE_EN_0_FIELD,
562 cfg.scrambling);
563 mp_region_cfg = bitfield_field32_write(
564 mp_region_cfg, RRAM_CTRL_MP_REGION_CFG_0_WR_EN_0_FIELD, perms.write);
565 mp_region_cfg = bitfield_field32_write(
566 mp_region_cfg, RRAM_CTRL_MP_REGION_CFG_0_RD_EN_0_FIELD, perms.read);
567 mp_region_cfg = bitfield_field32_write(
568 mp_region_cfg, RRAM_CTRL_MP_REGION_CFG_0_EN_0_FIELD, kMultiBitBool4True);
569
570 SEC_MMIO_ASSERT_WRITE_INCREMENT(kRramCtrlSecMmioDataRegionProtect, 2);
571 SEC_MMIO_ASSERT_WRITE_INCREMENT(kRramCtrlSecMmioDataRegionProtectLock, 1);
572 sec_mmio_write32(kBase + RRAM_CTRL_MP_REGION_CFG_0_REG_OFFSET + region,
573 mp_region_cfg);
574 if (lock != kHardenedBoolFalse) {
575 sec_mmio_write32(kBase + RRAM_CTRL_REGION_CFG_REGWEN_0_REG_OFFSET + region,
576 0);
577 }
578}
579
580void rram_ctrl_info_cfg_set(const rram_ctrl_info_page_t *info_page,
581 rram_ctrl_cfg_t cfg) {
582 HARDENED_CHECK_EQ(info_page->emulated, false);
583 SEC_MMIO_ASSERT_WRITE_INCREMENT(kRramCtrlSecMmioInfoCfgSet, 1);
584
585 uint32_t cfg_offset = RRAM_CTRL_INFO_PAGE_CFG_0_REG_OFFSET +
586 info_page->page_id * sizeof(uint32_t);
587 // Read first to preserve permission bits.
588 uint32_t reg = sec_mmio_read32(rram_ctrl_core_base() + cfg_offset);
589 reg = bitfield_field32_write(reg, RRAM_CTRL_INFO_PAGE_CFG_0_EN_0_FIELD,
590 kMultiBitBool4True);
591 reg = bitfield_field32_write(
592 reg, RRAM_CTRL_INFO_PAGE_CFG_0_SCRAMBLE_EN_0_FIELD, cfg.scrambling);
593 reg = bitfield_field32_write(reg, RRAM_CTRL_INFO_PAGE_CFG_0_ECC_EN_0_FIELD,
594 cfg.ecc);
595 sec_mmio_write32(rram_ctrl_core_base() + cfg_offset, reg);
596}
597
598void rram_ctrl_info_cfg_lock(const rram_ctrl_info_page_t *info_page) {
599 HARDENED_CHECK_EQ(info_page->emulated, false);
600 uint32_t regwen_offset = RRAM_CTRL_INFO_REGWEN_0_REG_OFFSET +
601 info_page->page_id * sizeof(uint32_t);
602 sec_mmio_write32(rram_ctrl_core_base() + regwen_offset, 0);
603}
604
605void rram_ctrl_info_page_lockdown(const rram_ctrl_info_page_t *info_page) {
606 HARDENED_CHECK_EQ(info_page->emulated, false);
607 uint32_t cfg_offset = RRAM_CTRL_INFO_PAGE_CFG_0_REG_OFFSET +
608 info_page->page_id * sizeof(uint32_t);
609 uint32_t regwen_offset = RRAM_CTRL_INFO_REGWEN_0_REG_OFFSET +
610 info_page->page_id * sizeof(uint32_t);
611 sec_mmio_write32(rram_ctrl_core_base() + cfg_offset, 0);
612 sec_mmio_write32(rram_ctrl_core_base() + regwen_offset, 0);
613}