Skip to content

Commit

Permalink
suit: Add module to define SUIT processing events
Browse files Browse the repository at this point in the history
Add a module that allows to synchronize SUIT processing among several
threads.
The primary use case is to control the main processor logic, based on
SSF requests.

Ref: NCSDK-29996

Signed-off-by: Tomasz Chyrowicz <tomasz.chyrowicz@nordicsemi.no>
  • Loading branch information
tomchy committed Nov 25, 2024
1 parent f0dea64 commit a611591
Show file tree
Hide file tree
Showing 15 changed files with 1,082 additions and 90 deletions.
1 change: 1 addition & 0 deletions subsys/suit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ add_subdirectory_ifdef(CONFIG_SUIT_DFU orchestrator_app)
add_subdirectory_ifdef(CONFIG_SUIT_ENVELOPE_INFO envelope_info)
add_subdirectory_ifdef(CONFIG_SUIT_EXECUTION_MODE execution_mode)
add_subdirectory_ifdef(CONFIG_SUIT_VALIDATOR validator)
add_subdirectory_ifdef(CONFIG_SUIT_EVENTS events)
2 changes: 2 additions & 0 deletions subsys/suit/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ config SUIT_ENABLE_DEFAULTS_SDFW
imply SUIT_UPDATE_REBOOT_ENABLED
imply SUIT_BOOT_RECOVERY_REBOOT_ENABLED
imply SUIT_VALIDATOR
imply SUIT_EVENTS

config SUIT_ENABLE_DEFAULTS_SDFW_EXTMEM
bool "SDFW SUIT defaults with external flash support"
Expand All @@ -196,6 +197,7 @@ rsource "envelope_info/Kconfig"
rsource "execution_mode/Kconfig"
rsource "memory_layout/Kconfig"
rsource "validator/Kconfig"
rsource "events/Kconfig"

# Configure SUIT_LOG_LEVEL
module = SUIT
Expand Down
13 changes: 13 additions & 0 deletions subsys/suit/events/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#
# Copyright (c) 2024 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

# SUIT Events API
zephyr_interface_library_named(suit_events)
target_include_directories(suit_events INTERFACE include)

zephyr_library()
zephyr_library_sources(src/suit_events.c)
zephyr_library_link_libraries(suit_events)
17 changes: 17 additions & 0 deletions subsys/suit/events/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#
# Copyright (c) 2024 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

config SUIT_EVENTS
bool "Enable SUIT events module"
select EVENTS

if SUIT_EVENTS

config APP_LINK_WITH_SUIT_EVENTS
bool
default y

endif # SUIT_EVENTS
98 changes: 98 additions & 0 deletions subsys/suit/events/include/suit_events.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#ifndef SUIT_EVENTS_H__
#define SUIT_EVENTS_H__

