Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion scripts/ci/check_compliance.py
Original file line number Diff line number Diff line change
Expand Up @@ -1300,12 +1300,26 @@ def check_no_undef_outside_kconfig(self, kconf):
"FOO_LOG_LEVEL",
"FOO_SETTING_1",
"FOO_SETTING_2",
"GEN_UICR_GENERATE_PERIPHCONF", # Used in specialized build tool, not part of main Kconfig
"GEN_UICR_APPROTECT_APPLICATION_PROTECTED",
"GEN_UICR_APPROTECT_CORESIGHT_PROTECTED",
"GEN_UICR_APPROTECT_RADIOCORE_PROTECTED",
"GEN_UICR_ERASEPROTECT",
"GEN_UICR_GENERATE_PERIPHCONF",
"GEN_UICR_LOCK",
"GEN_UICR_PROTECTEDMEM",
"GEN_UICR_PROTECTEDMEM_SIZE_BYTES",
"GEN_UICR_SECONDARY",
"GEN_UICR_SECONDARY_GENERATE_PERIPHCONF",
"GEN_UICR_SECONDARY_PROCESSOR_VALUE",
"GEN_UICR_SECONDARY_PROTECTEDMEM",
"GEN_UICR_SECONDARY_PROTECTEDMEM_SIZE_BYTES",
"GEN_UICR_SECONDARY_TRIGGER",
"GEN_UICR_SECONDARY_TRIGGER_APPLICATIONLOCKUP",
"GEN_UICR_SECONDARY_TRIGGER_APPLICATIONWDT0",
"GEN_UICR_SECONDARY_TRIGGER_APPLICATIONWDT1",
"GEN_UICR_SECONDARY_TRIGGER_RADIOCORELOCKUP",
"GEN_UICR_SECONDARY_TRIGGER_RADIOCOREWDT0",
"GEN_UICR_SECONDARY_TRIGGER_RADIOCOREWDT1",
"GEN_UICR_SECONDARY_WDTSTART",
"GEN_UICR_SECONDARY_WDTSTART_CRV",
"GEN_UICR_SECONDARY_WDTSTART_INSTANCE_CODE",
Expand Down
96 changes: 96 additions & 0 deletions soc/nordic/common/uicr/gen_uicr.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
# Common values for representing enabled/disabled in the UICR format.
ENABLED_VALUE = 0xFFFF_FFFF
DISABLED_VALUE = 0xBD23_28A8
PROTECTED_VALUE = ENABLED_VALUE # UICR_PROTECTED = UICR_ENABLED per uicr_defs.h
UNPROTECTED_VALUE = DISABLED_VALUE # Unprotected uses the default erased value

KB_4 = 4096

