blob: 40c911fd167691057179237e5269f345aa338a31 [file] [log] [blame]
Mate Toth-Pal57fadaf2025-02-06 10:21:30 +01001/*
2 * SPDX-License-Identifier: BSD-3-Clause
3 * SPDX-FileCopyrightText: Copyright TF-RMM Contributors.
4 */
5
6#include <app.h>
7#include <app_common.h>
8#include <app_services.h>
9#include <assert.h>
Mate Toth-Pal646c6032025-02-06 11:01:37 +010010#include <attest_services.h>
Soby Mathew1232bb52025-04-24 10:13:51 +010011#include <buffer.h>
Mate Toth-Pal57fadaf2025-02-06 10:21:30 +010012#include <console.h>
Soby Mathew1232bb52025-04-24 10:13:51 +010013#include <debug.h>
Mate Toth-Pal646c6032025-02-06 11:01:37 +010014#include <errno.h>
15#include <random_app.h>
16#include <rmm_el3_ifc.h>
Mate Toth-Pal57fadaf2025-02-06 10:21:30 +010017
18typedef uint64_t (*app_service_func)(struct app_data_cfg *app_data,
19 unsigned long arg0,
20 unsigned long arg1,
21 unsigned long arg2,
22 unsigned long arg3);
23
Soby Mathew1232bb52025-04-24 10:13:51 +010024struct ns_rw_data {
25 uintptr_t app_buf;
26 struct granule *ns_granule;
27};
28
Mate Toth-Pal57fadaf2025-02-06 10:21:30 +010029static uint64_t app_service_print(struct app_data_cfg *app_data,
30 unsigned long arg0,
31 unsigned long arg1,
32 unsigned long arg2,
33 unsigned long arg3)
34{
Mate Toth-Pal4129d892025-06-02 17:38:57 +020035 int character = (int)arg0;
Mate Toth-Pal57fadaf2025-02-06 10:21:30 +010036
Mate Toth-Pal4129d892025-06-02 17:38:57 +020037 (void)app_data;
Mate Toth-Pal57fadaf2025-02-06 10:21:30 +010038 (void)arg1;
39 (void)arg2;
40 (void)arg3;
41
Mate Toth-Pal4129d892025-06-02 17:38:57 +020042 (void)console_putc(character);
Mate Toth-Pal57fadaf2025-02-06 10:21:30 +010043 return 0;
44}
45
Mate Toth-Pal646c6032025-02-06 11:01:37 +010046static uint64_t app_service_get_random(struct app_data_cfg *app_data,
47 unsigned long arg0,
48 unsigned long arg1,
49 unsigned long arg2,
50 unsigned long arg3)
51{
52 size_t len = arg0;
53 uint8_t buf[GRANULE_SIZE];
54 int ret;
55 void *shared_page;
56
57 (void)arg1;
58 (void)arg2;
59 (void)arg3;
60
61 if (len >= GRANULE_SIZE) {
62 return (uint64_t)(-EINVAL);
63 }
64
65 /* TODO: The random app generates the random values to the shared memory between
66 * RMM and random app. that gets copied to buf. That's gets copied to the shared
67 * memory between RMM and calling app. This should be optimised.
68 */
69
70 struct app_data_cfg *random_app_data = random_app_get_data_cfg();
71
72 ret = random_app_prng_get_random(random_app_data, buf, len);
73 if (ret != 0) {
74 return (uint64_t)ret;
75 }
76
77 shared_page = app_data->el2_shared_page;
78 assert(shared_page != NULL);
79 /* coverity[misra_c_2012_rule_9_1_violation:SUPPRESS] */
80 (void)memcpy(shared_page, (void *)buf, len);
81 return 0;
82}
83
84static uint64_t app_service_get_realm_attestation_key(struct app_data_cfg *app_data,
85 unsigned long arg0,
86 unsigned long arg1,
87 unsigned long arg2,
88 unsigned long arg3)
89{
90 uintptr_t buf;
91 size_t attest_key_size;
92 struct service_get_realm_attestation_key_struct *shared_page;
93
94 (void)arg0;
95 (void)arg1;
96 (void)arg2;
97 (void)arg3;
98
99 /*
100 * Get the realm attestation key. The key is retrieved in raw format.
101 */
102 buf = rmm_el3_ifc_get_shared_buf_locked();
103
104 if (rmm_el3_ifc_get_realm_attest_key(buf,
105 rmm_el3_ifc_get_shared_buf_size(),
106 &attest_key_size,
107 ATTEST_KEY_CURVE_ECC_SECP384R1) != 0) {
108 rmm_el3_ifc_release_shared_buf();
109 return (uint64_t)(-EINVAL);
110 }
111
112 if (attest_key_size >= APP_MAX_ATTEST_KEY_SIZE) {
113 return (uint64_t)(-EINVAL);
114 }
115
116 shared_page = app_data->el2_shared_page;
117 assert(shared_page != NULL);
118 shared_page->attest_key_buf_size = attest_key_size;
119 (void)memcpy((void *)shared_page->attest_key_buf,
120 (void *)buf, shared_page->attest_key_buf_size);
121
122 /* Clear the private key from the buffer */
123 (void)memset((uint8_t *)buf, 0, attest_key_size);
124
125 rmm_el3_ifc_release_shared_buf();
126
127 return 0;
128}
129
130static uint64_t app_service_get_platform_token(struct app_data_cfg *app_data,
131 unsigned long arg0,
132 unsigned long arg1,
133 unsigned long arg2,
134 unsigned long arg3)
135{
136 size_t current_hunk_len = 0;
137 size_t bytes_remaining = 0;
138 size_t hash_size = arg0;
139 int ret;
140 uintptr_t shared_buf;
141 void *shared_page_void;
142 struct service_get_platform_token_struct *shared_page_get_plat_token;
143
144 size_t service_token_buf_len = sizeof(shared_page_get_plat_token->token_hunk_buf);
145
146 (void)arg1;
147 (void)arg2;
148 (void)arg3;
149
150 if (hash_size >= GRANULE_SIZE) {
151 return (uint64_t)(-EINVAL);
152 }
153
154 shared_buf = rmm_el3_ifc_get_shared_buf_locked();
155
156 shared_page_void = app_data->el2_shared_page;
157 assert(shared_page_void != NULL);
158 (void)memcpy((void *)shared_buf, shared_page_void, hash_size);
159
160 do {
161 ret = rmm_el3_ifc_get_platform_token(
162 shared_buf,
163 service_token_buf_len,
164 hash_size,
165 &current_hunk_len,
166 &bytes_remaining);
167 } while (ret == E_RMM_AGAIN);
168
169 if (ret != E_RMM_OK) {
170 assert(ret != 0);
171 rmm_el3_ifc_release_shared_buf();
172 return (uint64_t)ret;
173 }
174
175 shared_page_get_plat_token = app_data->el2_shared_page;
176 assert(shared_page_get_plat_token != NULL);
177 assert(current_hunk_len <= GRANULE_SIZE);
178 assert(current_hunk_len <= sizeof(shared_page_get_plat_token->token_hunk_buf));
179 /* coverity[misra_c_2012_rule_21_18_violation:SUPPRESS] */
180 (void)memcpy((void *)shared_page_get_plat_token->token_hunk_buf, (void *)shared_buf, current_hunk_len);
181 rmm_el3_ifc_release_shared_buf();
182
183 shared_page_get_plat_token->token_hunk_len = current_hunk_len;
184 shared_page_get_plat_token->remaining_len = bytes_remaining;
185
186 return 0;
187}
188
189#if ATTEST_EL3_TOKEN_SIGN
190static uint64_t app_service_get_realm_attest_pub_key_from_el3(struct app_data_cfg *app_data,
191 unsigned long arg0,
192 unsigned long arg1,
193 unsigned long arg2,
194 unsigned long arg3)
195{
196 uintptr_t buf;
197 size_t attest_key_size;
198 struct service_get_realm_attestation_pub_key_struct *shared_page;
199
200 (void)arg0;
201 (void)arg1;
202 (void)arg2;
203 (void)arg3;
204
205 /*
206 * Get the realm attestation key. The key is retrieved in raw format.
207 */
208 buf = rmm_el3_ifc_get_shared_buf_locked();
209
210 /* When EL3 service is used for attestation, EL3 returns public key in raw format */
211 if (rmm_el3_ifc_get_realm_attest_pub_key_from_el3(buf,
212 rmm_el3_ifc_get_shared_buf_size(),
213 &attest_key_size,
214 ATTEST_KEY_CURVE_ECC_SECP384R1) != 0) {
215 rmm_el3_ifc_release_shared_buf();
216 return -EINVAL;
217 }
218
219 shared_page = app_data->el2_shared_page;
220 assert(attest_key_size <= sizeof(shared_page->attest_pub_key_buf));
221 shared_page->attest_pub_key_buf_size = attest_key_size;
222 memcpy((void *)&(shared_page->attest_pub_key_buf), (const void *)buf, attest_key_size);
223 rmm_el3_ifc_release_shared_buf();
224 return 0;
225}
226
227static uint64_t app_service_el3_token_sign_queue_try_enqueue(struct app_data_cfg *app_data,
228 unsigned long arg0,
229 unsigned long arg1,
230 unsigned long arg2,
231 unsigned long arg3)
232{
233 uint64_t ret;
234 struct service_el3_token_sign_request *request = app_data->el2_shared_page;
235
236 (void)arg0;
237 (void)arg1;
238 (void)arg2;
239 (void)arg3;
240
241 ret = el3_token_sign_queue_try_enqueue(request);
242 return ret;
243}
244
245static uint64_t app_service_el3_ifc_el3_token_sign_supported(struct app_data_cfg *app_data,
246 unsigned long arg0,
247 unsigned long arg1,
248 unsigned long arg2,
249 unsigned long arg3)
250{
251 (void)app_data;
252 (void)arg0;
253 (void)arg1;
254 (void)arg2;
255 (void)arg3;
256
257 return rmm_el3_ifc_el3_token_sign_supported();
258}
259#endif
260
Soby Mathew1232bb52025-04-24 10:13:51 +0100261static struct ns_rw_data validate_and_get_ns_rw_data(struct app_data_cfg *app_data,
262 unsigned long app_buf_id,
263 unsigned long app_buf_offset,
264 unsigned long ns_addr,
265 unsigned long buf_len)
266{
267 struct ns_rw_data rw_data = {0, NULL};
268 uintptr_t app_buf = 0;
269
270 if ((app_buf_id != APP_SERVICE_RW_NS_BUF_SHARED) &&
271 (app_buf_id != APP_SERVICE_RW_NS_BUF_HEAP)) {
Mate Toth-Pal5c649342025-06-24 10:37:32 +0200272 ERROR("%s called with invalid app_buf_id 0x%lx\n", __func__, app_buf_id);
Soby Mathew1232bb52025-04-24 10:13:51 +0100273 return rw_data;
274 }
275
276 /* Based on app_buf_id, work out the size of app buffer */
277 unsigned long app_buf_size = (app_buf_id == APP_SERVICE_RW_NS_BUF_SHARED) ?
278 GRANULE_SIZE : app_data->heap_size;
279
280 if ((app_buf_offset > app_buf_size) ||
281 ((app_buf_size - app_buf_offset) < buf_len) ||
282 (!ALIGNED(buf_len, 8U)) ||
283 (!ALIGNED(app_buf_offset, 8U))) {
Mate Toth-Pal5c649342025-06-24 10:37:32 +0200284 ERROR("%s called with invalid buf offset 0x%lx or len 0x%lx\n",
Soby Mathew1232bb52025-04-24 10:13:51 +0100285 __func__, app_buf_offset, buf_len);
286 return rw_data;
287 }
288
289 if (app_buf_id == APP_SERVICE_RW_NS_BUF_SHARED) {
290 app_buf = (uintptr_t)app_data->el2_shared_page + app_buf_offset;
291 } else {
292 app_buf = (uintptr_t)app_get_heap_ptr(app_data) + app_buf_offset;
293 }
294
295 unsigned long ns_addr_offset = ns_addr & ~GRANULE_MASK;
296
297 /* The data rw should not cross page boundary as only the single NS page
298 * is mapped.
299 */
300 if (((ns_addr_offset + buf_len) > SZ_4K) || (!ALIGNED(ns_addr_offset, 8U))) {
Mate Toth-Pal5c649342025-06-24 10:37:32 +0200301 ERROR("%s called with invalid ns addr 0x%lx.\n",
Soby Mathew1232bb52025-04-24 10:13:51 +0100302 __func__, ns_addr);
303 return rw_data;
304 }
305
306 /* Copy the data from NS buffer */
307 rw_data.ns_granule = find_granule(ns_addr & GRANULE_MASK);
308 if ((rw_data.ns_granule == NULL) ||
309 (granule_unlocked_state(rw_data.ns_granule) != GRANULE_STATE_NS)) {
Mate Toth-Pal5c649342025-06-24 10:37:32 +0200310 ERROR("%s ns granule not found or invalid state for ns addr 0x%lx\n",
Soby Mathew1232bb52025-04-24 10:13:51 +0100311 __func__, ns_addr);
312 return rw_data;
313 }
314
315 rw_data.app_buf = app_buf;
316 return rw_data;
317}
318
319/*
320 * Service to write to NS Address from app shared page or shared heap
321 * with specified offset and length.
322 *
323 * Arguments:
324 * arg0 - App Buffer identifier (one of APP_SERVICE_RW_NS_BUF_*)
325 * arg1 - App Buffer offset (must be 8 byte aligned).
326 * arg2 - NS buf physical address (must be 8 byte aligned)
327 * arg3 - Length to write (must be 8 byte aligned)
328 *
329 * The App buffer offset + Length must be either less that PAGE_SIZE or heap_size,
330 * depending on App Buffer identifier. This is a sanity check to ensure that
331 * buffer is in App VA space. Similarly the NS Address write must be within the
332 * page. It is assumed that app buffer is already mapped in RMM S1 MMU.
333 *
334 * Return:
335 * 0 - Success
336 * -EINVAL - Failure
337 */
338static uint64_t app_service_write_to_ns_buf(struct app_data_cfg *app_data,
339 unsigned long app_buf_id,
340 unsigned long app_buf_offset,
341 unsigned long ns_addr,
342 unsigned long buf_len)
343{
344 bool ns_access_ok;
345 struct ns_rw_data rw_data = validate_and_get_ns_rw_data(app_data, app_buf_id,
346 app_buf_offset, ns_addr, buf_len);
347
348 if (rw_data.ns_granule == NULL) {
349 return (uint64_t)(-EINVAL);
350 }
351
352 ns_access_ok = ns_buffer_write(SLOT_NS, rw_data.ns_granule, 0, buf_len,
353 (void *)rw_data.app_buf);
354 if (!ns_access_ok) {
Mate Toth-Pal5c649342025-06-24 10:37:32 +0200355 ERROR("%s ns buffer read failed for ns addr 0x%lx and app_buf 0x%lx\n",
Soby Mathew1232bb52025-04-24 10:13:51 +0100356 __func__, ns_addr, rw_data.app_buf);
357 return (uint64_t)(-EINVAL);
358 }
359
360 return 0;
361}
362
363/*
364 * Service to read from NS Address to app shared page or shared heap
365 * with specified offset and length.
366 *
367 * Arguments:
368 * arg0 - App Buffer identifier (one of APP_SERVICE_RW_NS_BUF_*)
369 * arg1 - App Buffer offset (must be 8 byte aligned).
370 * arg2 - NS buf physical address (must be 8 byte aligned)
371 * arg3 - Length to read (must be 8 byte aligned)
372 *
373 * The App buffer offset + Length must be either less that PAGE_SIZE or heap_size,
374 * depending on App Buffer identifier. This is a sanity check to ensure that
375 * buffer is in App VA space. Similarly the NS Address read must be within the
376 * page. It is assumed that app buffer is already mapped in RMM S1 MMU.
377 *
378 * Return:
379 * 0 - Success
380 * -EINVAL - Failure
381 */
382static uint64_t app_service_read_from_ns_buf(struct app_data_cfg *app_data,
383 unsigned long app_buf_id,
384 unsigned long app_buf_offset,
385 unsigned long ns_addr,
386 unsigned long buf_len)
387{
388 bool ns_access_ok;
389 struct ns_rw_data rw_data = validate_and_get_ns_rw_data(app_data, app_buf_id,
390 app_buf_offset, ns_addr, buf_len);
391
392 if (rw_data.ns_granule == NULL) {
393 return (uint64_t)(-EINVAL);
394 }
395
396 ns_access_ok = ns_buffer_read(SLOT_NS, rw_data.ns_granule, 0, buf_len,
397 (void *)rw_data.app_buf);
398 if (!ns_access_ok) {
Mate Toth-Pal5c649342025-06-24 10:37:32 +0200399 ERROR("%s ns buffer read failed for ns addr 0x%lx and app_buf 0x%lx\n",
Soby Mathew1232bb52025-04-24 10:13:51 +0100400 __func__, ns_addr, rw_data.app_buf);
401 return (uint64_t)(-EINVAL);
402 }
403
404 return 0;
405}
406
407
Mate Toth-Pal57fadaf2025-02-06 10:21:30 +0100408static app_service_func service_functions[APP_SERVICE_COUNT] = {
Mate Toth-Pal646c6032025-02-06 11:01:37 +0100409 [APP_SERVICE_PRINT] = app_service_print,
410 [APP_SERVICE_RANDOM] = app_service_get_random,
411 [APP_SERVICE_GET_REALM_ATTESTATION_KEY] = app_service_get_realm_attestation_key,
412 [APP_SERVICE_GET_PLATFORM_TOKEN] = app_service_get_platform_token,
413#if ATTEST_EL3_TOKEN_SIGN
414 [APP_SERVICE_GET_REALM_ATTEST_PUB_KEY_FROM_EL3] = app_service_get_realm_attest_pub_key_from_el3,
415 [APP_SERVICE_EL3_TOKEN_SIGN_QUEUE_TRY_ENQUEUE] = app_service_el3_token_sign_queue_try_enqueue,
416 [APP_SERVICE_EL3_IFC_EL3_TOKEN_SIGN_SUPPORTED] = app_service_el3_ifc_el3_token_sign_supported,
417#endif /* ATTEST_EL3_TOKEN_SIGN */
Soby Mathew1232bb52025-04-24 10:13:51 +0100418 [APP_SERVICE_WRITE_TO_NS_BUF] = app_service_write_to_ns_buf,
419 [APP_SERVICE_READ_FROM_NS_BUF] = app_service_read_from_ns_buf,
Mate Toth-Pal646c6032025-02-06 11:01:37 +0100420 };
Mate Toth-Pal57fadaf2025-02-06 10:21:30 +0100421
422uint64_t call_app_service(unsigned long service_id,
423 struct app_data_cfg *app_data,
424 unsigned long arg0,
425 unsigned long arg1,
426 unsigned long arg2,
427 unsigned long arg3)
428{
429 (void)arg0;
430 (void)arg1;
431 (void)arg2;
432 (void)arg3;
433
434 assert(service_id < APP_SERVICE_COUNT);
435 assert(service_functions[service_id] != NULL);
436
437 return service_functions[service_id](app_data, arg0, arg1, arg2, arg3);
438}
439