Software APIs
nvm_ctrl.h
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#ifndef OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_NVM_CTRL_H_
6#define OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_NVM_CTRL_H_
7
8#include <stdint.h>
9
12#include "sw/device/lib/base/multibits.h"
13#include "sw/device/silicon_creator/lib/error.h"
14
15// Hardware parameter and address constants. Only nvm_ctrl.{h,c} may include
16// these headers directly; all other callers use the NVM_* aliases below.
17//
18// USE_FLASH/USE_RRAM select which backend's constants populate the NVM_*
19// aliases below; set per top by the `nvm_ctrl` build rule. Only the
20// flash_ctrl-backed implementation exists today (earlgrey,
21// englishbreakfast); a future RRAM-backed top would add a USE_RRAM branch
22// here with its own includes.
23#if defined(USE_FLASH)
24#include "hw/top/flash_ctrl_regs.h"
25#if defined(OPENTITAN_IS_EARLGREY)
27#elif defined(OPENTITAN_IS_ENGLISHBREAKFAST)
29#else
30#error "USE_FLASH set for an unsupported top"
31#endif
32#elif !defined(USE_RRAM)
33#error "nvm_ctrl.h requires USE_FLASH or USE_RRAM to be defined"
34#endif
35
36#ifdef __cplusplus
37extern "C" {
38#endif
39
40// ---------------------------------------------------------------------------
41// NVM layout constants
42// ---------------------------------------------------------------------------
43
44#if defined(USE_FLASH)
45/** Byte size of one NVM page. */
46#define NVM_BYTES_PER_PAGE FLASH_CTRL_PARAM_BYTES_PER_PAGE
47/** Byte size of one NVM program/read word. */
48#define NVM_BYTES_PER_WORD FLASH_CTRL_PARAM_BYTES_PER_WORD
49/** Byte size of one NVM bank. */
50#define NVM_BYTES_PER_BANK FLASH_CTRL_PARAM_BYTES_PER_BANK
51/** Number of NVM banks. */
52#define NVM_NUM_BANKS FLASH_CTRL_PARAM_REG_NUM_BANKS
53/** Number of data pages per NVM bank. */
54#define NVM_PAGES_PER_BANK FLASH_CTRL_PARAM_REG_PAGES_PER_BANK
55#if defined(OPENTITAN_IS_EARLGREY)
56/** Base address of the NVM data partition in the system memory map. */
57#define NVM_DATA_BASE_ADDR TOP_EARLGREY_FLASH_CTRL_MEM_BASE_ADDR
58/** Total byte size of the NVM data partition. */
59#define NVM_DATA_SIZE_BYTES TOP_EARLGREY_FLASH_CTRL_MEM_SIZE_BYTES
60#elif defined(OPENTITAN_IS_ENGLISHBREAKFAST)
61/** Base address of the NVM data partition in the system memory map. */
62#define NVM_DATA_BASE_ADDR TOP_ENGLISHBREAKFAST_FLASH_CTRL_MEM_BASE_ADDR
63/** Total byte size of the NVM data partition. */
64#define NVM_DATA_SIZE_BYTES TOP_ENGLISHBREAKFAST_FLASH_CTRL_MEM_SIZE_BYTES
65#endif
66#endif // USE_FLASH
67/** Byte size of one firmware slot (A or B); half of the data partition. */
68#define NVM_BYTES_PER_SLOT (NVM_DATA_SIZE_BYTES / 2)
69
70/** Value of a word in NVM after erase. */
71enum { kNvmErasedWord = UINT32_MAX };
72
73// ---------------------------------------------------------------------------
74// Access permission and configuration types
75// ---------------------------------------------------------------------------
76
77/**
78 * Access permission settings for an NVM page.
79 *
80 * Fields use `multi_bit_bool_t` values: `kMultiBitBool4True` enables the
81 * operation; `kMultiBitBool4False` disables it. Raw hardware register values
82 * are passed through without normalisation.
83 */
84typedef struct nvm_page_perms {
85 multi_bit_bool_t read;
86 multi_bit_bool_t write;
87 multi_bit_bool_t erase;
88} nvm_page_perms_t;
89
90/**
91 * Configuration settings for an NVM page.
92 *
93 * Fields use `multi_bit_bool_t` values: `kMultiBitBool4True` enables the
94 * feature; `kMultiBitBool4False` disables it. Raw hardware register values
95 * are passed through without normalisation.
96 */
97typedef struct nvm_page_cfg {
98 multi_bit_bool_t scrambling;
99 multi_bit_bool_t ecc;
100 multi_bit_bool_t he;
101} nvm_page_cfg_t;
102
103/** Read, write, and erase all enabled. */
104extern const nvm_page_perms_t kNvmPagePermsReadWrite;
105/** Read enabled; write and erase disabled. */
106extern const nvm_page_perms_t kNvmPagePermsReadOnly;
107/** All permissions disabled. */
108extern const nvm_page_perms_t kNvmPagePermsNone;
109/** Erase enabled; read and write disabled. */
110extern const nvm_page_perms_t kNvmPagePermsErase;
111
112/** Scrambling and ECC enabled; high-endurance disabled. */
113extern const nvm_page_cfg_t kNvmPageCfgScrambled;
114/** Scrambling disabled; ECC enabled; high-endurance disabled. */
115extern const nvm_page_cfg_t kNvmPageCfgPlain;
116/** Scrambling, ECC, and high-endurance all disabled. */
117extern const nvm_page_cfg_t kNvmPageCfgRaw;
118
119// ---------------------------------------------------------------------------
120// Info page identifiers
121// ---------------------------------------------------------------------------
122
123/**
124 * Named NVM info partition pages.
125 *
126 * Enum values are contiguous: bank 0 pages 0-9 map to values 0-9, bank 1
127 * pages 0-9 map to values 10-19. The mapping to physical hardware addresses
128 * is an internal detail of nvm_ctrl.c.
129 */
130typedef enum nvm_info_page {
131 // Bank 0
132 kNvmInfoPageFactoryId = 0,
133 kNvmInfoPageCreatorSecret = 1,
134 kNvmInfoPageOwnerSecret = 2,
135 kNvmInfoPageWaferAuthSecret = 3,
136 kNvmInfoPageAttestationKeySeeds = 4,
137 kNvmInfoPageOwnerReserved0 = 5,
138 kNvmInfoPageOwnerReserved1 = 6,
139 kNvmInfoPageOwnerReserved2 = 7,
140 kNvmInfoPageOwnerReserved3 = 8,
141 kNvmInfoPageFactoryCerts = 9,
142 // Bank 1
143 kNvmInfoPageBootData0 = 10,
144 kNvmInfoPageBootData1 = 11,
145 kNvmInfoPageOwnerSlot0 = 12,
146 kNvmInfoPageOwnerSlot1 = 13,
147 kNvmInfoPageCreatorReserved0 = 14,
148 kNvmInfoPageOwnerReserved4 = 15,
149 kNvmInfoPageOwnerReserved5 = 16,
150 kNvmInfoPageOwnerReserved6 = 17,
151 kNvmInfoPageOwnerReserved7 = 18,
152 kNvmInfoPageDiceCerts = 19,
153} nvm_info_page_t;
154
155// ---------------------------------------------------------------------------
156// SEC_MMIO write-increment constants
157// ---------------------------------------------------------------------------
158// Drop-in replacements for kFlashCtrlSecMmio* — identical numeric values.
159// Callers keep their SEC_MMIO_WRITE_INCREMENT() call sites; only the constant
160// name changes during migration.
161enum {
162 kNvmCtrlSecMmioCertInfoPageCreatorCfg = 2,
163 kNvmCtrlSecMmioCertInfoPageOwnerRestrict = 2,
164 kNvmCtrlSecMmioCertInfoPagesOwnerRestrict = 5,
165 kNvmCtrlSecMmioCreatorInfoPagesLockdown = 14,
166 kNvmCtrlSecMmioDataDefaultCfgSet = 1,
167 kNvmCtrlSecMmioDataDefaultPermsSet = 1,
168 kNvmCtrlSecMmioExecSet = 1,
169 kNvmCtrlSecMmioInfoCfgSet = 1,
170 kNvmCtrlSecMmioInfoCfgLock = 1,
171 kNvmCtrlSecMmioInfoPageLockdown = 2,
172 kNvmCtrlSecMmioInfoPermsSet = 1,
173 kNvmCtrlSecMmioBankErasePermsSet = 1,
174 kNvmCtrlSecMmioInit = 3,
175 kNvmCtrlSecMmioDataRegionProtect = 1,
176 kNvmCtrlSecMmioDataRegionProtectLock = 1,
177};
178
179// ---------------------------------------------------------------------------
180// Lifecycle
181// ---------------------------------------------------------------------------
182
183/**
184 * Kicks off initialization of the NVM controller.
185 *
186 * The caller is responsible for calling
187 * `SEC_MMIO_WRITE_INCREMENT(kNvmCtrlSecMmioInit)` when sec_mmio is used.
188 */
189void nvm_ctrl_init(void);
190
191/**
192 * Permanently disables the NVM controller.
193 */
194void nvm_ctrl_disable(void);
195
196// ---------------------------------------------------------------------------
197// Wire-format bridge (ownership layer only)
198// ---------------------------------------------------------------------------
199
200/**
201 * Translate a wire-format (bank, page) pair to a typed info page enum value.
202 *
203 * Intended for use only at the ownership-layer boundary, where page addresses
204 * are read from on-flash owner configuration structs that store raw bank and
205 * page integers. All NVM I/O then proceeds through the enum-based API.
206 *
207 * @param bank Bank index (must be < NVM_NUM_BANKS).
208 * @param page Page index within the info partition type 0.
209 * @param[out] out Translated info page enum value.
210 * @return kErrorOk on success, kErrorNvmCtrlInvalidInfoPage if out of range.
211 */
213rom_error_t nvm_ctrl_info_page_lookup(uint8_t bank, uint8_t page,
214 nvm_info_page_t *out);
215
216// ---------------------------------------------------------------------------
217// Data partition I/O
218// ---------------------------------------------------------------------------
219
221rom_error_t nvm_ctrl_data_read(uint32_t addr, uint32_t word_count, void *data);
222
224rom_error_t nvm_ctrl_data_write(uint32_t addr, uint32_t word_count,
225 const void *data);
226
228rom_error_t nvm_ctrl_data_erase(uint32_t addr);
229
231rom_error_t nvm_ctrl_data_erase_verify(uint32_t addr);
232
233/**
234 * Erases all NVM data banks.
235 *
236 * Enables bank-erase permissions, erases every bank, then re-disables
237 * bank-erase permissions. Bank count and addresses are internal details.
238 */
240rom_error_t nvm_ctrl_chip_erase(void);
241
242/**
243 * Verifies that all NVM data banks have been erased.
244 */
246rom_error_t nvm_ctrl_chip_erase_verify(void);
247
248/**
249 * Programs up to 256 bytes of NVM data starting at `addr`.
250 *
251 * If `byte_count` is not a multiple of the NVM word size it is rounded up to
252 * the next word boundary and padding bytes in `data` are set to 0xff. If
253 * `addr` is not 256-byte aligned the write is split so the first chunk fills
254 * up to the 256-byte boundary and the second starts at the aligned address,
255 * matching SPI PAGE_PROGRAM wrapping semantics. Write permissions are managed
256 * internally; the caller is responsible for address range validation.
257 *
258 * @param addr Start address; must be NVM-word aligned.
259 * @param byte_count Number of bytes to write.
260 * @param data Buffer; must be word aligned with room for up to one extra word
261 * of 0xff padding beyond `byte_count`.
262 */
264rom_error_t nvm_ctrl_page_program(uint32_t addr, size_t byte_count,
265 uint8_t *data);
266
267/**
268 * Erases the 4 KiB sector containing `addr` in the data partition.
269 *
270 * Because the NVM page size is 2 KiB, erasing a 4 KiB sector requires two
271 * consecutive page erases. `addr` is truncated to the nearest 4 KiB boundary
272 * before erasing; the caller is responsible for range validation.
273 * Erase permissions are managed internally.
274 */
276rom_error_t nvm_ctrl_sector_erase(uint32_t addr);
277
278// ---------------------------------------------------------------------------
279// Info page I/O
280// ---------------------------------------------------------------------------
281
283rom_error_t nvm_ctrl_info_read(nvm_info_page_t page, uint32_t offset,
284 uint32_t word_count, void *data);
285
286/**
287 * Read from an info page, returning all-zeros words on a read error.
288 */
290rom_error_t nvm_ctrl_info_read_zeros_on_read_error(nvm_info_page_t page,
291 uint32_t offset,
292 uint32_t word_count,
293 void *data);
294
296rom_error_t nvm_ctrl_info_write(nvm_info_page_t page, uint32_t offset,
297 uint32_t word_count, const void *data);
298
300rom_error_t nvm_ctrl_info_erase(nvm_info_page_t page);
301
302// ---------------------------------------------------------------------------
303// Permissions and configuration
304// ---------------------------------------------------------------------------
305
306/**
307 * Sets default access permissions for the data partition.
308 *
309 * The caller is responsible for calling
310 * `SEC_MMIO_WRITE_INCREMENT(kNvmCtrlSecMmioDataDefaultPermsSet)`.
311 */
312void nvm_ctrl_data_default_perms_set(nvm_page_perms_t perms);
313
314/**
315 * Sets access permissions for a named info page.
316 *
317 * The caller is responsible for calling
318 * `SEC_MMIO_WRITE_INCREMENT(kNvmCtrlSecMmioInfoPermsSet)`.
319 */
320void nvm_ctrl_info_perms_set(nvm_info_page_t page, nvm_page_perms_t perms);
321
322/**
323 * Sets default configuration for the data partition.
324 *
325 * The caller is responsible for calling
326 * `SEC_MMIO_WRITE_INCREMENT(kNvmCtrlSecMmioDataDefaultCfgSet)`.
327 */
328void nvm_ctrl_data_default_cfg_set(nvm_page_cfg_t cfg);
329
330/** Returns the current default configuration for the data partition. */
331nvm_page_cfg_t nvm_ctrl_data_default_cfg_get(void);
332
333/** Returns the boot-data info page configuration read from OTP. */
334nvm_page_cfg_t nvm_ctrl_boot_data_cfg_get(void);
335
336/**
337 * Sets configuration for a named info page.
338 *
339 * The caller is responsible for calling
340 * `SEC_MMIO_WRITE_INCREMENT(kNvmCtrlSecMmioInfoCfgSet)`.
341 */
342void nvm_ctrl_info_cfg_set(nvm_info_page_t page, nvm_page_cfg_t cfg);
343
344/**
345 * Write-locks configuration for a named info page.
346 *
347 * The caller is responsible for calling
348 * `SEC_MMIO_WRITE_INCREMENT(kNvmCtrlSecMmioInfoCfgLock)`.
349 */
350void nvm_ctrl_info_cfg_lock(nvm_info_page_t page);
351
352// ---------------------------------------------------------------------------
353// Data region protection
354// ---------------------------------------------------------------------------
355
356/**
357 * Configure memory protection for a data partition region.
358 *
359 * The caller is responsible for calling
360 * `SEC_MMIO_WRITE_INCREMENT(kNvmCtrlSecMmioDataRegionProtect)` (plus
361 * `kNvmCtrlSecMmioDataRegionProtectLock` when `lock` is true).
362 */
363void nvm_ctrl_data_region_protect(uint32_t region, uint32_t page_offset,
364 uint32_t num_pages, nvm_page_perms_t perms,
365 nvm_page_cfg_t cfg, hardened_bool_t lock);
366
367/**
368 * Set bank erase permissions for both NVM banks.
369 *
370 * The caller is responsible for calling
371 * `SEC_MMIO_WRITE_INCREMENT(kNvmCtrlSecMmioBankErasePermsSet)`.
372 */
373void nvm_ctrl_bank_erase_perms_set(hardened_bool_t enable);
374
375/**
376 * Enable or disable execution from NVM.
377 *
378 * The caller is responsible for calling
379 * `SEC_MMIO_WRITE_INCREMENT(kNvmCtrlSecMmioExecSet)`.
380 *
381 * @param exec_val `FLASH_CTRL_PARAM_EXEC_EN` enables execution; all other
382 * values disable it.
383 */
384void nvm_ctrl_exec_set(uint32_t exec_val);
385
386// ---------------------------------------------------------------------------
387// Lockdown and certificate page management
388// ---------------------------------------------------------------------------
389
390/** Certificate page configuration: scrambling and ECC enabled. */
391extern const nvm_page_cfg_t kNvmCertInfoPageCfg;
392/** Creator access: read, write, and erase enabled. */
393extern const nvm_page_perms_t kNvmCertInfoPageCreatorAccess;
394/** Owner access: read enabled; write and erase disabled. */
395extern const nvm_page_perms_t kNvmCertInfoPageOwnerAccess;
396
397/**
398 * Disables all access to silicon creator info pages until next reset.
399 *
400 * Must be called in ROM_EXT before handing over execution to the first owner
401 * boot stage.
402 *
403 * The caller is responsible for calling
404 * `SEC_MMIO_WRITE_INCREMENT(kNvmCtrlSecMmioCreatorInfoPagesLockdown)`.
405 */
406void nvm_ctrl_creator_info_pages_lockdown(void);
407
408/**
409 * Configures a certificate info page for full creator access.
410 *
411 * The caller is responsible for calling
412 * `SEC_MMIO_WRITE_INCREMENT(kNvmCtrlSecMmioCertInfoPageCreatorCfg)`.
413 */
414void nvm_ctrl_cert_info_page_creator_cfg(nvm_info_page_t page);
415
416/**
417 * Restricts a certificate info page to read-only for the silicon owner.
418 *
419 * The caller is responsible for calling
420 * `SEC_MMIO_WRITE_INCREMENT(kNvmCtrlSecMmioCertInfoPageOwnerRestrict)`.
421 */
422void nvm_ctrl_cert_info_page_owner_restrict(nvm_info_page_t page);
423
424// clang-format off
425/**
426 * Bitfields for the `access` word of owner NVM region configs.
427 */
428#define NVM_CONFIG_READ ((bitfield_field32_t) { .mask = 0xF, .index = 0 })
429#define NVM_CONFIG_PROGRAM ((bitfield_field32_t) { .mask = 0xF, .index = 4 })
430#define NVM_CONFIG_ERASE ((bitfield_field32_t) { .mask = 0xF, .index = 8 })
431#define NVM_CONFIG_PROTECT_WHEN_PRIMARY ((bitfield_field32_t) { .mask = 0xF, .index = 24 })
432#define NVM_CONFIG_LOCK ((bitfield_field32_t) { .mask = 0xF, .index = 28 })
433
434/**
435 * Bitfields for the `properties` word of owner NVM region configs.
436 */
437#define NVM_CONFIG_SCRAMBLE ((bitfield_field32_t) { .mask = 0xF, .index = 0 })
438#define NVM_CONFIG_ECC ((bitfield_field32_t) { .mask = 0xF, .index = 4 })
439#define NVM_CONFIG_HIGH_ENDURANCE ((bitfield_field32_t) { .mask = 0xF, .index = 8 })
440// clang-format on
441
442#ifdef __cplusplus
443}
444#endif
445
446#endif // OPENTITAN_SW_DEVICE_SILICON_CREATOR_LIB_NVM_CTRL_H_