Skip to content

Commit 07a4bee

Browse files
committed
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]>
1 parent f23b12d commit 07a4bee

File tree

4 files changed

+216
-1
lines changed

4 files changed

+216
-1
lines changed

scripts/ci/check_compliance.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,7 @@ def check_no_undef_outside_kconfig(self, kconf):
12661266
"GEN_UICR_GENERATE_PERIPHCONF", # Used in specialized build tool, not part of main Kconfig
12671267
"GEN_UICR_SECONDARY", # Used in specialized build tool, not part of main Kconfig
12681268
"GEN_UICR_SECONDARY_GENERATE_PERIPHCONF", # Used in specialized build tool, not part of main Kconfig
1269+
"GEN_UICR_SECURESTORAGE", # Used in specialized build tool, not part of main Kconfig
12691270
"HEAP_MEM_POOL_ADD_SIZE_", # Used as an option matching prefix
12701271
"HUGETLBFS", # Linux, in boards/xtensa/intel_adsp_cavs25/doc
12711272
"IAR_BUFFERED_WRITE",

soc/nordic/common/uicr/gen_uicr.py

Lines changed: 157 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,13 @@
2930
class ScriptError(RuntimeError): ...
3031

3132

33+
class PartitionInfo(NamedTuple):
34+
"""Information about a partition for secure storage validation."""
35+
address: int
36+
size: int
37+
name: str
38+
39+
3240
class PeriphconfEntry(c.LittleEndianStructure):
3341
_pack_ = 1
3442
_fields_ = [
@@ -198,6 +206,74 @@ class Uicr(c.LittleEndianStructure):
198206
]
199207

200208

