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