Expand Down Expand Up @@ -430,6 +432,39 @@ def main() -> None:
type=lambda s: int(s, 0),
help="Size in bytes of cpurad_its_partition (decimal or 0x-prefixed hex)",
)
parser.add_argument(
"--permit-permanently-transitioning-device-to-deployed",
action="store_true",
help=(
"Safety flag required to enable both UICR.LOCK and UICR.ERASEPROTECT together. "
"Must be explicitly provided to acknowledge permanent device state changes."
),
)
parser.add_argument(
"--lock",
action="store_true",
help="Enable UICR.LOCK to prevent modifications without ERASEALL",
)
parser.add_argument(
"--eraseprotect",
action="store_true",
help="Enable UICR.ERASEPROTECT to block ERASEALL operations",
)
parser.add_argument(
"--approtect-application-protected",
action="store_true",
help="Protect application domain access port (disable debug access)",
)
parser.add_argument(
"--approtect-radiocore-protected",
action="store_true",
help="Protect radio core access port (disable debug access)",
)
parser.add_argument(
"--approtect-coresight-protected",
action="store_true",
help="Protect CoreSight access port (disable debug access)",
)
parser.add_argument(
"--protectedmem",
action="store_true",
Expand Down Expand Up @@ -487,6 +522,26 @@ def main() -> None:
type=lambda s: int(s, 0),
help="Processor to boot for the secondary firmware ",
)
parser.add_argument(
"--secondary-trigger",
action="store_true",
help="Enable UICR.SECONDARY.TRIGGER for automatic secondary firmware boot on reset events",
)
parser.add_argument(
"--secondary-trigger-resetreas",
default=0,
type=lambda s: int(s, 0),
help=(
"Bitmask of reset reasons that trigger secondary firmware boot "
"(decimal or 0x-prefixed hex)"
),
)
parser.add_argument(
"--secondary-protectedmem-size",
default=None,
type=lambda s: int(s, 0),
help="Size in bytes of the secondary protected memory region (decimal or 0x-prefixed hex)",
)
parser.add_argument(
"--secondary-periphconf-address",
default=None,
Expand Down Expand Up @@ -577,6 +632,33 @@ def main() -> None:
uicr.SECURESTORAGE.ITS.APPLICATIONSIZE1KB = args.cpuapp_its_size // 1024
uicr.SECURESTORAGE.ITS.RADIOCORESIZE1KB = args.cpurad_its_size // 1024

# Handle LOCK and ERASEPROTECT configuration
# Check if both are enabled together - this requires explicit acknowledgment
if (
args.lock
and args.eraseprotect
and not args.permit_permanently_transitioning_device_to_deployed
):
raise ScriptError(
"Enabling both --lock and --eraseprotect requires "
"--permit-permanently-transitioning-device-to-deployed to be specified. "
"This combination permanently locks the device configuration and prevents "
"ERASEALL."
)

if args.lock:
uicr.LOCK = ENABLED_VALUE
if args.eraseprotect:
uicr.ERASEPROTECT = ENABLED_VALUE
# Handle APPROTECT configuration
if args.approtect_application_protected:
uicr.APPROTECT.APPLICATION = PROTECTED_VALUE

if args.approtect_radiocore_protected:
uicr.APPROTECT.RADIOCORE = PROTECTED_VALUE

if args.approtect_coresight_protected:
uicr.APPROTECT.CORESIGHT = PROTECTED_VALUE
# Handle protected memory configuration
if args.protectedmem:
if args.protectedmem_size_bytes % KB_4 != 0:
Expand Down Expand Up @@ -628,6 +710,20 @@ def main() -> None:
uicr.SECONDARY.ADDRESS = args.secondary_address
uicr.SECONDARY.PROCESSOR = args.secondary_processor

# Handle secondary TRIGGER configuration
if args.secondary_trigger:
uicr.SECONDARY.TRIGGER.ENABLE = ENABLED_VALUE
uicr.SECONDARY.TRIGGER.RESETREAS = args.secondary_trigger_resetreas

# Handle secondary PROTECTEDMEM configuration
if args.secondary_protectedmem_size:
uicr.SECONDARY.PROTECTEDMEM.ENABLE = ENABLED_VALUE
if args.secondary_protectedmem_size % 4096 != 0:
raise ScriptError(
f"args.secondary_protectedmem_size was {args.secondary_protectedmem_size}, "
f"but must be divisible by 4096"
)
uicr.SECONDARY.PROTECTEDMEM.SIZE4KB = args.secondary_protectedmem_size // 4096
# Handle secondary periphconf if provided
if args.out_secondary_periphconf_hex:
secondary_periphconf_combined = extract_and_combine_periphconfs(
Expand Down
62 changes: 62 additions & 0 deletions soc/nordic/common/uicr/gen_uicr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ endfunction()
if(CMAKE_VERBOSE_MAKEFILE)
endif()

set(lock_args)
set(eraseprotect_args)
set(approtect_args)
set(protectedmem_args)
set(periphconf_args)
set(wdtstart_args)
Expand Down Expand Up @@ -115,6 +118,29 @@ if(CONFIG_GEN_UICR_SECURESTORAGE)
list(APPEND securestorage_args --cpurad-its-size ${CPURAD_ITS_SIZE})
endif(CONFIG_GEN_UICR_SECURESTORAGE)

# Handle LOCK configuration
if(CONFIG_GEN_UICR_LOCK)
list(APPEND lock_args --lock)
endif()

# Handle ERASEPROTECT configuration
if(CONFIG_GEN_UICR_ERASEPROTECT)
list(APPEND eraseprotect_args --eraseprotect)
endif()

# Handle APPROTECT configuration
if(CONFIG_GEN_UICR_APPROTECT_APPLICATION_PROTECTED)
list(APPEND approtect_args --approtect-application-protected)
endif()

if(CONFIG_GEN_UICR_APPROTECT_RADIOCORE_PROTECTED)
list(APPEND approtect_args --approtect-radiocore-protected)
endif()

if(CONFIG_GEN_UICR_APPROTECT_CORESIGHT_PROTECTED)
list(APPEND approtect_args --approtect-coresight-protected)
endif()

# Handle protected memory configuration
if(CONFIG_GEN_UICR_PROTECTEDMEM)
list(APPEND protectedmem_args --protectedmem)
Expand Down Expand Up @@ -188,6 +214,39 @@ if(CONFIG_GEN_UICR_SECONDARY)
list(APPEND secondary_args --secondary-wdtstart-crv ${CONFIG_GEN_UICR_SECONDARY_WDTSTART_CRV})
endif()

# Handle secondary TRIGGER configuration
if(CONFIG_GEN_UICR_SECONDARY_TRIGGER)
list(APPEND secondary_args --secondary-trigger)

# Compute RESETREAS bitmask from individual trigger configs
set(resetreas_value 0)
if(CONFIG_GEN_UICR_SECONDARY_TRIGGER_APPLICATIONWDT0)
math(EXPR resetreas_value "${resetreas_value} + 0x001")
endif()
if(CONFIG_GEN_UICR_SECONDARY_TRIGGER_APPLICATIONWDT1)
math(EXPR resetreas_value "${resetreas_value} + 0x002")
endif()
if(CONFIG_GEN_UICR_SECONDARY_TRIGGER_APPLICATIONLOCKUP)
math(EXPR resetreas_value "${resetreas_value} + 0x008")
endif()
if(CONFIG_GEN_UICR_SECONDARY_TRIGGER_RADIOCOREWDT0)
math(EXPR resetreas_value "${resetreas_value} + 0x020")
endif()
if(CONFIG_GEN_UICR_SECONDARY_TRIGGER_RADIOCOREWDT1)
math(EXPR resetreas_value "${resetreas_value} + 0x040")
endif()
if(CONFIG_GEN_UICR_SECONDARY_TRIGGER_RADIOCORELOCKUP)
math(EXPR resetreas_value "${resetreas_value} + 0x100")
endif()

list(APPEND secondary_args --secondary-trigger-resetreas ${resetreas_value})
endif()

# Handle secondary PROTECTEDMEM configuration
if(CONFIG_GEN_UICR_SECONDARY_PROTECTEDMEM)
list(APPEND secondary_args --secondary-protectedmem-size ${CONFIG_GEN_UICR_SECONDARY_PROTECTEDMEM_SIZE_BYTES})
endif()

if(CONFIG_GEN_UICR_SECONDARY_GENERATE_PERIPHCONF)
# Compute SECONDARY_PERIPHCONF absolute address and size from this image's devicetree
compute_partition_address_and_size("secondary_periphconf_partition" SECONDARY_PERIPHCONF_ADDRESS SECONDARY_PERIPHCONF_SIZE)
Expand All @@ -210,6 +269,9 @@ add_custom_command(
--uicr-address ${UICR_ADDRESS}
--out-merged-hex ${merged_hex_file}
--out-uicr-hex ${uicr_hex_file}
${lock_args}
${eraseprotect_args}
${approtect_args}
${wdtstart_args}
${periphconf_args}
${securestorage_args}
Expand Down
103 changes: 103 additions & 0 deletions soc/nordic/common/uicr/gen_uicr/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,53 @@ config GEN_UICR_SECURESTORAGE
- At least one subpartition must be defined
- Combined subpartition sizes must equal secure_storage_partition size

config GEN_UICR_LOCK
bool "Enable UICR.LOCK"
help
When enabled, locks the entire contents of the NVR0 page located in
MRAM10. This includes all values in both the UICR and the BICR (Board
Information Configuration Registers). Once locked, the UICR can only
be modified by performing an ERASEALL operation.

This should be enabled only in production devices to prevent
unauthorized modification.

config GEN_UICR_ERASEPROTECT
bool "Enable UICR.ERASEPROTECT"
depends on ! GEN_UICR_LOCK
help
When enabled, ERASEALL operations are blocked.

This option is mutually exclusive with UICR.LOCK in Kconfig to prevent
accidental configuration where both are enabled simultaneously. If both
were enabled, the UICR would become impossible to modify in any way.
Note that gen_uicr.py can be used directly to create a configuration
with both enabled if needed.

menu "UICR.APPROTECT - Access Port Protection"

config GEN_UICR_APPROTECT_APPLICATION_PROTECTED
bool "Protect application domain access port"
help
When enabled, disables debug access to the application domain processor,
preventing debugger connection to application memory, registers, and debug
features. When disabled, full debug access is enabled.

config GEN_UICR_APPROTECT_RADIOCORE_PROTECTED
bool "Protect radio core access port"
help
When enabled, disables debug access to the radio core processor,
preventing debugger connection to radio core memory, registers, and debug
features. When disabled, full debug access is enabled.

config GEN_UICR_APPROTECT_CORESIGHT_PROTECTED
bool "Disable CoreSight subsystem"
help
When enabled will disable the coresight subsystem, preventing
system level trace features.

endmenu

config GEN_UICR_PROTECTEDMEM
bool "Enable UICR.PROTECTEDMEM"
help
Expand Down Expand Up @@ -166,6 +213,62 @@ config GEN_UICR_SECONDARY_PROCESSOR_VALUE
default 0xBD2328A8 if GEN_UICR_SECONDARY_PROCESSOR_APPLICATION
default 0x1730C77F if GEN_UICR_SECONDARY_PROCESSOR_RADIOCORE

config GEN_UICR_SECONDARY_TRIGGER
bool "Enable UICR.SECONDARY.TRIGGER"
help
When enabled, configures automatic triggers that cause IronSide SE
to boot the secondary firmware instead of the primary firmware based
on specific reset reasons.

if GEN_UICR_SECONDARY_TRIGGER

config GEN_UICR_SECONDARY_TRIGGER_APPLICATIONWDT0
bool "Trigger on Application domain watchdog 0 reset"
help
Boot secondary firmware when Application domain watchdog 0 causes a reset.

config GEN_UICR_SECONDARY_TRIGGER_APPLICATIONWDT1
bool "Trigger on Application domain watchdog 1 reset"
help
Boot secondary firmware when Application domain watchdog 1 causes a reset.

config GEN_UICR_SECONDARY_TRIGGER_APPLICATIONLOCKUP
bool "Trigger on Application domain CPU lockup reset"
help
Boot secondary firmware when Application domain CPU lockup causes a reset.

config GEN_UICR_SECONDARY_TRIGGER_RADIOCOREWDT0
bool "Trigger on Radio core watchdog 0 reset"
help
Boot secondary firmware when Radio core watchdog 0 causes a reset.

config GEN_UICR_SECONDARY_TRIGGER_RADIOCOREWDT1
bool "Trigger on Radio core watchdog 1 reset"
help
Boot secondary firmware when Radio core watchdog 1 causes a reset.

config GEN_UICR_SECONDARY_TRIGGER_RADIOCORELOCKUP
bool "Trigger on Radio core CPU lockup reset"
help
Boot secondary firmware when Radio core CPU lockup causes a reset.

endif # GEN_UICR_SECONDARY_TRIGGER

config GEN_UICR_SECONDARY_PROTECTEDMEM
bool "Enable UICR.SECONDARY.PROTECTEDMEM"
depends on GEN_UICR_SECONDARY
help
When enabled, the UICR generator will configure the
protected memory region for the secondary firmware.

config GEN_UICR_SECONDARY_PROTECTEDMEM_SIZE_BYTES
int "Secondary protected memory size in bytes"
default 4096
depends on GEN_UICR_SECONDARY_PROTECTEDMEM
help
Size of the secondary protected memory region in bytes.
This value must be divisible by 4096 (4 kiB).

endif # GEN_UICR_SECONDARY

endmenu
Expand Down
Loading