diff --git a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp_iron.dts b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp_iron.dts index dbd20dafc85..245c4ee28d8 100644 --- a/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp_iron.dts +++ b/boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp_iron.dts @@ -17,6 +17,10 @@ }; }; +&cpusec_bellboard { + status = "okay"; +}; + &cpusec_cpuapp_ipc { mbox-names = "tx", "rx"; status = "okay"; diff --git a/drivers/firmware/CMakeLists.txt b/drivers/firmware/CMakeLists.txt index 167d21addb5..062106cf92b 100644 --- a/drivers/firmware/CMakeLists.txt +++ b/drivers/firmware/CMakeLists.txt @@ -1,6 +1,6 @@ # SPDX-License-Identifier: Apache-2.0 # zephyr-keep-sorted-start -add_subdirectory(nrf_ironside) add_subdirectory_ifdef(CONFIG_ARM_SCMI scmi) +add_subdirectory_ifdef(CONFIG_NRF_IRONSIDE nrf_ironside) # zephyr-keep-sorted-stop diff --git a/drivers/firmware/nrf_ironside/CMakeLists.txt b/drivers/firmware/nrf_ironside/CMakeLists.txt index 8f31acfef00..d21a132d67d 100644 --- a/drivers/firmware/nrf_ironside/CMakeLists.txt +++ b/drivers/firmware/nrf_ironside/CMakeLists.txt @@ -6,3 +6,4 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_CALL call.c) zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_CPUCONF_SERVICE cpuconf.c) +zephyr_library_sources_ifdef(CONFIG_NRF_IRONSIDE_UPDATE_SERVICE update.c) diff --git a/drivers/firmware/nrf_ironside/Kconfig b/drivers/firmware/nrf_ironside/Kconfig index b0f05966fcd..97e3604bf72 100644 --- a/drivers/firmware/nrf_ironside/Kconfig +++ b/drivers/firmware/nrf_ironside/Kconfig @@ -1,10 +1,16 @@ # Copyright (c) 2025 Nordic Semiconductor ASA # SPDX-License-Identifier: Apache-2.0 +config NRF_IRONSIDE + bool + depends on SOC_NRF54H20_IRON + help + This is selected by drivers interacting with Nordic IRONside firmware. + config NRF_IRONSIDE_CALL bool depends on DT_HAS_NORDIC_IRONSIDE_CALL_ENABLED - depends on SOC_NRF54H20_IRON + select NRF_IRONSIDE select EVENTS select MBOX help @@ -31,4 +37,10 @@ config NRF_IRONSIDE_CPUCONF_SERVICE help Service used to boot local domain cores. +config NRF_IRONSIDE_UPDATE_SERVICE + bool "IRONside update service" + select NRF_IRONSIDE_CALL + help + Service used to update the IRONside SE firmware. + endmenu diff --git a/drivers/firmware/nrf_ironside/call.c b/drivers/firmware/nrf_ironside/call.c index 8d77119828c..f120c017549 100644 --- a/drivers/firmware/nrf_ironside/call.c +++ b/drivers/firmware/nrf_ironside/call.c @@ -29,8 +29,8 @@ BUILD_ASSERT((sizeof(struct ironside_call_buf) % CONFIG_DCACHE_LINE_SIZE) == 0); static const struct mbox_dt_spec mbox_rx = MBOX_DT_SPEC_INST_GET(0, rx); static const struct mbox_dt_spec mbox_tx = MBOX_DT_SPEC_INST_GET(0, tx); -K_EVENT_DEFINE(alloc_evts); -K_EVENT_DEFINE(rsp_evts); +static K_EVENT_DEFINE(alloc_evts); +static K_EVENT_DEFINE(rsp_evts); static void ironside_call_rsp(const struct device *dev, mbox_channel_id_t channel_id, void *user_data, struct mbox_msg *data) diff --git a/drivers/firmware/nrf_ironside/update.c b/drivers/firmware/nrf_ironside/update.c new file mode 100644 index 00000000000..8de21303b05 --- /dev/null +++ b/drivers/firmware/nrf_ironside/update.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +int ironside_update(const struct ironside_update_blob *update) +{ + int err; + struct ironside_call_buf *const buf = ironside_call_alloc(); + + buf->id = IRONSIDE_CALL_ID_UPDATE_SERVICE_V0; + buf->args[IRONSIDE_UPDATE_SERVICE_UPDATE_PTR_IDX] = (uintptr_t)update; + + ironside_call_dispatch(buf); + + if (buf->status == IRONSIDE_CALL_STATUS_RSP_SUCCESS) { + err = buf->args[IRONSIDE_UPDATE_SERVICE_RETCODE_IDX]; + } else { + err = buf->status; + } + + ironside_call_release(buf); + + return err; +} diff --git a/include/zephyr/drivers/firmware/nrf_ironside/update.h b/include/zephyr/drivers/firmware/nrf_ironside/update.h new file mode 100644 index 00000000000..62191b3285b --- /dev/null +++ b/include/zephyr/drivers/firmware/nrf_ironside/update.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_ZEPHYR_DRIVERS_FIRMWARE_NRF_IRONSIDE_UPDATE_H_ +#define ZEPHYR_INCLUDE_ZEPHYR_DRIVERS_FIRMWARE_NRF_IRONSIDE_UPDATE_H_ + +#include +#include + +/** + * @name Update service error codes. + * @{ + */ + +/** Caller does not have access to the provided update candidate buffer. */ +#define IRONSIDE_UPDATE_ERROR_NOT_PERMITTED (1) +/** Failed to write the update metadata to SICR. */ +#define IRONSIDE_UPDATE_ERROR_SICR_WRITE_FAILED (2) + +/** + * @} + */ + +/** Length of the update manifest in bytes */ +#define IRONSIDE_UPDATE_MANIFEST_LENGTH (256) +/** Length of the update public key in bytes. */ +#define IRONSIDE_UPDATE_PUBKEY_LENGTH (32) +/** Length of the update signature in bytes. */ +#define IRONSIDE_UPDATE_SIGNATURE_LENGTH (64) + +/* IRONside call identifiers with implicit versions. + * + * With the initial "version 0", the service ABI is allowed to break until the + * first production release of IRONside SE. + */ +#define IRONSIDE_CALL_ID_UPDATE_SERVICE_V0 1 + +/* Index of the update blob pointer within the service buffer. */ +#define IRONSIDE_UPDATE_SERVICE_UPDATE_PTR_IDX (0) +/* Index of the return code within the service buffer. */ +#define IRONSIDE_UPDATE_SERVICE_RETCODE_IDX (0) + +/** + * @brief IRONside update blob. + */ +struct ironside_update_blob { + uint8_t manifest[IRONSIDE_UPDATE_MANIFEST_LENGTH]; + uint8_t pubkey[IRONSIDE_UPDATE_PUBKEY_LENGTH]; + uint8_t signature[IRONSIDE_UPDATE_SIGNATURE_LENGTH]; + uint32_t firmware[]; +}; + +/** + * @brief Request a firmware upgrade of the IRONside SE. + * + * This invokes the IRONside SE update service. The device must be restarted for the update + * to be installed. Check the update status in the application boot report to see if the update + * was successfully installed. + * + * @param update Pointer to update blob + * + * @retval -IRONSIDE_UPDATE_ERROR_NOT_PERMITTED if missing access to the update candidate. + * @retval -IRONSIDE_UPDATE_ERROR_SICR_WRITE_FAILED if writing update parameters to SICR failed. + * @returns Positive non-0 error status if reported by IRONside call. + * @returns 0 on a successful request (although the update itself may still fail). + * + */ +int ironside_update(const struct ironside_update_blob *update); + +#endif /* ZEPHYR_INCLUDE_ZEPHYR_DRIVERS_FIRMWARE_NRF_IRONSIDE_UPDATE_H_ */ diff --git a/samples/drivers/firmware/index.rst b/samples/drivers/firmware/index.rst new file mode 100644 index 00000000000..1862e7477a1 --- /dev/null +++ b/samples/drivers/firmware/index.rst @@ -0,0 +1,6 @@ +.. zephyr:code-sample-category:: firmware + :name: Firmware drivers + :show-listing: + :glob: **/* + + These samples demonstrate how to use firmware driver APIs. diff --git a/samples/drivers/firmware/nrf_ironside/update/CMakeLists.txt b/samples/drivers/firmware/nrf_ironside/update/CMakeLists.txt new file mode 100644 index 00000000000..b3aa8c35c2a --- /dev/null +++ b/samples/drivers/firmware/nrf_ironside/update/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) + +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) + +project(ironside_se_update) + +target_sources(app PRIVATE src/main.c) diff --git a/samples/drivers/firmware/nrf_ironside/update/Kconfig b/samples/drivers/firmware/nrf_ironside/update/Kconfig new file mode 100644 index 00000000000..702b943ff60 --- /dev/null +++ b/samples/drivers/firmware/nrf_ironside/update/Kconfig @@ -0,0 +1,11 @@ +# Copyright (c) 2025 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +config UPDATE_BLOB_ADDRESS + hex "Address of the update blob" + default 0xe100000 + help + Address of the update blob. The default value matches the placement of the + update blobs delivered with the IRONside SE firmware. + +source "Kconfig.zephyr" diff --git a/samples/drivers/firmware/nrf_ironside/update/README.rst b/samples/drivers/firmware/nrf_ironside/update/README.rst new file mode 100644 index 00000000000..75cadfe6f72 --- /dev/null +++ b/samples/drivers/firmware/nrf_ironside/update/README.rst @@ -0,0 +1,74 @@ +.. zephyr:code-sample:: nrf_ironside_update + :name: Nordic IRONside SE firmware update + + Update the Nordic IRONside SE firmware. + +Overview +******** + +The Nordic IRONside SE Update sample updates the IRONside SE firmware on a SoC that already has IRONside SE installed. +It can update both the main image and the recovery image of IRONside SE using the IRONside SE firmware release ZIP file. + +Update procedure +**************** + +The update procedure works as follows: + +1. The application invokes the IRONside SE update service and passes the parameters that correspond to the location of the HEX file of the IRONside SE firmware update. + +#. The application prints the return value of the service call and outputs information from the update HEX file. + +#. After the service call completes, the IRONside SE firmware updates the internal state of the device. + +#. The firmware installs the update during the next device boot. + This operation can take several seconds. + +Once the operation has completed, you can read the boot report to verify that the update has taken place. + +Building and running the application for nrf54h20dk/nrf54h20/cpuapp/iron +************************************************************************ + +.. note:: + You can use this application only when there is already a version of IRONside SE installed on the device. + +1. Unzip the IRONside SE release ZIP to get the update hex file: + + .. code-block:: console + + unzip nrf54h20_soc_binaries_v.*.zip + +#. Program the appropriate update hex file from the release ZIP using one (not both) of the following commands: + + a) To update IRONside SE firmware: + + .. code-block:: console + + nrfutil device program --traits jlink --firmware update/ironside_se_update.hex + + b) To update IRONside SE recovery firmware: + + .. code-block:: console + + nrfutil device program --traits jlink --firmware update/ironside_se_recovery_update.hex + +#. Build and program the application: + + .. zephyr-app-commands:: + :zephyr-app: samples/drivers/firmware/nrf_ironside/update + :board: nrf54h20dk/nrf54h20/cpuapp/iron + :goals: flash + +#. Trigger a reset: + +.. code-block:: console + + nrfutil device reset --reset-kind RESET_PIN --traits jlink + +#. Check that the new version is installed: + + .. code-block:: console + + # Read the version fields from the boot report + nrfutil x-read --direct --address 0x2f88fd04 --bytes 16 --traits jlink + # Read the update status in the boot report + nrfutil x-read --direct --address 0x2f88fd24 --bytes 4 --traits jlink diff --git a/samples/drivers/firmware/nrf_ironside/update/prj.conf b/samples/drivers/firmware/nrf_ironside/update/prj.conf new file mode 100644 index 00000000000..8682307eca6 --- /dev/null +++ b/samples/drivers/firmware/nrf_ironside/update/prj.conf @@ -0,0 +1,3 @@ +CONFIG_LOG=y + +CONFIG_NRF_IRONSIDE_UPDATE_SERVICE=y diff --git a/samples/drivers/firmware/nrf_ironside/update/sample.yaml b/samples/drivers/firmware/nrf_ironside/update/sample.yaml new file mode 100644 index 00000000000..0d7a0517f12 --- /dev/null +++ b/samples/drivers/firmware/nrf_ironside/update/sample.yaml @@ -0,0 +1,12 @@ +sample: + name: Nordic IRONside SE update service + description: Demonstrates how to update the Nordic IRONside SE firmware +common: + build_only: true + tags: nrf_ironside + integration_platforms: + - nrf54h20dk/nrf54h20/cpuapp/iron + +tests: + sample.drivers.firmware.nrf_ironside.update: + platform_allow: nrf54h20dk/nrf54h20/cpuapp/iron diff --git a/samples/drivers/firmware/nrf_ironside/update/src/main.c b/samples/drivers/firmware/nrf_ironside/update/src/main.c new file mode 100644 index 00000000000..09513497de9 --- /dev/null +++ b/samples/drivers/firmware/nrf_ironside/update/src/main.c @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 Nordic Semiconductor ASA. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +LOG_MODULE_REGISTER(app, LOG_LEVEL_INF); + +int main(void) +{ + int err; + const struct ironside_update_blob *update = (void *)CONFIG_UPDATE_BLOB_ADDRESS; + + err = ironside_update(update); + LOG_INF("IRONside update retval: 0x%x", err); + + if (err == 0) { + LOG_HEXDUMP_INF(update->manifest, sizeof(update->manifest), "Update manifest:"); + LOG_HEXDUMP_INF(update->pubkey, sizeof(update->pubkey), "Public key:"); + LOG_HEXDUMP_INF(update->signature, sizeof(update->signature), "Signature:"); + LOG_HEXDUMP_INF(update->firmware, 8, "First 8 bytes of encrypted fw:"); + LOG_INF("Reboot the device to trigger the update"); + } else { + LOG_ERR("The request to update failed"); + } + + return 0; +}