blob: 0a829c410a7c5c321e200a15173574fd960bf6da [file] [log] [blame]
From 652259af2f795a5d69c628ae7b1e79d33c234abd Mon Sep 17 00:00:00 2001
From: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Date: Thu, 11 Nov 2021 16:27:59 +0000
Subject: [PATCH 11/24] efi: corstone1000: introduce EFI capsule update
This commit provides capsule update feature for Corstone1000.
This feature is available before and after ExitBootServices().
A platform specific capsule buffer is allocated. This buffer
is physically contiguous and allocated at the start of the DDR
memory after u-boot relocation to the end of DDR.
The capsule buffer is shared between u-boot and the secure world.
On UpdateCapsule() , capsule data is copied to the buffer
and a buffer ready event is generated using FF-A transport.
On ExitBootServices() a kernel started event is sent to the
SE Proxy FW update service. This event is generated on each boot.
Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
---
include/configs/corstone1000.h | 18 +++++
include/efi_loader.h | 4 +-
lib/efi_loader/efi_boottime.c | 47 ++++++++++++
lib/efi_loader/efi_capsule.c | 135 ++++++++++++++++++++++++++++++++-
lib/efi_loader/efi_setup.c | 15 ++++
5 files changed, 215 insertions(+), 4 deletions(-)
diff --git a/include/configs/corstone1000.h b/include/configs/corstone1000.h
index afc9ccfc192b..a400cdef69d0 100644
--- a/include/configs/corstone1000.h
+++ b/include/configs/corstone1000.h
@@ -14,6 +14,24 @@
#include <linux/sizes.h>
+/* The SE Proxy partition ID*/
+#define CORSTONE1000_SEPROXY_PART_ID (0x8002)
+
+/* Update service ID provided by the SE Proxy secure partition*/
+#define CORSTONE1000_SEPROXY_UPDATE_SVC_ID (0x4)
+
+/* Notification events used with SE Proxy update service */
+#define CORSTONE1000_BUFFER_READY_EVT (0x1)
+#define CORSTONE1000_KERNEL_STARTED_EVT (0x2)
+
+/* Size in 4KB pages of the EFI capsule buffer */
+#define CORSTONE1000_CAPSULE_BUFFER_SIZE (8192) /* 32 MB */
+
+/* Capsule GUID */
+#define EFI_CORSTONE1000_CAPSULE_ID_GUID \
+ EFI_GUID(0x3a770ddc, 0x409b, 0x48b2, 0x81, 0x41, \
+ 0x93, 0xb7, 0xc6, 0x0b, 0x20, 0x9e)
+
/* MM SP UUID binary data (little-endian format) */
#define MM_SP_UUID_DATA \
0xed, 0x32, 0xd5, 0x33, \
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 5b41985244e2..796419b69b40 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -984,11 +984,11 @@ extern const struct efi_firmware_management_protocol efi_fmp_fit;
extern const struct efi_firmware_management_protocol efi_fmp_raw;
/* Capsule update */
-efi_status_t EFIAPI efi_update_capsule(
+efi_status_t __efi_runtime EFIAPI efi_update_capsule(
struct efi_capsule_header **capsule_header_array,
efi_uintn_t capsule_count,
u64 scatter_gather_list);
-efi_status_t EFIAPI efi_query_capsule_caps(
+efi_status_t __efi_runtime EFIAPI efi_query_capsule_caps(
struct efi_capsule_header **capsule_header_array,
efi_uintn_t capsule_count,
u64 *maximum_capsule_size,
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index c68d9ed4f0bd..f2b5c7834c01 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -2095,6 +2095,44 @@ static void efi_exit_caches(void)
#endif
}
+#if IS_ENABLED(CONFIG_TARGET_CORSTONE1000)
+/**
+ * efi_corstone1000_kernel_started_event - notifies SE Proxy FW update service
+ *
+ * This function notifies the SE Proxy update service that the kernel has already started
+ *
+ * Return:
+ *
+ * 0: on success, otherwise failure
+ */
+static int efi_corstone1000_kernel_started_event(void)
+{
+ struct ffa_interface_data func_data = {0};
+ struct ffa_send_direct_data msg = {0};
+ u16 part_id = CORSTONE1000_SEPROXY_PART_ID;
+
+ log_debug("[%s]\n", __func__);
+
+ /*
+ * telling the driver which partition to use
+ */
+ func_data.data0_size = sizeof(part_id);
+ func_data.data0 = &part_id;
+
+ /*
+ * setting the kernel started event arguments
+ */
+ msg.a3 = CORSTONE1000_SEPROXY_UPDATE_SVC_ID;
+ msg.a5 = CORSTONE1000_KERNEL_STARTED_EVT;
+
+ func_data.data1_size = sizeof(msg);
+ func_data.data1 = &msg;
+
+ return ffa_helper_msg_send_direct_req(&func_data);
+}
+
+#endif
+
/**
* efi_exit_boot_services() - stop all boot services
* @image_handle: handle of the loaded image
@@ -2208,6 +2246,15 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
/* Recalculate CRC32 */
efi_update_table_header_crc32(&systab.hdr);
+#if IS_ENABLED(CONFIG_TARGET_CORSTONE1000)
+ /* Notifying SE Proxy FW update service */
+ ffa_ret = efi_corstone1000_kernel_started_event();
+ if (ffa_ret)
+ debug("[efi_boottime][ERROR]: Failure to notify SE Proxy FW update service\n");
+ else
+ debug("[efi_boottime][INFO]: SE Proxy FW update service notified\n");
+#endif
+
/* Give the payload some time to boot */
efi_set_watchdog(0);
WATCHDOG_RESET();
diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
index a6b98f066a0b..a0689ba912fc 100644
--- a/lib/efi_loader/efi_capsule.c
+++ b/lib/efi_loader/efi_capsule.c
@@ -25,6 +25,14 @@
#include <crypto/pkcs7_parser.h>
#include <linux/err.h>
+#ifdef CONFIG_TARGET_CORSTONE1000
+#include <arm_ffa_helper.h>
+#include <cpu_func.h>
+
+void *__efi_runtime_data corstone1000_capsule_buf; /* capsule shared buffer virtual address */
+efi_guid_t corstone1000_capsule_guid = EFI_CORSTONE1000_CAPSULE_ID_GUID;
+#endif
+
DECLARE_GLOBAL_DATA_PTR;
const efi_guid_t efi_guid_capsule_report = EFI_CAPSULE_REPORT_GUID;
@@ -512,6 +520,89 @@ static efi_status_t efi_capsule_update_firmware(
}
#endif /* CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT */
+#if IS_ENABLED(CONFIG_TARGET_CORSTONE1000)
+
+/**
+ * efi_corstone1000_alloc_capsule_shared_buf - allocate capsule shared buffer
+ * @capsule_image_size: The capsule data (header + payload)
+ *
+ * This function allocates the physically contiguous buffer shared between u-boot
+ * and the secure world. On UpdateCapsule() capsule data is copied to the buffer
+ * and a door bell event is generated.
+ * The buffer is allocated at the start of the DDR memory after u-boot has been relocated
+ * to the end of DDR.
+ *
+ * Return:
+ *
+ * 0: on success, otherwise failure
+ */
+efi_status_t efi_corstone1000_alloc_capsule_shared_buf(void)
+{
+ efi_status_t efi_ret;
+ u64 ram_base = CONFIG_SYS_SDRAM_BASE;
+
+ log_debug("[%s]\n", __func__);
+
+ efi_ret = efi_allocate_pages(EFI_ALLOCATE_ADDRESS,
+ EFI_RUNTIME_SERVICES_DATA,
+ CORSTONE1000_CAPSULE_BUFFER_SIZE,
+ &ram_base);
+
+ if (efi_ret != EFI_SUCCESS) {
+ corstone1000_capsule_buf = NULL;
+ log_err("EFI: Corstone1000: Allocating capsule shared buffer error (%d)\n"
+ , (int)efi_ret);
+ return efi_ret;
+ }
+
+ log_info("EFI: Corstone1000: Capsule shared buffer at 0x%x , size %d pages\n"
+ , (unsigned int)ram_base,
+ CORSTONE1000_CAPSULE_BUFFER_SIZE);
+
+ corstone1000_capsule_buf = (void *)map_sysmem((phys_addr_t)ram_base, 0);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * efi_corstone1000_buffer_ready_event - issue door bell event
+ * @capsule_image_size: The capsule data (header + payload)
+ *
+ * This function notifies the SE Proxy update service that capsule data is available
+ * in the capsule shared buffer.
+ *
+ * Return:
+ *
+ * 0: on success, otherwise failure
+ */
+static int __efi_runtime efi_corstone1000_buffer_ready_event(u32 capsule_image_size)
+{
+ struct ffa_interface_data func_data = {0};
+ struct ffa_send_direct_data msg = {0};
+ u16 part_id = CORSTONE1000_SEPROXY_PART_ID;
+
+ log_debug("[%s]\n", __func__);
+
+ /*
+ * telling the driver which partition to use
+ */
+ func_data.data0_size = sizeof(part_id);
+ func_data.data0 = &part_id;
+
+ /*
+ * setting the buffer ready event arguments
+ */
+ msg.a3 = CORSTONE1000_SEPROXY_UPDATE_SVC_ID;
+ msg.a4 = capsule_image_size;
+ msg.a5 = CORSTONE1000_BUFFER_READY_EVT;
+
+ func_data.data1_size = sizeof(msg);
+ func_data.data1 = &msg;
+
+ return ffa_helper_msg_send_direct_req(&func_data);
+}
+#endif
+
/**
* efi_update_capsule() - process information from operating system
* @capsule_header_array: Array of virtual address pointers
@@ -525,7 +616,7 @@ static efi_status_t efi_capsule_update_firmware(
*
* Return: status code
*/
-efi_status_t EFIAPI efi_update_capsule(
+efi_status_t __efi_runtime EFIAPI efi_update_capsule(
struct efi_capsule_header **capsule_header_array,
efi_uintn_t capsule_count,
u64 scatter_gather_list)
@@ -542,6 +633,13 @@ efi_status_t EFIAPI efi_update_capsule(
goto out;
}
+#if IS_ENABLED(CONFIG_TARGET_CORSTONE1000)
+ if (capsule_count != 1 || !corstone1000_capsule_buf) {
+ ret = EFI_INVALID_PARAMETER;
+ goto out;
+ }
+#endif
+
ret = EFI_SUCCESS;
for (i = 0, capsule = *capsule_header_array; i < capsule_count;
i++, capsule = *(++capsule_header_array)) {
@@ -554,6 +652,39 @@ efi_status_t EFIAPI efi_update_capsule(
log_debug("Capsule[%d] (guid:%pUs)\n",
i, &capsule->capsule_guid);
+
+#if CONFIG_IS_ENABLED(TARGET_CORSTONE1000)
+ if (guidcmp(&corstone1000_capsule_guid, &capsule->capsule_guid)) {
+ ret = EFI_INVALID_PARAMETER;
+ log_err("Corstone1000: Invalid capsule GUID\n");
+ goto out;
+ }
+
+ if (efi_size_in_pages(capsule->capsule_image_size) >
+ CORSTONE1000_CAPSULE_BUFFER_SIZE) {
+ log_err("Corstone1000: Capsule data size exceeds the shared buffer size\n");
+ ret = EFI_BUFFER_TOO_SMALL;
+ goto out;
+ }
+
+ /* copy the data to the contiguous buffer */
+ efi_memcpy_runtime(corstone1000_capsule_buf, capsule, capsule->capsule_image_size);
+
+ /* invalidate the data cache */
+ invalidate_dcache_all();
+
+ /* issue buffer ready event */
+ ret = efi_corstone1000_buffer_ready_event(capsule->capsule_image_size);
+ if (ret) {
+ log_err("EFI: Corstone1000: Buffer ready event error (%d)\n", (int)ret);
+ ret = EFI_DEVICE_ERROR;
+ } else {
+ ret = EFI_SUCCESS;
+ }
+
+ goto out;
+#endif
+
if (!guidcmp(&capsule->capsule_guid,
&efi_guid_firmware_management_capsule_id)) {
ret = efi_capsule_update_firmware(capsule);
@@ -592,7 +723,7 @@ out:
*
* Return: status code
*/
-efi_status_t EFIAPI efi_query_capsule_caps(
+efi_status_t __efi_runtime EFIAPI efi_query_capsule_caps(
struct efi_capsule_header **capsule_header_array,
efi_uintn_t capsule_count,
u64 *maximum_capsule_size,
diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c
index 492ecf4cb15c..bfd4687e10b5 100644
--- a/lib/efi_loader/efi_setup.c
+++ b/lib/efi_loader/efi_setup.c
@@ -16,6 +16,13 @@
efi_status_t efi_obj_list_initialized = OBJ_LIST_NOT_INITIALIZED;
+#if IS_ENABLED(CONFIG_TARGET_CORSTONE1000)
+/**
+ * efi_corstone1000_alloc_capsule_shared_buf - allocate capsule shared buffer
+ */
+extern efi_status_t efi_corstone1000_alloc_capsule_shared_buf(void);
+#endif
+
/*
* Allow unaligned memory access.
*
@@ -128,6 +135,14 @@ static efi_status_t efi_init_capsule(void)
{
efi_status_t ret = EFI_SUCCESS;
+#if IS_ENABLED(CONFIG_TARGET_CORSTONE1000)
+ ret = efi_corstone1000_alloc_capsule_shared_buf();
+ if (ret != EFI_SUCCESS) {
+ printf("EFI: Corstone-1000: cannot allocate caspsule shared buffer\n");
+ return ret;
+ }
+#endif
+
if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_UPDATE)) {
ret = efi_set_variable_int(u"CapsuleMax",
&efi_guid_capsule_report,
--
2.37.1