Use the statically reserved FF-A shared MM buffer for EFI variable runtime communication after ExitBootServices(), since dynamic allocation is no longer available.
Keep the shared-buffer pointer convertible across SetVirtualAddressMap(), add the buffer to the EFI runtime memory map, and reject runtime requests that do not fit in the configured shared buffer. Reviewed-by: Simon Glass <[email protected]> Reviewed-by: Abdellatif El Khlifi <[email protected]> Signed-off-by: Harsimran Singh Tungal <[email protected]> --- lib/efi_loader/efi_variable_tee.c | 118 +++++++++++++++++++++++++++--- 1 file changed, 107 insertions(+), 11 deletions(-) diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c index 8de258bb36b..5c7104662e9 100644 --- a/lib/efi_loader/efi_variable_tee.c +++ b/lib/efi_loader/efi_variable_tee.c @@ -54,9 +54,10 @@ static const char *mm_sp_svc_uuid = MM_SP_UUID; static u16 __efi_runtime_data mm_sp_id; #endif +static void *__efi_runtime_data ffa_shared_buf; extern struct efi_var_file __efi_runtime_data *efi_var_buf; -static efi_uintn_t max_buffer_size; /* comm + var + func + data */ -static efi_uintn_t max_payload_size; /* func + data */ +static efi_uintn_t __efi_runtime_data max_buffer_size; /* comm + var + func + data */ +static efi_uintn_t __efi_runtime_data max_payload_size; /* func + data */ static const u16 __efi_runtime_rodata pk[] = u"PK"; static bool __efi_runtime_data ebs_called; @@ -524,8 +525,60 @@ static efi_status_t __efi_runtime mm_communicate(u8 *comm_buf, } /** - * setup_mm_hdr() - Allocate a buffer for StandAloneMM and initialize the - * header data. + * get_comm_buf() - Obtain a communication buffer for MM/FF-A exchange + * @payload_size: size of the payload that will be appended to the + * MM communication header + * + * This helper returns a buffer suitable for constructing an + * EFI_MM_COMMUNICATE message. During the boot phase a new buffer is + * dynamically allocated. After ExitBootServices(), dynamic + * allocation is no longer permitted, and all runtime communication must + * use the statically reserved FF-A shared buffer. + * + * The caller owns the returned buffer only during the boot phase and + * must release it with free(). During the runtime phase, the returned + * pointer aliases the static FF-A shared buffer and must not be freed. + * + * Return: + * Pointer to a valid communication buffer on success. + * NULL if no suitable communication buffer is available. + */ +static __efi_runtime u8 *get_comm_buf(efi_uintn_t payload_size) +{ + efi_uintn_t comm_buf_size; + u8 *comm_buf; + + comm_buf_size = MM_COMMUNICATE_HEADER_SIZE + + MM_VARIABLE_COMMUNICATE_SIZE + + payload_size; + + /* + * After ExitBootServices(), dynamic allocation is no longer permitted. + * Use the predefined FF-A shared buffer at runtime; otherwise allocate + * a fresh buffer during the boot phase. + */ + if (efi_at_runtime()) { + if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) { + if (comm_buf_size > CONFIG_FFA_SHARED_MM_BUF_SIZE) + return NULL; + comm_buf = ffa_shared_buf; + if (!comm_buf) + return NULL; + efi_memset_runtime(comm_buf, 0, comm_buf_size); + } else { + return NULL; + } + } else { + comm_buf = calloc(1, comm_buf_size); + if (!comm_buf) + return NULL; + } + return comm_buf; +} + +/** + * setup_mm_hdr() - Obtain a communication buffer for StandAloneMM and + * initialize the MM header * * @dptr: pointer address of the corresponding StandAloneMM * function @@ -534,10 +587,11 @@ static efi_status_t __efi_runtime mm_communicate(u8 *comm_buf, * @ret: EFI return code * Return: buffer or NULL */ -static u8 *setup_mm_hdr(void **dptr, efi_uintn_t payload_size, - efi_uintn_t func, efi_status_t *ret) +static __efi_runtime u8 *setup_mm_hdr(void **dptr, efi_uintn_t payload_size, + efi_uintn_t func, efi_status_t *ret) { - const efi_guid_t mm_var_guid = EFI_MM_VARIABLE_GUID; + static const __efi_runtime_rodata efi_guid_t mm_var_guid = + EFI_MM_VARIABLE_GUID; struct efi_mm_communicate_header *mm_hdr; struct smm_variable_communicate_header *var_hdr; u8 *comm_buf; @@ -555,16 +609,15 @@ static u8 *setup_mm_hdr(void **dptr, efi_uintn_t payload_size, return NULL; } - comm_buf = calloc(1, MM_COMMUNICATE_HEADER_SIZE + - MM_VARIABLE_COMMUNICATE_SIZE + - payload_size); + comm_buf = get_comm_buf(payload_size); if (!comm_buf) { *ret = EFI_OUT_OF_RESOURCES; return NULL; } mm_hdr = (struct efi_mm_communicate_header *)comm_buf; - guidcpy(&mm_hdr->header_guid, &mm_var_guid); + efi_memcpy_runtime(&mm_hdr->header_guid, &mm_var_guid, + sizeof(mm_hdr->header_guid)); mm_hdr->message_len = MM_VARIABLE_COMMUNICATE_SIZE + payload_size; var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data; @@ -1077,6 +1130,18 @@ void efi_variables_boot_exit_notify(void) ebs_called = true; } +/** + * ffa_shared_buf_notify_virtual_address_map() - SetVirtualAddressMap callback + * + * @event: callback event + * @context: callback context + */ +static void EFIAPI __efi_runtime +ffa_shared_buf_notify_virtual_address_map(struct efi_event *event, void *context) +{ + efi_convert_pointer(0, (void **)&ffa_shared_buf); +} + /** * efi_init_variables() - initialize variable services * @@ -1085,6 +1150,7 @@ void efi_variables_boot_exit_notify(void) efi_status_t efi_init_variables(void) { efi_status_t ret; + struct efi_event *event; /* Create a cached copy of the variables that will be enabled on ExitBootServices() */ ret = efi_var_mem_init(); @@ -1103,5 +1169,35 @@ efi_status_t efi_init_variables(void) if (ret != EFI_SUCCESS) return ret; + if (IS_ENABLED(CONFIG_ARM_FFA_RT_MODE)) { + /* + * The FF-A shared buffer is accessed by EFI runtime services, so + * keep the resident pointer convertible across + * SetVirtualAddressMap() and mark the region as runtime memory. + * + * CONFIG_FFA_SHARED_MM_BUF_ADDR is expected to be EFI-page aligned. + */ + BUILD_BUG_ON(CONFIG_FFA_SHARED_MM_BUF_ADDR & EFI_PAGE_MASK); + ffa_shared_buf = (void *)CONFIG_FFA_SHARED_MM_BUF_ADDR; + ret = efi_create_event(EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, + TPL_CALLBACK, + ffa_shared_buf_notify_virtual_address_map, + NULL, NULL, &event); + if (ret != EFI_SUCCESS) + return ret; + ret = efi_add_memory_map(CONFIG_FFA_SHARED_MM_BUF_ADDR, + CONFIG_FFA_SHARED_MM_BUF_SIZE, + EFI_RUNTIME_SERVICES_DATA); + if (ret != EFI_SUCCESS) { + efi_close_event(event); + log_err("EFI: failed to add FF-A shared buffer to runtime map (%lu)\n", + ret); + return ret; + } + log_info("EFI: FF-A shared buffer runtime map: addr=0x%lx size=0x%lx\n", + (ulong)CONFIG_FFA_SHARED_MM_BUF_ADDR, + (ulong)CONFIG_FFA_SHARED_MM_BUF_SIZE); + } + return EFI_SUCCESS; } -- 2.34.1
