Skip to content

Commit 39463d6

Browse files
committed
[nrf fromtree] soc: nordic: uicr: Add support for SECURESTORAGE
Add UICR.SECURESTORAGE configuration based on device tree partitions. Validates partition layout and populates size fields in 1KB units. Handles missing partitions gracefully. Signed-off-by: Sebastian Bøe <[email protected]> (cherry picked from commit 38a0f71)
1 parent 2c60073 commit 39463d6

File tree

4 files changed

+266
-1
lines changed

4 files changed

+266
-1
lines changed

scripts/ci/check_compliance.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,6 +1303,7 @@ def check_no_undef_outside_kconfig(self, kconf):
13031303
"GEN_UICR_GENERATE_PERIPHCONF", # Used in specialized build tool, not part of main Kconfig
13041304
"GEN_UICR_SECONDARY", # Used in specialized build tool, not part of main Kconfig
13051305
"GEN_UICR_SECONDARY_GENERATE_PERIPHCONF", # Used in specialized build tool, not part of main Kconfig
1306+
"GEN_UICR_SECURESTORAGE", # Used in specialized build tool, not part of main Kconfig
13061307
"HEAP_MEM_POOL_ADD_SIZE_", # Used as an option matching prefix
13071308
"HUGETLBFS", # Linux, in boards/xtensa/intel_adsp_cavs25/doc
13081309
"IAR_BUFFERED_WRITE",

soc/nordic/common/uicr/gen_uicr.py

Lines changed: 197 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
import argparse
99
import ctypes as c
1010
import sys
11-
from itertools import groupby
11+
from itertools import groupby, pairwise
12+
from typing import NamedTuple
1213

1314
from elftools.elf.elffile import ELFFile
1415
from intelhex import IntelHex
@@ -29,6 +30,14 @@
2930
class ScriptError(RuntimeError): ...
3031

3132

33+
class PartitionInfo(NamedTuple):
34+
"""Information about a partition for secure storage validation."""
35+
36+
address: int
37+
size: int
38+
name: str
39+
40+
3241
class PeriphconfEntry(c.LittleEndianStructure):
3342
_pack_ = 1
3443
_fields_ = [
@@ -198,6 +207,105 @@ class Uicr(c.LittleEndianStructure):
198207
]
199208

200209

