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
4 changes: 4 additions & 0 deletions boards/nordic/nrf54h20dk/nrf54h20dk_nrf54h20_cpuapp_iron.dts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
};
};

&cpusec_bellboard {
status = "okay";
};

&cpusec_cpuapp_ipc {
mbox-names = "tx", "rx";
status = "okay";
Expand Down
2 changes: 1 addition & 1 deletion drivers/firmware/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions drivers/firmware/nrf_ironside/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
14 changes: 13 additions & 1 deletion drivers/firmware/nrf_ironside/Kconfig
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
4 changes: 2 additions & 2 deletions drivers/firmware/nrf_ironside/call.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
28 changes: 28 additions & 0 deletions drivers/firmware/nrf_ironside/update.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2025 Nordic Semiconductor ASA
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/drivers/firmware/nrf_ironside/update.h>
#include <zephyr/drivers/firmware/nrf_ironside/call.h>

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;
}
72 changes: 72 additions & 0 deletions include/zephyr/drivers/firmware/nrf_ironside/update.h
Original file line number Diff line number Diff line change
@@ -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 <stdint.h>
#include <stddef.h>

/**
* @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_ */
6 changes: 6 additions & 0 deletions samples/drivers/firmware/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.. zephyr:code-sample-category:: firmware
:name: Firmware drivers
:show-listing:
:glob: **/*

These samples demonstrate how to use firmware driver APIs.
10 changes: 10 additions & 0 deletions samples/drivers/firmware/nrf_ironside/update/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
11 changes: 11 additions & 0 deletions samples/drivers/firmware/nrf_ironside/update/Kconfig
Original file line number Diff line number Diff line change
@@ -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"
74 changes: 74 additions & 0 deletions samples/drivers/firmware/nrf_ironside/update/README.rst
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions samples/drivers/firmware/nrf_ironside/update/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CONFIG_LOG=y

CONFIG_NRF_IRONSIDE_UPDATE_SERVICE=y
12 changes: 12 additions & 0 deletions samples/drivers/firmware/nrf_ironside/update/sample.yaml
Original file line number Diff line number Diff line change
@@ -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
31 changes: 31 additions & 0 deletions samples/drivers/firmware/nrf_ironside/update/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2025 Nordic Semiconductor ASA.
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/drivers/firmware/nrf_ironside/update.h>
#include <zephyr/logging/log.h>

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;
}