209+
def validate_secure_storage_partitions(args: argparse.Namespace) -> None:
210+
"""
211+
Validate that secure storage partitions are laid out correctly.
212+
213+
Args:
214+
args: Parsed command line arguments containing partition information
215+
216+
Raises:
217+
ScriptError: If validation fails
218+
"""
219+
# Expected order: cpuapp_crypto_partition, cpurad_crypto_partition,
220+
# cpuapp_its_partition, cpurad_its_partition
221+
partitions = [
222+
PartitionInfo(args.cpuapp_crypto_address, args.cpuapp_crypto_size, "cpuapp_crypto_partition"),
223+
PartitionInfo(args.cpurad_crypto_address, args.cpurad_crypto_size, "cpurad_crypto_partition"),
224+
PartitionInfo(args.cpuapp_its_address, args.cpuapp_its_size, "cpuapp_its_partition"),
225+
PartitionInfo(args.cpurad_its_address, args.cpurad_its_size, "cpurad_its_partition"),
226+
]
227+
228+
# Filter out zero-sized partitions (missing partitions)
229+
present_partitions = [p for p in partitions if p.size > 0]
230+
231+
if not present_partitions:
232+
# No partitions present - this is valid
233+
return
234+
235+
# Check that the first present partition starts at the secure storage address
236+
first_partition = present_partitions[0]
237+
if first_partition.address != args.securestorage_address:
238+
raise ScriptError(
239+
f"First partition {first_partition.name} starts at {first_partition.address}, "
240+
f"but must start at secure storage address {args.securestorage_address}"
241+
)
242+
243+
# Check that all present partitions have sizes that are multiples of 1KB
244+
for partition in present_partitions:
245+
if partition.size % 1024 != 0:
246+
raise ScriptError(
247+
f"Partition {partition.name} has size {partition.size} bytes, but must be "
248+
f"a multiple of 1024 bytes (1KB)"
249+
)
250+
251+
# Check that partitions are in correct order and don't overlap
252+
for curr_partition, next_partition in pairwise(present_partitions):
253+
# Check order - partitions should be in ascending address order
254+
if curr_partition.address >= next_partition.address:
255+
raise ScriptError(
256+
f"Partition {curr_partition.name} (starts at {curr_partition.address}) "
257+
f"must come before {next_partition.name} (starts at {next_partition.address})"
258+
)
259+
260+
# Check for overlap
261+
curr_end = curr_partition.address + curr_partition.size
262+
if curr_end > next_partition.address:
263+
raise ScriptError(
264+
f"Partition {curr_partition.name} (ends at {curr_end}) overlaps with "
265+
f"{next_partition.name} (starts at {next_partition.address})"
266+
)
267+
268+
# Check for gaps (should be no gaps between consecutive partitions)
269+
if curr_end < next_partition.address:
270+
gap = next_partition.address - curr_end
271+
raise ScriptError(
272+
f"Gap of {gap} bytes between {curr_partition.name} (ends at {curr_end}) and "
273+
f"{next_partition.name} (starts at {next_partition.address})"
274+
)
275+
276+
201277
def main() -> None:
202278
parser = argparse.ArgumentParser(
203279
allow_abbrev=False,
@@ -255,6 +331,65 @@ def main() -> None:
255331
type=lambda s: int(s, 0),
256332
help="Absolute flash address of the UICR region (decimal or 0x-prefixed hex)",
257333
)
334+
parser.add_argument(
335+
"--securestorage",
336+
action="store_true",
337+
help="Enable secure storage support in UICR",
338+
)
339+
parser.add_argument(
340+
"--securestorage-address",
341+
default=None,
342+
type=lambda s: int(s, 0),
343+
help="Absolute flash address of the secure storage partition (decimal or 0x-prefixed hex)",
344+
)
345+
parser.add_argument(
346+
"--cpuapp-crypto-address",
347+
default=0,
348+
type=lambda s: int(s, 0),
349+
help="Absolute flash address of cpuapp_crypto_partition (decimal or 0x-prefixed hex)",
350+
)
351+
parser.add_argument(
352+
"--cpuapp-crypto-size",
353+
default=0,
354+
type=lambda s: int(s, 0),
355+
help="Size in bytes of cpuapp_crypto_partition (decimal or 0x-prefixed hex)",
356+
)
357+
parser.add_argument(
358+
"--cpurad-crypto-address",
359+
default=0,
360+
type=lambda s: int(s, 0),
361+
help="Absolute flash address of cpurad_crypto_partition (decimal or 0x-prefixed hex)",
362+
)
363+
parser.add_argument(
364+
"--cpurad-crypto-size",
365+
default=0,
366+
type=lambda s: int(s, 0),
367+
help="Size in bytes of cpurad_crypto_partition (decimal or 0x-prefixed hex)",
368+
)
369+
parser.add_argument(
370+
"--cpuapp-its-address",
371+
default=0,
372+
type=lambda s: int(s, 0),
373+
help="Absolute flash address of cpuapp_its_partition (decimal or 0x-prefixed hex)",
374+
)
375+
parser.add_argument(
376+
"--cpuapp-its-size",
377+
default=0,
378+
type=lambda s: int(s, 0),
379+
help="Size in bytes of cpuapp_its_partition (decimal or 0x-prefixed hex)",
380+
)
381+
parser.add_argument(
382+
"--cpurad-its-address",
383+
default=0,
384+
type=lambda s: int(s, 0),
385+
help="Absolute flash address of cpurad_its_partition (decimal or 0x-prefixed hex)",
386+
)
387+
parser.add_argument(
388+
"--cpurad-its-size",
389+
default=0,
390+
type=lambda s: int(s, 0),
391+
help="Size in bytes of cpurad_its_partition (decimal or 0x-prefixed hex)",
392+
)
258393
parser.add_argument(
259394
"--secondary",
260395
action="store_true",
@@ -327,12 +462,33 @@ def main() -> None:
327462
"--out-secondary-periphconf-hex is used"
328463
)
329464

