fix(spmd): fix FFA_VERSION forwarding
When FFA_VERSION is forwarded from SPMD to SPMC, ensure that the full
NS GP regs context incl. x8-x17 is carried when building the SPMD to
SPMC direct message.
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
Change-Id: I3467c0e04de95ab80f7c86a0763021a5fa961e4d
diff --git a/services/std_svc/spmd/spmd_main.c b/services/std_svc/spmd/spmd_main.c
index d830403..066571e 100644
--- a/services/std_svc/spmd/spmd_main.c
+++ b/services/std_svc/spmd/spmd_main.c
@@ -110,6 +110,12 @@
spmd_spmc_id_get());
write_ctx_reg(gpregs, CTX_GPREG_X2, BIT(31) | target_func);
write_ctx_reg(gpregs, CTX_GPREG_X3, message);
+
+ /* Zero out x4-x7 for the direct request emitted towards the SPMC. */
+ write_ctx_reg(gpregs, CTX_GPREG_X4, 0);
+ write_ctx_reg(gpregs, CTX_GPREG_X5, 0);
+ write_ctx_reg(gpregs, CTX_GPREG_X6, 0);
+ write_ctx_reg(gpregs, CTX_GPREG_X7, 0);
}
@@ -945,6 +951,21 @@
SPMD_FWK_MSG_FFA_VERSION_REQ,
input_version);
+ /*
+ * Ensure x8-x17 NS GP register values are untouched when returning
+ * from the SPMC.
+ */
+ write_ctx_reg(gpregs, CTX_GPREG_X8, SMC_GET_GP(handle, CTX_GPREG_X8));
+ write_ctx_reg(gpregs, CTX_GPREG_X9, SMC_GET_GP(handle, CTX_GPREG_X9));
+ write_ctx_reg(gpregs, CTX_GPREG_X10, SMC_GET_GP(handle, CTX_GPREG_X10));
+ write_ctx_reg(gpregs, CTX_GPREG_X11, SMC_GET_GP(handle, CTX_GPREG_X11));
+ write_ctx_reg(gpregs, CTX_GPREG_X12, SMC_GET_GP(handle, CTX_GPREG_X12));
+ write_ctx_reg(gpregs, CTX_GPREG_X13, SMC_GET_GP(handle, CTX_GPREG_X13));
+ write_ctx_reg(gpregs, CTX_GPREG_X14, SMC_GET_GP(handle, CTX_GPREG_X14));
+ write_ctx_reg(gpregs, CTX_GPREG_X15, SMC_GET_GP(handle, CTX_GPREG_X15));
+ write_ctx_reg(gpregs, CTX_GPREG_X16, SMC_GET_GP(handle, CTX_GPREG_X16));
+ write_ctx_reg(gpregs, CTX_GPREG_X17, SMC_GET_GP(handle, CTX_GPREG_X17));
+
rc = spmd_spm_core_sync_entry(ctx);
if ((rc != 0ULL) ||
@@ -960,6 +981,14 @@
}
/*
+ * x0-x4 are updated by spmd_smc_forward below.
+ * Zero out x5-x7 in the FFA_VERSION response.
+ */
+ write_ctx_reg(gpregs, CTX_GPREG_X5, 0);
+ write_ctx_reg(gpregs, CTX_GPREG_X6, 0);
+ write_ctx_reg(gpregs, CTX_GPREG_X7, 0);
+
+ /*
* Return here after SPMC has handled FFA_VERSION.
* The returned SPMC version is held in X3.
* Forward this version in X0 to the non-secure caller.
diff --git a/services/std_svc/spmd/spmd_pm.c b/services/std_svc/spmd/spmd_pm.c
index a2704dd..fd89c81 100644
--- a/services/std_svc/spmd/spmd_pm.c
+++ b/services/std_svc/spmd/spmd_pm.c
@@ -122,8 +122,20 @@
assert(ctx->state != SPMC_STATE_OFF);
/* Build an SPMD to SPMC direct message request. */
- spmd_build_spmc_message(get_gpregs_ctx(&ctx->cpu_ctx),
- FFA_FWK_MSG_PSCI, PSCI_CPU_OFF);
+ gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx);
+ spmd_build_spmc_message(gpregs, FFA_FWK_MSG_PSCI, PSCI_CPU_OFF);
+
+ /* Clear remaining x8 - x17 at EL3/SEL2 or EL3/SEL1 boundary. */
+ write_ctx_reg(gpregs, CTX_GPREG_X8, 0);
+ write_ctx_reg(gpregs, CTX_GPREG_X9, 0);
+ write_ctx_reg(gpregs, CTX_GPREG_X10, 0);
+ write_ctx_reg(gpregs, CTX_GPREG_X11, 0);
+ write_ctx_reg(gpregs, CTX_GPREG_X12, 0);
+ write_ctx_reg(gpregs, CTX_GPREG_X13, 0);
+ write_ctx_reg(gpregs, CTX_GPREG_X14, 0);
+ write_ctx_reg(gpregs, CTX_GPREG_X15, 0);
+ write_ctx_reg(gpregs, CTX_GPREG_X16, 0);
+ write_ctx_reg(gpregs, CTX_GPREG_X17, 0);
rc = spmd_spm_core_sync_entry(ctx);
if (rc != 0ULL) {