#ifdef __cplusplus
extern "C" {
#endif

#include <stdint.h>
#include <stdbool.h>

/* Pendable events that threads can wait for. */

/** Event indicating a successful execution of the suit-invoke command. */
#define SUIT_EVENT_INVOKE_SUCCESS BIT(0)

/** Event indicating an unsuccessful execution of the suit-invoke command. */
#define SUIT_EVENT_INVOKE_FAIL BIT(1)

/** Mask for events, related to the execution of the suit-invoke command. */
#define SUIT_EVENT_INVOKE_MASK (SUIT_EVENT_INVOKE_SUCCESS | SUIT_EVENT_INVOKE_FAIL)

/** CPU ID indicating all supported CPU IDs */
#define SUIT_EVENT_CPU_ID_ANY 0xFF

/** Special value of the timeout that represents infinite time. */
#define SUIT_WAIT_FOREVER 0xFFFFFFFF

/**
* @brief Post one or more events for a given CPU.
*
* This routine posts one or more events to an internal event object for a given CPU.
* All tasks waiting using @ref suit_event_wait whose waiting conditions become met by this
* posting immediately unpend.
*
* @note This API is a proxy for @ref k_event_post API that splits the event mask
* into 8 distinct 4-bit pools for 8 different CPU IDs.
*
* @param cpu_id The CPU ID for which the events will be posted.
* Use @ref SUIT_EVENT_CPU_ID_ANY to post an event for all of the CPUs.
* @param events Set of events to post for a given CPU.
*
* @retval Previous value of the events for a given CPU.
*/
uint32_t suit_event_post(uint8_t cpu_id, uint8_t events);

/**
* @brief Clear the events for given CPU.
*
* This routine clears (resets) the specified events for given CPU stored in
* an event object. Use @ref SUIT_EVENT_CPU_ID_ANY to clear events for all CPUs.
*
* @note This API is a proxy for @ref k_event_clear API that splits the event mask
* into 8 distinct 4-bit pools for 8 different CPU IDs.
*
* @param cpu_id The CPU ID for which the events will be cleared.
* Use @ref SUIT_EVENT_CPU_ID_ANY to clear events for all of the CPUs.
* @param events Set of events to clear for a given CPU.
*
* @retval Previous value of the events for a given CPU.
*/
uint32_t suit_event_clear(uint8_t cpu_id, uint8_t events);

/**
* @brief Wait for any of the specified events assigned to a given CPU.
*
* This routine waits on internal @a event object untli any of the specifies
* events for a given CPU ID have been posted, or the maximum wait time
* @a timeout has expired.
* A thread may wait on up to 4 distinctly numbered events that are expressed
* as bits in a single 8-bit word.
*
* @note This API is a proxy for @ref k_event_wait API that splits the event mask
* into 8 distinct 4-bit pools for 8 different CPU IDs.
*
* @param cpu_id The CPU ID whose events to wait for.
* Use @ref SUIT_EVENT_CPU_ID_ANY to wait for an event for any of the CPUs.
* @param events Set of desired events on which to wait
* @param reset If true, clear the set of events for given CPU ID tracked by the
* event object before waiting. If false, do not clear the events.
* @param timeout Waiting period for the desired set of events.
* Use @ref SUIT_WAIT_FOREVER to wait forever.
*
* @retval set of matching events for a given CPU upon success.
* @retval 0 if matching events were not received for a given CPU within the specified time.
*/
uint32_t suit_event_wait(uint8_t cpu_id, uint8_t events, bool reset, uint32_t timeout_ms);

#ifdef __cplusplus
}
#endif

#endif /* SUIT_EVENTS_H__ */
119 changes: 119 additions & 0 deletions subsys/suit/events/src/suit_events.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#include <suit_events.h>
#include <zephyr/kernel.h>

/* Helper mask, with 0th bits for all processors set. */
#define ALL_CPUS_MASK 0x11111111

/* Helper mask, with all event bits for a given processor set. */
#define ALL_EVENT_MASK 0x0F

/* The maximum CPU ID handled by this module. */
#define CPU_N 8

/* The number of bits per CPU inside the event mask. */
#define BITS_N 4

/* Internal event structure, common for all API calls. */
static K_EVENT_DEFINE(suit_events);

/* Convert (cpu_id, event mask) pair into global (common for all CPUs) event mask. */
static uint32_t cpu_events_to_suit_events_mask(uint8_t cpu_id, uint8_t events)
{
/* Check for valid CPU ID values. */
if ((cpu_id >= CPU_N) && (cpu_id != SUIT_EVENT_CPU_ID_ANY)) {
return 0;
}

/* Mask all unsupported events. */
events &= ALL_EVENT_MASK;

if (cpu_id == SUIT_EVENT_CPU_ID_ANY) {
return events * ALL_CPUS_MASK;
}

return (uint32_t)events << (cpu_id * BITS_N);
}