465+
# Validate secure storage argument dependencies
466+
if args.securestorage:
467+
if args.securestorage_address is None:
468+
raise ScriptError(
469+
"--securestorage-address is required when --securestorage is used"
470+
)
471+
472+
# Validate partition layout
473+
validate_secure_storage_partitions(args)
474+
330475
init_values = DISABLED_VALUE.to_bytes(4, "little") * (c.sizeof(Uicr) // 4)
331476
uicr = Uicr.from_buffer_copy(init_values)
332477

333478
uicr.VERSION.MAJOR = UICR_FORMAT_VERSION_MAJOR
334479
uicr.VERSION.MINOR = UICR_FORMAT_VERSION_MINOR
335480

481+
# Handle secure storage configuration
482+
if args.securestorage:
483+
uicr.SECURESTORAGE.ENABLE = ENABLED_VALUE
484+
uicr.SECURESTORAGE.ADDRESS = args.securestorage_address
485+
486+
# Set partition sizes in 1KB units
487+
uicr.SECURESTORAGE.CRYPTO.APPLICATIONSIZE1KB = args.cpuapp_crypto_size // 1024
488+
uicr.SECURESTORAGE.CRYPTO.RADIOCORESIZE1KB = args.cpurad_crypto_size // 1024
489+
uicr.SECURESTORAGE.ITS.APPLICATIONSIZE1KB = args.cpuapp_its_size // 1024
490+
uicr.SECURESTORAGE.ITS.RADIOCORESIZE1KB = args.cpurad_its_size // 1024
491+
336492
# Process periphconf data first and configure UICR completely before creating hex objects
337493
periphconf_hex = IntelHex()
338494
secondary_periphconf_hex = IntelHex()

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,20 @@ 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+
compute_partition_address_and_size(${partition_nodelabel} ${output_address_var} ${output_size_var})
58+
endif()
59+
endfunction()
60+
4761
# Use CMAKE_VERBOSE_MAKEFILE to silence an unused-variable warning.
4862
if(CMAKE_VERBOSE_MAKEFILE)
4963
endif()
@@ -60,6 +74,31 @@ set(secondary_periphconf_hex_file ${APPLICATION_BINARY_DIR}/zephyr/secondary_per
6074
dt_nodelabel(uicr_path NODELABEL "uicr" REQUIRED)
6175
dt_reg_addr(UICR_ADDRESS PATH ${uicr_path} REQUIRED)
6276

77+
# Handle secure storage configuration
78+
set(securestorage_args)
79+
if(CONFIG_GEN_UICR_SECURESTORAGE)
80+
list(APPEND securestorage_args --securestorage)
81+
82+
# Extract secure storage partition information (required)
83+
compute_partition_address_and_size("secure_storage_partition" SECURE_STORAGE_ADDRESS SECURE_STORAGE_SIZE)
84+
list(APPEND securestorage_args --securestorage-address ${SECURE_STORAGE_ADDRESS})
85+
86+
# Extract individual partition information for validation (optional partitions)
87+
compute_optional_partition_address_and_size("cpuapp_crypto_partition" CPUAPP_CRYPTO_ADDRESS CPUAPP_CRYPTO_SIZE)
88+
compute_optional_partition_address_and_size("cpurad_crypto_partition" CPURAD_CRYPTO_ADDRESS CPURAD_CRYPTO_SIZE)
89+
compute_optional_partition_address_and_size("cpuapp_its_partition" CPUAPP_ITS_ADDRESS CPUAPP_ITS_SIZE)
90+
compute_optional_partition_address_and_size("cpurad_its_partition" CPURAD_ITS_ADDRESS CPURAD_ITS_SIZE)
91+
92+
list(APPEND securestorage_args --cpuapp-crypto-address ${CPUAPP_CRYPTO_ADDRESS})
93+
list(APPEND securestorage_args --cpuapp-crypto-size ${CPUAPP_CRYPTO_SIZE})
94+
list(APPEND securestorage_args --cpurad-crypto-address ${CPURAD_CRYPTO_ADDRESS})
95+
list(APPEND securestorage_args --cpurad-crypto-size ${CPURAD_CRYPTO_SIZE})
96+
list(APPEND securestorage_args --cpuapp-its-address ${CPUAPP_ITS_ADDRESS})
97+
list(APPEND securestorage_args --cpuapp-its-size ${CPUAPP_ITS_SIZE})
98+
list(APPEND securestorage_args --cpurad-its-address ${CPURAD_ITS_ADDRESS})
99+
list(APPEND securestorage_args --cpurad-its-size ${CPURAD_ITS_SIZE})
100+
endif(CONFIG_GEN_UICR_SECURESTORAGE)
101+
63102
if(CONFIG_GEN_UICR_GENERATE_PERIPHCONF)
64103
# gen_uicr.py parses all zephyr.elf files. To find these files (which
65104
# have not been built yet) we scan sibling build directories for
@@ -134,6 +173,7 @@ add_custom_command(
134173
--out-merged-hex ${merged_hex_file}
135174
--out-uicr-hex ${uicr_hex_file}
136175
${periphconf_args}
176+
${securestorage_args}
137177
${secondary_args}
138178
DEPENDS ${periphconf_elfs} ${secondary_periphconf_elfs}
139179
WORKING_DIRECTORY ${APPLICATION_BINARY_DIR}

soc/nordic/common/uicr/gen_uicr/Kconfig

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,24 @@ 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+
All partitions must be multiples of 1KB and laid out contiguously
40+
without gaps. Missing partitions are handled gracefully with zero size.
41+
2442
endmenu
2543

2644
source "Kconfig.zephyr"

0 commit comments

Comments
 (0)