1 /*
2 * Copyright (c) 2023-2026, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6 #include <common/debug.h>
7 #include <services/el3_spmd_logical_sp.h>
8 #include <services/ffa_svc.h>
9 #include <services/lfa_svc.h>
10 #include <smccc_helpers.h>
11
12 #include <plat/arm/common/plat_arm_lfa_components.h>
13
14 #define SPMD_LP_PARTITION_ID SPMD_LP_ID_START
15 #define SPMD_LP_UUID {0xe98e43ad, 0xb7db524f, 0x47a3bf57, 0x1588f4e3}
16
17 /* SPMD Logical SP currently only supports sending direct message. */
18 #define SPMD_PARTITION_PROPERTIES FFA_PARTITION_DIRECT_REQ_SEND
19
20 #define SPMD_LP_MAX_SUPPORTED_SP 10
21
22 #define SP_IMAGE_PKG_SIZE 0x100000
23
24 #define COMPONENT_ID_SP1 LFA_SP1
25 #define COMPONENT_ID_SP2 LFA_SP2
26
fvp_spmd_logical_partition_init(void)27 static int32_t fvp_spmd_logical_partition_init(void)
28 {
29 INFO("FVP SPMD LSP: Init function called.\n");
30
31 return 0;
32 }
33
34 /*
35 * Platform specific SMC handler used to translate SIP SMCs or other platform
36 * specific SMCs into FF-A direct messages.
37 */
plat_spmd_logical_sp_smc_handler(unsigned int 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)38 uintptr_t plat_spmd_logical_sp_smc_handler(unsigned int smc_fid,
39 u_register_t x1,
40 u_register_t x2,
41 u_register_t x3,
42 u_register_t x4,
43 void *cookie,
44 void *handle,
45 u_register_t flags)
46 {
47 struct ffa_value retval = { 0 };
48 uint64_t send_recv_id = SPMD_LP_PARTITION_ID << 16 | 0x8001;
49
50 /*
51 * Forward the SMC as direct request.
52 */
53 if (!spmd_el3_ffa_msg_direct_req(send_recv_id, x2, x3, x4, 0U, 0U, 0U, handle, &retval)) {
54 panic();
55 }
56
57 SMC_RET8(handle, retval.func, retval.arg1, retval.arg2, retval.arg3,
58 retval.arg4, retval.arg5, retval.arg6, retval.arg7);
59 }
60
61 #if SUPPORT_SP_LIVE_ACTIVATION
62
lfa_sp_prime(struct lfa_component_status * activation)63 static int32_t lfa_sp_prime(struct lfa_component_status *activation)
64 {
65 /**
66 * On the FVP simulation platform, Secure Partitions are assumed to be
67 * preloaded and authenticated, so skip PRIME. This callback is expected
68 * to be implemented thoroughly for real platforms.
69 */
70 return LFA_SUCCESS;
71 }
72
component_id_to_sp_ffa_id(uint32_t component_id)73 static uint16_t component_id_to_sp_ffa_id(uint32_t component_id)
74 {
75 switch (component_id) {
76 case COMPONENT_ID_SP1:
77 return FFA_ID_SP1;
78 case COMPONENT_ID_SP2:
79 return FFA_ID_SP2;
80 default:
81 return 0;
82 }
83 }
84
find_sp_image_base_in_staging(uint16_t sp_id)85 static uintptr_t find_sp_image_base_in_staging(uint16_t sp_id)
86 {
87 if (sp_id == FFA_ID_SP1) {
88 return FVP_SP1_STAGING_MEM_BASE;
89 } else if (sp_id == FFA_ID_SP2) {
90 return FVP_SP2_STAGING_MEM_BASE;
91 }
92
93 return 0U;
94 }
95
get_sp_id_and_uuid(uint32_t component_id,uint16_t * sp_id,uint32_t * target_uuid)96 bool get_sp_id_and_uuid(uint32_t component_id, uint16_t *sp_id, uint32_t *target_uuid)
97 {
98 const uuid_t uuid_sp1 = IMAGE_UUID_SECURE_PARTITION_1;
99 const uuid_t uuid_sp2 = IMAGE_UUID_SECURE_PARTITION_2;
100
101 assert(target_uuid != NULL && sp_id != NULL);
102
103 *sp_id = component_id_to_sp_ffa_id(component_id);
104
105 if (*sp_id == 0U) {
106 return false;
107 }
108
109 /* Convert uuid to flattened format */
110 if (*sp_id == FFA_ID_SP1) {
111 convert_uuid_to_u32_array(uuid_sp1, target_uuid);
112 } else {
113 convert_uuid_to_u32_array(uuid_sp2, target_uuid);
114 }
115
116 return true;
117 }
118
lfa_sp_activate(struct lfa_component_status * activation,uint64_t ep_address,uint64_t context_id)119 static int32_t lfa_sp_activate(struct lfa_component_status *activation,
120 uint64_t ep_address, uint64_t context_id)
121 {
122 enum lfa_retc ret_lfa;
123 uint16_t sp_id = 0U;
124 uintptr_t image_base;
125 uint32_t target_uuid[4] = { 0 };
126 static struct ffa_partition_info_v1_3 target_info;
127 struct ffa_value ret = { 0 };
128 uint64_t image_page_count = SP_IMAGE_PKG_SIZE / PAGE_SIZE;
129
130 if (activation == NULL) {
131 ERROR("Live activation of endpoint not supported by platform\n");
132 return LFA_NOT_SUPPORTED;
133 }
134
135 if (!get_sp_id_and_uuid(activation->component_id, &sp_id, target_uuid)) {
136 ERROR("Unrecognized endpoint specified for live activation\n");
137 return LFA_NOT_SUPPORTED;
138 }
139
140 /* Get partition properties. */
141 if (!spmd_el3_invoke_partition_info_get(target_uuid, 0, 0, &ret)) {
142 ERROR("Unable to retrieve partition info\n");
143 return LFA_COMPONENT_WRONG_STATE;
144 }
145
146 if (is_ffa_error(&ret)) {
147 return convert_ffa_error_code_to_lfa((int32_t)ret.arg2);
148 }
149
150 /*
151 * Extract partition information from the first descriptor. The number
152 * of descriptors may be more than 1 if the SP exposes multiple protocol
153 * UUIDs.
154 */
155 if (!ffa_partition_info_regs_get_part_info(&ret, 0, &target_info)) {
156 ERROR("Failed to obtain partition info\n");
157 return LFA_COMPONENT_WRONG_STATE;
158 }
159
160 if (target_info.ep_id != sp_id) {
161 ERROR("Mismatch in SP endpoint ID\n");
162 return LFA_COMPONENT_WRONG_STATE;
163 }
164
165 /* Ensure it is UP SP. */
166 if (target_info.execution_ctx_count != 1) {
167 ERROR("Live activation not supported for MP SP\n");
168 return LFA_NOT_SUPPORTED;
169 }
170
171 /* Ensure it supports live activation. */
172 if ((target_info.properties & FFA_PARTITION_LIVE_ACTIVATION) == 0U) {
173 ERROR("Partition does not support live activation\n");
174 return LFA_NOT_SUPPORTED;
175 }
176
177 /* Ensure CPU rendezvous is not required. */
178 if ((target_info.properties & FFA_PARTITION_CPU_RENDEZVOUS) != 0U) {
179 ERROR("Partition requires CPU Rendezvous. Not supported\n");
180 return LFA_NOT_SUPPORTED;
181 }
182
183 image_base = find_sp_image_base_in_staging(sp_id);
184
185 /*
186 * Check if the new firmware image could not be loaded from live
187 * activation store to staging area.
188 */
189 if (image_base == 0U) {
190 return LFA_DEVICE_ERROR;
191 }
192
193 INFO("LSP: Initiate Live activation start request\n");
194 /* SP live activation start request. */
195 ret_lfa = spmd_lsp_start_request_sp_live_activation(
196 SPMD_LP_PARTITION_ID, sp_id, image_base, image_page_count, 0,
197 0);
198
199 if (ret_lfa != LFA_SUCCESS) {
200 ERROR("LSP: Live activation start request failed\n");
201 return ret_lfa;
202 }
203
204 INFO("LSP: Initiate Live activation finish request\n");
205
206 /* SP live activation finish request. */
207 ret_lfa = spmd_lsp_finish_request_sp_live_activation(
208 SPMD_LP_PARTITION_ID, sp_id);
209
210 if (ret_lfa != LFA_SUCCESS) {
211 ERROR("LSP: Live activation finish request failed\n");
212
213 /*
214 * The target SP's old image has already been replaced by
215 * new image. Since the activation failed, the SP is no
216 * longer able to provide any services. The only choice left
217 * is system reset.
218 */
219 return LFA_CRITICAL_ERROR;
220 }
221
222 return ret_lfa;
223 }
224
225 static struct lfa_component_ops secure_partition_activator = {
226 .prime = lfa_sp_prime,
227 .activate = lfa_sp_activate,
228 .may_reset_cpu = false,
229 .cpu_rendezvous_required = false,
230 };
231
get_secure_partition_activator(void)232 struct lfa_component_ops *get_secure_partition_activator(void)
233 {
234 return &secure_partition_activator;
235 }
236
237 #endif /* SUPPORT_SP_LIVE_ACTIVATION */
238
239 /* Register SPMD logical partition */
240 DECLARE_SPMD_LOGICAL_PARTITION(
241 fvp_spmd_logical_partition,
242 fvp_spmd_logical_partition_init,/* Init Function */
243 SPMD_LP_PARTITION_ID, /* FF-A Partition ID */
244 SPMD_LP_UUID, /* UUID */
245 SPMD_PARTITION_PROPERTIES /* Partition Properties. */
246 );
247