xref: /rk3399_ARM-atf/plat/arm/board/fvp/fvp_spmd_logical_sp.c (revision aea8f36ccb999395ee8c47f4e8dc2363ac164953)
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