210+
def validate_secure_storage_partitions(args: argparse.Namespace) -> None:
211+
"""
212+
Validate that secure storage partitions are laid out correctly.
213+
214+
Args:
215+
args: Parsed command line arguments containing partition information
216+
217+
Raises:
218+
ScriptError: If validation fails
219+
"""
220+
# Expected order: cpuapp_crypto_partition, cpurad_crypto_partition,
221+
# cpuapp_its_partition, cpurad_its_partition
222+
partitions = [
223+
PartitionInfo(
224+
args.cpuapp_crypto_address, args.cpuapp_crypto_size, "cpuapp_crypto_partition"
225+
),
226+
PartitionInfo(
227+
args.cpurad_crypto_address, args.cpurad_crypto_size, "cpurad_crypto_partition"
228+
),
229+
PartitionInfo(args.cpuapp_its_address, args.cpuapp_its_size, "cpuapp_its_partition"),
230+
PartitionInfo(args.cpurad_its_address, args.cpurad_its_size, "cpurad_its_partition"),
231+
]
232+
233+
# Filter out zero-sized partitions (missing partitions)
234+
present_partitions = [p for p in partitions if p.size > 0]
235+
236+
# Require at least one subpartition to be present
237+
if not present_partitions:
238+
raise ScriptError(
239+
"At least one secure storage subpartition must be defined. "
240+
"Define one or more of: cpuapp_crypto_partition, cpurad_crypto_partition, "
241+
"cpuapp_its_partition, cpurad_its_partition"
242+
)
243+
244+
# Check 4KB alignment for secure storage start address
245+
if args.securestorage_address % 4096 != 0:
246+
raise ScriptError(
247+
f"Secure storage address {args.securestorage_address:#x} must be aligned to 4KB "
248+
f"(4096 bytes)"
249+
)
250+
251+
# Check 4KB alignment for secure storage size
252+
if args.securestorage_size % 4096 != 0:
253+
raise ScriptError(
254+
f"Secure storage size {args.securestorage_size} bytes must be aligned to 4KB "
255+
f"(4096 bytes)"
256+
)
257+
258+
# Check that the first present partition starts at the secure storage address
259+
first_partition = present_partitions[0]
260+
if first_partition.address != args.securestorage_address:
261+
raise ScriptError(
262+
f"First partition {first_partition.name} starts at {first_partition.address:#x}, "
263+
f"but must start at secure storage address {args.securestorage_address:#x}"
264+
)
265+
266+
# Check that all present partitions have sizes that are multiples of 1KB
267+
for partition in present_partitions:
268+
if partition.size % 1024 != 0:
269+
raise ScriptError(
270+
f"Partition {partition.name} has size {partition.size} bytes, but must be "
271+
f"a multiple of 1024 bytes (1KB)"
272+
)
273+
274+
# Check that partitions are in correct order and don't overlap
275+
for curr_partition, next_partition in pairwise(present_partitions):
276+
# Check order - partitions should be in ascending address order
277+
if curr_partition.address >= next_partition.address:
278+
raise ScriptError(
279+
f"Partition {curr_partition.name} (starts at {curr_partition.address:#x}) "
280+
f"must come before {next_partition.name} (starts at {next_partition.address:#x})"
281+
)
282+
283+
# Check for overlap
284+
curr_end = curr_partition.address + curr_partition.size
285+
if curr_end > next_partition.address:
286+
raise ScriptError(
287+
f"Partition {curr_partition.name} (ends at {curr_end:#x}) overlaps with "
288+
f"{next_partition.name} (starts at {next_partition.address:#x})"
289+
)
290+
291+
# Check for gaps (should be no gaps between consecutive partitions)
292+
if curr_end < next_partition.address:
293+
gap = next_partition.address - curr_end
294+
raise ScriptError(
295+
f"Gap of {gap} bytes between {curr_partition.name} (ends at {curr_end:#x}) and "
296+
f"{next_partition.name} (starts at {next_partition.address:#x})"
297+
)
298+
299+
# Check that combined subpartition sizes equal secure_storage_partition size
300+
total_subpartition_size = sum(p.size for p in present_partitions)
301+
if total_subpartition_size != args.securestorage_size:
302+
raise ScriptError(
303+
f"Combined size of subpartitions ({total_subpartition_size} bytes) does not match "
304+
f"secure_storage_partition size ({args.securestorage_size} bytes). "
305+
f"The definition is not coherent."
306+
)
307+
308+
201309
def main() -> None:
202310
parser = argparse.ArgumentParser(
203311
allow_abbrev=False,
@@ -255,6 +363,71 @@ def main() -> None:
255363
type=lambda s: int(s, 0),
256364
help="Absolute flash address of the UICR region (decimal or 0x-prefixed hex)",
257365
)
366+
parser.add_argument(
367+
"--securestorage",
368+
action="store_true",
369+
help="Enable secure storage support in UICR",
370+
)
371+
parser.add_argument(
372+
"--securestorage-address",
373+
default=None,
374+
type=lambda s: int(s, 0),
375+
help="Absolute flash address of the secure storage partition (decimal or 0x-prefixed hex)",
376+
)
377+
parser.add_argument(
378+
"--securestorage-size",
379+
default=None,
380+
type=lambda s: int(s, 0),
381+
help="Size in bytes of the secure storage partition (decimal or 0x-prefixed hex)",
382+
)
383+
parser.add_argument(
384+
"--cpuapp-crypto-address",
385+
default=0,
386+
type=lambda s: int(s, 0),
387+
help="Absolute flash address of cpuapp_crypto_partition (decimal or 0x-prefixed hex)",
388+
)
389+
parser.add_argument(
390+
"--cpuapp-crypto-size",
391+
default=0,
392+
type=lambda s: int(s, 0),
393+
help="Size in bytes of cpuapp_crypto_partition (decimal or 0x-prefixed hex)",
394+
)
395+
parser.add_argument(
396+
"--cpurad-crypto-address",
397+
default=0,
398+
type=lambda s: int(s, 0),
399+
help="Absolute flash address of cpurad_crypto_partition (decimal or 0x-prefixed hex)",
400+
)
401+
parser.add_argument(
402+
"--cpurad-crypto-size",
403+
default=0,
404+
type=lambda s: int(s, 0),
405+
help="Size in bytes of cpurad_crypto_partition (decimal or 0x-prefixed hex)",
406+
)
407+
parser.add_argument(
408+
"--cpuapp-its-address",
409+
default=0,
410+
type=lambda s: int(s, 0),
411+
help="Absolute flash address of cpuapp_its_partition (decimal or 0x-prefixed hex)",
412+
)
413+
parser.add_argument(
414+
"--cpuapp-its-size",
415+
default=0,
416+
type=lambda s: int(s, 0),
417+
help="Size in bytes of cpuapp_its_partition (decimal or 0x-prefixed hex)",
418+
)
419+
parser.add_argument(
420+
"--cpurad-its-address",
421+
default=0,
422+
type=lambda s: int(s, 0),
423+
help="Absolute flash address of cpurad_its_partition (decimal or 0x-prefixed hex)",
424+
)
425+
parser.add_argument(
426+
"--cpurad-its-size",
427+
default=0,
428+
type=lambda s: int(s, 0),
429+
help="Size in bytes of cpurad_its_partition (decimal or 0x-prefixed hex)",
430+
)
258431
parser.add_argument(
259432
"--secondary",
260433
action="store_true",
@@ -327,12 +500,35 @@ def main() -> None:
327500
"--out-secondary-periphconf-hex is used"
328501
)
329502

