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) {
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 abs_mmio_write32(rram_ctrl_core_base() + RRAM_CTRL_DIS_REG_OFFSET, 0);
373}
374
375void rram_ctrl_status_get(rram_ctrl_status_t *status) {
376 uint32_t reg =
377 abs_mmio_read32(rram_ctrl_core_base() + RRAM_CTRL_STATUS_REG_OFFSET);
378 status->rd_full = bitfield_bit32_read(reg, RRAM_CTRL_STATUS_RD_FULL_BIT);
379 status->rd_empty = bitfield_bit32_read(reg, RRAM_CTRL_STATUS_RD_EMPTY_BIT);
380 status->wr_full = bitfield_bit32_read(reg, RRAM_CTRL_STATUS_WR_FULL_BIT);
381 status->wr_empty = bitfield_bit32_read(reg, RRAM_CTRL_STATUS_WR_EMPTY_BIT);
382 status->init_done = bitfield_bit32_read(reg, RRAM_CTRL_STATUS_INIT_DONE_BIT);
383}
384
385void rram_ctrl_error_code_get(rram_ctrl_error_code_t *error_code) {
386 uint32_t code =
387 abs_mmio_read32(rram_ctrl_core_base() + RRAM_CTRL_ERR_CODE_REG_OFFSET);
388 error_code->op_err = bitfield_bit32_read(code, RRAM_CTRL_ERR_CODE_OP_ERR_BIT);
389 error_code->mp_err = bitfield_bit32_read(code, RRAM_CTRL_ERR_CODE_MP_ERR_BIT);
390 error_code->rd_err = bitfield_bit32_read(code, RRAM_CTRL_ERR_CODE_RD_ERR_BIT);
391 error_code->wr_err = bitfield_bit32_read(code, RRAM_CTRL_ERR_CODE_WR_ERR_BIT);
392}
393
394rom_error_t rram_ctrl_data_read(uint32_t addr, uint32_t word_count,
395 void *data) {
396 return read(addr, /*is_info=*/false, word_count, data,
397 kErrorRramCtrlDataRead);
398}
399
400static uint32_t info_page_addr(const rram_ctrl_info_page_t *info_page,
401 uint32_t offset) {
402 HARDENED_CHECK_EQ(info_page->emulated, false);
403 return info_page->page_id * RRAM_CTRL_PARAM_BYTES_PER_PAGE + offset;
404}
405
406rom_error_t rram_ctrl_info_read(const rram_ctrl_info_page_t *info_page,
407 uint32_t offset, uint32_t word_count,
408 void *data) {
409 return read(info_page_addr(info_page, offset), /*is_info=*/true, word_count,
410 data, kErrorRramCtrlInfoRead);
411}
412
413rom_error_t rram_ctrl_info_read_zeros_on_read_error(
414 const rram_ctrl_info_page_t *info_page, uint32_t offset,
415 uint32_t word_count, void *data) {
416 rom_error_t err = rram_ctrl_info_read(info_page, offset, word_count, data);
417 if (err != kErrorOk) {
418 rram_ctrl_error_code_t rram_ctrl_err_code;
419 rram_ctrl_error_code_get(&rram_ctrl_err_code);
420 if (rram_ctrl_err_code.rd_err) {
421 // If we encountered a read error, return all 0s.
422 memset(data, 0, word_count * sizeof(uint32_t));
423 return kErrorOk;
424 }
425 }
426 return err;
427}
428
429rom_error_t rram_ctrl_data_write(uint32_t addr, uint32_t word_count,
430 const void *data) {
431 return write(addr, /*is_info=*/false, word_count, data,
432 kErrorRramCtrlDataWrite, kErrorRramCtrlDataRead);
433}
434
435rom_error_t rram_ctrl_info_write(const rram_ctrl_info_page_t *info_page,
436 uint32_t offset, uint32_t word_count,
437 const void *data) {
438 return write(info_page_addr(info_page, offset), /*is_info=*/true, word_count,
439 data, kErrorRramCtrlInfoWrite, kErrorRramCtrlInfoRead);
440}
441
442void rram_ctrl_exec_set(uint32_t exec_val) {
443 SEC_MMIO_ASSERT_WRITE_INCREMENT(kRramCtrlSecMmioExecSet, 1);
444 sec_mmio_write32(rram_ctrl_core_base() + RRAM_CTRL_EXEC_REG_OFFSET, exec_val);
445}
446
447void rram_ctrl_data_default_perms_set(rram_ctrl_perms_t perms) {
448 SEC_MMIO_ASSERT_WRITE_INCREMENT(kRramCtrlSecMmioDataDefaultPermsSet, 1);
449
450 // Read first to preserve ECC and scrambling bits.
451 uint32_t reg = sec_mmio_read32(rram_ctrl_core_base() +
452 RRAM_CTRL_DEFAULT_REGION_REG_OFFSET);
453 reg = bitfield_field32_write(reg, RRAM_CTRL_DEFAULT_REGION_RD_EN_FIELD,
454 perms.read);
455 reg = bitfield_field32_write(reg, RRAM_CTRL_DEFAULT_REGION_WR_EN_FIELD,
456 perms.write);
457 sec_mmio_write32(rram_ctrl_core_base() + RRAM_CTRL_DEFAULT_REGION_REG_OFFSET,
458 reg);
459}
460
461void rram_ctrl_info_perms_set(const rram_ctrl_info_page_t *info_page,
462 rram_ctrl_perms_t perms) {
463 HARDENED_CHECK_EQ(info_page->emulated, false);
464 SEC_MMIO_ASSERT_WRITE_INCREMENT(kRramCtrlSecMmioInfoPermsSet, 1);
465
466 uint32_t cfg_offset = RRAM_CTRL_INFO_PAGE_CFG_0_REG_OFFSET +
467 info_page->page_id * sizeof(uint32_t);
468 // Read first to preserve ECC and scrambling bits.
469 uint32_t reg = sec_mmio_read32(rram_ctrl_core_base() + cfg_offset);
470 reg = bitfield_field32_write(reg, RRAM_CTRL_INFO_PAGE_CFG_0_EN_0_FIELD,
471 kMultiBitBool4True);
472 reg = bitfield_field32_write(reg, RRAM_CTRL_INFO_PAGE_CFG_0_RD_EN_0_FIELD,
473 perms.read);
474 reg = bitfield_field32_write(reg, RRAM_CTRL_INFO_PAGE_CFG_0_WR_EN_0_FIELD,
475 perms.write);
476 sec_mmio_write32(rram_ctrl_core_base() + cfg_offset, reg);
477}
478
479void rram_ctrl_data_default_cfg_set(rram_ctrl_cfg_t cfg) {
480 SEC_MMIO_ASSERT_WRITE_INCREMENT(kRramCtrlSecMmioDataDefaultCfgSet, 1);
481
482 // Read first to preserve permission bits.
483 uint32_t reg = sec_mmio_read32(rram_ctrl_core_base() +
484 RRAM_CTRL_DEFAULT_REGION_REG_OFFSET);
485 reg = bitfield_field32_write(reg, RRAM_CTRL_DEFAULT_REGION_SCRAMBLE_EN_FIELD,
486 cfg.scrambling);
487 reg = bitfield_field32_write(reg, RRAM_CTRL_DEFAULT_REGION_ECC_EN_FIELD,
488 cfg.ecc);
489 sec_mmio_write32(rram_ctrl_core_base() + RRAM_CTRL_DEFAULT_REGION_REG_OFFSET,
490 reg);
491}
492
493rram_ctrl_cfg_t rram_ctrl_data_default_cfg_get(void) {
494 const uint32_t default_region = sec_mmio_read32(
495 rram_ctrl_core_base() + RRAM_CTRL_DEFAULT_REGION_REG_OFFSET);
496 return (rram_ctrl_cfg_t){
497 .scrambling = bitfield_field32_read(
498 default_region, RRAM_CTRL_DEFAULT_REGION_SCRAMBLE_EN_FIELD),
499 .ecc = bitfield_field32_read(default_region,
500 RRAM_CTRL_DEFAULT_REGION_ECC_EN_FIELD),
501 };
502}
503
504rram_ctrl_cfg_t rram_ctrl_boot_data_cfg_get(void) {
505 uint32_t otp_val =
506 otp_read32(OTP_CTRL_PARAM_CREATOR_SW_CFG_NVM_INFO_BOOT_DATA_CFG_OFFSET);
507 return (rram_ctrl_cfg_t){
508 .scrambling =
509 bitfield_field32_read(otp_val, RRAM_CTRL_OTP_FIELD_SCRAMBLING),
510 .ecc = bitfield_field32_read(otp_val, RRAM_CTRL_OTP_FIELD_ECC),
511 };
512}
513
514void rram_ctrl_data_region_protect(rram_ctrl_region_index_t region,
515 uint32_t page_offset, uint32_t num_pages,
516 rram_ctrl_perms_t perms, rram_ctrl_cfg_t cfg,
517 hardened_bool_t lock) {
518 const uint32_t kBase = rram_ctrl_core_base();
519 HARDENED_CHECK_GE(region, 0);
520 HARDENED_CHECK_LT(region, RRAM_CTRL_PARAM_NUM_REGIONS);
521 // The hardware has no way to express an empty region
522 // (`rram_ctrl_mp_region_sel.sv` matches `addr <= base + size`, inclusive,
523 // so a zero size would protect exactly one page.
524 HARDENED_CHECK_GE(num_pages, 1);
525 region *= sizeof(uint32_t);
526
527 // Reset the region's configuration via the MP_REGION_CFG_${region}
528 // register. This temporarily disables memory protection for the region.
529 //
530 // We use abs_mmio here because we're going to re-write this value later
531 // and the intermediate REG_RESVAL should not be considered a valid data
532 // pattern in this register when we perform a sec_mmio check.
533 abs_mmio_write32(kBase + RRAM_CTRL_MP_REGION_CFG_0_REG_OFFSET + region,
534 RRAM_CTRL_MP_REGION_CFG_0_REG_RESVAL);
535
536 // Set the region's bounds in the MP_REGION_${region} register.
537 //
538 // `rram_ctrl_mp_region_sel.sv` matches `addr <= base + size` (inclusive),
539 // one page past the exclusive `[page_offset, page_offset + num_pages)`
540 // range this function documents. Write `num_pages - 1` to compensate, so
541 // callers keep using the exclusive convention; safe since `num_pages` is
542 // checked nonzero above.
543 uint32_t mp_region = RRAM_CTRL_MP_REGION_0_REG_RESVAL;
544 mp_region = bitfield_field32_write(
545 mp_region, RRAM_CTRL_MP_REGION_0_BASE_0_FIELD, page_offset);
546 mp_region = bitfield_field32_write(
547 mp_region, RRAM_CTRL_MP_REGION_0_SIZE_0_FIELD, num_pages - 1);
548 sec_mmio_write32(kBase + RRAM_CTRL_MP_REGION_0_REG_OFFSET + region,
549 mp_region);
550
551 // Write the new value of MP_REGION_CFG_${region}.
552 uint32_t mp_region_cfg = RRAM_CTRL_MP_REGION_CFG_0_REG_RESVAL;
553 mp_region_cfg = bitfield_field32_write(
554 mp_region_cfg, RRAM_CTRL_MP_REGION_CFG_0_ECC_EN_0_FIELD, cfg.ecc);
555 mp_region_cfg = bitfield_field32_write(
556 mp_region_cfg, RRAM_CTRL_MP_REGION_CFG_0_SCRAMBLE_EN_0_FIELD,
557 cfg.scrambling);
558 mp_region_cfg = bitfield_field32_write(
559 mp_region_cfg, RRAM_CTRL_MP_REGION_CFG_0_WR_EN_0_FIELD, perms.write);
560 mp_region_cfg = bitfield_field32_write(
561 mp_region_cfg, RRAM_CTRL_MP_REGION_CFG_0_RD_EN_0_FIELD, perms.read);
562 mp_region_cfg = bitfield_field32_write(
563 mp_region_cfg, RRAM_CTRL_MP_REGION_CFG_0_EN_0_FIELD, kMultiBitBool4True);
564
565 SEC_MMIO_ASSERT_WRITE_INCREMENT(kRramCtrlSecMmioDataRegionProtect, 2);
566 SEC_MMIO_ASSERT_WRITE_INCREMENT(kRramCtrlSecMmioDataRegionProtectLock, 1);
567 sec_mmio_write32(kBase + RRAM_CTRL_MP_REGION_CFG_0_REG_OFFSET + region,
568 mp_region_cfg);
569 if (lock != kHardenedBoolFalse) {
570 sec_mmio_write32(kBase + RRAM_CTRL_REGION_CFG_REGWEN_0_REG_OFFSET + region,
571 0);
572 }
573}
574
575void rram_ctrl_info_cfg_set(const rram_ctrl_info_page_t *info_page,
576 rram_ctrl_cfg_t cfg) {
577 HARDENED_CHECK_EQ(info_page->emulated, false);
578 SEC_MMIO_ASSERT_WRITE_INCREMENT(kRramCtrlSecMmioInfoCfgSet, 1);
579
580 uint32_t cfg_offset = RRAM_CTRL_INFO_PAGE_CFG_0_REG_OFFSET +
581 info_page->page_id * sizeof(uint32_t);
582 // Read first to preserve permission bits.
583 uint32_t reg = sec_mmio_read32(rram_ctrl_core_base() + cfg_offset);
584 reg = bitfield_field32_write(reg, RRAM_CTRL_INFO_PAGE_CFG_0_EN_0_FIELD,
585 kMultiBitBool4True);
586 reg = bitfield_field32_write(
587 reg, RRAM_CTRL_INFO_PAGE_CFG_0_SCRAMBLE_EN_0_FIELD, cfg.scrambling);
588 reg = bitfield_field32_write(reg, RRAM_CTRL_INFO_PAGE_CFG_0_ECC_EN_0_FIELD,
589 cfg.ecc);
590 sec_mmio_write32(rram_ctrl_core_base() + cfg_offset, reg);
591}
592
593void rram_ctrl_info_cfg_lock(const rram_ctrl_info_page_t *info_page) {
594 HARDENED_CHECK_EQ(info_page->emulated, false);
595 uint32_t regwen_offset = RRAM_CTRL_INFO_REGWEN_0_REG_OFFSET +
596 info_page->page_id * sizeof(uint32_t);
597 sec_mmio_write32(rram_ctrl_core_base() + regwen_offset, 0);
598}
599
600void rram_ctrl_info_page_lockdown(const rram_ctrl_info_page_t *info_page) {
601 HARDENED_CHECK_EQ(info_page->emulated, false);
602 uint32_t cfg_offset = RRAM_CTRL_INFO_PAGE_CFG_0_REG_OFFSET +
603 info_page->page_id * sizeof(uint32_t);
604 uint32_t regwen_offset = RRAM_CTRL_INFO_REGWEN_0_REG_OFFSET +
605 info_page->page_id * sizeof(uint32_t);
606 sec_mmio_write32(rram_ctrl_core_base() + cfg_offset, 0);
607 sec_mmio_write32(rram_ctrl_core_base() + regwen_offset, 0);
608}