summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Powell <john.powell@arm.com>2026-06-26 13:52:52 -0500
committerJohn Powell <john.powell@arm.com>2026-06-30 15:42:43 +0000
commite6bccf43c4f93a25a0e1c7877107022537a17cad (patch)
tree23c99170f8f2f431345d7e370c7b7b8826bf5a8b
parent567e4357fb29be24ab5917102d2a5ed6f6feba4d (diff)
downloadarm-trusted-firmware-e6bccf43c4f93a25a0e1c7877107022537a17cad.tar.gz
arm-trusted-firmware-e6bccf43c4f93a25a0e1c7877107022537a17cad.zip
feat(lfa): lfa service updates
This patch updates the LFA service components in preparation for BL31 specific changes. Change-Id: I6d4dd90b11fa1d8729c4f9026d2ddce0272aea76 Signed-off-by: John Powell <john.powell@arm.com>
-rw-r--r--include/services/lfa_component_desc.h37
-rw-r--r--include/services/lfa_svc.h7
-rw-r--r--services/std_svc/lfa/lfa_main.c99
-rw-r--r--services/std_svc/rmmd/rmmd_rmm_lfa.c1
4 files changed, 88 insertions, 56 deletions
diff --git a/include/services/lfa_component_desc.h b/include/services/lfa_component_desc.h
index aefef953a..d15041e17 100644
--- a/include/services/lfa_component_desc.h
+++ b/include/services/lfa_component_desc.h
@@ -16,20 +16,55 @@ typedef enum {
PRIME_COMPLETE,
} lfa_prime_status_t;
+/*
+ * This structure contains the status of a component that is currently in the
+ * process of being activated.
+ *
+ * component_id ID of the activation component currently in progress.
+ * Can be either RMM or BL31.
+ * prime_status Current prime status of this component.
+ * image_size Size of the image file to be activated.
+ * image_address Address of the image file to be activated.
+ * reset Flag indicating that the core will warm reset after the
+ * activation.
+ * cpu_rendezvous Flag indicating that active CPUs will rendezvous prior
+ * to activation. This is set to true by default and can
+ * only be cleared if the caller requests it and the flag
+ * cpu_rendezvous_required in the component ops structure
+ * is clear.
+ */
struct lfa_component_status {
uint32_t component_id;
lfa_prime_status_t prime_status;
- bool cpu_rendezvous_required;
+ size_t image_size;
+ uintptr_t image_address;
+ bool reset;
+ bool cpu_rendezvous;
};
typedef int (*component_prime_fn)(struct lfa_component_status *activation);
typedef int (*component_activate_fn)(struct lfa_component_status *activation,
uint64_t ep_address,
uint64_t context_id);
+typedef int (*component_cancel_fn)(struct lfa_component_status *activation);
+/*
+ * This structure is defined per-component and contains pointers to the prime
+ * and activate functions as well as some basic requirements for activation of
+ * that component.
+ *
+ * prime Pointer to prime function for a component.
+ * activate Pointer to activate function for a component.
+ * may_reset_cpu Flag letting the caller know to expect a CPU warm
+ * reset after activation.
+ * cpu_rendezvous_required Flag indicating that a CPU reset is not optional. If
+ * this flag is set, the caller cannot request skipping
+ * the CPU rendezvous.
+ */
struct lfa_component_ops {
component_prime_fn prime;
component_activate_fn activate;
+ component_cancel_fn cancel;
bool may_reset_cpu;
bool cpu_rendezvous_required;
};
diff --git a/include/services/lfa_svc.h b/include/services/lfa_svc.h
index f585cf3e5..3485a7234 100644
--- a/include/services/lfa_svc.h
+++ b/include/services/lfa_svc.h
@@ -77,6 +77,12 @@ enum lfa_retc {
LFA_ACTIVATION_FAILED = -11,
};
+typedef struct {
+ entry_point_info_t ep;
+ uint64_t spinlock_p;
+ uintptr_t plat_wr_mailbox;
+} lfa_mailbox_message_t;
+
/* Initialization routine for the LFA service */
int lfa_setup(void);
@@ -85,5 +91,6 @@ uint64_t lfa_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2,
void *handle, u_register_t flags);
void lfa_reset_activation(void);
bool lfa_is_prime_complete(uint32_t lfa_component_id);
+uint64_t prepare_warm_reset(uintptr_t lfa_ns_ep, uint64_t context_id, uint64_t cpu_spinlock);
#endif /* LFA_SVC_H */
diff --git a/services/std_svc/lfa/lfa_main.c b/services/std_svc/lfa/lfa_main.c
index 819b169a7..0022e0331 100644
--- a/services/std_svc/lfa/lfa_main.c
+++ b/services/std_svc/lfa/lfa_main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2025, Arm Limited. All rights reserved.
+ * Copyright (c) 2025-2026, Arm Limited. All rights reserved.
* Copyright (c) 2025, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -32,7 +32,6 @@ void lfa_reset_activation(void)
{
current_activation.component_id = LFA_INVALID_COMPONENT;
current_activation.prime_status = PRIME_NONE;
- current_activation.cpu_rendezvous_required = false;
}
static int convert_to_lfa_error(int ret)
@@ -54,8 +53,7 @@ static bool lfa_initialize_components(void)
lfa_component_count = plat_lfa_get_components(&lfa_components);
if (lfa_component_count == 0U || lfa_components == NULL) {
- /* unlikely to reach here */
- ERROR("Invalid LFA component setup: count = 0 or components are NULL");
+ ERROR("Could not retrieve LFA components.\n");
return false;
}
@@ -64,8 +62,7 @@ static bool lfa_initialize_components(void)
static uint64_t get_fw_activation_flags(uint32_t fw_seq_id)
{
- const plat_lfa_component_info_t *comp =
- &lfa_components[fw_seq_id];
+ const plat_lfa_component_info_t *comp = &lfa_components[fw_seq_id];
uint64_t flags = 0ULL;
flags |= ((comp->activator == NULL ? 0ULL : 1ULL)
@@ -86,6 +83,7 @@ static uint64_t get_fw_activation_flags(uint32_t fw_seq_id)
static int lfa_cancel(uint32_t component_id)
{
int ret = LFA_SUCCESS;
+ struct lfa_component_ops *activator;
if (lfa_component_count == 0U) {
return LFA_WRONG_STATE;
@@ -97,6 +95,14 @@ static int lfa_cancel(uint32_t component_id)
return LFA_INVALID_PARAMETERS;
}
+ activator = lfa_components[component_id].activator;
+ if (activator->cancel != NULL) {
+ ret = activator->cancel(&current_activation);
+ if (ret != LFA_SUCCESS) {
+ return LFA_BUSY;
+ }
+ }
+
ret = plat_lfa_cancel(component_id);
if (ret != LFA_SUCCESS) {
return LFA_BUSY;
@@ -120,13 +126,13 @@ static int lfa_activate(uint32_t component_id, uint64_t flags,
return LFA_COMPONENT_WRONG_STATE;
}
- /* Check if fw_seq_id is in range. */
if ((component_id >= lfa_component_count) ||
(current_activation.component_id != component_id)) {
return LFA_INVALID_PARAMETERS;
}
- if (lfa_components[component_id].activator == NULL) {
+ activator = lfa_components[component_id].activator;
+ if (activator == NULL) {
return LFA_NOT_SUPPORTED;
}
@@ -135,35 +141,20 @@ static int lfa_activate(uint32_t component_id, uint64_t flags,
return LFA_ACTIVATION_FAILED;
}
- activator = lfa_components[component_id].activator;
- if (activator->activate != NULL) {
- /*
- * Pass skip_cpu_rendezvous (flag[0]) only if flag[0]==1
- * & CPU_RENDEZVOUS is not required.
- */
- if (flags & LFA_SKIP_CPU_RENDEZVOUS_BIT) {
- if (!activator->cpu_rendezvous_required) {
- INFO("Skipping rendezvous requested by caller.\n");
- current_activation.cpu_rendezvous_required = false;
- }
- /*
- * Return error if caller tries to skip rendezvous when
- * it is required.
- */
- else {
- ERROR("CPU Rendezvous is required, can't skip.\n");
- return LFA_INVALID_PARAMETERS;
- }
+ /* If caller requests it, see if we can skip CPU rendezvous. */
+ if (flags & LFA_SKIP_CPU_RENDEZVOUS_BIT) {
+ if (!activator->cpu_rendezvous_required) {
+ INFO("Caller requested skip CPU rendezvous.\n");
+ current_activation.cpu_rendezvous = false;
+ } else {
+ ERROR("CPU rendezvous cannot be skipped!\n");
+ return LFA_INVALID_PARAMETERS;
}
-
- ret = activator->activate(&current_activation, ep_address,
- context_id);
}
- /*
- * Update the activation pending flag only if the activation was
- * successful.
- */
+ ret = activator->activate(&current_activation, ep_address, context_id);
+
+ /* Clear pending flag on successful activation. */
if (ret == LFA_SUCCESS) {
lfa_components[component_id].activation_pending = false;
}
@@ -225,7 +216,13 @@ static int lfa_prime(uint32_t component_id, uint64_t *flags)
}
}
+ /*
+ * Update current activation status fields. CPU rendezvous is enabled
+ * by default but can be disabled if requested and allowed.
+ */
+ current_activation.cpu_rendezvous = true;
current_activation.prime_status = PRIME_COMPLETE;
+ current_activation.reset = lfa_components[component_id].activator->may_reset_cpu;
}
/*
@@ -268,8 +265,9 @@ uint64_t lfa_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2,
u_register_t x3, u_register_t x4, void *cookie,
void *handle, u_register_t flags)
{
- uint64_t retx1, retx2;
- uint64_t lfa_flags;
+ uint64_t retx1;
+ uint64_t retx2;
+ uint64_t lfa_flags = 0;
uint8_t *uuid_p;
uint32_t fw_seq_id = (uint32_t)x1;
int ret;
@@ -292,9 +290,9 @@ uint64_t lfa_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2,
break;
case LFA_GET_INFO:
- /**
+ /*
* The current specification limits this input parameter to be zero for
- * version 1.0 of LFA
+ * version 1.0 of LFA.
*/
if (x1 == 0ULL) {
SMC_RET3(handle, LFA_SUCCESS, lfa_component_count, 0);
@@ -309,29 +307,27 @@ uint64_t lfa_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2,
}
/*
- * Check if fw_seq_id is in range. LFA_GET_INFO must be called first to scan
- * platform firmware and create a valid number of firmware components.
+ * Check if fw_seq_id is in range. LFA_GET_INFO must be called
+ * first to scan platform firmware and create a valid number of
+ * firmware components.
*/
if (fw_seq_id >= lfa_component_count) {
SMC_RET1(handle, LFA_INVALID_PARAMETERS);
}
- /*
- * grab the UUID of asked fw_seq_id and set the return UUID
- * variables
- */
+ /* Get the UUID of requested fw_seq_id. */
uuid_p = (uint8_t *)&lfa_components[fw_seq_id].uuid;
memcpy(&retx1, uuid_p, sizeof(uint64_t));
memcpy(&retx2, uuid_p + sizeof(uint64_t), sizeof(uint64_t));
/*
- * check the given fw_seq_id's update available
- * and accordingly set the active_pending flag
+ * Check the given fw_seq_id update available and accordingly
+ * set the active_pending flag.
*/
lfa_components[fw_seq_id].activation_pending =
is_plat_lfa_activation_pending(fw_seq_id);
- INFO("Component %lu %s live activation:\n", x1,
+ INFO("Component %lu %s live activation.\n", x1,
lfa_components[fw_seq_id].activator ? "supports" :
"does not support");
@@ -340,10 +336,7 @@ uint64_t lfa_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2,
lfa_components[fw_seq_id].activation_pending ? "true" : "false");
}
- INFO("x1 = 0x%016lx, x2 = 0x%016lx\n", retx1, retx2);
-
SMC_RET4(handle, LFA_SUCCESS, retx1, retx2, get_fw_activation_flags(fw_seq_id));
-
break;
case LFA_PRIME:
@@ -372,7 +365,6 @@ uint64_t lfa_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2,
ret = lfa_activate(fw_seq_id, x2, x3, x4);
/* TODO: implement activate again */
SMC_RET2(handle, ret, 0ULL);
-
break;
case LFA_CANCEL:
@@ -383,11 +375,8 @@ uint64_t lfa_smc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2,
default:
WARN("Unimplemented LFA Service Call: 0x%x\n", smc_fid);
SMC_RET1(handle, SMC_UNK);
- break; /* unreachable */
-
+ break;
}
- SMC_RET1(handle, SMC_UNK);
-
return 0;
}
diff --git a/services/std_svc/rmmd/rmmd_rmm_lfa.c b/services/std_svc/rmmd/rmmd_rmm_lfa.c
index 74c8cdddc..23c14e23c 100644
--- a/services/std_svc/rmmd/rmmd_rmm_lfa.c
+++ b/services/std_svc/rmmd/rmmd_rmm_lfa.c
@@ -78,6 +78,7 @@ static int lfa_rmm_activate(struct lfa_component_status *activation,
static struct lfa_component_ops rmm_activator = {
.prime = lfa_rmm_prime,
.activate = lfa_rmm_activate,
+ .cancel = NULL,
.may_reset_cpu = false,
.cpu_rendezvous_required = true,
};