|
@@ -4,16 +4,38 @@
|
|
|
*
|
|
|
* Copyright (C) 2019 Linaro Ltd. <sughosh.ganu@linaro.org>
|
|
|
* Copyright (C) 2019 Linaro Ltd. <ilias.apalodimas@linaro.org>
|
|
|
+ * Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
|
|
|
+ *
|
|
|
+ * Authors:
|
|
|
+ * Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
|
|
|
*/
|
|
|
|
|
|
#include <common.h>
|
|
|
+#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
|
|
|
+#include <arm_ffa.h>
|
|
|
+#endif
|
|
|
+#include <cpu_func.h>
|
|
|
+#include <dm.h>
|
|
|
#include <efi.h>
|
|
|
#include <efi_api.h>
|
|
|
#include <efi_loader.h>
|
|
|
#include <efi_variable.h>
|
|
|
-#include <tee.h>
|
|
|
#include <malloc.h>
|
|
|
+#include <mapmem.h>
|
|
|
#include <mm_communication.h>
|
|
|
+#include <tee.h>
|
|
|
+
|
|
|
+#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
|
|
|
+/* MM return codes */
|
|
|
+#define MM_SUCCESS (0)
|
|
|
+#define MM_NOT_SUPPORTED (-1)
|
|
|
+#define MM_INVALID_PARAMETER (-2)
|
|
|
+#define MM_DENIED (-3)
|
|
|
+#define MM_NO_MEMORY (-5)
|
|
|
+
|
|
|
+static const char *mm_sp_svc_uuid = MM_SP_UUID;
|
|
|
+static u16 mm_sp_id;
|
|
|
+#endif
|
|
|
|
|
|
extern struct efi_var_file __efi_runtime_data *efi_var_buf;
|
|
|
static efi_uintn_t max_buffer_size; /* comm + var + func + data */
|
|
@@ -144,12 +166,238 @@ static efi_status_t optee_mm_communicate(void *comm_buf, ulong dsize)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
|
|
|
+/**
|
|
|
+ * ffa_notify_mm_sp() - Announce there is data in the shared buffer
|
|
|
+ *
|
|
|
+ * Notify the MM partition in the trusted world that
|
|
|
+ * data is available in the shared buffer.
|
|
|
+ * This is a blocking call during which trusted world has exclusive access
|
|
|
+ * to the MM shared buffer.
|
|
|
+ *
|
|
|
+ * Return:
|
|
|
+ *
|
|
|
+ * 0 on success
|
|
|
+ */
|
|
|
+static int ffa_notify_mm_sp(void)
|
|
|
+{
|
|
|
+ struct ffa_send_direct_data msg = {0};
|
|
|
+ int ret;
|
|
|
+ int sp_event_ret;
|
|
|
+ struct udevice *dev;
|
|
|
+
|
|
|
+ ret = uclass_first_device_err(UCLASS_FFA, &dev);
|
|
|
+ if (ret) {
|
|
|
+ log_err("EFI: Cannot find FF-A bus device, notify MM SP failure\n");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ msg.data0 = CONFIG_FFA_SHARED_MM_BUF_OFFSET; /* x3 */
|
|
|
+
|
|
|
+ ret = ffa_sync_send_receive(dev, mm_sp_id, &msg, 1);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ sp_event_ret = msg.data0; /* x3 */
|
|
|
+
|
|
|
+ switch (sp_event_ret) {
|
|
|
+ case MM_SUCCESS:
|
|
|
+ ret = 0;
|
|
|
+ break;
|
|
|
+ case MM_NOT_SUPPORTED:
|
|
|
+ ret = -EINVAL;
|
|
|
+ break;
|
|
|
+ case MM_INVALID_PARAMETER:
|
|
|
+ ret = -EPERM;
|
|
|
+ break;
|
|
|
+ case MM_DENIED:
|
|
|
+ ret = -EACCES;
|
|
|
+ break;
|
|
|
+ case MM_NO_MEMORY:
|
|
|
+ ret = -EBUSY;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ ret = -EACCES;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * ffa_discover_mm_sp_id() - Query the MM partition ID
|
|
|
+ *
|
|
|
+ * Use the FF-A driver to get the MM partition ID.
|
|
|
+ * If multiple partitions are found, use the first one.
|
|
|
+ * This is a boot time function.
|
|
|
+ *
|
|
|
+ * Return:
|
|
|
+ *
|
|
|
+ * 0 on success
|
|
|
+ */
|
|
|
+static int ffa_discover_mm_sp_id(void)
|
|
|
+{
|
|
|
+ u32 count = 0;
|
|
|
+ int ret;
|
|
|
+ struct ffa_partition_desc *descs;
|
|
|
+ struct udevice *dev;
|
|
|
+
|
|
|
+ ret = uclass_first_device_err(UCLASS_FFA, &dev);
|
|
|
+ if (ret) {
|
|
|
+ log_err("EFI: Cannot find FF-A bus device, MM SP discovery failure\n");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Ask the driver to fill the buffer with the SPs info */
|
|
|
+ ret = ffa_partition_info_get(dev, mm_sp_svc_uuid, &count, &descs);
|
|
|
+ if (ret) {
|
|
|
+ log_err("EFI: Failure in querying SPs info (%d), MM SP discovery failure\n", ret);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* MM SPs found , use the first one */
|
|
|
+
|
|
|
+ mm_sp_id = descs[0].info.id;
|
|
|
+
|
|
|
+ log_info("EFI: MM partition ID 0x%x\n", mm_sp_id);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
- * mm_communicate() - Adjust the cmonnucation buffer to StandAlonneMM and send
|
|
|
+ * ffa_mm_communicate() - Exchange EFI services data with the MM partition using FF-A
|
|
|
+ * @comm_buf: locally allocated communication buffer used for rx/tx
|
|
|
+ * @dsize: communication buffer size
|
|
|
+ *
|
|
|
+ * Issue a door bell event to notify the MM partition (SP) running in OP-TEE
|
|
|
+ * that there is data to read from the shared buffer.
|
|
|
+ * Communication with the MM SP is performed using FF-A transport.
|
|
|
+ * On the event, MM SP can read the data from the buffer and
|
|
|
+ * update the MM shared buffer with response data.
|
|
|
+ * The response data is copied back to the communication buffer.
|
|
|
+ *
|
|
|
+ * Return:
|
|
|
+ *
|
|
|
+ * EFI status code
|
|
|
+ */
|
|
|
+static efi_status_t ffa_mm_communicate(void *comm_buf, ulong comm_buf_size)
|
|
|
+{
|
|
|
+ ulong tx_data_size;
|
|
|
+ int ffa_ret;
|
|
|
+ efi_status_t efi_ret;
|
|
|
+ struct efi_mm_communicate_header *mm_hdr;
|
|
|
+ void *virt_shared_buf;
|
|
|
+
|
|
|
+ if (!comm_buf)
|
|
|
+ return EFI_INVALID_PARAMETER;
|
|
|
+
|
|
|
+ /* Discover MM partition ID at boot time */
|
|
|
+ if (!mm_sp_id && ffa_discover_mm_sp_id()) {
|
|
|
+ log_err("EFI: Failure to discover MM SP ID at boot time, FF-A MM comms failure\n");
|
|
|
+ return EFI_UNSUPPORTED;
|
|
|
+ }
|
|
|
+
|
|
|
+ mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
|
|
|
+ tx_data_size = mm_hdr->message_len + sizeof(efi_guid_t) + sizeof(size_t);
|
|
|
+
|
|
|
+ if (comm_buf_size != tx_data_size || tx_data_size > CONFIG_FFA_SHARED_MM_BUF_SIZE)
|
|
|
+ return EFI_INVALID_PARAMETER;
|
|
|
+
|
|
|
+ /* Copy the data to the shared buffer */
|
|
|
+
|
|
|
+ virt_shared_buf = map_sysmem((phys_addr_t)CONFIG_FFA_SHARED_MM_BUF_ADDR, 0);
|
|
|
+ memcpy(virt_shared_buf, comm_buf, tx_data_size);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The secure world might have cache disabled for
|
|
|
+ * the device region used for shared buffer (which is the case for Optee).
|
|
|
+ * In this case, the secure world reads the data from DRAM.
|
|
|
+ * Let's flush the cache so the DRAM is updated with the latest data.
|
|
|
+ */
|
|
|
+#ifdef CONFIG_ARM64
|
|
|
+ invalidate_dcache_all();
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Announce there is data in the shared buffer */
|
|
|
+
|
|
|
+ ffa_ret = ffa_notify_mm_sp();
|
|
|
+
|
|
|
+ switch (ffa_ret) {
|
|
|
+ case 0: {
|
|
|
+ ulong rx_data_size;
|
|
|
+ /* Copy the MM SP response from the shared buffer to the communication buffer */
|
|
|
+ rx_data_size = ((struct efi_mm_communicate_header *)virt_shared_buf)->message_len +
|
|
|
+ sizeof(efi_guid_t) +
|
|
|
+ sizeof(size_t);
|
|
|
+
|
|
|
+ if (rx_data_size > comm_buf_size) {
|
|
|
+ efi_ret = EFI_OUT_OF_RESOURCES;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ memcpy(comm_buf, virt_shared_buf, rx_data_size);
|
|
|
+ efi_ret = EFI_SUCCESS;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case -EINVAL:
|
|
|
+ efi_ret = EFI_DEVICE_ERROR;
|
|
|
+ break;
|
|
|
+ case -EPERM:
|
|
|
+ efi_ret = EFI_INVALID_PARAMETER;
|
|
|
+ break;
|
|
|
+ case -EACCES:
|
|
|
+ efi_ret = EFI_ACCESS_DENIED;
|
|
|
+ break;
|
|
|
+ case -EBUSY:
|
|
|
+ efi_ret = EFI_OUT_OF_RESOURCES;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ efi_ret = EFI_ACCESS_DENIED;
|
|
|
+ }
|
|
|
+
|
|
|
+ unmap_sysmem(virt_shared_buf);
|
|
|
+ return efi_ret;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * get_mm_comms() - detect the available MM transport
|
|
|
+ *
|
|
|
+ * Make sure the FF-A bus is probed successfully
|
|
|
+ * which means FF-A communication with secure world works and ready
|
|
|
+ * for use.
|
|
|
+ *
|
|
|
+ * If FF-A bus is not ready, use OPTEE comms.
|
|
|
+ *
|
|
|
+ * Return:
|
|
|
+ *
|
|
|
+ * MM_COMMS_FFA or MM_COMMS_OPTEE
|
|
|
+ */
|
|
|
+static enum mm_comms_select get_mm_comms(void)
|
|
|
+{
|
|
|
+ struct udevice *dev;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = uclass_first_device_err(UCLASS_FFA, &dev);
|
|
|
+ if (ret) {
|
|
|
+ log_debug("EFI: Cannot find FF-A bus device, trying Optee comms\n");
|
|
|
+ return MM_COMMS_OPTEE;
|
|
|
+ }
|
|
|
+
|
|
|
+ return MM_COMMS_FFA;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+/**
|
|
|
+ * mm_communicate() - Adjust the communication buffer to the MM SP and send
|
|
|
* it to OP-TEE
|
|
|
*
|
|
|
- * @comm_buf: locally allocted communcation buffer
|
|
|
+ * @comm_buf: locally allocated communication buffer
|
|
|
* @dsize: buffer size
|
|
|
+ *
|
|
|
+ * The SP (also called partition) can be any MM SP such as StandAlonneMM or smm-gateway.
|
|
|
+ * The comm_buf format is the same for both partitions.
|
|
|
+ * When using the u-boot OP-TEE driver, StandAlonneMM is supported.
|
|
|
+ * When using the u-boot FF-A driver, any MM SP is supported.
|
|
|
+ *
|
|
|
* Return: status code
|
|
|
*/
|
|
|
static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
|
|
@@ -157,12 +405,24 @@ static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize)
|
|
|
efi_status_t ret;
|
|
|
struct efi_mm_communicate_header *mm_hdr;
|
|
|
struct smm_variable_communicate_header *var_hdr;
|
|
|
+#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
|
|
|
+ enum mm_comms_select mm_comms;
|
|
|
+#endif
|
|
|
|
|
|
dsize += MM_COMMUNICATE_HEADER_SIZE + MM_VARIABLE_COMMUNICATE_SIZE;
|
|
|
mm_hdr = (struct efi_mm_communicate_header *)comm_buf;
|
|
|
var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data;
|
|
|
|
|
|
- ret = optee_mm_communicate(comm_buf, dsize);
|
|
|
+#if CONFIG_IS_ENABLED(ARM_FFA_TRANSPORT)
|
|
|
+ mm_comms = get_mm_comms();
|
|
|
+ if (mm_comms == MM_COMMS_FFA)
|
|
|
+ ret = ffa_mm_communicate(comm_buf, dsize);
|
|
|
+ else
|
|
|
+ ret = optee_mm_communicate(comm_buf, dsize);
|
|
|
+#else
|
|
|
+ ret = optee_mm_communicate(comm_buf, dsize);
|
|
|
+#endif
|
|
|
+
|
|
|
if (ret != EFI_SUCCESS) {
|
|
|
log_err("%s failed!\n", __func__);
|
|
|
return ret;
|
|
@@ -697,7 +957,7 @@ void efi_variables_boot_exit_notify(void)
|
|
|
ret = EFI_NOT_FOUND;
|
|
|
|
|
|
if (ret != EFI_SUCCESS)
|
|
|
- log_err("Unable to notify StMM for ExitBootServices\n");
|
|
|
+ log_err("Unable to notify the MM partition for ExitBootServices\n");
|
|
|
free(comm_buf);
|
|
|
|
|
|
/*
|