/* Convert global (common for all CPUs) event mask into an event mask for a given CPU. */
static uint8_t suit_events_mask_to_cpu_events(uint8_t cpu_id, uint32_t events)
{
uint32_t cpu_shift = 0;
uint32_t cpu_events = 0;

/* Check for valid CPU ID values. */
if ((cpu_id >= CPU_N) && (cpu_id != SUIT_EVENT_CPU_ID_ANY)) {
return 0;
}

if (cpu_id == SUIT_EVENT_CPU_ID_ANY) {
uint8_t common_mask = 0;

for (size_t id = 0; id < CPU_N; id++) {
cpu_shift = (id * BITS_N);
cpu_events =
(events & ((uint32_t)ALL_EVENT_MASK << cpu_shift)) >> cpu_shift;
common_mask |= (cpu_events & ALL_EVENT_MASK);
}

return common_mask;
}

cpu_shift = (cpu_id * BITS_N);
cpu_events = (events & ((uint32_t)ALL_EVENT_MASK << cpu_shift)) >> cpu_shift;

return (cpu_events & ALL_EVENT_MASK);
}

uint32_t suit_event_post(uint8_t cpu_id, uint8_t events)
{
uint32_t main_mask = cpu_events_to_suit_events_mask(cpu_id, events);

if (main_mask == 0) {
/* Unsupported CPU ID. */
return 0;
}

return suit_events_mask_to_cpu_events(cpu_id, k_event_post(&suit_events, main_mask));
}

uint32_t suit_event_clear(uint8_t cpu_id, uint8_t events)
{
uint32_t main_mask = cpu_events_to_suit_events_mask(cpu_id, events);

if (main_mask == 0) {
/* Unsupported CPU ID. */
return 0;
}

return suit_events_mask_to_cpu_events(cpu_id, k_event_clear(&suit_events, main_mask));
}

uint32_t suit_event_wait(uint8_t cpu_id, uint8_t events, bool reset, uint32_t timeout_ms)
{
k_timeout_t timeout = K_NO_WAIT;
uint32_t main_mask = cpu_events_to_suit_events_mask(cpu_id, events);

if (main_mask == 0) {
/* Unsupported CPU ID. */
return 0;
}

if (reset) {
(void)suit_event_clear(cpu_id, main_mask);
}

if (timeout_ms == SUIT_WAIT_FOREVER) {
timeout = K_FOREVER;
} else if (timeout_ms != 0) {
timeout = K_MSEC(timeout_ms);
}

return suit_events_mask_to_cpu_events(
cpu_id, k_event_wait(&suit_events, main_mask, false, timeout));
}
1 change: 1 addition & 0 deletions subsys/suit/platform/sdfw/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ zephyr_library_link_libraries_ifdef(CONFIG_SUIT_DEVCONFIG suit_mci)
zephyr_library_link_libraries_ifdef(CONFIG_SUIT_AUTHENTICATE suit_mci)
zephyr_library_link_libraries_ifdef(CONFIG_SUIT_PLAT_CHECK_COMPONENT_COMPATIBILITY suit_mci)
zephyr_library_link_libraries_ifdef(CONFIG_SUIT_STREAM_FILTER_DECRYPT suit_stream_filters_interface)
zephyr_library_link_libraries_ifdef(CONFIG_SUIT_EVENTS suit_events)


zephyr_library_link_libraries(suit_sdfw_platform)
Expand Down
1 change: 1 addition & 0 deletions subsys/suit/platform/sdfw/include/suit_cpu_run.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#ifndef SUIT_PLAT_RUN_CPU_H__
#define SUIT_PLAT_RUN_CPU_H__

#include <stdint.h>
#include <suit_plat_err.h>

#ifdef __cplusplus
Expand Down
55 changes: 48 additions & 7 deletions subsys/suit/platform/sdfw/src/suit_plat_invoke.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
#include <suit_platform.h>
#include <suit_plat_decode_util.h>
#include <suit_cpu_run.h>
#ifdef CONFIG_SUIT_EVENTS
#include <suit_events.h>
#endif /* CONFIG_SUIT_EVENTS */

LOG_MODULE_REGISTER(suit_plat_invoke, CONFIG_SUIT_LOG_LEVEL);

Expand All @@ -26,8 +29,8 @@ int suit_plat_check_invoke(suit_component_t image_handle, struct zcbor_string *i
return SUIT_ERR_UNSUPPORTED_COMPONENT_ID;
}

