blob: 79429c774738b251b1c5207be71dab5be5f67747 [file] [log] [blame]
Patrick Williams2390b1b2022-11-03 13:47:49 -05001From 6430bf31a25a1ef67e9141f85dbd070feb0d1a1e Mon Sep 17 00:00:00 2001
2From: Satish Kumar <satish.kumar01@arm.com>
3Date: Fri, 8 Jul 2022 09:48:06 +0100
4Subject: [PATCH] FMP Support in Corstone1000.
5
6The FMP support is used by u-boot to pupolate ESRT information
7for the kernel.
8
9The solution is platform specific and needs to be revisted.
10
11Signed-off-by: Satish Kumar <satish.kumar01@arm.com>
12
13Upstream-Status: Inappropriate [The solution is platform specific and needs to be revisted]
14---
15 .../provider/capsule_update_provider.c | 5 +
16 .../capsule_update/provider/component.cmake | 1 +
17 .../provider/corstone1000_fmp_service.c | 307 ++++++++++++++++++
18 .../provider/corstone1000_fmp_service.h | 26 ++
19 4 files changed, 339 insertions(+)
20 create mode 100644 components/service/capsule_update/provider/corstone1000_fmp_service.c
21 create mode 100644 components/service/capsule_update/provider/corstone1000_fmp_service.h
22
23diff --git a/components/service/capsule_update/provider/capsule_update_provider.c b/components/service/capsule_update/provider/capsule_update_provider.c
24index 9bbd7abc..871d6bcf 100644
25--- a/components/service/capsule_update/provider/capsule_update_provider.c
26+++ b/components/service/capsule_update/provider/capsule_update_provider.c
27@@ -11,6 +11,7 @@
28 #include <protocols/service/capsule_update/capsule_update_proto.h>
29 #include <protocols/rpc/common/packed-c/status.h>
30 #include "capsule_update_provider.h"
31+#include "corstone1000_fmp_service.h"
32
33
34 #define CAPSULE_UPDATE_REQUEST (0x1)
35@@ -47,6 +48,8 @@ struct rpc_interface *capsule_update_provider_init(
36 rpc_interface = service_provider_get_rpc_interface(&context->base_provider);
37 }
38
39+ provision_fmp_variables_metadata(context->client.caller);
40+
41 return rpc_interface;
42 }
43
44@@ -85,6 +88,7 @@ static rpc_status_t event_handler(uint32_t opcode, struct rpc_caller *caller)
45 }
46 psa_call(caller,handle, PSA_IPC_CALL,
47 in_vec,IOVEC_LEN(in_vec), NULL, 0);
48+ set_fmp_image_info(caller, handle);
49 break;
50
51 case KERNEL_STARTED_EVENT:
52@@ -99,6 +103,7 @@ static rpc_status_t event_handler(uint32_t opcode, struct rpc_caller *caller)
53 }
54 psa_call(caller,handle, PSA_IPC_CALL,
55 in_vec,IOVEC_LEN(in_vec), NULL, 0);
56+ set_fmp_image_info(caller, handle);
57 break;
58 default:
59 EMSG("%s unsupported opcode", __func__);
60diff --git a/components/service/capsule_update/provider/component.cmake b/components/service/capsule_update/provider/component.cmake
61index 1d412eb2..6b060149 100644
62--- a/components/service/capsule_update/provider/component.cmake
63+++ b/components/service/capsule_update/provider/component.cmake
64@@ -10,4 +10,5 @@ endif()
65
66 target_sources(${TGT} PRIVATE
67 "${CMAKE_CURRENT_LIST_DIR}/capsule_update_provider.c"
68+ "${CMAKE_CURRENT_LIST_DIR}/corstone1000_fmp_service.c"
69 )
70diff --git a/components/service/capsule_update/provider/corstone1000_fmp_service.c b/components/service/capsule_update/provider/corstone1000_fmp_service.c
71new file mode 100644
72index 00000000..6a7a47a7
73--- /dev/null
74+++ b/components/service/capsule_update/provider/corstone1000_fmp_service.c
75@@ -0,0 +1,307 @@
76+/*
77+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
78+ *
79+ * SPDX-License-Identifier: BSD-3-Clause
80+ */
81+
82+#include "corstone1000_fmp_service.h"
83+#include <psa/client.h>
84+#include <psa/sid.h>
85+#include <psa/storage_common.h>
86+#include <trace.h>
87+
88+#include <service/smm_variable/backend/variable_index.h>
89+
90+#define VARIABLE_INDEX_STORAGE_UID (0x787)
91+
92+/**
93+ * Variable attributes
94+ */
95+#define EFI_VARIABLE_NON_VOLATILE (0x00000001)
96+#define EFI_VARIABLE_BOOTSERVICE_ACCESS (0x00000002)
97+#define EFI_VARIABLE_RUNTIME_ACCESS (0x00000004)
98+#define EFI_VARIABLE_HARDWARE_ERROR_RECORD (0x00000008)
99+#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS (0x00000010)
100+#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS (0x00000020)
101+#define EFI_VARIABLE_APPEND_WRITE (0x00000040)
102+#define EFI_VARIABLE_MASK \
103+ (EFI_VARIABLE_NON_VOLATILE | \
104+ EFI_VARIABLE_BOOTSERVICE_ACCESS | \
105+ EFI_VARIABLE_RUNTIME_ACCESS | \
106+ EFI_VARIABLE_HARDWARE_ERROR_RECORD | \
107+ EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | \
108+ EFI_VARIABLE_APPEND_WRITE)
109+
110+#define FMP_VARIABLES_COUNT 6
111+
112+static struct variable_metadata fmp_variables_metadata[FMP_VARIABLES_COUNT] = {
113+ {
114+ { 0x86c77a67, 0x0b97, 0x4633, \
115+ { 0xa1, 0x87, 0x49, 0x10, 0x4d, 0x06, 0x85, 0xc7} },
116+ /* name size = (variable_name + \0) * sizeof(u16) */
117+ .name_size = 42, { 'F', 'm', 'p', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'V', 'e', 'r', 's', 'i', 'o', 'n' },
118+ .attributes = EFI_VARIABLE_NON_VOLATILE, .uid = 0
119+ },
120+ {
121+ { 0x86c77a67, 0x0b97, 0x4633, \
122+ { 0xa1, 0x87, 0x49, 0x10, 0x4d, 0x06, 0x85, 0xc7} },
123+ /* name size = (variable_name + \0) * sizeof(u16) */
124+ .name_size = 34, { 'F', 'm', 'p', 'I', 'm', 'a', 'g', 'e', 'I', 'n', 'f', 'o', 'S', 'i', 'z', 'e' },
125+ .attributes = EFI_VARIABLE_NON_VOLATILE, .uid = 0
126+ },
127+ {
128+ { 0x86c77a67, 0x0b97, 0x4633, \
129+ { 0xa1, 0x87, 0x49, 0x10, 0x4d, 0x06, 0x85, 0xc7} },
130+ /* name size = (variable_name + \0) * sizeof(u16) */
131+ .name_size = 38, { 'F', 'm', 'p', 'D', 'e', 's', 'c', 'r', 'i', 'p', 't', 'o', 'r', 'C', 'o', 'u', 'n', 't' },
132+ .attributes = EFI_VARIABLE_NON_VOLATILE, .uid = 0
133+ },
134+ {
135+ { 0x86c77a67, 0x0b97, 0x4633, \
136+ { 0xa1, 0x87, 0x49, 0x10, 0x4d, 0x06, 0x85, 0xc7} },
137+ /* name size = (variable_name + \0) * sizeof(u16) */
138+ .name_size = 26, { 'F', 'm', 'p', 'I', 'm', 'a', 'g', 'e', 'I', 'n', 'f', 'o' },
139+ .attributes = EFI_VARIABLE_NON_VOLATILE, .uid = 0
140+ },
141+ {
142+ { 0x86c77a67, 0x0b97, 0x4633, \
143+ { 0xa1, 0x87, 0x49, 0x10, 0x4d, 0x06, 0x85, 0xc7} },
144+ /* name size = (variable_name + \0) * sizeof(u16) */
145+ .name_size = 28, { 'F', 'm', 'p', 'I', 'm', 'a', 'g', 'e', 'N', 'a', 'm', 'e', '1' },
146+ .attributes = EFI_VARIABLE_NON_VOLATILE, .uid = 0
147+ },
148+ {
149+ { 0x86c77a67, 0x0b97, 0x4633, \
150+ { 0xa1, 0x87, 0x49, 0x10, 0x4d, 0x06, 0x85, 0xc7} },
151+ /* name size = (variable_name + \0) * sizeof(u16) */
152+ .name_size = 32, { 'F', 'm', 'p', 'V', 'e', 'r', 's', 'i', 'o', 'n', 'N', 'a', 'm', 'e', '1' },
153+ .attributes = EFI_VARIABLE_NON_VOLATILE, .uid = 0
154+ },
155+};
156+
157+static psa_status_t protected_storage_set(struct rpc_caller *caller,
158+ psa_storage_uid_t uid, size_t data_length, const void *p_data)
159+{
160+ psa_status_t psa_status;
161+ psa_storage_create_flags_t create_flags = PSA_STORAGE_FLAG_NONE;
162+
163+ struct psa_invec in_vec[] = {
164+ { .base = psa_ptr_to_u32(&uid), .len = sizeof(uid) },
165+ { .base = psa_ptr_const_to_u32(p_data), .len = data_length },
166+ { .base = psa_ptr_to_u32(&create_flags), .len = sizeof(create_flags) },
167+ };
168+
169+ psa_status = psa_call(caller, TFM_PROTECTED_STORAGE_SERVICE_HANDLE, TFM_PS_ITS_SET,
170+ in_vec, IOVEC_LEN(in_vec), NULL, 0);
171+ if (psa_status < 0)
172+ EMSG("ipc_set: psa_call failed: %d", psa_status);
173+
174+ return psa_status;
175+}
176+
177+static psa_status_t protected_storage_get(struct rpc_caller *caller,
178+ psa_storage_uid_t uid, size_t data_size, void *p_data)
179+{
180+ psa_status_t psa_status;
181+ uint32_t offset = 0;
182+
183+ struct psa_invec in_vec[] = {
184+ { .base = psa_ptr_to_u32(&uid), .len = sizeof(uid) },
185+ { .base = psa_ptr_to_u32(&offset), .len = sizeof(offset) },
186+ };
187+
188+ struct psa_outvec out_vec[] = {
189+ { .base = psa_ptr_to_u32(p_data), .len = data_size },
190+ };
191+
192+ psa_status = psa_call(caller, TFM_PROTECTED_STORAGE_SERVICE_HANDLE,
193+ TFM_PS_ITS_GET, in_vec, IOVEC_LEN(in_vec),
194+ out_vec, IOVEC_LEN(out_vec));
195+
196+ if (psa_status == PSA_SUCCESS && out_vec[0].len != data_size) {
197+ EMSG("Return size does not match with expected size.");
198+ return PSA_ERROR_BUFFER_TOO_SMALL;
199+ }
200+
201+ return psa_status;
202+}
203+
204+static uint64_t name_hash(EFI_GUID *guid, size_t name_size,
205+ const int16_t *name)
206+{
207+ /* Using djb2 hash by Dan Bernstein */
208+ uint64_t hash = 5381;
209+
210+ /* Calculate hash over GUID */
211+ hash = ((hash << 5) + hash) + guid->Data1;
212+ hash = ((hash << 5) + hash) + guid->Data2;
213+ hash = ((hash << 5) + hash) + guid->Data3;
214+
215+ for (int i = 0; i < 8; ++i) {
216+
217+ hash = ((hash << 5) + hash) + guid->Data4[i];
218+ }
219+
220+ /* Extend to cover name up to but not including null terminator */
221+ for (int i = 0; i < name_size / sizeof(int16_t); ++i) {
222+
223+ if (!name[i]) break;
224+ hash = ((hash << 5) + hash) + name[i];
225+ }
226+
227+ return hash;
228+}
229+
230+
231+static void initialize_metadata(void)
232+{
233+ for (int i = 0; i < FMP_VARIABLES_COUNT; i++) {
234+
235+ fmp_variables_metadata[i].uid = name_hash(
236+ &fmp_variables_metadata[i].guid,
237+ fmp_variables_metadata[i].name_size,
238+ fmp_variables_metadata[i].name);
239+ }
240+}
241+
242+
243+void provision_fmp_variables_metadata(struct rpc_caller *caller)
244+{
245+ struct variable_metadata metadata;
246+ psa_status_t status;
247+ uint32_t dummy_values = 0xDEAD;
248+
249+ EMSG("Provisioning FMP metadata.");
250+
251+ initialize_metadata();
252+
253+ status = protected_storage_get(caller, VARIABLE_INDEX_STORAGE_UID,
254+ sizeof(struct variable_metadata), &metadata);
255+
256+ if (status == PSA_SUCCESS) {
257+ EMSG("UEFI variables store is already provisioned.");
258+ return;
259+ }
260+
261+ /* Provision FMP variables with dummy values. */
262+ for (int i = 0; i < FMP_VARIABLES_COUNT; i++) {
263+ protected_storage_set(caller, fmp_variables_metadata[i].uid,
264+ sizeof(dummy_values), &dummy_values);
265+ }
266+
267+ status = protected_storage_set(caller, VARIABLE_INDEX_STORAGE_UID,
268+ sizeof(struct variable_metadata) * FMP_VARIABLES_COUNT,
269+ fmp_variables_metadata);
270+
271+ if (status != EFI_SUCCESS) {
272+ return;
273+ }
274+
275+ EMSG("FMP metadata is provisioned");
276+}
277+
278+typedef struct {
279+ void *base;
280+ int len;
281+} variable_data_t;
282+
283+static variable_data_t fmp_variables_data[FMP_VARIABLES_COUNT];
284+
285+#define IMAGE_INFO_BUFFER_SIZE 256
286+static char image_info_buffer[IMAGE_INFO_BUFFER_SIZE];
287+#define IOCTL_CORSTONE1000_FMP_IMAGE_INFO 2
288+
289+static psa_status_t unpack_image_info(void *buffer, uint32_t size)
290+{
291+ typedef struct __attribute__ ((__packed__)) {
292+ uint32_t variable_count;
293+ uint32_t variable_size[FMP_VARIABLES_COUNT];
294+ uint8_t variable[];
295+ } packed_buffer_t;
296+
297+ packed_buffer_t *packed_buffer = buffer;
298+ int runner = 0;
299+
300+ if (packed_buffer->variable_count != FMP_VARIABLES_COUNT) {
301+ EMSG("Expected fmp varaibles = %u, but received = %u",
302+ FMP_VARIABLES_COUNT, packed_buffer->variable_count);
303+ return PSA_ERROR_PROGRAMMER_ERROR;
304+ }
305+
306+ for (int i = 0; i < packed_buffer->variable_count; i++) {
307+ EMSG("FMP variable %d : size %u", i, packed_buffer->variable_size[i]);
308+ fmp_variables_data[i].base = &packed_buffer->variable[runner];
309+ fmp_variables_data[i].len= packed_buffer->variable_size[i];
310+ runner += packed_buffer->variable_size[i];
311+ }
312+
313+ return PSA_SUCCESS;
314+}
315+
316+static psa_status_t get_image_info(struct rpc_caller *caller,
317+ psa_handle_t platform_service_handle)
318+{
319+ psa_status_t status;
320+ psa_handle_t handle;
321+ uint32_t ioctl_id = IOCTL_CORSTONE1000_FMP_IMAGE_INFO;
322+
323+ struct psa_invec in_vec[] = {
324+ { .base = &ioctl_id, .len = sizeof(ioctl_id) },
325+ };
326+
327+ struct psa_outvec out_vec[] = {
328+ { .base = image_info_buffer, .len = IMAGE_INFO_BUFFER_SIZE },
329+ };
330+
331+ memset(image_info_buffer, 0, IMAGE_INFO_BUFFER_SIZE);
332+
333+ psa_call(caller, platform_service_handle, PSA_IPC_CALL,
334+ in_vec, IOVEC_LEN(in_vec), out_vec, IOVEC_LEN(out_vec));
335+
336+ status = unpack_image_info(image_info_buffer, IMAGE_INFO_BUFFER_SIZE);
337+ if (status != PSA_SUCCESS) {
338+ return status;
339+ }
340+
341+ return PSA_SUCCESS;
342+}
343+
344+static psa_status_t set_image_info(struct rpc_caller *caller)
345+{
346+ psa_status_t status;
347+
348+ for (int i = 0; i < FMP_VARIABLES_COUNT; i++) {
349+
350+ status = protected_storage_set(caller,
351+ fmp_variables_metadata[i].uid,
352+ fmp_variables_data[i].len, fmp_variables_data[i].base);
353+
354+ if (status != PSA_SUCCESS) {
355+
356+ EMSG("FMP variable %d set unsuccessful", i);
357+ return status;
358+ }
359+
360+ EMSG("FMP variable %d set success", i);
361+ }
362+
363+ return PSA_SUCCESS;
364+}
365+
366+void set_fmp_image_info(struct rpc_caller *caller,
367+ psa_handle_t platform_service_handle)
368+{
369+ psa_status_t status;
370+
371+ status = get_image_info(caller, platform_service_handle);
372+ if (status != PSA_SUCCESS) {
373+ return;
374+ }
375+
376+ status = set_image_info(caller);
377+ if (status != PSA_SUCCESS) {
378+ return;
379+ }
380+
381+ return;
382+}
383diff --git a/components/service/capsule_update/provider/corstone1000_fmp_service.h b/components/service/capsule_update/provider/corstone1000_fmp_service.h
384new file mode 100644
385index 00000000..95fba2a0
386--- /dev/null
387+++ b/components/service/capsule_update/provider/corstone1000_fmp_service.h
388@@ -0,0 +1,26 @@
389+/*
390+ * Copyright (c) 2022, Arm Limited and Contributors. All rights reserved.
391+ *
392+ * SPDX-License-Identifier: BSD-3-Clause
393+ */
394+
395+#ifndef CORSTONE1000_FMP_SERVICE_H
396+#define CORSTONE1000_FMP_SERVICE_H
397+
398+#ifdef __cplusplus
399+extern "C" {
400+#endif
401+
402+#include <rpc_caller.h>
403+#include <psa/client.h>
404+
405+void provision_fmp_variables_metadata(struct rpc_caller *caller);
406+
407+void set_fmp_image_info(struct rpc_caller *caller,
408+ psa_handle_t platform_service_handle);
409+
410+#ifdef __cplusplus
411+} /* extern "C" */
412+#endif
413+
414+#endif /* CORSTONE1000_FMP_SERVICE_H */
415--
4162.17.1
417