fix(spmd): check pwr mgmt status for SPMC framework response
The direct message response received by the SPMD upon a CPU_OFF power
management operation must be a framework message. If message indicates
SPMC denied the CPU_OFF operation, SPMD shall panic.
However, if SPMC does not support receiving power management
related framework messages from SPMD, it will return FFA_ERROR.
In such case, SPMD takes an implementation defined choice to ignore the
the FFA_ERROR and proceed with power management operation.
Change-Id: I18b9ee3fb8fd605bcd4aaa6802c969e9d36ccbe1
Signed-off-by: Madhukar Pappireddy <madhukar.pappireddy@arm.com>
diff --git a/include/services/ffa_svc.h b/include/services/ffa_svc.h
index f5a9a2d..0010d2b 100644
--- a/include/services/ffa_svc.h
+++ b/include/services/ffa_svc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2020-2025, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -57,8 +57,8 @@
<< FFA_MSG_SEND_ATTRS_BLK_SHIFT)
/* Defines for FF-A framework messages exchanged using direct messages. */
-#define FFA_FWK_MSG_BIT BIT(31)
-#define FFA_FWK_MSG_MASK 0xFF
+#define FFA_FWK_MSG_BIT BIT_32(31)
+#define FFA_FWK_MSG_MASK U(0xFF)
#define FFA_FWK_MSG_PSCI U(0x0)
/* Defines for FF-A power management messages framework messages. */
diff --git a/services/std_svc/spmd/spmd_main.c b/services/std_svc/spmd/spmd_main.c
index 94634f2..310610d 100644
--- a/services/std_svc/spmd/spmd_main.c
+++ b/services/std_svc/spmd/spmd_main.c
@@ -888,11 +888,15 @@
}
/*
- * If there was an SPMD logical partition direct request on-going,
+ * Perform a synchronous exit:
+ * 1. If there was an SPMD logical partition direct request on-going,
* return back to the SPMD logical partition so the error can be
* consumed.
+ * 2. SPMC sent FFA_ERROR in response to a power management
+ * operation sent through direct request.
*/
- if (is_spmd_logical_sp_dir_req_in_progress(ctx)) {
+ if (is_spmd_logical_sp_dir_req_in_progress(ctx) ||
+ ctx->psci_operation_ongoing) {
assert(secure_origin);
spmd_spm_core_sync_exit(0ULL);
}
diff --git a/services/std_svc/spmd/spmd_pm.c b/services/std_svc/spmd/spmd_pm.c
index fd89c81..4ed3e2f 100644
--- a/services/std_svc/spmd/spmd_pm.c
+++ b/services/std_svc/spmd/spmd_pm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2025, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -117,6 +117,8 @@
spmd_spm_core_context_t *ctx = spmd_get_context();
unsigned int linear_id = plat_my_core_pos();
int64_t rc;
+ uint32_t ffa_resp_func_id, msg_flags;
+ int status;
assert(ctx != NULL);
assert(ctx->state != SPMC_STATE_OFF);
@@ -137,24 +139,60 @@
write_ctx_reg(gpregs, CTX_GPREG_X16, 0);
write_ctx_reg(gpregs, CTX_GPREG_X17, 0);
+ /* Mark current core as processing a PSCI operation. */
+ ctx->psci_operation_ongoing = true;
+
rc = spmd_spm_core_sync_entry(ctx);
+
if (rc != 0ULL) {
ERROR("%s failed (%" PRIu64 ") on CPU%u\n", __func__, rc, linear_id);
}
+ ctx->psci_operation_ongoing = false;
+
/* Expect a direct message response from the SPMC. */
- u_register_t ffa_resp_func = read_ctx_reg(get_gpregs_ctx(&ctx->cpu_ctx),
+ ffa_resp_func_id = (uint32_t)read_ctx_reg(get_gpregs_ctx(&ctx->cpu_ctx),
CTX_GPREG_X0);
- if (ffa_resp_func != FFA_MSG_SEND_DIRECT_RESP_SMC32) {
- ERROR("%s invalid SPMC response (%lx).\n",
- __func__, ffa_resp_func);
- return -EINVAL;
+
+ /*
+ * Retrieve flags indicating framework message and power management
+ * response.
+ */
+ msg_flags = (uint32_t)read_ctx_reg(get_gpregs_ctx(&ctx->cpu_ctx),
+ CTX_GPREG_X2);
+
+ /* Retrieve error code indicating status of power management operation. */
+ status = (int)read_ctx_reg(get_gpregs_ctx(&ctx->cpu_ctx),
+ CTX_GPREG_X3);
+
+ if (ffa_resp_func_id == FFA_ERROR) {
+ /*
+ * It is likely that SPMC does not support receiving PSCI
+ * operation through framework message. SPMD takes an
+ * implementation defined choice to not treat it as a fatal
+ * error. Consequently, SPMD ignores the error and continues
+ * with power management operation.
+ */
+ VERBOSE("SPMC ignored PSCI CPU_OFF framework message\n");
+ } else if (ffa_resp_func_id != FFA_MSG_SEND_DIRECT_RESP_SMC32) {
+ ERROR("%s invalid SPMC response (%x).\n",
+ __func__, ffa_resp_func_id);
+ panic();
+ } else if (((msg_flags & FFA_FWK_MSG_BIT) == 0U) ||
+ ((msg_flags & FFA_FWK_MSG_MASK) != FFA_PM_MSG_PM_RESP)) {
+ ERROR("SPMC failed to send framework message response for power"
+ " management operation, message flags = (%x)\n",
+ msg_flags);
+ panic();
+ } else if (status != PSCI_E_SUCCESS) {
+ ERROR("SPMC denied CPU_OFF power management request\n");
+ panic();
+ } else {
+ VERBOSE("CPU %u off!\n", linear_id);
}
ctx->state = SPMC_STATE_OFF;
- VERBOSE("CPU %u off!\n", linear_id);
-
return 0;
}
diff --git a/services/std_svc/spmd/spmd_private.h b/services/std_svc/spmd/spmd_private.h
index 2cd18a2..0dfad02 100644
--- a/services/std_svc/spmd/spmd_private.h
+++ b/services/std_svc/spmd/spmd_private.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2025, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -52,6 +52,7 @@
cpu_context_t cpu_ctx;
spmc_state_t state;
bool secure_interrupt_ongoing;
+ bool psci_operation_ongoing;
#if ENABLE_SPMD_LP
uint8_t spmd_lp_sync_req_ongoing;
#endif