if (suit_plat_decode_component_id(component_id, &cpu_id, &run_address, &size)
!= SUIT_PLAT_SUCCESS) {
if (suit_plat_decode_component_id(component_id, &cpu_id, &run_address, &size) !=
SUIT_PLAT_SUCCESS) {
LOG_ERR("suit_plat_decode_component_id failed");
return SUIT_ERR_UNSUPPORTED_COMPONENT_ID;
}
Expand All @@ -37,6 +40,11 @@ int suit_plat_check_invoke(suit_component_t image_handle, struct zcbor_string *i
return SUIT_ERR_UNSUPPORTED_COMPONENT_ID;
}

if (suit_plat_decode_invoke_args(invoke_args, NULL, NULL)) {
LOG_ERR("suit_plat_decode_invoke_args failed");
return SUIT_ERR_UNSUPPORTED_PARAMETER;
}

/* Check if component type supports invocation */
switch (component_type) {
case SUIT_COMPONENT_TYPE_MEM:
Expand All @@ -54,6 +62,9 @@ int suit_plat_invoke(suit_component_t image_handle, struct zcbor_string *invoke_
{
struct zcbor_string *component_id;
suit_component_type_t component_type = SUIT_COMPONENT_TYPE_UNSUPPORTED;
uint32_t timeout_ms = 0;
bool synchronous = false;
int ret = 0;
intptr_t run_address;
uint8_t cpu_id;
size_t size;
Expand All @@ -63,8 +74,8 @@ int suit_plat_invoke(suit_component_t image_handle, struct zcbor_string *invoke_
return SUIT_ERR_UNSUPPORTED_COMPONENT_ID;
}

if (suit_plat_decode_component_id(component_id, &cpu_id, &run_address, &size)
!= SUIT_PLAT_SUCCESS) {
if (suit_plat_decode_component_id(component_id, &cpu_id, &run_address, &size) !=
SUIT_PLAT_SUCCESS) {
LOG_ERR("suit_plat_decode_component_id failed");
return SUIT_ERR_UNSUPPORTED_COMPONENT_ID;
}
Expand All @@ -74,15 +85,45 @@ int suit_plat_invoke(suit_component_t image_handle, struct zcbor_string *invoke_
return SUIT_ERR_UNSUPPORTED_COMPONENT_ID;
}

if (suit_plat_decode_invoke_args(invoke_args, &synchronous, &timeout_ms)) {
LOG_ERR("suit_plat_decode_invoke_args failed");
return SUIT_ERR_UNSUPPORTED_PARAMETER;
}

#ifdef CONFIG_SUIT_EVENTS
/* Clear all pending invoke events */
(void)suit_event_clear(cpu_id, SUIT_EVENT_INVOKE_MASK);
#endif /* CONFIG_SUIT_EVENTS */

/* Check if component type supports invocation */
switch (component_type) {
case SUIT_COMPONENT_TYPE_MEM:
/* memory-mapped */
return suit_plat_cpu_run(cpu_id, run_address);
ret = suit_plat_cpu_run(cpu_id, run_address);
break;
default:
LOG_ERR("Unsupported component type");
break;
return SUIT_ERR_UNSUPPORTED_COMPONENT_ID;
}

return SUIT_ERR_UNSUPPORTED_COMPONENT_ID;
if ((ret == SUIT_SUCCESS) && synchronous) {
#ifdef CONFIG_SUIT_EVENTS
/* Wait for one of the invoke events */
uint32_t invoke_events =
suit_event_wait(cpu_id, SUIT_EVENT_INVOKE_MASK, false, timeout_ms);

if (invoke_events & SUIT_EVENT_INVOKE_SUCCESS) {
return SUIT_SUCCESS;
}

/* Event timeout or invoke failed */
/* Allow to handle invoke failure inside the manifest. */
return SUIT_FAIL_CONDITION;
#else
/* Synchronous invoke not supported */
return SUIT_ERR_CRASH;
#endif /* CONFIG_SUIT_EVENTS */
}

return ret;
}
Loading

0 comments on commit a611591

Please sign in to comment.