| From 90b2741149a538c93aed61522c0d3363351bd578 Mon Sep 17 00:00:00 2001 |
| From: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com> |
| Date: Mon, 17 Jul 2023 15:56:18 +0100 |
| Subject: [PATCH 11/33] efi: corstone1000: fwu: 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 efi_init_capsule() in U-Boot, an EFI started event is sent to SE Proxy FW update service. This event is generated on each boot. |
| |
| Note: The SE proxy SP requires that the interface/event IDs are passed using register w4 for the buffer ready event and the EFI started event. |
| |
| interface ID (31:16) |
| event ID (15:0) |
| |
| Signed-off-by: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com> |
| Signed-off-by: Vishnu Banavath <vishnu.banavath@arm.com> |
| Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org> |
| Upstream-Status: Pending [Not submitted to upstream yet] |
| --- |
| board/armltd/corstone1000/corstone1000.c | 4 + |
| configs/corstone1000_defconfig | 3 + |
| include/configs/corstone1000.h | 24 ++++ |
| include/efi_loader.h | 4 +- |
| lib/efi_loader/efi_boottime.c | 7 ++ |
| lib/efi_loader/efi_capsule.c | 136 ++++++++++++++++++++++- |
| lib/efi_loader/efi_setup.c | 64 +++++++++++ |
| 7 files changed, 238 insertions(+), 4 deletions(-) |
| |
| diff --git a/board/armltd/corstone1000/corstone1000.c b/board/armltd/corstone1000/corstone1000.c |
| index 6ec8e6144f..c840290885 100644 |
| --- a/board/armltd/corstone1000/corstone1000.c |
| +++ b/board/armltd/corstone1000/corstone1000.c |
| @@ -67,6 +67,10 @@ static struct mm_region corstone1000_mem_map[] = { |
| |
| struct mm_region *mem_map = corstone1000_mem_map; |
| |
| +void set_dfu_alt_info(char *interface, char *devstr) |
| +{ |
| +} |
| + |
| int board_init(void) |
| { |
| return 0; |
| diff --git a/configs/corstone1000_defconfig b/configs/corstone1000_defconfig |
| index ee5481b63c..40ba415ecb 100644 |
| --- a/configs/corstone1000_defconfig |
| +++ b/configs/corstone1000_defconfig |
| @@ -58,3 +58,6 @@ CONFIG_EFI_MM_COMM_TEE=y |
| CONFIG_FFA_SHARED_MM_BUF_SIZE=4096 |
| CONFIG_FFA_SHARED_MM_BUF_OFFSET=0 |
| CONFIG_FFA_SHARED_MM_BUF_ADDR=0x02000000 |
| +CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y |
| +CONFIG_EFI_CAPSULE_FIRMWARE_FIT=y |
| +CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y |
| diff --git a/include/configs/corstone1000.h b/include/configs/corstone1000.h |
| index 3347c11792..8927b09499 100644 |
| --- a/include/configs/corstone1000.h |
| +++ b/include/configs/corstone1000.h |
| @@ -14,6 +14,30 @@ |
| |
| #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_UBOOT_EFI_STARTED_EVT (0x2) |
| + |
| +#define PREP_SEPROXY_SVC_ID_MASK GENMASK(31, 16) |
| +#define PREP_SEPROXY_SVC_ID(x) (FIELD_PREP(PREP_SEPROXY_SVC_ID_MASK, (x))) |
| + |
| +#define PREP_SEPROXY_EVT_MASK GENMASK(15, 0) |
| +#define PREP_SEPROXY_EVT(x) (FIELD_PREP(PREP_SEPROXY_EVT_MASK, (x))) |
| + |
| +/* 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) |
| + |
| #define V2M_BASE 0x80000000 |
| |
| #define CFG_PL011_CLOCK 50000000 |
| diff --git a/include/efi_loader.h b/include/efi_loader.h |
| index 38d7f66bab..0a613ed51e 100644 |
| --- a/include/efi_loader.h |
| +++ b/include/efi_loader.h |
| @@ -1036,11 +1036,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 d5065f296a..a5da77c36c 100644 |
| --- a/lib/efi_loader/efi_boottime.c |
| +++ b/lib/efi_loader/efi_boottime.c |
| @@ -23,6 +23,13 @@ |
| #include <asm/setjmp.h> |
| #include <linux/libfdt_env.h> |
| |
| +#if IS_ENABLED(CONFIG_TARGET_CORSTONE1000) |
| +#include <arm_ffa.h> |
| +#include <dm.h> |
| +#include <linux/bitfield.h> |
| +#include <linux/bitops.h> |
| +#endif |
| + |
| DECLARE_GLOBAL_DATA_PTR; |
| |
| /* Task priority level */ |
| diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c |
| index 7a6f195cbc..ea084e4ed2 100644 |
| --- a/lib/efi_loader/efi_capsule.c |
| +++ b/lib/efi_loader/efi_capsule.c |
| @@ -26,6 +26,17 @@ |
| #include <crypto/pkcs7_parser.h> |
| #include <linux/err.h> |
| |
| +#ifdef CONFIG_TARGET_CORSTONE1000 |
| +#include <arm_ffa.h> |
| +#include <cpu_func.h> |
| +#include <dm.h> |
| +#include <linux/bitfield.h> |
| +#include <linux/bitops.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; |
| @@ -709,6 +720,87 @@ 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 = CFG_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_send_direct_data msg = {0}; |
| + int ret; |
| + struct udevice *dev; |
| + |
| + log_debug("[%s]\n", __func__); |
| + |
| + ret = uclass_first_device_err(UCLASS_FFA, &dev); |
| + if (ret) { |
| + log_err("Cannot find FF-A bus device\n"); |
| + return ret; |
| + } |
| + |
| + /* |
| + * setting the buffer ready event arguments in register w4: |
| + * - capsule update interface ID (31:16) |
| + * - the buffer ready event ID (15:0) |
| + */ |
| + msg.data1 = PREP_SEPROXY_SVC_ID(CORSTONE1000_SEPROXY_UPDATE_SVC_ID) | |
| + PREP_SEPROXY_EVT(CORSTONE1000_BUFFER_READY_EVT); /* w4 */ |
| + |
| + return ffa_sync_send_receive(dev, CORSTONE1000_SEPROXY_PART_ID, &msg, 0); |
| +} |
| +#endif |
| + |
| /** |
| * efi_update_capsule() - process information from operating system |
| * @capsule_header_array: Array of virtual address pointers |
| @@ -722,7 +814,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) |
| @@ -739,6 +831,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)) { |
| @@ -751,6 +850,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); |
| @@ -789,7 +921,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 58d4e13402..bf90a98b5a 100644 |
| --- a/lib/efi_loader/efi_setup.c |
| +++ b/lib/efi_loader/efi_setup.c |
| @@ -17,6 +17,18 @@ |
| |
| efi_status_t efi_obj_list_initialized = OBJ_LIST_NOT_INITIALIZED; |
| |
| +#if IS_ENABLED(CONFIG_TARGET_CORSTONE1000) |
| +#include <linux/bitfield.h> |
| +#include <linux/bitops.h> |
| +#include <arm_ffa.h> |
| +#include <dm.h> |
| + |
| +/** |
| + * 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. |
| * |
| @@ -120,6 +132,42 @@ static efi_status_t efi_init_secure_boot(void) |
| } |
| #endif /* CONFIG_EFI_SECURE_BOOT */ |
| |
| +#if IS_ENABLED(CONFIG_TARGET_CORSTONE1000) |
| +/** |
| + * efi_corstone1000_uboot-efi_started_event - notifies SE Proxy FW update service |
| + * |
| + * This function notifies the SE Proxy update service that uboot efi has already started |
| + * |
| + * Return: |
| + * |
| + * 0: on success, otherwise failure |
| + * */ |
| +static int efi_corstone1000_uboot_efi_started_event(void) |
| +{ |
| + struct ffa_send_direct_data msg = {0}; |
| + int ret; |
| + struct udevice *dev; |
| + |
| + log_debug("[%s]\n", __func__); |
| + |
| + ret = uclass_first_device_err(UCLASS_FFA, &dev); |
| + if (ret) { |
| + log_err("Cannot find FF-A bus device\n"); |
| + return ret; |
| + } |
| + |
| + /* |
| + * setting the kernel started event arguments: |
| + * setting capsule update interface ID(31:16) |
| + * the kernel started event ID(15:0) |
| + */ |
| + msg.data1 = PREP_SEPROXY_SVC_ID(CORSTONE1000_SEPROXY_UPDATE_SVC_ID) | |
| + PREP_SEPROXY_EVT(CORSTONE1000_UBOOT_EFI_STARTED_EVT); /* w4 */ |
| + |
| + return ffa_sync_send_receive(dev, CORSTONE1000_SEPROXY_PART_ID, &msg, 0); |
| +} |
| +#endif |
| + |
| /** |
| * efi_init_capsule - initialize capsule update state |
| * |
| @@ -129,6 +177,22 @@ static efi_status_t efi_init_capsule(void) |
| { |
| efi_status_t ret = EFI_SUCCESS; |
| |
| +#if IS_ENABLED(CONFIG_TARGET_CORSTONE1000) |
| + int ffa_ret; |
| + |
| + ffa_ret = efi_corstone1000_uboot_efi_started_event(); |
| + if (ffa_ret) |
| + log_err("Failure to notify SE Proxy FW update service\n"); |
| + else |
| + debug("SE Proxy FW update service notified\n"); |
| + |
| + 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_SUPPORT)) { |
| u16 var_name16[12]; |
| |
| -- |
| 2.25.1 |
| |