503+
# Validate secure storage argument dependencies
504+
if args.securestorage:
505+
if args.securestorage_address is None:
506+
raise ScriptError(
507+
"--securestorage-address is required when --securestorage is used"
508+
)
509+
if args.securestorage_size is None:
510+
raise ScriptError("--securestorage-size is required when --securestorage is used")
511+
512+
# Validate partition layout
513+
validate_secure_storage_partitions(args)
514+
330515
init_values = DISABLED_VALUE.to_bytes(4, "little") * (c.sizeof(Uicr) // 4)
331516
uicr = Uicr.from_buffer_copy(init_values)
332517

333518
uicr.VERSION.MAJOR = UICR_FORMAT_VERSION_MAJOR
334519
uicr.VERSION.MINOR = UICR_FORMAT_VERSION_MINOR
335520

521+
# Handle secure storage configuration
522+
if args.securestorage:
523+
uicr.SECURESTORAGE.ENABLE = ENABLED_VALUE
524+
uicr.SECURESTORAGE.ADDRESS = args.securestorage_address
525+
526+
# Set partition sizes in 1KB units
527+
uicr.SECURESTORAGE.CRYPTO.APPLICATIONSIZE1KB = args.cpuapp_crypto_size // 1024
528+
uicr.SECURESTORAGE.CRYPTO.RADIOCORESIZE1KB = args.cpurad_crypto_size // 1024
529+
uicr.SECURESTORAGE.ITS.APPLICATIONSIZE1KB = args.cpuapp_its_size // 1024
530+
uicr.SECURESTORAGE.ITS.RADIOCORESIZE1KB = args.cpurad_its_size // 1024
531+
336532
# Process periphconf data first and configure UICR completely before creating hex objects
337533
periphconf_hex = IntelHex()
338534
secondary_periphconf_hex = IntelHex()

soc/nordic/common/uicr/gen_uicr/CMakeLists.txt

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,25 @@ function(compute_partition_address_and_size partition_nodelabel output_address_v
4444
set(${output_size_var} ${partition_size} PARENT_SCOPE)
4545
endfunction()
4646

47+
# Function to compute optional partition address and size from devicetree
48+
# If partition doesn't exist, sets both address and size to 0
49+
function(compute_optional_partition_address_and_size partition_nodelabel output_address_var output_size_var)
50+
# Initialize with default values
51+
set(${output_address_var} 0 PARENT_SCOPE)
52+
set(${output_size_var} 0 PARENT_SCOPE)
53+
54+
# Check if partition exists
55+
dt_nodelabel(partition_path NODELABEL ${partition_nodelabel} QUIET)
56+
if(partition_path)
57+
# Call nested function with different variable names to avoid naming conflicts
58+
compute_partition_address_and_size(${partition_nodelabel} temp_addr temp_size)
59+
60+
# Copy the results to the output variables in parent scope
61+
set(${output_address_var} ${temp_addr} PARENT_SCOPE)
62+
set(${output_size_var} ${temp_size} PARENT_SCOPE)
63+
endif()
64+
endfunction()
65+
4766
# Use CMAKE_VERBOSE_MAKEFILE to silence an unused-variable warning.
4867
if(CMAKE_VERBOSE_MAKEFILE)
4968
endif()
@@ -60,6 +79,32 @@ set(secondary_periphconf_hex_file ${APPLICATION_BINARY_DIR}/zephyr/secondary_per
6079
dt_nodelabel(uicr_path NODELABEL "uicr" REQUIRED)
6180
dt_reg_addr(UICR_ADDRESS PATH ${uicr_path} REQUIRED)
6281

82+
# Handle secure storage configuration
83+
set(securestorage_args)
84+
if(CONFIG_GEN_UICR_SECURESTORAGE)
85+
list(APPEND securestorage_args --securestorage)
86+
87+
# Extract secure storage partition information (required)
88+
compute_partition_address_and_size("secure_storage_partition" SECURE_STORAGE_ADDRESS SECURE_STORAGE_SIZE)
89+
list(APPEND securestorage_args --securestorage-address ${SECURE_STORAGE_ADDRESS})
90+
list(APPEND securestorage_args --securestorage-size ${SECURE_STORAGE_SIZE})
91+
92+
# Extract individual partition information for validation (optional partitions)
93+
compute_optional_partition_address_and_size("cpuapp_crypto_partition" CPUAPP_CRYPTO_ADDRESS CPUAPP_CRYPTO_SIZE)
94+
compute_optional_partition_address_and_size("cpurad_crypto_partition" CPURAD_CRYPTO_ADDRESS CPURAD_CRYPTO_SIZE)
95+
compute_optional_partition_address_and_size("cpuapp_its_partition" CPUAPP_ITS_ADDRESS CPUAPP_ITS_SIZE)
96+
compute_optional_partition_address_and_size("cpurad_its_partition" CPURAD_ITS_ADDRESS CPURAD_ITS_SIZE)
97+
98+
list(APPEND securestorage_args --cpuapp-crypto-address ${CPUAPP_CRYPTO_ADDRESS})
99+
list(APPEND securestorage_args --cpuapp-crypto-size ${CPUAPP_CRYPTO_SIZE})
100+
list(APPEND securestorage_args --cpurad-crypto-address ${CPURAD_CRYPTO_ADDRESS})
101+
list(APPEND securestorage_args --cpurad-crypto-size ${CPURAD_CRYPTO_SIZE})
102+
list(APPEND securestorage_args --cpuapp-its-address ${CPUAPP_ITS_ADDRESS})
103+
list(APPEND securestorage_args --cpuapp-its-size ${CPUAPP_ITS_SIZE})
104+
list(APPEND securestorage_args --cpurad-its-address ${CPURAD_ITS_ADDRESS})
105+
list(APPEND securestorage_args --cpurad-its-size ${CPURAD_ITS_SIZE})
106+
endif(CONFIG_GEN_UICR_SECURESTORAGE)
107+
63108
if(CONFIG_GEN_UICR_GENERATE_PERIPHCONF)
64109
# gen_uicr.py parses all zephyr.elf files. To find these files (which
65110
# have not been built yet) we scan sibling build directories for
@@ -134,6 +179,7 @@ add_custom_command(
134179
--out-merged-hex ${merged_hex_file}
135180
--out-uicr-hex ${uicr_hex_file}
136181
${periphconf_args}
182+
${securestorage_args}
137183
${secondary_args}
138184
DEPENDS ${periphconf_elfs} ${secondary_periphconf_elfs}
139185
WORKING_DIRECTORY ${APPLICATION_BINARY_DIR}

soc/nordic/common/uicr/gen_uicr/Kconfig

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,28 @@ config GEN_UICR_SECONDARY_GENERATE_PERIPHCONF
2121
When enabled, the UICR generator will populate the
2222
secondary_periphconf_partition partition.
2323

24+
config GEN_UICR_SECURESTORAGE
25+
bool "Enable UICR.SECURESTORAGE"
26+
default y
27+
depends on $(dt_nodelabel_enabled,secure_storage_partition)
28+
help
29+
When enabled, the UICR generator will configure the
30+
secure storage region based on device tree partitions.
31+
32+
The following device tree partitions are used:
33+
- secure_storage_partition: Main secure storage partition (required)
34+
- cpuapp_crypto_partition: Application processor crypto storage (optional)
35+
- cpurad_crypto_partition: Radio core crypto storage (optional)
36+
- cpuapp_its_partition: Application processor internal trusted storage (optional)
37+
- cpurad_its_partition: Radio core internal trusted storage (optional)
38+
39+
Requirements:
40+
- The secure_storage_partition address and size must be aligned to 4KB
41+
- All subpartitions must be multiples of 1KB and laid out contiguously
42+
without gaps
43+
- At least one subpartition must be defined
44+
- Combined subpartition sizes must equal secure_storage_partition size
45+
2446
endmenu
2547

2648
source "Kconfig.zephyr"

0 commit comments

Comments
 (0)