From patchwork Tue Mar 29 15:16:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abdellatif El Khlifi X-Patchwork-Id: 1610732 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KSZRY3xXyz9sCq for ; Wed, 30 Mar 2022 03:15:37 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 05E2E84038; Tue, 29 Mar 2022 18:14:59 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=fail (p=none dis=none) header.from=arm.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by phobos.denx.de (Postfix, from userid 109) id 6EA468400A; Tue, 29 Mar 2022 17:17:28 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.2 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by phobos.denx.de (Postfix) with ESMTP id 36AEA83FCF for ; Tue, 29 Mar 2022 17:17:14 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=abdellatif.elkhlifi@arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 615041477; Tue, 29 Mar 2022 08:17:13 -0700 (PDT) Received: from e121910.arm.com (unknown [10.57.40.79]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 6B6703F73B; Tue, 29 Mar 2022 08:17:11 -0700 (PDT) From: abdellatif.elkhlifi@arm.com To: u-boot@lists.denx.de Cc: nd@arm.com, trini@konsulko.com, Abdellatif El Khlifi Subject: [PATCH 1/6] arm_ffa: introduce Arm FF-A low-level driver Date: Tue, 29 Mar 2022 16:16:54 +0100 Message-Id: <20220329151659.16894-2-abdellatif.elkhlifi@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220329151659.16894-1-abdellatif.elkhlifi@arm.com> References: <20220329151659.16894-1-abdellatif.elkhlifi@arm.com> X-Mailman-Approved-At: Tue, 29 Mar 2022 18:14:45 +0200 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.5 at phobos.denx.de X-Virus-Status: Clean From: Abdellatif El Khlifi Add the driver implementing Arm Firmware Framework for Armv8-A v1.0 The Firmware Framework for Arm A-profile processors (FF-A) describes interfaces (ABIs) that standardize communication between the Secure World and Normal World leveraging TrustZone technology. This driver uses SMC32 calling convention. The driver provides helper FF-A interfaces for user layers. These helper functions allow clients to pass data and select the FF-A function to use for the communication with secure world. Signed-off-by: Abdellatif El Khlifi Cc: Tom Rini --- MAINTAINERS | 8 + arch/arm/cpu/armv8/smccc-call.S | 27 + arch/arm/lib/asm-offsets.c | 6 + common/board_r.c | 7 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/arm-ffa/Kconfig | 25 + drivers/arm-ffa/Makefile | 6 + drivers/arm-ffa/arm-ffa-uclass.c | 65 ++ drivers/arm-ffa/arm_ffa_prv.h | 200 +++++ drivers/arm-ffa/core.c | 1427 ++++++++++++++++++++++++++++++ include/arm_ffa.h | 190 ++++ include/arm_ffa_helper.h | 45 + include/dm/uclass-id.h | 1 + include/linux/arm-smccc.h | 28 +- lib/Kconfig | 1 + lib/Makefile | 1 + lib/arm-ffa/Kconfig | 6 + lib/arm-ffa/Makefile | 8 + lib/arm-ffa/arm_ffa_helper.c | 188 ++++ lib/efi_loader/efi_boottime.c | 17 + 21 files changed, 2258 insertions(+), 1 deletion(-) create mode 100644 drivers/arm-ffa/Kconfig create mode 100644 drivers/arm-ffa/Makefile create mode 100644 drivers/arm-ffa/arm-ffa-uclass.c create mode 100644 drivers/arm-ffa/arm_ffa_prv.h create mode 100644 drivers/arm-ffa/core.c create mode 100644 include/arm_ffa.h create mode 100644 include/arm_ffa_helper.h create mode 100644 lib/arm-ffa/Kconfig create mode 100644 lib/arm-ffa/Makefile create mode 100644 lib/arm-ffa/arm_ffa_helper.c diff --git a/MAINTAINERS b/MAINTAINERS index 74d5263fb1..c5b608eb60 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -232,6 +232,14 @@ F: board/CZ.NIC/ F: configs/turris_*_defconfig F: include/configs/turris_*.h +ARM FF-A +M: Abdellatif El Khlifi +S: Maintained +F: drivers/arm-ffa/ +F: include/arm_ffa.h +F: include/arm_ffa_helper.h +F: lib/arm-ffa/ + ARM FREESCALE IMX M: Stefano Babic M: Fabio Estevam diff --git a/arch/arm/cpu/armv8/smccc-call.S b/arch/arm/cpu/armv8/smccc-call.S index dc92b28777..9a6aebf194 100644 --- a/arch/arm/cpu/armv8/smccc-call.S +++ b/arch/arm/cpu/armv8/smccc-call.S @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2015, Linaro Limited + * (C) Copyright 2022 ARM Limited + * Abdellatif El Khlifi */ #include #include @@ -45,3 +47,28 @@ ENDPROC(__arm_smccc_smc) ENTRY(__arm_smccc_hvc) SMCCC hvc ENDPROC(__arm_smccc_hvc) + +#if (IS_ENABLED(CONFIG_ARM_FFA_TRANSPORT)) + + .macro FFASMCCC instr + .cfi_startproc + \instr #0 + ldr x9, [sp] + stp x0, x1, [x9, #ARM_SMCCC_RES_X0_OFFS] + stp x2, x3, [x9, #ARM_SMCCC_RES_X2_OFFS] + stp x4, x5, [x9, #ARM_SMCCC_RES_X4_OFFS] + stp x6, x7, [x9, #ARM_SMCCC_RES_X6_OFFS] + ret + .cfi_endproc + .endm + +/* + * void arm_ffa_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2, + * unsigned long a3, unsigned long a4, unsigned long a5, + * unsigned long a6, unsigned long a7, struct arm_smccc_res *res) + */ +ENTRY(__arm_ffa_smccc_smc) + FFASMCCC smc +ENDPROC(__arm_ffa_smccc_smc) + +#endif diff --git a/arch/arm/lib/asm-offsets.c b/arch/arm/lib/asm-offsets.c index 22fd541f9a..02a4a42fe6 100644 --- a/arch/arm/lib/asm-offsets.c +++ b/arch/arm/lib/asm-offsets.c @@ -9,6 +9,8 @@ * generate asm statements containing #defines, * compile this file to assembler, and then extract the * #defines from the assembly-language output. + * + * (C) Copyright 2022 ARM Limited */ #include @@ -115,6 +117,10 @@ int main(void) #ifdef CONFIG_ARM_SMCCC DEFINE(ARM_SMCCC_RES_X0_OFFS, offsetof(struct arm_smccc_res, a0)); DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2)); +#if (IS_ENABLED(CONFIG_ARM_FFA_TRANSPORT)) + DEFINE(ARM_SMCCC_RES_X4_OFFS, offsetof(struct arm_smccc_res, a4)); + DEFINE(ARM_SMCCC_RES_X6_OFFS, offsetof(struct arm_smccc_res, a6)); +#endif DEFINE(ARM_SMCCC_QUIRK_ID_OFFS, offsetof(struct arm_smccc_quirk, id)); DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS, offsetof(struct arm_smccc_quirk, state)); #endif diff --git a/common/board_r.c b/common/board_r.c index b92c1bb0be..7866ec3ad5 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -62,6 +62,10 @@ #include #include +#ifdef CONFIG_ARM_FFA_TRANSPORT +#include +#endif + DECLARE_GLOBAL_DATA_PTR; ulong monitor_flash_len; @@ -771,6 +775,9 @@ static init_fnc_t init_sequence_r[] = { INIT_FUNC_WATCHDOG_RESET initr_net, #endif +#ifdef CONFIG_ARM_FFA_TRANSPORT + ffa_helper_init_device, +#endif #ifdef CONFIG_POST initr_post, #endif diff --git a/drivers/Kconfig b/drivers/Kconfig index b26ca8cf70..e83c23789d 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -6,6 +6,8 @@ source "drivers/core/Kconfig" source "drivers/adc/Kconfig" +source "drivers/arm-ffa/Kconfig" + source "drivers/ata/Kconfig" source "drivers/axi/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 4e7cf28440..6671d2a604 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -107,6 +107,7 @@ obj-y += iommu/ obj-y += smem/ obj-y += thermal/ obj-$(CONFIG_TEE) += tee/ +obj-$(CONFIG_ARM_FFA_TRANSPORT) += arm-ffa/ obj-y += axi/ obj-y += ufs/ obj-$(CONFIG_W1) += w1/ diff --git a/drivers/arm-ffa/Kconfig b/drivers/arm-ffa/Kconfig new file mode 100644 index 0000000000..e503dfaebf --- /dev/null +++ b/drivers/arm-ffa/Kconfig @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0 + +config ARM_FFA_TRANSPORT + bool "Enable Arm Firmware Framework for Armv8-A driver" + depends on DM && ARM64 + select ARM_SMCCC if ARM64 + select LIB_UUID + select ARM_FFA_TRANSPORT_HELPERS + help + The Firmware Framework for Arm A-profile processors (FF-A) + describes interfaces (ABIs) that standardize communication + between the Secure World and Normal World leveraging TrustZone + technology. + + This driver is based on FF-A specification v1.0 and uses SMC32 + calling convention. + + FF-A specification: + + https://developer.arm.com/documentation/den0077/a/?lang=en + + In u-boot FF-A design, the Secure World is considered as one + entity to communicate with. FF-A communication is handled by + one device and one instance. This device takes care of + all the interactions between Normal world and Secure World. diff --git a/drivers/arm-ffa/Makefile b/drivers/arm-ffa/Makefile new file mode 100644 index 0000000000..7bc9a336a9 --- /dev/null +++ b/drivers/arm-ffa/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2022 Abdellatif El Khlifi +# + +obj-y += arm-ffa-uclass.o core.o diff --git a/drivers/arm-ffa/arm-ffa-uclass.c b/drivers/arm-ffa/arm-ffa-uclass.c new file mode 100644 index 0000000000..0bf661d397 --- /dev/null +++ b/drivers/arm-ffa/arm-ffa-uclass.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2022 ARM Limited + * Abdellatif El Khlifi + */ + +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +UCLASS_DRIVER(ffa) = { + .name = "ffa", + .id = UCLASS_FFA, +}; + +/** + * ffa_get_invoke_func - performs a call to the FF-A driver dispatcher + * @func_id: The FF-A function to be used + * @func_data: Pointer to the FF-A function arguments + * container structure. This also includes + * pointers to the returned data needed by + * clients. + * + * This runtime function passes the FF-A function ID and its arguments to + * the FF-A driver dispatcher. + * This function is called by the FF-A helper functions. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +int __ffa_runtime ffa_get_invoke_func(u32 func_id, struct ffa_interface_data *func_data) +{ + if (!ffa_device_get_ops()->invoke_func) + return -EINVAL; + + return ffa_device_get_ops()->invoke_func(func_id, func_data); +} + +/** + * ffa_init_device - probes the arm_ffa device + * + * This boot time function makes sure the arm_ffa device is probed + * and ready for use. + * This function is called automatically at initcalls + * level (after u-boot relocation). + * + * Arm FF-A transport is implemented through a single u-boot + * device (arm_ffa). So, there is only one device belonging to UCLASS_FFA. + * All FF-A clients should use the arm_ffa device to use the FF-A + * transport. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +int ffa_init_device(void) +{ + return ffa_get_device(); +} diff --git a/drivers/arm-ffa/arm_ffa_prv.h b/drivers/arm-ffa/arm_ffa_prv.h new file mode 100644 index 0000000000..c788d0bd53 --- /dev/null +++ b/drivers/arm-ffa/arm_ffa_prv.h @@ -0,0 +1,200 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2022 ARM Limited + * Abdellatif El Khlifi + */ + +#ifndef __ARM_FFA_PRV_H +#define __ARM_FFA_PRV_H + +#include +#include +#include +#include + +/* + * This header is private. It is exclusively used by the FF-A driver + */ + +/* FF-A driver version definitions */ + +#define MAJOR_VERSION_MASK GENMASK(30, 16) +#define MINOR_VERSION_MASK GENMASK(15, 0) +#define GET_FFA_MAJOR_VERSION(x) \ + ((u16)(FIELD_GET(MAJOR_VERSION_MASK, (x)))) +#define GET_FFA_MINOR_VERSION(x) \ + ((u16)(FIELD_GET(MINOR_VERSION_MASK, (x)))) +#define PACK_VERSION_INFO(major, minor) \ + (FIELD_PREP(MAJOR_VERSION_MASK, (major)) | \ + FIELD_PREP(MINOR_VERSION_MASK, (minor))) + +#define FFA_MAJOR_VERSION (1) +#define FFA_MINOR_VERSION (0) +#define FFA_VERSION_1_0 \ + PACK_VERSION_INFO(FFA_MAJOR_VERSION, FFA_MINOR_VERSION) + +/* Endpoint ID mask (u-boot endpoint ID) */ + +#define GET_SELF_ENDPOINT_ID_MASK GENMASK(15, 0) +#define GET_SELF_ENDPOINT_ID(x) \ + ((u16)(FIELD_GET(GET_SELF_ENDPOINT_ID_MASK, (x)))) + +#define PREP_SELF_ENDPOINT_ID_MASK GENMASK(31, 16) +#define PREP_SELF_ENDPOINT_ID(x) \ + (FIELD_PREP(PREP_SELF_ENDPOINT_ID_MASK, (x))) + +/* Partition endpoint ID mask (partition with which u-boot communicates with) */ + +#define PREP_PART_ENDPOINT_ID_MASK GENMASK(15, 0) +#define PREP_PART_ENDPOINT_ID(x) \ + (FIELD_PREP(PREP_PART_ENDPOINT_ID_MASK, (x))) + +/* The FF-A SMC function prototype definition */ + +typedef void (*invoke_ffa_fn_t)(unsigned long a0, unsigned long a1, + unsigned long a2, unsigned long a3, unsigned long a4, + unsigned long a5, unsigned long a6, unsigned long a7, + struct arm_smccc_res *res); + +/** + * enum ffa_conduit - Arm FF-A conduits supported by the Arm FF-A driver + * Currently only SMC32 is supported. + */ +enum ffa_conduit { + FFA_CONDUIT_SMC = 0, +}; + +/** + * FFA_DECLARE_ARGS - FF-A functions local variables + * @a0-a7: local variables used to set registers x0-x7 + * @res: the structure hosting the FF-A function return data + * + * A helper macro for declaring local variables for the FF-A functions arguments. + * The x0-x7 registers are used to exchange data with the secure world. + * But, only the bottom 32-bit of thes registers contains the data. + */ +#define FFA_DECLARE_ARGS \ + unsigned long a0 = 0; \ + unsigned long a1 = 0; \ + unsigned long a2 = 0; \ + unsigned long a3 = 0; \ + unsigned long a4 = 0; \ + unsigned long a5 = 0; \ + unsigned long a6 = 0; \ + unsigned long a7 = 0; \ + struct arm_smccc_res res = {0} + +/* FF-A error codes */ +#define FFA_ERR_STAT_NOT_SUPPORTED (-1) +#define FFA_ERR_STAT_INVALID_PARAMETERS (-2) +#define FFA_ERR_STAT_NO_MEMORY (-3) +#define FFA_ERR_STAT_BUSY (-4) +#define FFA_ERR_STAT_INTERRUPTED (-5) +#define FFA_ERR_STAT_DENIED (-6) +#define FFA_ERR_STAT_RETRY (-7) +#define FFA_ERR_STAT_ABORTED (-8) + +/** + * struct ffa_features_desc - FF-A functions features + * @func_id: FF-A function + * @field1: features read from register w2 + * @field2: features read from register w3 + * + * Data structure describing the features of the FF-A functions queried by + * FFA_FEATURES + */ +struct ffa_features_desc { + u32 func_id; + u32 field1; + u32 field2; +}; + +/** + * enum ffa_rxtx_buf_sizes - minimum sizes supported + * for the RX/TX buffers + */ +enum ffa_rxtx_buf_sizes { + RXTX_4K, + RXTX_64K, + RXTX_16K +}; + +/* + * Number of the FF-A interfaces features descriptors + * currently only FFA_RXTX_MAP descriptor is supported + */ +#define FFA_FEATURE_DESC_CNT (1) + +/** + * struct ffa_pdata - platform data for the arm_ffa device + * @conduit: The FF-A conduit used + * + * Platform data structure read from the device tree + */ +struct ffa_pdata { + enum ffa_conduit conduit; +}; + +/** + * struct ffa_rxtxpair - structure hosting the RX/TX buffers virtual addresses + * @rxbuf: virtual address of the RX buffer + * @txbuf: virtual address of the TX buffer + * + * Data structure hosting the virtual addresses of the mapped RX/TX buffers + * These addresses are used by the FF-A functions that use the RX/TX buffers + */ +struct ffa_rxtxpair { + u64 rxbuf; /* virtual address */ + u64 txbuf; /* virtual address */ +}; + +/** + * struct ffa_partition_desc - the secure partition descriptor + * @info: partition information + * @UUID: UUID + * + * Each partition has its descriptor containing the partitions information and the UUID + */ +struct ffa_partition_desc { + struct ffa_partition_info info; + union ffa_partition_uuid UUID; +}; + +/** + * struct ffa_partitions - descriptors for all secure partitions + * @count: The number of partitions descriptors + * @descs The partitions descriptors table + * + * This data structure contains the partitions descriptors table + */ +struct ffa_partitions { + u32 count; + struct ffa_partition_desc *descs; /* virtual address */ +}; + +/** + * struct ffa_prvdata - the driver private data structure + * + * @dev: The arm_ffa device under u-boot driver model + * @fwk_version: FF-A framework version + * @id: u-boot endpoint ID + * @partitions: The partitions descriptors structure + * @pair: The RX/TX buffers pair + * @conduit: The selected conduit + * @invoke_ffa_fn: The function executing the FF-A function + * @features: Table of the FF-A functions having features + * + * The driver data structure hosting all resident data. + */ +struct ffa_prvdata { + struct udevice *dev; + u32 fwk_version; + u16 id; + struct ffa_partitions partitions; + struct ffa_rxtxpair pair; + enum ffa_conduit conduit; + invoke_ffa_fn_t invoke_ffa_fn; + struct ffa_features_desc features[FFA_FEATURE_DESC_CNT]; +}; + +#endif diff --git a/drivers/arm-ffa/core.c b/drivers/arm-ffa/core.c new file mode 100644 index 0000000000..9d0dab1d36 --- /dev/null +++ b/drivers/arm-ffa/core.c @@ -0,0 +1,1427 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2022 ARM Limited + * Abdellatif El Khlifi + */ + +#include "arm_ffa_prv.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/** + * The device private data structure containing all the resident + * data read from secure world + */ +struct ffa_prvdata __ffa_runtime_data ffa_priv_data = {0}; + +/* + * Driver functions + */ + +/** + * ffa_get_device - probes the arm_ffa device + * + * This boot time function makes sure the arm_ffa device is probed + * and ready for use. This is done using uclass_get_device. + * The arm_ffa driver belongs to UCLASS_FFA. + * This function should be called before using the driver. + * + * Arm FF-A transport is implemented through a single u-boot + * device (arm_ffa). So, there is only one device belonging to UCLASS_FFA. + * All FF-A clients should use the arm_ffa device to use the FF-A + * transport. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +int ffa_get_device(void) +{ + int ret; + int devnum = 0; + + if (ffa_priv_data.dev) + return FFA_ERR_STAT_SUCCESS; + + /* + * searching and probing the device + */ + ret = uclass_get_device(UCLASS_FFA, devnum, &ffa_priv_data.dev); + if (ret) { + ffa_err("can not find the device"); + ffa_priv_data.dev = NULL; + return -ENODEV; + } + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * ffa_get_version - FFA_VERSION handler function + * + * This is the boot time function that implements FFA_VERSION FF-A function + * to get from the secure world the FF-A framework version + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +static int ffa_get_version(void) +{ + u16 major, minor; + + FFA_DECLARE_ARGS; + + if (!ffa_priv_data.invoke_ffa_fn) + panic("[FFA] no private data found\n"); + + a0 = FFA_VERSION; + a1 = FFA_VERSION_1_0; + ffa_priv_data.invoke_ffa_fn(a0, a1, a2, a3, a4, a5, a6, a7, &res); + + if (res.a0 == FFA_ERR_STAT_NOT_SUPPORTED) { + ffa_err("A Firmware Framework implementation does not exist"); + return -EOPNOTSUPP; + } + + major = GET_FFA_MAJOR_VERSION(res.a0); + minor = GET_FFA_MINOR_VERSION(res.a0); + + ffa_info("FF-A driver %d.%d\nFF-A framework %d.%d", + FFA_MAJOR_VERSION, FFA_MINOR_VERSION, major, minor); + + if ((major == FFA_MAJOR_VERSION && minor >= FFA_MINOR_VERSION)) { + ffa_info("Versions are compatible "); + + ffa_priv_data.fwk_version = res.a0; + + return FFA_ERR_STAT_SUCCESS; + } + + ffa_info("Versions are incompatible "); + return -EPROTONOSUPPORT; +} + +/** + * ffa_get_endpoint_id - FFA_ID_GET handler function + * + * This is the boot time function that implements FFA_ID_GET FF-A function + * to get from the secure world u-boot endpoint ID + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +static int ffa_get_endpoint_id(void) +{ + FFA_DECLARE_ARGS; + + if (!ffa_priv_data.invoke_ffa_fn) + panic("[FFA] no private data found\n"); + + a0 = FFA_ID_GET; + + ffa_priv_data.invoke_ffa_fn(a0, a1, a2, a3, a4, a5, a6, a7, &res); + + switch (res.a0) { + case FFA_ERROR: + { + if (((int)res.a2) == FFA_ERR_STAT_NOT_SUPPORTED) { + ffa_err("This function is not implemented at this FF-A instance"); + return -EOPNOTSUPP; + } + + ffa_err("Undefined error code (%d)", ((int)res.a2)); + return -EINVAL; + } + case FFA_SUCCESS: + { + ffa_priv_data.id = GET_SELF_ENDPOINT_ID(res.a2); + ffa_info("endpoint ID is %u", ffa_priv_data.id); + + return FFA_ERR_STAT_SUCCESS; + } + default: + { + ffa_err("Undefined response function (0x%lx)", res.a0); + return -EINVAL; + } + } +} + +/** + * ffa_get_features_desc - returns the features descriptor of the specified + * FF-A function + * @func_id: the FF-A function which the features are to be retrieved + * + * This is a boot time function that searches the features descriptor of the + * specified FF-A function + * + * Return: + * + * When found, the address of the features descriptor is returned. Otherwise, NULL. + */ +static struct ffa_features_desc *ffa_get_features_desc(u32 func_id) +{ + u32 desc_idx; + + /* + * search for the descriptor of the selected FF-A interface + */ + for (desc_idx = 0; desc_idx < FFA_FEATURE_DESC_CNT ; desc_idx++) + if (ffa_priv_data.features[desc_idx].func_id == func_id) + return &ffa_priv_data.features[desc_idx]; + + return NULL; +} + +/** + * ffa_get_rxtx_map_features - FFA_FEATURES handler function with FFA_RXTX_MAP + * argument + * + * This is the boot time function that implements FFA_FEATURES FF-A function + * to retrieve the FFA_RXTX_MAP features + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +static int ffa_get_rxtx_map_features(void) +{ + FFA_DECLARE_ARGS; + + if (!ffa_priv_data.invoke_ffa_fn) + panic("[FFA] no private data found\n"); + + a0 = FFA_FEATURES; + a1 = FFA_RXTX_MAP; + + ffa_priv_data.invoke_ffa_fn(a0, a1, a2, a3, a4, a5, a6, a7, &res); + + switch (res.a0) { + case FFA_ERROR: + { + if (((int)res.a2) == FFA_ERR_STAT_NOT_SUPPORTED) { + ffa_err("FFA_RXTX_MAP is not implemented at this FF-A instance"); + return -EOPNOTSUPP; + } + + ffa_err("Undefined error code (%d)", ((int)res.a2)); + return -EINVAL; + } + case FFA_SUCCESS: + { + u32 desc_idx; + + /* + * search for an empty descriptor + */ + for (desc_idx = 0; desc_idx < FFA_FEATURE_DESC_CNT ; desc_idx++) + if (!ffa_priv_data.features[desc_idx].func_id) { + /* + * populate the descriptor with + * the interface features data + */ + ffa_priv_data.features[desc_idx].func_id = + FFA_RXTX_MAP; + ffa_priv_data.features[desc_idx].field1 = + res.a2; + + ffa_info("FFA_RXTX_MAP features data 0x%lx", + res.a2); + + return FFA_ERR_STAT_SUCCESS; + } + + ffa_err("Cannot save FFA_RXTX_MAP features data. Descriptors table full"); + return -ENOBUFS; + } + default: + { + ffa_err("Undefined response function (0x%lx)", + res.a0); + return -EINVAL; + } + } +} + +/** + * ffa_get_rxtx_buffers_pages_cnt - reads from the features data descriptors + * the minimum number of pages in each of the RX/TX + * buffers + * @buf_4k_pages: Pointer to the minimum number of pages + * + * This is the boot time function that returns the minimum number of pages + * in each of the RX/TX buffers + * + * Return: + * + * buf_4k_pages points to the returned number of pages + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +static int ffa_get_rxtx_buffers_pages_cnt(size_t *buf_4k_pages) +{ + struct ffa_features_desc *desc = NULL; + + if (!buf_4k_pages) + return -EINVAL; + + desc = ffa_get_features_desc(FFA_RXTX_MAP); + if (!desc) + return -EINVAL; + + switch (desc->field1) { + case RXTX_4K: + *buf_4k_pages = 1; + break; + case RXTX_16K: + *buf_4k_pages = 4; + break; + case RXTX_64K: + *buf_4k_pages = 16; + break; + default: + ffa_err("RX/TX buffer size not supported"); + return -EINVAL; + } + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * ffa_free_rxtx_buffers - frees the RX/TX buffers + * @buf_4k_pages: the minimum number of pages in each of the RX/TX + * buffers + * + * This is the boot time function used to free the RX/TX buffers + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +static int ffa_free_rxtx_buffers(size_t buf_4k_pages) +{ + efi_status_t free_rxbuf_ret, free_txbuf_ret; + + ffa_info("Freeing RX/TX buffers"); + + free_rxbuf_ret = efi_free_pages(ffa_priv_data.pair.rxbuf, buf_4k_pages); + free_txbuf_ret = efi_free_pages(ffa_priv_data.pair.txbuf, buf_4k_pages); + + if (free_rxbuf_ret != EFI_SUCCESS || free_txbuf_ret != EFI_SUCCESS) { + ffa_err("Failed to free RX/TX buffers (rx: %lu , tx: %lu)", + free_rxbuf_ret, + free_txbuf_ret); + return -EINVAL; + } + + ffa_priv_data.pair.rxbuf = 0; + ffa_priv_data.pair.txbuf = 0; + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * ffa_alloc_rxtx_buffers - allocates the RX/TX buffers + * @buf_4k_pages: the minimum number of pages in each of the RX/TX + * buffers + * + * This is the boot time function used by ffa_map_rxtx_buffers to allocate + * the RX/TX buffers before mapping them + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +static int ffa_alloc_rxtx_buffers(size_t buf_4k_pages) +{ +#if CONFIG_IS_ENABLED(EFI_LOADER) + + efi_status_t efi_ret; + void *virt_txbuf; + void *virt_rxbuf; + + ffa_info("Using %lu 4KB page(s) for RX/TX buffers size", + buf_4k_pages); + + efi_ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, + EFI_BOOT_SERVICES_DATA, + buf_4k_pages, + &ffa_priv_data.pair.rxbuf); + + if (efi_ret != EFI_SUCCESS) { + ffa_priv_data.pair.rxbuf = 0; + ffa_err("Failure to allocate RX buffer (EFI error: 0x%lx)", + efi_ret); + + return -ENOBUFS; + } + + ffa_info("RX buffer at virtual address 0x%llx", + ffa_priv_data.pair.rxbuf); + + virt_rxbuf = (void *)ffa_priv_data.pair.rxbuf; + + /* + * make sure the buffer is clean before use + */ + memset(virt_rxbuf, 0, buf_4k_pages * SZ_4K); + + efi_ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, + EFI_RUNTIME_SERVICES_DATA, + buf_4k_pages, + &ffa_priv_data.pair.txbuf); + + if (efi_ret != EFI_SUCCESS) { + efi_free_pages(ffa_priv_data.pair.rxbuf, buf_4k_pages); + ffa_priv_data.pair.rxbuf = 0; + ffa_priv_data.pair.txbuf = 0; + ffa_err("Failure to allocate the TX buffer (EFI error: 0x%lx)" + , efi_ret); + + return -ENOBUFS; + } + + ffa_info("TX buffer at virtual address 0x%llx", + ffa_priv_data.pair.txbuf); + + virt_txbuf = (void *)ffa_priv_data.pair.txbuf; + + /* + * make sure the buffer is clean before use + */ + memset(virt_txbuf, 0, buf_4k_pages * SZ_4K); + + return FFA_ERR_STAT_SUCCESS; + +#else + return -ENOBUFS; +#endif +} + +/** + * ffa_map_rxtx_buffers - FFA_RXTX_MAP handler function + * @buf_4k_pages: the minimum number of pages in each of the RX/TX + * buffers + * + * This is the boot time function that implements FFA_RXTX_MAP FF-A function + * to map the RX/TX buffers + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +static int ffa_map_rxtx_buffers(size_t buf_4k_pages) +{ + int ret; + + FFA_DECLARE_ARGS; + + if (!ffa_priv_data.invoke_ffa_fn) + panic("[FFA] no private data found\n"); + + ret = ffa_alloc_rxtx_buffers(buf_4k_pages); + if (ret != FFA_ERR_STAT_SUCCESS) + return ret; + + a0 = FFA_RXTX_MAP; + a1 = ffa_priv_data.pair.txbuf; + a2 = ffa_priv_data.pair.rxbuf; + a3 = buf_4k_pages; + + ffa_priv_data.invoke_ffa_fn(a0, a1, a2, a3, a4, a5, a6, a7, &res); + + switch (res.a0) { + case FFA_ERROR: + { + switch (((int)res.a2)) { + case FFA_ERR_STAT_INVALID_PARAMETERS: + ffa_err("One or more fields in input parameters is incorrectly encoded"); + ret = -EPERM; + break; + case FFA_ERR_STAT_NO_MEMORY: + ffa_err("Not enough memory"); + ret = -ENOMEM; + break; + case FFA_ERR_STAT_DENIED: + ffa_err("Buffer pair already registered"); + ret = -EACCES; + break; + case FFA_ERR_STAT_NOT_SUPPORTED: + ffa_err("This function is not implemented at this FF-A instance"); + ret = -EOPNOTSUPP; + break; + default: + ffa_err("Undefined error (%d)", + ((int)res.a2)); + ret = -EINVAL; + } + break; + } + case FFA_SUCCESS: + ffa_info("RX/TX buffers mapped"); + return FFA_ERR_STAT_SUCCESS; + default: + ffa_err("Undefined response function (0x%lx)", + res.a0); + ret = -EINVAL; + } + + ffa_free_rxtx_buffers(buf_4k_pages); + + return ret; +} + +/** + * ffa_unmap_rxtx_buffers - FFA_RXTX_UNMAP handler function + * + * This is the boot time function that implements FFA_RXTX_UNMAP FF-A function + * to unmap the RX/TX buffers + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +static int ffa_unmap_rxtx_buffers(void) +{ + FFA_DECLARE_ARGS; + + if (!ffa_priv_data.invoke_ffa_fn) + panic("[FFA] no private data found\n"); + + a0 = FFA_RXTX_UNMAP; + a1 = PREP_SELF_ENDPOINT_ID(ffa_priv_data.id); + + ffa_priv_data.invoke_ffa_fn(a0, a1, a2, a3, a4, a5, a6, a7, &res); + + switch (res.a0) { + case FFA_ERROR: + { + if (((int)res.a2) == FFA_ERR_STAT_NOT_SUPPORTED) + panic("[FFA] FFA_RXTX_UNMAP is not implemented at this FF-A instance\n"); + else if (((int)res.a2) == FFA_ERR_STAT_INVALID_PARAMETERS) + panic("[FFA] There is no buffer pair registered on behalf of the caller\n"); + else + panic("[FFA] Undefined error (%d)\n", ((int)res.a2)); + } + case FFA_SUCCESS: + { + size_t buf_4k_pages = 0; + int ret; + + ret = ffa_get_rxtx_buffers_pages_cnt(&buf_4k_pages); + if (ret != FFA_ERR_STAT_SUCCESS) + panic("[FFA] RX/TX buffers unmapped but failure in getting pages count\n"); + + ret = ffa_free_rxtx_buffers(buf_4k_pages); + if (ret != FFA_ERR_STAT_SUCCESS) + panic("[FFA] RX/TX buffers unmapped but failure in freeing the memory\n"); + + ffa_info("RX/TX buffers unmapped and memory freed"); + + return FFA_ERR_STAT_SUCCESS; + } + default: + panic("[FFA] Undefined response function (0x%lx)", res.a0); + } +} + +/** + * ffa_release_rx_buffer - FFA_RX_RELEASE handler function + * + * This is the boot time function that invokes FFA_RX_RELEASE FF-A function + * to release the ownership of the RX buffer + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +static int ffa_release_rx_buffer(void) +{ + FFA_DECLARE_ARGS; + + if (!ffa_priv_data.invoke_ffa_fn) + panic("[FFA] no private data found\n"); + + a0 = FFA_RX_RELEASE; + + ffa_priv_data.invoke_ffa_fn(a0, a1, a2, a3, a4, a5, a6, a7, &res); + + switch (res.a0) { + case FFA_ERROR: + { + if (((int)res.a2) == FFA_ERR_STAT_NOT_SUPPORTED) + panic("[FFA] FFA_RX_RELEASE is not implemented at this FF-A instance\n"); + else if (((int)res.a2) == FFA_ERR_STAT_DENIED) + panic("[FFA] Caller did not have ownership of the RX buffer\n"); + else + panic("[FFA] Undefined error (%d)\n", ((int)res.a2)); + } + case FFA_SUCCESS: + return FFA_ERR_STAT_SUCCESS; + + default: + panic("[FFA] Undefined response function (0x%lx)\n", res.a0); + } +} + +/** + * ffa_uuid_are_identical - checks whether two given UUIDs are identical + * @uuid1: first UUID + * @uuid2: second UUID + * + * This is a boot time function used by ffa_read_partitions_info to search + * for a UUID in the partitions descriptors table + * + * Return: + * + * 1 when UUIDs match. Otherwise, 0 + */ +int ffa_uuid_are_identical(const union ffa_partition_uuid *uuid1, + const union ffa_partition_uuid *uuid2) +{ + if (!uuid1 || !uuid2) + return 0; + + return (!memcmp(uuid1, uuid2, sizeof(union ffa_partition_uuid))); +} + +/** + * ffa_read_partitions_info - reads the data queried by FFA_PARTITION_INFO_GET + * and saves it in the private structure + * @count: The number of partitions queried + * @part_uuid: Pointer to the partition(s) UUID + * + * This is the boot time function that reads the partitions information + * returned by the FFA_PARTITION_INFO_GET and saves it in the private + * data structure. + * + * Return: + * + * The private data structure is updated with the partition(s) information + * FFA_ERR_STAT_SUCCESS is returned on success. Otherwise, failure + */ +static int ffa_read_partitions_info(u32 count, union ffa_partition_uuid *part_uuid) +{ + if (!count) { + ffa_err("No partition detected"); + return -ENODATA; + } + + ffa_info("Reading partitions data from the RX buffer"); + +#if CONFIG_IS_ENABLED(EFI_LOADER) + + if (!part_uuid) { + /* + * querying information of all partitions + */ + u64 data_pages; + u64 data_bytes; + efi_status_t efi_ret; + size_t buf_4k_pages = 0; + u32 desc_idx; + struct ffa_partition_info *parts_info; + int ret; + + data_bytes = count * sizeof(struct ffa_partition_desc); + data_pages = efi_size_in_pages(data_bytes); + + /* + * get the RX buffer size in pages + */ + ret = ffa_get_rxtx_buffers_pages_cnt(&buf_4k_pages); + if (ret != FFA_ERR_STAT_SUCCESS) { + ffa_err("Can not get the RX buffer size (error %d)", ret); + return ret; + } + + if (data_pages > buf_4k_pages) { + ffa_err("Partitions data size exceeds the RX buffer size:"); + ffa_err(" Sizes in pages: data %llu , RX buffer %lu ", + data_pages, + buf_4k_pages); + + return -ENOMEM; + } + + efi_ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, + EFI_RUNTIME_SERVICES_DATA, + data_pages, + (u64 *)&ffa_priv_data.partitions.descs); + + if (efi_ret != EFI_SUCCESS) { + ffa_priv_data.partitions.descs = NULL; + + ffa_err("Cannot allocate partitions data buffer (EFI error 0x%lx)", + efi_ret); + + return -ENOBUFS; + } + + /* + * make sure the buffer is clean before use + */ + memset(ffa_priv_data.partitions.descs, 0, + data_pages * SZ_4K); + + parts_info = (struct ffa_partition_info *)ffa_priv_data.pair.rxbuf; + + for (desc_idx = 0 ; desc_idx < count ; desc_idx++) { + ffa_priv_data.partitions.descs[desc_idx].info = + parts_info[desc_idx]; + + ffa_info("Partition ID %x : info cached", + ffa_priv_data.partitions.descs[desc_idx].info.id); + } + + ffa_priv_data.partitions.count = count; + + ffa_info("%d partition(s) found and cached", count); + + } else { + u32 rx_desc_idx, cached_desc_idx; + struct ffa_partition_info *parts_info; + u8 desc_found; + + parts_info = (struct ffa_partition_info *)ffa_priv_data.pair.rxbuf; + + /* + * search for the SP IDs read from the RX buffer + * in the already cached SPs. + * Update the UUID when ID found. + */ + for (rx_desc_idx = 0; rx_desc_idx < count ; rx_desc_idx++) { + desc_found = 0; + + /* + * search the current ID in the cached partitions + */ + for (cached_desc_idx = 0; + cached_desc_idx < ffa_priv_data.partitions.count; + cached_desc_idx++) { + /* + * save the UUID + */ + if (ffa_priv_data.partitions.descs[cached_desc_idx].info.id == + parts_info[rx_desc_idx].id) { + ffa_priv_data.partitions.descs[cached_desc_idx].UUID = + *part_uuid; + + desc_found = 1; + break; + } + } + + if (!desc_found) + return -ENODATA; + } + } +#else +#warning "arm_ffa: reading FFA_PARTITION_INFO_GET data not implemented" +#endif + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * ffa_query_partitions_info - invokes FFA_PARTITION_INFO_GET + * and saves partitions data + * @part_uuid: Pointer to the partition(s) UUID + * @pcount: Pointer to the number of partitions variable filled when querying + * + * This is the boot time function that executes the FFA_PARTITION_INFO_GET + * to query the partitions data. Then, it calls ffa_read_partitions_info + * to save the data in the private data structure. + * + * After reading the data the RX buffer is released using ffa_release_rx_buffer + * + * Return: + * + * When part_uuid is NULL, all partitions data are retrieved from secure world + * When part_uuid is non NULL, data for partitions matching the given UUID are + * retrieved and the number of partitions is returned + * FFA_ERR_STAT_SUCCESS is returned on success. Otherwise, failure + */ +static int ffa_query_partitions_info(union ffa_partition_uuid *part_uuid, + u32 *pcount) +{ + unsigned long a0 = 0; + union ffa_partition_uuid query_uuid = {0}; + unsigned long a5 = 0; + unsigned long a6 = 0; + unsigned long a7 = 0; + struct arm_smccc_res res = {0}; + + if (!ffa_priv_data.invoke_ffa_fn) + panic("[FFA] no private data found\n"); + + a0 = FFA_PARTITION_INFO_GET; + + /* + * If a UUID is specified. Information for one or more + * partitions in the system is queried. Otherwise, information + * for all installed partitions is queried + */ + + if (part_uuid) { + if (!pcount) + return -EINVAL; + + query_uuid = *part_uuid; + } + + ffa_priv_data.invoke_ffa_fn(a0, query_uuid.words.a1, query_uuid.words.a2, + query_uuid.words.a3, query_uuid.words.a4, + a5, a6, a7, &res); + + switch (res.a0) { + case FFA_ERROR: + { + switch (((int)res.a2)) { + case FFA_ERR_STAT_INVALID_PARAMETERS: + ffa_err("Unrecognized UUID"); + return -EPERM; + case FFA_ERR_STAT_NO_MEMORY: + ffa_err("Results cannot fit in RX buffer of the caller"); + return -ENOMEM; + case FFA_ERR_STAT_DENIED: + ffa_err("Callee is not in a state to handle this request"); + return -EACCES; + case FFA_ERR_STAT_NOT_SUPPORTED: + ffa_err("This function is not implemented at this FF-A instance"); + return -EOPNOTSUPP; + case FFA_ERR_STAT_BUSY: + ffa_err("RX buffer of the caller is not free"); + return -EBUSY; + default: + ffa_err("Undefined error (%d)", ((int)res.a2)); + return -EINVAL; + } + } + case FFA_SUCCESS: + { + int ret; + + /* + * res.a2 contains the count of partition information descriptors + * populated in the RX buffer + */ + if (res.a2) { + ret = ffa_read_partitions_info(res.a2, part_uuid); + if (ret) + ffa_err("Failed to read partition(s) data , error (%d)", ret); + } + + /* + * return the SP count + */ + if (part_uuid) { + if (!ret) + *pcount = res.a2; + else + *pcount = 0; + } + /* + * After calling FFA_PARTITION_INFO_GET the buffer ownership + * is assigned to the consumer (u-boot). So, we need to give + * the ownership back to the secure world + */ + ret = ffa_release_rx_buffer(); + + if (!part_uuid && !res.a2) { + ffa_err("[FFA] no partition installed in the system"); + return -ENODEV; + } + + return ret; + } + default: + ffa_err("Undefined response function (0x%lx)", res.a0); + return -EINVAL; + } +} + +/** + * ffa_get_partitions_info - FFA_PARTITION_INFO_GET handler function + * @func_data: Pointer to the FF-A function arguments container structure. + * The passed arguments: + * Mode 1: When getting from the driver the number of + * secure partitions: + * @data0_size: UUID size + * @data0: pointer to the UUID (little endian) + * @data1_size: size of the number of partitions + * variable + * @data1: pointer to the number of partitions + * variable. The variable will be set + * by the driver + * Mode 2: When requesting the driver to return the + * partitions information: + * @data0_size: UUID size + * @data0: pointer to the UUID (little endian) + * @data1_size: size of the SPs information buffer + * @data1: pointer to SPs information buffer + * (allocated by the client). + * The buffer will be filled by the driver + * + * This is the boot time function that queries the secure partition data from + * the private data structure. If not found, it invokes FFA_PARTITION_INFO_GET + * FF-A function to query the partition information from secure world. + * + * A client of the FF-A driver should know the UUID of the service it wants to + * access. It should use the UUID to request the FF-A driver to provide the + * partition(s) information of the service. The FF-A driver uses + * PARTITION_INFO_GET to obtain this information. This is implemented through + * ffa_get_partitions_info function. + * A new FFA_PARTITION_INFO_GET call is issued (first one performed through + * ffa_cache_partitions_info) allowing to retrieve the partition(s) information. + * They are not saved (already done). We only update the UUID in the cached area. + * This assumes that partitions data does not change in the secure world. + * Otherwise u-boot will have an outdated partition data. The benefit of caching + * the information in the FF-A driver is to accommodate discovery after + * ExitBootServices(). + * + * When invoked through a client request, ffa_get_partitions_info should be + * called twice. First call is to get from the driver the number of secure + * partitions (SPs) associated to a particular UUID. + * Then, the caller (client) allocates the buffer to host the SPs data and + * issues a 2nd call. Then, the driver fills the SPs data in the pre-allocated + * buffer. + * + * To achieve the mechanism described above, ffa_get_partitions_info uses the + * following functions: + * ffa_read_partitions_info + * ffa_query_partitions_info + * + * Return: + * + * @data1: When pointing to the number of partitions variable, the number is + * set by the driver. + * When pointing to the partitions information buffer, the buffer will be + * filled by the driver. + * + * On success FFA_ERR_STAT_SUCCESS is returned. Otherwise, failure + */ +static int ffa_get_partitions_info(struct ffa_interface_data *func_data) +{ + /* + * fill_data: + * 0: return the SP count + * 1: fill SP data and return it to the caller + * -1: undefined mode + */ + int fill_data = -1; + u32 desc_idx, client_desc_idx; + union ffa_partition_uuid *part_uuid; + u32 client_desc_max_cnt; + u32 parts_found = 0; + + if (!func_data) { + ffa_err("No function data provided"); + return -EINVAL; + } + + if (!ffa_priv_data.partitions.count || !ffa_priv_data.partitions.descs) + panic("[FFA] No partition installed\n"); + + if (func_data->data0_size == sizeof(union ffa_partition_uuid) && + func_data->data0 && + func_data->data1_size == sizeof(u32) && + func_data->data1) { + /* + * data0 (in): pointer to UUID + * data1 (in): pointer to SP count + * Out: SP count returned in the count variable pointed by data1 + */ + + fill_data = 0; + + ffa_info("Preparing for checking partitions count"); + + } else if ((func_data->data0_size == sizeof(union ffa_partition_uuid)) && + func_data->data0 && + (func_data->data1_size >= sizeof(struct ffa_partition_info)) && + !(func_data->data1_size % sizeof(struct ffa_partition_info)) && + func_data->data1) { + /* + * data0 (in): pointer to UUID + * data1 (in): pointer to SPs descriptors buffer + * (created by the client) + * Out: SPs descriptors returned in the buffer + * pointed by data1 + */ + + fill_data = 1; + + client_desc_idx = 0; + + /* + * number of empty descriptors preallocated by the caller + */ + client_desc_max_cnt = + func_data->data1_size / sizeof(struct ffa_partition_info); + + ffa_info("Preparing for filling partitions info"); + + } else { + ffa_err("Invalid function arguments provided"); + return -EINVAL; + } + + part_uuid = (union ffa_partition_uuid *)func_data->data0; + + ffa_info("Searching partitions using the provided UUID"); + + /* + * search in the cached partitions + */ + for (desc_idx = 0; + desc_idx < ffa_priv_data.partitions.count; + desc_idx++) { + if (ffa_uuid_are_identical(&ffa_priv_data.partitions.descs[desc_idx].UUID, + part_uuid)) { + ffa_info("Partition ID %x matches the provided UUID", + ffa_priv_data.partitions.descs[desc_idx].info.id); + + parts_found++; + + if (fill_data) { + /* + * trying to fill the partition info in data1 + */ + + if (client_desc_idx < client_desc_max_cnt) { + ((struct ffa_partition_info *) + func_data->data1)[client_desc_idx++] = + ffa_priv_data.partitions.descs[desc_idx].info; + continue; + } + + ffa_err("Failed to fill the current descriptor client buffer full"); + return -ENOBUFS; + } + } + } + + if (!parts_found) { + int ret; + + ffa_info("No partition found. Querying framework ..."); + + ret = ffa_query_partitions_info(part_uuid, &parts_found); + + if (ret == FFA_ERR_STAT_SUCCESS) { + if (!fill_data) { + *((u32 *)func_data->data1) = parts_found; + + ffa_info("Number of partition(s) found matching the UUID: %d", + parts_found); + } else { + /* + * we want to read SPs info + */ + + /* + * If SPs data filled, retry searching SP info again + */ + if (parts_found) + ret = ffa_get_partitions_info(func_data); + else + ret = -ENODATA; + } + } + + return ret; + } + + /* partition(s) found */ + if (!fill_data) + *((u32 *)func_data->data1) = parts_found; + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * ffa_cache_partitions_info - Queries and saves all secure partitions data + * + * This is a boot time function that invokes FFA_PARTITION_INFO_GET FF-A + * function to query from secure world all partitions information. + * + * The FFA_PARTITION_INFO_GET call is issued with nil UUID as an argument. + * All installed partitions information are returned. We cache them in the + * resident private data structure and we keep the UUID field empty + * (in FF-A 1.0 UUID is not provided by the partition descriptor) + * + * This function is called at the device probing level. + * ffa_cache_partitions_info uses ffa_query_partitions_info to get the data + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +static int ffa_cache_partitions_info(void) +{ + return ffa_query_partitions_info(NULL, NULL); +} + +/** + * ffa_msg_send_direct_req - FFA_MSG_SEND_DIRECT_{REQ,RESP} handler function + * @func_data: Pointer to the FF-A function arguments container structure. + * The passed arguments: + * @data0_size: partition ID size + * @data0: pointer to the partition ID + * @data1_size: exchanged data size + * @data1: pointer to the data buffer preallocated by + * the client (in/out) + * + * This is the runtime function that implements FFA_MSG_SEND_DIRECT_{REQ,RESP} + * FF-A functions. + * + * FFA_MSG_SEND_DIRECT_REQ is used to send the data to the secure partition. + * The response from the secure partition is handled by reading the + * FFA_MSG_SEND_DIRECT_RESP arguments. + * + * The maximum size of the data that can be exchanged is 20 bytes which is + * sizeof(struct ffa_send_direct_data) as defined by the FF-A specification 1.0 + * in the section relevant to FFA_MSG_SEND_DIRECT_{REQ,RESP} + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +static int __ffa_runtime ffa_msg_send_direct_req(struct ffa_interface_data + *func_data) +{ + u16 dst_part_id; + unsigned long a0 = 0; + unsigned long a1 = 0; + unsigned long a2 = 0; + struct ffa_send_direct_data *msg; + struct arm_smccc_res res = {0}; + + if (!ffa_priv_data.invoke_ffa_fn) + return -ENODEV; + + if (!func_data) + return -EINVAL; + + /* No partition installed */ + if (!ffa_priv_data.partitions.count || !ffa_priv_data.partitions.descs) + return -ENODEV; + + /* Undefined interface parameters */ + if (func_data->data0_size != sizeof(u16) || + !func_data->data0 || + func_data->data1_size != FFA_MSG_SEND_DIRECT_MAX_SIZE || + !func_data->data1) + return -EINVAL; + + dst_part_id = *((u16 *)func_data->data0); + msg = func_data->data1; + + a0 = FFA_MSG_SEND_DIRECT_REQ; + + a1 = PREP_SELF_ENDPOINT_ID(ffa_priv_data.id) | + PREP_PART_ENDPOINT_ID(dst_part_id); + + ffa_priv_data.invoke_ffa_fn(a0, a1, a2, + msg->a3, + msg->a4, + msg->a5, + msg->a6, + msg->a7, + &res); + + while (res.a0 == FFA_INTERRUPT) + ffa_priv_data.invoke_ffa_fn(FFA_RUN, res.a1, + 0, 0, 0, 0, 0, 0, + &res); + + switch (res.a0) { + case FFA_ERROR: + { + switch (((int)res.a2)) { + case FFA_ERR_STAT_INVALID_PARAMETERS: + /* Invalid endpoint ID or non-zero reserved register */ + return -EPERM; + case FFA_ERR_STAT_ABORTED: + /* Message target ran into unexpected error and has aborted */ + return -ECONNABORTED; + case FFA_ERR_STAT_DENIED: + /* Callee is not in a state to handle this request */ + return -EACCES; + case FFA_ERR_STAT_NOT_SUPPORTED: + /* This function is not implemented at this FF-A instance */ + return -EOPNOTSUPP; + case FFA_ERR_STAT_BUSY: + /* Message target is busy */ + return -EBUSY; + default: + /* Undefined error */ + return -ENXIO; + } + } + case FFA_SUCCESS: + + /* Message sent with no response */ + return FFA_ERR_STAT_SUCCESS; + + case FFA_MSG_SEND_DIRECT_RESP: + + /* + * Message sent with response + * extract the 32-bit wide return data + */ + msg->a3 = (u32)res.a3; + msg->a4 = (u32)res.a4; + msg->a5 = (u32)res.a5; + msg->a6 = (u32)res.a6; + msg->a7 = (u32)res.a7; + + return FFA_ERR_STAT_SUCCESS; + + default: + /* Undefined response function */ + return -ENOENT; + } +} + +/** + * invoke_ffa_drv_api - The driver dispatcher function + * @func_id: The FF-A function to be used + * @func_data: Pointer to the FF-A function arguments container + * structure. This also includes pointers to the + * returned data needed by clients. + * The dispatcher is a runtime function that selects the FF-A function handler + * based on the input FF-A function ID. + * The input arguments are passed to the handler function. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +int __ffa_runtime invoke_ffa_drv_api(u32 func_id, + struct ffa_interface_data *func_data) +{ + if (!ffa_priv_data.dev) + return -ENODEV; + + switch (func_id) { + case FFA_PARTITION_INFO_GET: + return ffa_get_partitions_info(func_data); + case FFA_RXTX_UNMAP: + return ffa_unmap_rxtx_buffers(); + case FFA_MSG_SEND_DIRECT_REQ: + return ffa_msg_send_direct_req(func_data); + default: + /* Undefined FF-A interface */ + return -EINVAL; + } +} + +/** + * ffa_init_private_data - Initialization of the private data + * @dev: the arm_ffa device + * + * This boot time function reads data from the platform data structure + * and populates the private data structure + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +static int ffa_init_private_data(struct udevice *dev) +{ + struct ffa_pdata *pdata = dev_get_plat(dev); + + ffa_priv_data.conduit = pdata->conduit; + + if (ffa_priv_data.conduit == FFA_CONDUIT_SMC) { + ffa_priv_data.invoke_ffa_fn = arm_ffa_smccc_smc; + } else { + ffa_err("Undefined FF-A conduit (%d)", ffa_priv_data.conduit); + return -EINVAL; + } + + ffa_info("Conduit is %s", + ((ffa_priv_data.conduit == FFA_CONDUIT_SMC) ? + "SMC" : "NOT SUPPORTED")); + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * ffa_bind - The driver bind function + * @dev: the arm_ffa device + * + * Called when the driver is bound with the device based on the DTB node. + * The private data structure is cleared before use. + * This makes sure that when the device added/removed multiple times the previous + * private structure is cleared. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS + */ +static int ffa_bind(struct udevice *dev) +{ + memset(&ffa_priv_data, 0, sizeof(ffa_priv_data)); + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * ffa_probe - The driver probe function + * @dev: the arm_ffa device + * + * Probing is done at boot time and triggered by the uclass device discovery. + * At probe level the following actions are done: + * - initialization of the driver private data structure + * - querying from secure world the FF-A framework version + * - querying from secure world the u-boot endpoint ID + * - querying from secure world the supported features of the specified FF-A calls + * - mapping the RX/TX buffers + * - querying from secure world all the partitions information + * + * All data queried from secure world is saved in the resident private data structure. + * + * The probe will fail if either FF-A framework is not detected or the + * FF-A requests are not behaving correctly. This ensures that the + * driver is not installed and its operations are not exported to the clients. + * However, once the driver is successfully probed and an FF-A anomaly is + * detected when clients invoke the driver operations, the driver cause + * u-boot to panic because the client would not know what to do in such conditions. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +static int ffa_probe(struct udevice *dev) +{ + int ret; + size_t buf_4k_pages = 0; + + ret = ffa_init_private_data(dev); + + if (ret != FFA_ERR_STAT_SUCCESS) + return ret; + + ret = ffa_get_version(); + + if (ret != FFA_ERR_STAT_SUCCESS) + return ret; + + ret = ffa_get_endpoint_id(); + + if (ret != FFA_ERR_STAT_SUCCESS) + return ret; + + ret = ffa_get_rxtx_map_features(); + + if (ret != FFA_ERR_STAT_SUCCESS) + return ret; + + ret = ffa_get_rxtx_buffers_pages_cnt(&buf_4k_pages); + + if (ret != FFA_ERR_STAT_SUCCESS) + return ret; + + ret = ffa_map_rxtx_buffers(buf_4k_pages); + + if (ret != FFA_ERR_STAT_SUCCESS) + return ret; + + ret = ffa_cache_partitions_info(); + + if (ret != FFA_ERR_STAT_SUCCESS) { + ffa_free_rxtx_buffers(buf_4k_pages); + return ret; + } + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * ffa_of_to_plat - Reads the device tree node + * @dev: the arm_ffa device + * + * This boot time function reads data from the device tree node and populates + * the platform data structure + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +static int ffa_of_to_plat(struct udevice *dev) +{ + struct ffa_pdata *pdata = dev_get_plat(dev); + const char *conduit = NULL; + + conduit = dev_read_string(dev, "method"); + + if (!conduit) { + ffa_err("Failure to read the conduit from device tree"); + return -EINVAL; + } + + if (strcmp("smc", conduit)) { + ffa_err("Unsupported conduit"); + return -EINVAL; + } + + pdata->conduit = FFA_CONDUIT_SMC; + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * ffa_drv_ops - The driver operations runtime structure + * @invoke_func: The driver dispatcher + */ +struct ffa_ops __ffa_runtime_data ffa_drv_ops = { + .invoke_func = invoke_ffa_drv_api +}; + +/** + * ffa_device_get_ops - driver operations getter + * + * Return: + * This runtime function returns a pointer to the driver operations structure + */ +const struct ffa_ops * __ffa_runtime ffa_device_get_ops(void) +{ + return &ffa_drv_ops; +} + +/** + * Defining the device tree compatible string + */ + +static const struct udevice_id ffa_match_id[] = { + {"arm,ffa", 0}, + {}, +}; + +/** + * Declaring the arm_ffa driver under UCLASS_FFA + */ + +U_BOOT_DRIVER(arm_ffa) = { + .name = "arm_ffa", + .of_match = ffa_match_id, + .id = UCLASS_FFA, + .of_to_plat = ffa_of_to_plat, + .probe = ffa_probe, + .bind = ffa_bind, + .plat_auto = sizeof(struct ffa_pdata), +}; diff --git a/include/arm_ffa.h b/include/arm_ffa.h new file mode 100644 index 0000000000..5a2151f8e4 --- /dev/null +++ b/include/arm_ffa.h @@ -0,0 +1,190 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2022 ARM Limited + * Abdellatif El Khlifi + */ + +#ifndef __ARM_FFA_H +#define __ARM_FFA_H + +#include +#include + +/* + * This header is public. It can be used by clients to access + * data structures and definitions they need + */ + +/* + * Macros for displaying logs + */ + +#define ffa_info(fmt, ...) pr_info("[FFA] " fmt "\n", ##__VA_ARGS__) +#define ffa_err(fmt, ...) pr_err("[FFA] " fmt "\n", ##__VA_ARGS__) + +/* + * The driver operations success error code + */ +#define FFA_ERR_STAT_SUCCESS (0) + +#if CONFIG_IS_ENABLED(EFI_LOADER) + +#include + +/* + * __ffa_runtime_data and __ffa_runtime - controls whether data/code are + * available after calling the EFI ExitBootServices service. + * Data/code tagged with these keywords are resident (available at boot time and + * at runtime) + */ + +#define __ffa_runtime_data __efi_runtime_data +#define __ffa_runtime __efi_runtime + +#else + +#define __ffa_runtime_data +#define __ffa_runtime + +#endif + +/* + * Definitions of the Arm FF-A interfaces supported by the Arm FF-A driver + */ + +#define FFA_SMC(calling_convention, func_num) \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, (calling_convention), \ + ARM_SMCCC_OWNER_STANDARD, (func_num)) + +#define FFA_SMC_32(func_num) FFA_SMC(ARM_SMCCC_SMC_32, (func_num)) + +#define FFA_VERSION FFA_SMC_32(0x63) +#define FFA_ID_GET FFA_SMC_32(0x69) +#define FFA_FEATURES FFA_SMC_32(0x64) +#define FFA_PARTITION_INFO_GET FFA_SMC_32(0x68) +#define FFA_RXTX_MAP FFA_SMC_32(0x66) +#define FFA_RXTX_UNMAP FFA_SMC_32(0x67) +#define FFA_RX_RELEASE FFA_SMC_32(0x65) +#define FFA_MSG_SEND_DIRECT_REQ FFA_SMC_32(0x6F) +#define FFA_MSG_SEND_DIRECT_RESP FFA_SMC_32(0x70) +#define FFA_RUN FFA_SMC_32(0x6D) +#define FFA_ERROR FFA_SMC_32(0x60) +#define FFA_SUCCESS FFA_SMC_32(0x61) +#define FFA_INTERRUPT FFA_SMC_32(0x62) + +/* + * struct ffa_partition_info - Partition information descriptor + * @id: Partition ID + * @exec_ctxt: Execution context count + * @properties: Partition properties + * + * Data structure containing information about partitions instantiated in the system + * This structure is filled with the data queried by FFA_PARTITION_INFO_GET + */ +struct __packed ffa_partition_info { + u16 id; + u16 exec_ctxt; +/* partition supports receipt of direct requests */ +#define FFA_PARTITION_DIRECT_RECV BIT(0) +/* partition can send direct requests. */ +#define FFA_PARTITION_DIRECT_SEND BIT(1) +/* partition can send and receive indirect messages. */ +#define FFA_PARTITION_INDIRECT_MSG BIT(2) + u32 properties; +}; + +/* + * struct ffa_send_direct_data - Data structure hosting the data + * used by FFA_MSG_SEND_DIRECT_{REQ,RESP} + * @a3-a7: Data read/written from/to w3-w7 registers + * + * Data structure containing the data to be sent by FFA_MSG_SEND_DIRECT_REQ + * or read from FFA_MSG_SEND_DIRECT_RESP + */ +struct __packed ffa_send_direct_data { + u32 a3; /* w3 */ + u32 a4; /* w4 */ + u32 a5; /* w5 */ + u32 a6; /* w6 */ + u32 a7; /* w7 */ +}; + +#define FFA_MSG_SEND_DIRECT_MAX_SIZE (sizeof(struct ffa_send_direct_data)) + +/* UUID data size */ +#define UUID_SIZE (16) + +/* + * union ffa_partition_uuid - Data union hosting the UUID + * transmitted by FFA_PARTITION_INFO_GET + * @words: data structure giving 32-bit words access to the UUID data + * @bytes: data structure giving byte access to the UUID data + * + * The structure holds little-endian UUID data. + */ +union ffa_partition_uuid { + struct __packed words { + u32 a1; /* w1 */ + u32 a2; /* w2 */ + u32 a3; /* w3 */ + u32 a4; /* w4 */ + } words; + u8 bytes[UUID_SIZE]; +}; + +/** + * struct ffa_interface_data - generic FF-A interface data structure used to exchange + * data between user layers and the driver + * @data0_size: size of the first argument + * @data0: pointer to the first argument + * @data1_size>: size of the second argument + * @data1: pointer to the second argument + * + * Using this structure user layers can pass various types of data with different sizes. + * The driver internal functions can detect the nature of this data, verfy compliance + * then execute the request when appropriate. + */ +struct ffa_interface_data { + u32 data0_size; /* size of the first argument */ + void *data0; /* pointer to the first argument */ + u32 data1_size; /* size of the second argument */ + void *data1; /* pointer to the second argument */ +}; + +/** + * struct ffa_ops - The driver operations structure + * @invoke_func: function pointer to the invoke function + * + * The data structure providing all the operations supported by the driver. + * This structure is resident. + */ +struct ffa_ops { + /* the driver dispatcher */ + int (*invoke_func)(u32 func_id, struct ffa_interface_data *func_data); +}; + +/** + * The device driver and the Uclass driver public functions + */ + +/** + * ffa_get_invoke_func - performs a call to the FF-A driver dispatcher + */ +int __ffa_runtime ffa_get_invoke_func(u32 func_id, + struct ffa_interface_data *func_data); + +/** + * ffa_device_get_ops - driver operations getter + */ +const struct ffa_ops * __ffa_runtime ffa_device_get_ops(void); + +/** + * ffa_get_device - probes the arm_ffa device + */ +int ffa_get_device(void); + +/** + * ffa_init_device - probes the arm_ffa device + */ +int ffa_init_device(void); +#endif diff --git a/include/arm_ffa_helper.h b/include/arm_ffa_helper.h new file mode 100644 index 0000000000..76f7a9fd29 --- /dev/null +++ b/include/arm_ffa_helper.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2022 ARM Limited + * Abdellatif El Khlifi + */ + +#ifndef __ARM_FFA_HELPER_H +#define __ARM_FFA_HELPER_H + +#include + +/* + * This header is public. Including this header provides all data structures + * and definitions needed by clients to use the FF-A transport driver + * + * It also provides helper functions allowing to pass data and invoke FF-A functions + */ + +/** + * ffa_helper_get_partitions_info - Wrapper function for FFA_PARTITION_INFO_GET + */ +int ffa_helper_get_partitions_info(struct ffa_interface_data *func_data); + +/** + * ffa_helper_unmap_rxtx_buffers - Wrapper function for FFA_RXTX_UNMAP + */ +int ffa_helper_unmap_rxtx_buffers(void); + +/** + * ffa_helper_msg_send_direct_req - Wrapper function for + * FFA_MSG_SEND_DIRECT_{REQ,RESP} + */ +int __ffa_runtime ffa_helper_msg_send_direct_req(struct ffa_interface_data + *func_data); + +/** + * ffa_helper_init_device - Wrapper function for probing the arm_ffa device + */ +int ffa_helper_init_device(void); + +/** + * ffa_uuid_str_to_bin - Converts a big endian UUID string to a little endian buffer + */ +int ffa_uuid_str_to_bin(const char *uuid_str, unsigned char *uuid_bin); +#endif diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 0e26e1d138..a1181b8f48 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -52,6 +52,7 @@ enum uclass_id { UCLASS_EFI_MEDIA, /* Devices provided by UEFI firmware */ UCLASS_ETH, /* Ethernet device */ UCLASS_ETH_PHY, /* Ethernet PHY device */ + UCLASS_FFA, /* Arm Firmware Framework for Armv8-A */ UCLASS_FIRMWARE, /* Firmware */ UCLASS_FS_FIRMWARE_LOADER, /* Generic loader */ UCLASS_GPIO, /* Bank of general-purpose I/O pins */ diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h index 7f2be23394..d58c7c104b 100644 --- a/include/linux/arm-smccc.h +++ b/include/linux/arm-smccc.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2015, Linaro Limited + * (C) Copyright 2022 ARM Limited + * Abdellatif El Khlifi */ #ifndef __LINUX_ARM_SMCCC_H #define __LINUX_ARM_SMCCC_H @@ -57,13 +59,17 @@ #include /** * struct arm_smccc_res - Result from SMC/HVC call - * @a0-a3 result values from registers 0 to 3 + * @a0-a7 result values from registers 0 to 7 */ struct arm_smccc_res { unsigned long a0; unsigned long a1; unsigned long a2; unsigned long a3; + unsigned long a4; + unsigned long a5; + unsigned long a6; + unsigned long a7; }; /** @@ -113,6 +119,26 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a5, unsigned long a6, unsigned long a7, struct arm_smccc_res *res, struct arm_smccc_quirk *quirk); +#if (IS_ENABLED(CONFIG_ARM_FFA_TRANSPORT)) +/** + * __arm_ffa_smccc_smc() - make SMC calls used for FF-A transport + * @a0-a7: arguments passed in 64-bit registers x0 to x7 + * @res: result values from 64-bit registers x0 to x7 + * + * This function is used to make SMC calls following SMC32 Calling Convention. + * The content of the supplied parameters is copied to registers x0 to x7 prior + * to the SMC instruction. The SMC call return data is 32-bit data read from + * registers x0 tp x7. + */ +asmlinkage void __arm_ffa_smccc_smc(unsigned long a0, unsigned long a1, + unsigned long a2, unsigned long a3, unsigned long a4, + unsigned long a5, unsigned long a6, unsigned long a7, + struct arm_smccc_res *res); + +#define arm_ffa_smccc_smc __arm_ffa_smccc_smc + +#endif + #define arm_smccc_smc(...) __arm_smccc_smc(__VA_ARGS__, NULL) #define arm_smccc_smc_quirk(...) __arm_smccc_smc(__VA_ARGS__) diff --git a/lib/Kconfig b/lib/Kconfig index 3c6fa99b1a..473821b882 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -810,6 +810,7 @@ config SMBIOS_PARSER source lib/efi/Kconfig source lib/efi_loader/Kconfig source lib/optee/Kconfig +source lib/arm-ffa/Kconfig config TEST_FDTDEC bool "enable fdtdec test" diff --git a/lib/Makefile b/lib/Makefile index 11b03d1cbe..8e6fad6130 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_EFI) += efi/ obj-$(CONFIG_EFI_LOADER) += efi_driver/ obj-$(CONFIG_EFI_LOADER) += efi_loader/ obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += efi_selftest/ +obj-$(CONFIG_ARM_FFA_TRANSPORT_HELPERS) += arm-ffa/ obj-$(CONFIG_LZMA) += lzma/ obj-$(CONFIG_BZIP2) += bzip2/ obj-$(CONFIG_TIZEN) += tizen/ diff --git a/lib/arm-ffa/Kconfig b/lib/arm-ffa/Kconfig new file mode 100644 index 0000000000..79acbc5a8f --- /dev/null +++ b/lib/arm-ffa/Kconfig @@ -0,0 +1,6 @@ +config ARM_FFA_TRANSPORT_HELPERS + bool "Enable interface helpers for Arm Firmware Framework for Armv8-A" + depends on ARM_FFA_TRANSPORT + help + User layers call FF-A interfaces using helper functions which + pass the data and the FF-A function ID to the low level driver diff --git a/lib/arm-ffa/Makefile b/lib/arm-ffa/Makefile new file mode 100644 index 0000000000..cba625fde4 --- /dev/null +++ b/lib/arm-ffa/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2022 Abdellatif El Khlifi +# + +# This file only gets included when CONFIG_ARM_FFA_TRANSPORT_HELPERS is set + +obj-y += arm_ffa_helper.o diff --git a/lib/arm-ffa/arm_ffa_helper.c b/lib/arm-ffa/arm_ffa_helper.c new file mode 100644 index 0000000000..67a3a4e9ab --- /dev/null +++ b/lib/arm-ffa/arm_ffa_helper.c @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2022 ARM Limited + * Abdellatif El Khlifi + */ + +#include +#include +#include + +/** + * ffa_helper_get_partitions_info - Wrapper function for FFA_PARTITION_INFO_GET + * + * @func_data: Pointer to the FF-A function arguments container + * structure. + * The passed arguments: + * Mode 1: When getting from the driver the number of + * secure partitions: + * @data0_size: UUID size + * @data0: pointer to the UUID (little endian) + * @data1_size: size of the number of partitions + * variable + * @data1: pointer to the number of partitions + * variable. The variable will be set + * by the driver + * Mode 2: When requesting the driver to return the + * partitions information: + * @data0_size: UUID size + * @data0: pointer to the UUID (little endian) + * @data1_size: size of the SPs information buffer + * @data1: pointer to SPs information buffer + * (allocated by the client). + * The buffer will be filled by the driver + * + * This is the boot time function used by clients who wants to get from secure + * world the partition(s) information. + * + * A client of the FF-A driver should know the UUID of the service it wants to + * access. It should use the UUID to request the FF-A driver to provide the + * partition(s) information of the service. The client should use + * ffa_helper_get_partitions_info to pass the UUID information to the driver + * which uses PARTITION_INFO_GET to obtain the partition(s) information. + * + * ffa_helper_get_partitions_info should be called twice. First call is to get + * from the driver the number of secure partitions (SPs) associated to a + * particular UUID. Then, the caller (client) allocates the buffer to host the + * SPs data and issues a 2nd call. Then, the driver fills the SPs data in the + * pre-allocated buffer. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +int ffa_helper_get_partitions_info(struct ffa_interface_data *func_data) +{ + return ffa_get_invoke_func(FFA_PARTITION_INFO_GET, func_data); +} + +/** + * ffa_helper_unmap_rxtx_buffers - Wrapper function for FFA_RXTX_UNMAP + * + * This is the boot time function that allows clients to unmap the RX/TX + * buffers + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +int ffa_helper_unmap_rxtx_buffers(void) +{ + return ffa_get_invoke_func(FFA_RXTX_UNMAP, NULL); +} + +/** + * ffa_helper_msg_send_direct_req - Wrapper function for + * FFA_MSG_SEND_DIRECT_{REQ,RESP} + * @func_data: Pointer to the FF-A function arguments container structure. + * The passed arguments: + * @data0_size: partition ID size + * @data0: pointer to the partition ID + * @data1_size: exchanged data size + * @data1: pointer to the data buffer preallocated by the client (in/out) + * + * This is the runtime function that allows clients to send data to the secure + * world partitions. The arm_ffa driver uses FFA_MSG_SEND_DIRECT_REQ to send the + * data to the secure partition. The response from the secure partition is + * handled internally by the driver using FFA_MSG_SEND_DIRECT_RESP and returned + * to ffa_helper_msg_send_direct_req through @func_data + * + * The maximum size of the data that can be exchanged is 20 bytes which is + * sizeof(struct ffa_send_direct_data) as defined by the FF-A specification 1.0 + * in the section relevant to FFA_MSG_SEND_DIRECT_{REQ,RESP} + * + * The client should pre-allocate a buffer pointed by @data1 which the size + * is sizeof(struct ffa_send_direct_data) + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +int __ffa_runtime ffa_helper_msg_send_direct_req(struct ffa_interface_data + *func_data) +{ + return ffa_get_invoke_func(FFA_MSG_SEND_DIRECT_REQ, func_data); +} + +/** + * ffa_helper_init_device - Wrapper function for probing the arm_ffa device + * + * This boot time function should be called to probe the arm_ffa device so + * it becomes ready for use. + * To achieve that, this function is called automatically at initcalls + * level (after u-boot relocation). + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +int ffa_helper_init_device(void) +{ + return ffa_init_device(); +} + +/** + * ffa_uuid_str_to_bin - Converts a big endian UUID string to a little endian buffer + * @uuid_str: UUID string in big endian format (36 bytes wide + '/0') + * @uuid_bin: preallocated 16 bytes UUID buffer in little endian format + * + * UUID binary format used by the FF-A framework (16 bytes): + * + * [LSB] 4B-2B-2B-2B-6B (little endian data fields) + * + * UUID string is 36 length of characters (36 bytes): + * + * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + * be be be be be + * + * where x is a hexadecimal character. Fields are separated by '-'s. + * When converting to a binary UUID, these endianness rules apply: + * be: means the field in the string is considered a big endian hex number + * and should be converted to little endian binary format + * + * Return: + * + * uuid_bin filled with little endian UUID data + * On success 0 is returned. Otherwise, failure code. + */ +int ffa_uuid_str_to_bin(const char *uuid_str, unsigned char *uuid_bin) +{ + u16 tmp16 = 0; + u32 tmp32 = 0; + u64 tmp64 = 0; + + if (!uuid_str_valid(uuid_str) || !uuid_bin) + return -EINVAL; + + /* + * reverse bytes from big to little endian + */ + tmp32 = simple_strtoul(uuid_str, NULL, 16); + memcpy(uuid_bin, &tmp32, 4); + + /* + * reverse bytes from big to little endian + */ + tmp16 = simple_strtoul(uuid_str + 9, NULL, 16); + memcpy(uuid_bin + 4, &tmp16, 2); + + /* + * reverse bytes from big to little endian + */ + tmp16 = simple_strtoul(uuid_str + 14, NULL, 16); + memcpy(uuid_bin + 6, &tmp16, 2); + + /* + * reverse bytes from big to little endian + */ + tmp16 = simple_strtoul(uuid_str + 19, NULL, 16); + memcpy(uuid_bin + 8, &tmp16, 2); + + /* + * reverse bytes from big to little endian + */ + tmp64 = simple_strtoull(uuid_str + 24, NULL, 16); + memcpy(uuid_bin + 10, (char *)&tmp64, 6); + + return 0; +} diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 5bcb8253ed..cffa2c69d6 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -23,6 +23,10 @@ #include #include +#if defined(CONFIG_ARM_FFA_TRANSPORT) +#include +#endif + DECLARE_GLOBAL_DATA_PTR; /* Task priority level */ @@ -2114,6 +2118,10 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, struct efi_event *evt, *next_event; efi_status_t ret = EFI_SUCCESS; +#if defined(CONFIG_ARM_FFA_TRANSPORT) + int ffa_ret; +#endif + EFI_ENTRY("%p, %zx", image_handle, map_key); /* Check that the caller has read the current memory map */ @@ -2174,6 +2182,15 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL); } +#if defined(CONFIG_ARM_FFA_TRANSPORT) + /* unmap FF-A RX/TX buffers */ + ffa_ret = ffa_helper_unmap_rxtx_buffers(); + if (ffa_ret) + debug("[efi_boottime][ERROR]: can not unmap FF-A RX/TX buffers\n"); + else + debug("[efi_boottime][INFO]: FF-A RX/TX buffers unmapped\n"); +#endif + /* Patch out unsupported runtime function */ efi_runtime_detach(); From patchwork Tue Mar 29 15:16:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abdellatif El Khlifi X-Patchwork-Id: 1610729 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KSZQz1wpdz9sCq for ; Wed, 30 Mar 2022 03:15:07 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 6BDF984016; Tue, 29 Mar 2022 18:14:49 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=fail (p=none dis=none) header.from=arm.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by phobos.denx.de (Postfix, from userid 109) id 48C3384013; Tue, 29 Mar 2022 17:17:20 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.2 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by phobos.denx.de (Postfix) with ESMTP id B75B684007 for ; Tue, 29 Mar 2022 17:17:15 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=abdellatif.elkhlifi@arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 0B99A14BF; Tue, 29 Mar 2022 08:17:15 -0700 (PDT) Received: from e121910.arm.com (unknown [10.57.40.79]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id C9E3F3F73B; Tue, 29 Mar 2022 08:17:13 -0700 (PDT) From: abdellatif.elkhlifi@arm.com To: u-boot@lists.denx.de Cc: nd@arm.com, trini@konsulko.com, Abdellatif El Khlifi Subject: [PATCH 2/6] arm_ffa: introduce armffa command Date: Tue, 29 Mar 2022 16:16:55 +0100 Message-Id: <20220329151659.16894-3-abdellatif.elkhlifi@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220329151659.16894-1-abdellatif.elkhlifi@arm.com> References: <20220329151659.16894-1-abdellatif.elkhlifi@arm.com> X-Mailman-Approved-At: Tue, 29 Mar 2022 18:14:45 +0200 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.5 at phobos.denx.de X-Virus-Status: Clean From: Abdellatif El Khlifi Provide armffa command showcasing the use of the FF-A driver The armffa command allows to query secure partitions data from the secure world and exchanging messages with the partitions. Signed-off-by: Abdellatif El Khlifi Cc: Tom Rini --- MAINTAINERS | 1 + cmd/Kconfig | 10 ++ cmd/Makefile | 2 + cmd/armffa.c | 266 ++++++++++++++++++++++++++++++++++++++++ drivers/arm-ffa/Kconfig | 1 + 5 files changed, 280 insertions(+) create mode 100644 cmd/armffa.c diff --git a/MAINTAINERS b/MAINTAINERS index c5b608eb60..50ccd6a7ba 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -235,6 +235,7 @@ F: include/configs/turris_*.h ARM FF-A M: Abdellatif El Khlifi S: Maintained +F: cmd/armffa.c F: drivers/arm-ffa/ F: include/arm_ffa.h F: include/arm_ffa_helper.h diff --git a/cmd/Kconfig b/cmd/Kconfig index 79219bcb74..de5bea1404 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -813,6 +813,16 @@ endmenu menu "Device access commands" +config CMD_ARMFFA + bool "Arm FF-A test command" + depends on ARM_FFA_TRANSPORT + help + Provides a test command for the Arm FF-A driver + supported options: + - Listing the partition(s) info + - Sending a data pattern to the specified partition + - Displaying the arm_ffa device info + config CMD_ARMFLASH #depends on FLASH_CFI_DRIVER bool "armflash" diff --git a/cmd/Makefile b/cmd/Makefile index ede634d731..2905ce63cf 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -12,6 +12,8 @@ obj-y += panic.o obj-y += version.o # command + +obj-$(CONFIG_CMD_ARMFFA) += armffa.o obj-$(CONFIG_CMD_ACPI) += acpi.o obj-$(CONFIG_CMD_ADDRMAP) += addrmap.o obj-$(CONFIG_CMD_AES) += aes.o diff --git a/cmd/armffa.c b/cmd/armffa.c new file mode 100644 index 0000000000..fcfc3a06bd --- /dev/null +++ b/cmd/armffa.c @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2022 ARM Limited + * Abdellatif El Khlifi + */ + +#include +#include +#include +#include +#include +#include +#include + +/** + * do_ffa_get_singular_partition_info - implementation of the getpart subcommand + * @cmdtp: Command Table + * @flag: flags + * @argc: number of arguments + * @argv: arguments + * + * This function queries the secure partition information which the UUID is provided + * as an argument. The function uses the arm_ffa driver helper function + * to retrieve the data. + * The input UUID string is expected to be in big endian format. + * + * Return: + * + * CMD_RET_SUCCESS: on success, otherwise failure + */ +static int do_ffa_get_singular_partition_info(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct ffa_interface_data func_data = {0}; + u32 count = 0; + int ret; + union ffa_partition_uuid service_uuid = {0}; + struct ffa_partition_info *parts_info; + u32 info_idx; + + if (argc != 1) + return -EINVAL; + + if (ffa_uuid_str_to_bin(argv[0], (unsigned char *)&service_uuid)) { + ffa_err("Invalid UUID"); + return -EINVAL; + } + + /* + * get from the driver the count of the SPs matching the UUID + */ + func_data.data0_size = sizeof(service_uuid); + func_data.data0 = &service_uuid; + func_data.data1_size = sizeof(count); + func_data.data1 = &count; + + ret = ffa_helper_get_partitions_info(&func_data); + if (ret != FFA_ERR_STAT_SUCCESS) { + ffa_err("Failure in querying partitions count (error code: %d)", ret); + return ret; + } + + if (!count) { + ffa_info("No secure partition found"); + return ret; + } + + /* + * pre-allocate a buffer to be filled by the driver + * with ffa_partition_info structs + */ + + parts_info = calloc(count, sizeof(struct ffa_partition_info)); + if (!parts_info) + return -EINVAL; + + ffa_info("Pre-allocating %d partition(s) info structures", count); + + func_data.data1_size = count * sizeof(struct ffa_partition_info); + func_data.data1 = parts_info; + + /* + * ask the driver to fill the buffer with the SPs info + */ + ret = ffa_helper_get_partitions_info(&func_data); + if (ret != FFA_ERR_STAT_SUCCESS) { + ffa_err("Failure in querying partition(s) info (error code: %d)", ret); + free(parts_info); + return ret; + } + + /* + * SPs found , show the partition information + */ + for (info_idx = 0; info_idx < count ; info_idx++) { + ffa_info("Partition: id = 0x%x , exec_ctxt 0x%x , properties 0x%x", + parts_info[info_idx].id, + parts_info[info_idx].exec_ctxt, + parts_info[info_idx].properties); + } + + free(parts_info); + + return 0; +} + +/** + * do_ffa_msg_send_direct_req - implementation of the ping subcommand + * @cmdtp: Command Table + * @flag: flags + * @argc: number of arguments + * @argv: arguments + * + * This function sends data to the secure partition which the ID is provided + * as an argument. The function uses the arm_ffa driver helper function + * to send data. + * + * Return: + * + * CMD_RET_SUCCESS: on success, otherwise failure + */ +int do_ffa_msg_send_direct_req(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct ffa_interface_data func_data = {0}; + struct ffa_send_direct_data msg = {0}; + u32 pattern = 0xaabbccd0; + u16 part_id; + int ret; + + if (argc != 1) + return -EINVAL; + + errno = 0; + part_id = strtoul(argv[0], NULL, 16); + + if (errno) { + ffa_err("Invalid partition ID"); + return -EINVAL; + } + + /* + * telling the driver which partition to use + */ + func_data.data0_size = sizeof(part_id); + func_data.data0 = &part_id; + + /* + * filling the message data + */ + msg.a3 = ++pattern; + msg.a4 = ++pattern; + msg.a5 = ++pattern; + msg.a6 = ++pattern; + msg.a7 = ++pattern; + func_data.data1_size = sizeof(msg); + func_data.data1 = &msg; + + ret = ffa_helper_msg_send_direct_req(&func_data); + if (ret == FFA_ERR_STAT_SUCCESS) { + u8 cnt; + + ffa_info("SP response:\n[LSB]"); + for (cnt = 0; + cnt < sizeof(struct ffa_send_direct_data) / sizeof(u32); + cnt++) + ffa_info("0x%x", ((u32 *)&msg)[cnt]); + } else { + ffa_err("Sending direct request error (%d)", ret); + } + + return ret; +} + +/** + *do_ffa_dev_list - implementation of the devlist subcommand + * @cmdtp: [in] Command Table + * @flag: flags + * @argc: number of arguments + * @argv: arguments + * + * This function queries the devices belonging to the UCLASS_FFA + * class. Currently, one device is expected to show up: the arm_ffa device + * + * Return: + * + * CMD_RET_SUCCESS: on success, otherwise failure + */ +int do_ffa_dev_list(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + struct udevice *dev = NULL; + int i, ret; + + ffa_info("arm_ffa uclass entries:"); + + for (i = 0, ret = uclass_first_device(UCLASS_FFA, &dev); + dev; + ret = uclass_next_device(&dev), i++) { + if (ret) + break; + + ffa_info("entry %d - instance %08x, ops %08x, plat %08x", + i, + (u32)map_to_sysmem(dev), + (u32)map_to_sysmem(dev->driver->ops), + (u32)map_to_sysmem(dev_get_plat(dev))); + } + + return cmd_process_error(cmdtp, ret); +} + +static struct cmd_tbl armffa_commands[] = { + U_BOOT_CMD_MKENT(getpart, 1, 1, do_ffa_get_singular_partition_info, "", ""), + U_BOOT_CMD_MKENT(ping, 1, 1, do_ffa_msg_send_direct_req, "", ""), + U_BOOT_CMD_MKENT(devlist, 0, 1, do_ffa_dev_list, "", ""), +}; + +/** + * do_armffa - the armffa command main function + * @cmdtp: Command Table + * @flag: flags + * @argc: number of arguments + * @argv: arguments + * + * This function identifies which armffa subcommand to run. + * Then, it makes sure the arm_ffa device is probed and + * ready for use. + * Then, it runs the subcommand. + * + * Return: + * + * CMD_RET_SUCCESS: on success, otherwise failure + */ +static int do_armffa(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + struct cmd_tbl *armffa_cmd; + int ret; + + if (argc < 2) + return CMD_RET_USAGE; + + armffa_cmd = find_cmd_tbl(argv[1], armffa_commands, ARRAY_SIZE(armffa_commands)); + + argc -= 2; + argv += 2; + + if (!armffa_cmd || argc > armffa_cmd->maxargs) + return CMD_RET_USAGE; + + ret = ffa_helper_init_device(); + if (ret != FFA_ERR_STAT_SUCCESS) + return cmd_process_error(cmdtp, ret); + + ret = armffa_cmd->cmd(armffa_cmd, flag, argc, argv); + + return cmd_process_error(armffa_cmd, ret); +} + +U_BOOT_CMD(armffa, 4, 1, do_armffa, + "Arm FF-A operations test command", + "getpart \n" + " - lists the partition(s) info\n" + "ping \n" + " - sends a data pattern to the specified partition\n" + "devlist\n" + " - displays the arm_ffa device info\n"); diff --git a/drivers/arm-ffa/Kconfig b/drivers/arm-ffa/Kconfig index e503dfaebf..7b7cfe26b1 100644 --- a/drivers/arm-ffa/Kconfig +++ b/drivers/arm-ffa/Kconfig @@ -4,6 +4,7 @@ config ARM_FFA_TRANSPORT bool "Enable Arm Firmware Framework for Armv8-A driver" depends on DM && ARM64 select ARM_SMCCC if ARM64 + select CMD_ARMFFA select LIB_UUID select ARM_FFA_TRANSPORT_HELPERS help From patchwork Tue Mar 29 15:16:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abdellatif El Khlifi X-Patchwork-Id: 1610734 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KSZS32MX8z9sCq for ; Wed, 30 Mar 2022 03:16:03 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 1899B84043; Tue, 29 Mar 2022 18:15:08 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=fail (p=none dis=none) header.from=arm.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by phobos.denx.de (Postfix, from userid 109) id 5C56E83FCF; Tue, 29 Mar 2022 17:17:30 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.2 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by phobos.denx.de (Postfix) with ESMTP id 3CEA584012 for ; Tue, 29 Mar 2022 17:17:17 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=abdellatif.elkhlifi@arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id A814C23A; Tue, 29 Mar 2022 08:17:16 -0700 (PDT) Received: from e121910.arm.com (unknown [10.57.40.79]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 6DE583F73B; Tue, 29 Mar 2022 08:17:15 -0700 (PDT) From: abdellatif.elkhlifi@arm.com To: u-boot@lists.denx.de Cc: nd@arm.com, trini@konsulko.com, Abdellatif El Khlifi Subject: [PATCH 3/6] arm_ffa: introduce the FF-A Sandbox driver Date: Tue, 29 Mar 2022 16:16:56 +0100 Message-Id: <20220329151659.16894-4-abdellatif.elkhlifi@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220329151659.16894-1-abdellatif.elkhlifi@arm.com> References: <20220329151659.16894-1-abdellatif.elkhlifi@arm.com> X-Mailman-Approved-At: Tue, 29 Mar 2022 18:14:45 +0200 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.5 at phobos.denx.de X-Virus-Status: Clean From: Abdellatif El Khlifi Provide a Sandbox driver to emulate the FF-A ABIs The emulated ABIs are those supported by the FF-A core driver and according to FF-A specification v1.0. The Sandbox driver provides operations allowing the test application to read the status of all the inspected ABIs and perform functional tests based on that. Signed-off-by: Abdellatif El Khlifi Cc: Tom Rini --- MAINTAINERS | 2 + arch/sandbox/dts/sandbox.dtsi | 10 + arch/sandbox/dts/test.dts | 10 + common/board_r.c | 2 +- configs/sandbox64_defconfig | 2 + configs/sandbox_defconfig | 2 + doc/arch/sandbox.rst | 1 + drivers/arm-ffa/Kconfig | 8 +- drivers/arm-ffa/Makefile | 1 + drivers/arm-ffa/arm-ffa-uclass.c | 51 +- drivers/arm-ffa/core.c | 94 +++- drivers/arm-ffa/sandbox.c | 735 ++++++++++++++++++++++++++ drivers/arm-ffa/sandbox_arm_ffa_prv.h | 128 +++++ include/arm_ffa.h | 9 +- include/sandbox_arm_ffa.h | 31 ++ include/sandbox_arm_ffa_helper.h | 26 + lib/arm-ffa/Makefile | 1 + lib/arm-ffa/arm_ffa_helper.c | 6 +- lib/arm-ffa/sandbox_arm_ffa_helper.c | 23 + lib/efi_loader/efi_boottime.c | 4 +- 20 files changed, 1102 insertions(+), 44 deletions(-) create mode 100644 drivers/arm-ffa/sandbox.c create mode 100644 drivers/arm-ffa/sandbox_arm_ffa_prv.h create mode 100644 include/sandbox_arm_ffa.h create mode 100644 include/sandbox_arm_ffa_helper.h create mode 100644 lib/arm-ffa/sandbox_arm_ffa_helper.c diff --git a/MAINTAINERS b/MAINTAINERS index 50ccd6a7ba..84524d7caf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -239,6 +239,8 @@ F: cmd/armffa.c F: drivers/arm-ffa/ F: include/arm_ffa.h F: include/arm_ffa_helper.h +F: include/sandbox_arm_ffa.h +F: include/sandbox_arm_ffa_helper.h F: lib/arm-ffa/ ARM FREESCALE IMX diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi index 66b813faad..523ffcc27d 100644 --- a/arch/sandbox/dts/sandbox.dtsi +++ b/arch/sandbox/dts/sandbox.dtsi @@ -416,6 +416,16 @@ sandbox_tee { compatible = "sandbox,tee"; }; + + arm_ffa { + compatible = "arm,ffa"; + method = "smc"; + }; + + sandbox_arm_ffa { + compatible = "sandbox,ffa"; + method = "smc"; + }; }; &cros_ec { diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 3d206fdb3c..2c638af042 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -1598,6 +1598,16 @@ compatible = "sandbox,regmap_test"; }; }; + + arm_ffa { + compatible = "arm,ffa"; + method = "smc"; + }; + + sandbox_arm_ffa { + compatible = "sandbox,ffa"; + method = "smc"; + }; }; #include "sandbox_pmic.dtsi" diff --git a/common/board_r.c b/common/board_r.c index 7866ec3ad5..3b82f74bb0 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -775,7 +775,7 @@ static init_fnc_t init_sequence_r[] = { INIT_FUNC_WATCHDOG_RESET initr_net, #endif -#ifdef CONFIG_ARM_FFA_TRANSPORT +#if defined(CONFIG_ARM_FFA_TRANSPORT) && !defined(CONFIG_SANDBOX_FFA) ffa_helper_init_device, #endif #ifdef CONFIG_POST diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig index 40d1422a37..301c6f320f 100644 --- a/configs/sandbox64_defconfig +++ b/configs/sandbox64_defconfig @@ -252,3 +252,5 @@ CONFIG_TEST_FDTDEC=y CONFIG_UNIT_TEST=y CONFIG_UT_TIME=y CONFIG_UT_DM=y +CONFIG_ARM_FFA_TRANSPORT=y +CONFIG_SANDBOX_FFA=y \ No newline at end of file diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 0f43101ab5..a2f273056f 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -324,3 +324,5 @@ CONFIG_TEST_FDTDEC=y CONFIG_UNIT_TEST=y CONFIG_UT_TIME=y CONFIG_UT_DM=y +CONFIG_ARM_FFA_TRANSPORT=y +CONFIG_SANDBOX_FFA=y \ No newline at end of file diff --git a/doc/arch/sandbox.rst b/doc/arch/sandbox.rst index f8804e1f41..7cb5ea307c 100644 --- a/doc/arch/sandbox.rst +++ b/doc/arch/sandbox.rst @@ -203,6 +203,7 @@ Supported Drivers U-Boot sandbox supports these emulations: +- Arm FF-A - Block devices - Chrome OS EC - GPIO diff --git a/drivers/arm-ffa/Kconfig b/drivers/arm-ffa/Kconfig index 7b7cfe26b1..61103daa42 100644 --- a/drivers/arm-ffa/Kconfig +++ b/drivers/arm-ffa/Kconfig @@ -2,7 +2,7 @@ config ARM_FFA_TRANSPORT bool "Enable Arm Firmware Framework for Armv8-A driver" - depends on DM && ARM64 + depends on DM && (ARM64 || SANDBOX) select ARM_SMCCC if ARM64 select CMD_ARMFFA select LIB_UUID @@ -24,3 +24,9 @@ config ARM_FFA_TRANSPORT entity to communicate with. FF-A communication is handled by one device and one instance. This device takes care of all the interactions between Normal world and Secure World. + +config SANDBOX_FFA + bool "FF-A Sandbox driver" + depends on ARM_FFA_TRANSPORT && SANDBOX + help + This emulates the FF-A handling under Sandbox and allows to test the FF-A driver diff --git a/drivers/arm-ffa/Makefile b/drivers/arm-ffa/Makefile index 7bc9a336a9..df1cfe6ef0 100644 --- a/drivers/arm-ffa/Makefile +++ b/drivers/arm-ffa/Makefile @@ -4,3 +4,4 @@ # obj-y += arm-ffa-uclass.o core.o +obj-$(CONFIG_SANDBOX_FFA) += sandbox.o diff --git a/drivers/arm-ffa/arm-ffa-uclass.c b/drivers/arm-ffa/arm-ffa-uclass.c index 0bf661d397..a5945afb9d 100644 --- a/drivers/arm-ffa/arm-ffa-uclass.c +++ b/drivers/arm-ffa/arm-ffa-uclass.c @@ -11,6 +11,10 @@ #include #include +#if CONFIG_IS_ENABLED(SANDBOX_FFA) +#include +#endif + DECLARE_GLOBAL_DATA_PTR; UCLASS_DRIVER(ffa) = { @@ -42,18 +46,42 @@ int __ffa_runtime ffa_get_invoke_func(u32 func_id, struct ffa_interface_data *fu return ffa_device_get_ops()->invoke_func(func_id, func_data); } +#if CONFIG_IS_ENABLED(SANDBOX_FFA) + /** - * ffa_init_device - probes the arm_ffa device + * sandbox_ffa_get_invoke_func - performs a call to the Sandbox FF-A driver dispatcher + * @func_id: The FF-A function to be queried + * @func_data: Pointer to the query arguments + * container structure. + * + * This function passes the FF-A function ID to be queried during sandbox test cases + * and its arguments to the Sandbox FF-A driver dispatcher. + * This function is called by the Sandbox FF-A helper function. + * + * Return: * - * This boot time function makes sure the arm_ffa device is probed + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +int sandbox_ffa_get_invoke_func(u32 func_id, struct ffa_interface_data *func_data) +{ + if (!sandbox_ffa_device_get_ops()->invoke_func) + return -EINVAL; + + return sandbox_ffa_device_get_ops()->invoke_func(func_id, func_data); +} +#endif + +/** + * ffa_init_device - probes the arm_ffa and sandbox_arm_ffa devices + * + * This boot time function makes sure the arm_ffa and sandbox_arm_ffa devices are probed * and ready for use. * This function is called automatically at initcalls * level (after u-boot relocation). * - * Arm FF-A transport is implemented through a single u-boot - * device (arm_ffa). So, there is only one device belonging to UCLASS_FFA. - * All FF-A clients should use the arm_ffa device to use the FF-A - * transport. + * Arm FF-A transport is implemented through arm_ffa u-boot device managing the FF-A + * communication. In Sandbox mode sandbox_arm_ffa is used to test arm_ffa driver. + * All FF-A clients should use the arm_ffa device to use the FF-A transport. * * Return: * @@ -61,5 +89,14 @@ int __ffa_runtime ffa_get_invoke_func(u32 func_id, struct ffa_interface_data *fu */ int ffa_init_device(void) { - return ffa_get_device(); + int ret; + + ret = ffa_get_device(); + +#if CONFIG_IS_ENABLED(SANDBOX_FFA) + if (ret == FFA_ERR_STAT_SUCCESS) + ret = sandbox_ffa_get_device(); +#endif + + return ret; } diff --git a/drivers/arm-ffa/core.c b/drivers/arm-ffa/core.c index 9d0dab1d36..a4d9c08482 100644 --- a/drivers/arm-ffa/core.c +++ b/drivers/arm-ffa/core.c @@ -5,6 +5,11 @@ */ #include "arm_ffa_prv.h" + +#if CONFIG_IS_ENABLED(SANDBOX_FFA) +#include "sandbox_arm_ffa_prv.h" +#endif + #include #include #include @@ -82,8 +87,10 @@ static int ffa_get_version(void) FFA_DECLARE_ARGS; - if (!ffa_priv_data.invoke_ffa_fn) - panic("[FFA] no private data found\n"); + if (!ffa_priv_data.invoke_ffa_fn) { + ffa_panic("no private data found\n"); + return -ENODEV; + } a0 = FFA_VERSION; a1 = FFA_VERSION_1_0; @@ -126,8 +133,10 @@ static int ffa_get_endpoint_id(void) { FFA_DECLARE_ARGS; - if (!ffa_priv_data.invoke_ffa_fn) - panic("[FFA] no private data found\n"); + if (!ffa_priv_data.invoke_ffa_fn) { + ffa_panic("no private data found\n"); + return -ENODEV; + } a0 = FFA_ID_GET; @@ -200,8 +209,10 @@ static int ffa_get_rxtx_map_features(void) { FFA_DECLARE_ARGS; - if (!ffa_priv_data.invoke_ffa_fn) - panic("[FFA] no private data found\n"); + if (!ffa_priv_data.invoke_ffa_fn) { + ffa_panic("no private data found\n"); + return -ENODEV; + } a0 = FFA_FEATURES; a1 = FFA_RXTX_MAP; @@ -427,8 +438,10 @@ static int ffa_map_rxtx_buffers(size_t buf_4k_pages) FFA_DECLARE_ARGS; - if (!ffa_priv_data.invoke_ffa_fn) - panic("[FFA] no private data found\n"); + if (!ffa_priv_data.invoke_ffa_fn) { + ffa_panic("no private data found\n"); + return -ENODEV; + } ret = ffa_alloc_rxtx_buffers(buf_4k_pages); if (ret != FFA_ERR_STAT_SUCCESS) @@ -496,8 +509,10 @@ static int ffa_unmap_rxtx_buffers(void) { FFA_DECLARE_ARGS; - if (!ffa_priv_data.invoke_ffa_fn) - panic("[FFA] no private data found\n"); + if (!ffa_priv_data.invoke_ffa_fn) { + ffa_panic("no private data found\n"); + return -ENODEV; + } a0 = FFA_RXTX_UNMAP; a1 = PREP_SELF_ENDPOINT_ID(ffa_priv_data.id); @@ -508,11 +523,12 @@ static int ffa_unmap_rxtx_buffers(void) case FFA_ERROR: { if (((int)res.a2) == FFA_ERR_STAT_NOT_SUPPORTED) - panic("[FFA] FFA_RXTX_UNMAP is not implemented at this FF-A instance\n"); + ffa_panic("FFA_RXTX_UNMAP is not implemented at this FF-A instance\n"); else if (((int)res.a2) == FFA_ERR_STAT_INVALID_PARAMETERS) - panic("[FFA] There is no buffer pair registered on behalf of the caller\n"); + ffa_panic("There is no buffer pair registered on behalf of the caller\n"); else - panic("[FFA] Undefined error (%d)\n", ((int)res.a2)); + ffa_panic("Undefined error (%d)\n", ((int)res.a2)); + return -ENODEV; } case FFA_SUCCESS: { @@ -520,19 +536,24 @@ static int ffa_unmap_rxtx_buffers(void) int ret; ret = ffa_get_rxtx_buffers_pages_cnt(&buf_4k_pages); - if (ret != FFA_ERR_STAT_SUCCESS) - panic("[FFA] RX/TX buffers unmapped but failure in getting pages count\n"); + if (ret != FFA_ERR_STAT_SUCCESS) { + ffa_panic("RX/TX buffers unmapped but failure in getting pages count\n"); + return -ENODEV; + } ret = ffa_free_rxtx_buffers(buf_4k_pages); - if (ret != FFA_ERR_STAT_SUCCESS) - panic("[FFA] RX/TX buffers unmapped but failure in freeing the memory\n"); + if (ret != FFA_ERR_STAT_SUCCESS) { + ffa_panic("RX/TX buffers unmapped but failure in freeing the memory\n"); + return -ENODEV; + } ffa_info("RX/TX buffers unmapped and memory freed"); return FFA_ERR_STAT_SUCCESS; } default: - panic("[FFA] Undefined response function (0x%lx)", res.a0); + ffa_panic("Undefined response function (0x%lx)", res.a0); + return -ENODEV; } } @@ -550,8 +571,10 @@ static int ffa_release_rx_buffer(void) { FFA_DECLARE_ARGS; - if (!ffa_priv_data.invoke_ffa_fn) - panic("[FFA] no private data found\n"); + if (!ffa_priv_data.invoke_ffa_fn) { + ffa_panic("no private data found\n"); + return -ENODEV; + } a0 = FFA_RX_RELEASE; @@ -561,17 +584,19 @@ static int ffa_release_rx_buffer(void) case FFA_ERROR: { if (((int)res.a2) == FFA_ERR_STAT_NOT_SUPPORTED) - panic("[FFA] FFA_RX_RELEASE is not implemented at this FF-A instance\n"); + ffa_panic("FFA_RX_RELEASE is not implemented at this FF-A instance\n"); else if (((int)res.a2) == FFA_ERR_STAT_DENIED) - panic("[FFA] Caller did not have ownership of the RX buffer\n"); + ffa_panic("Caller did not have ownership of the RX buffer\n"); else - panic("[FFA] Undefined error (%d)\n", ((int)res.a2)); + ffa_panic("Undefined error (%d)\n", ((int)res.a2)); + return -ENODEV; } case FFA_SUCCESS: return FFA_ERR_STAT_SUCCESS; default: - panic("[FFA] Undefined response function (0x%lx)\n", res.a0); + ffa_panic("Undefined response function (0x%lx)\n", res.a0); + return -ENODEV; } } @@ -763,8 +788,10 @@ static int ffa_query_partitions_info(union ffa_partition_uuid *part_uuid, unsigned long a7 = 0; struct arm_smccc_res res = {0}; - if (!ffa_priv_data.invoke_ffa_fn) - panic("[FFA] no private data found\n"); + if (!ffa_priv_data.invoke_ffa_fn) { + ffa_panic("no private data found\n"); + return -ENODEV; + } a0 = FFA_PARTITION_INFO_GET; @@ -840,7 +867,7 @@ static int ffa_query_partitions_info(union ffa_partition_uuid *part_uuid, ret = ffa_release_rx_buffer(); if (!part_uuid && !res.a2) { - ffa_err("[FFA] no partition installed in the system"); + ffa_err("no partition installed in the system"); return -ENODEV; } @@ -931,8 +958,10 @@ static int ffa_get_partitions_info(struct ffa_interface_data *func_data) return -EINVAL; } - if (!ffa_priv_data.partitions.count || !ffa_priv_data.partitions.descs) - panic("[FFA] No partition installed\n"); + if (!ffa_priv_data.partitions.count || !ffa_priv_data.partitions.descs) { + ffa_panic("No partition installed\n"); + return -ENODEV; + } if (func_data->data0_size == sizeof(union ffa_partition_uuid) && func_data->data0 && @@ -1170,6 +1199,7 @@ static int __ffa_runtime ffa_msg_send_direct_req(struct ffa_interface_data /* Undefined error */ return -ENXIO; } + return -ENODEV; } case FFA_SUCCESS: @@ -1247,7 +1277,13 @@ static int ffa_init_private_data(struct udevice *dev) ffa_priv_data.conduit = pdata->conduit; if (ffa_priv_data.conduit == FFA_CONDUIT_SMC) { +#if CONFIG_IS_ENABLED(SANDBOX_FFA) + ffa_priv_data.invoke_ffa_fn = sandbox_arm_ffa_smccc_smc; + ffa_info("Using SMC emulation"); +#else ffa_priv_data.invoke_ffa_fn = arm_ffa_smccc_smc; +#endif + } else { ffa_err("Undefined FF-A conduit (%d)", ffa_priv_data.conduit); return -EINVAL; diff --git a/drivers/arm-ffa/sandbox.c b/drivers/arm-ffa/sandbox.c new file mode 100644 index 0000000000..fcabd4b59b --- /dev/null +++ b/drivers/arm-ffa/sandbox.c @@ -0,0 +1,735 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2022 ARM Limited + * Abdellatif El Khlifi + */ + +#include "sandbox_arm_ffa_prv.h" +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/** + * The device private data structure containing all the emulated secure world data + */ +static struct sandbox_ffa_prvdata sandbox_ffa_priv_data = {0}; + +/* The partitions (SPs) table */ +static struct ffa_partition_desc sandbox_partitions[SANDBOX_PARTITIONS_CNT] = { + { + .info = { .id = 0x1245, .exec_ctxt = 0x5687, .properties = 0x89325621 }, + .UUID = { .bytes = {SANDBOX_SERVICE1_UUID_DATA}} + }, + { + .info = { .id = 0x9836, .exec_ctxt = 0x9587, .properties = 0x45325621 }, + .UUID = { .bytes = {SANDBOX_SERVICE2_UUID_DATA}} + }, + { + .info = { .id = 0x6452, .exec_ctxt = 0x7687, .properties = 0x23325621 }, + .UUID = { .bytes = {SANDBOX_SERVICE1_UUID_DATA}} + }, + { + .info = { .id = 0x7814, .exec_ctxt = 0x1487, .properties = 0x70325621 }, + .UUID = { .bytes = {SANDBOX_SERVICE2_UUID_DATA}} + } + +}; + +/* + * Driver functions + */ + +/** + * sandbox_ffa_get_device - probes the sandbox_arm_ffa device + * + * This function makes sure the sandbox_arm_ffa device is probed + * and ready for use. This is done using uclass_get_device. + * The arm_ffa driver belongs to UCLASS_FFA. + * This function should be called before using the driver. + * + * sandbox_arm_ffa depends on arm_ffa device. This dependency is + * handled by ffa_init_device function. arm_ffa is probed first then + * it probes sandbox_arm_ffa using sandbox_ffa_get_device. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +int sandbox_ffa_get_device(void) +{ + int ret; + int devnum = 1; + + if (sandbox_ffa_priv_data.dev) + return FFA_ERR_STAT_SUCCESS; + + /* + * searching and probing the device + */ + ret = uclass_get_device(UCLASS_FFA, devnum, &sandbox_ffa_priv_data.dev); + if (ret) { + ffa_err("[Sandbox] Can not find the FF-A Sandbox device"); + sandbox_ffa_priv_data.dev = NULL; + return -ENODEV; + } + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * sandbox_ffa_version - Emulated FFA_VERSION handler function + * @{a0-a7} , res: The SMC call arguments and return structure. + * + * This is the function that emulates FFA_VERSION FF-A function. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +SANDBOX_SMC_FFA_ABI(ffa_version) +{ + sandbox_ffa_priv_data.fwk_version = FFA_VERSION_1_0; + res->a0 = sandbox_ffa_priv_data.fwk_version; + + /* w1-w7 MBZ */ + memset(FFA_W1W7_MBZ_REG_START, 0, FFA_W1W7_MBZ_CNT * sizeof(unsigned long)); + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * sandbox_ffa_id_get - Emulated FFA_ID_GET handler function + * @{a0-a7} , res: The SMC call arguments and return structure. + * + * This is the function that emulates FFA_ID_GET FF-A function. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +SANDBOX_SMC_FFA_ABI(ffa_id_get) +{ + res->a0 = FFA_SUCCESS; + res->a1 = 0; + + sandbox_ffa_priv_data.id = NS_PHYS_ENDPOINT_ID; + res->a2 = sandbox_ffa_priv_data.id; + + /* w3-w7 MBZ */ + memset(FFA_W3_MBZ_REG_START, 0, FFA_W3W7_MBZ_CNT * sizeof(unsigned long)); + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * sandbox_ffa_features - Emulated FFA_FEATURES handler function + * @{a0-a7} , res: The SMC call arguments and return structure. + * + * This is the function that emulates FFA_FEATURES FF-A function. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +SANDBOX_SMC_FFA_ABI(ffa_features) +{ + switch (a1) { + case FFA_RXTX_MAP: + { + res->a0 = FFA_SUCCESS; + res->a2 = RXTX_BUFFERS_MIN_SIZE; + res->a3 = 0; + /* w4-w7 MBZ */ + memset(FFA_W4W7_MBZ_REG_START, + 0, FFA_W4W7_MBZ_CNT * sizeof(unsigned long)); + break; + } + default: + { + res->a0 = FFA_ERROR; + res->a2 = FFA_ERR_STAT_NOT_SUPPORTED; + /* w3-w7 MBZ */ + memset(FFA_W3_MBZ_REG_START, + 0, FFA_W3W7_MBZ_CNT * sizeof(unsigned long)); + ffa_err("[Sandbox] FF-A interface 0x%lx not implemented", a1); + } + } + + res->a1 = 0; + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * sandbox_ffa_partition_info_get - Emulated FFA_PARTITION_INFO_GET handler function + * @{a0-a7} , res: The SMC call arguments and return structure. + * + * This is the function that emulates FFA_PARTITION_INFO_GET FF-A function. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +SANDBOX_SMC_FFA_ABI(ffa_partition_info_get) +{ + struct ffa_partition_info *rxbuf_desc_info = NULL; + u32 descs_cnt; + u32 descs_size_bytes; + + res->a0 = FFA_ERROR; + + if (!sandbox_ffa_priv_data.pair.rxbuf) { + res->a2 = FFA_ERR_STAT_DENIED; + goto cleanup; + } + + if (sandbox_ffa_priv_data.pair_info.rxbuf_owned) { + res->a2 = FFA_ERR_STAT_BUSY; + goto cleanup; + } + + if (!sandbox_ffa_priv_data.partitions.descs) { + sandbox_ffa_priv_data.partitions.descs = sandbox_partitions; + sandbox_ffa_priv_data.partitions.count = SANDBOX_PARTITIONS_CNT; + } + + descs_size_bytes = SANDBOX_PARTITIONS_CNT * sizeof(struct ffa_partition_desc); + + /* Abort if the RX buffer size is smaller than the descriptors buffer size */ + if ((sandbox_ffa_priv_data.pair_info.rxtx_buf_size * SZ_4K) < descs_size_bytes) { + res->a2 = FFA_ERR_STAT_NO_MEMORY; + goto cleanup; + } + + rxbuf_desc_info = (struct ffa_partition_info *)sandbox_ffa_priv_data.pair.rxbuf; + + /* No UUID specified. Return the information of all partitions */ + if (!a1 && !a2 && !a3 && !a4) { + for (descs_cnt = 0 ; descs_cnt < SANDBOX_PARTITIONS_CNT ; descs_cnt++) + *(rxbuf_desc_info++) = + sandbox_ffa_priv_data.partitions.descs[descs_cnt].info; + + res->a0 = FFA_SUCCESS; + res->a2 = SANDBOX_PARTITIONS_CNT; + /* transfer ownership to the consumer: the non secure world */ + sandbox_ffa_priv_data.pair_info.rxbuf_owned = 1; + + goto cleanup; + } + + /* + * A UUID is specified. Return the information of all partitions matching + * the UUID + */ + + for (descs_cnt = 0 ; descs_cnt < SANDBOX_PARTITIONS_CNT ; descs_cnt++) + if (a1 == sandbox_ffa_priv_data.partitions.descs[descs_cnt].UUID.words.a1 && + a2 == sandbox_ffa_priv_data.partitions.descs[descs_cnt].UUID.words.a2 && + a3 == sandbox_ffa_priv_data.partitions.descs[descs_cnt].UUID.words.a3 && + a4 == sandbox_ffa_priv_data.partitions.descs[descs_cnt].UUID.words.a4) { + *(rxbuf_desc_info++) = + sandbox_ffa_priv_data.partitions.descs[descs_cnt].info; + } + + if (rxbuf_desc_info != ((struct ffa_partition_info *)sandbox_ffa_priv_data.pair.rxbuf)) { + res->a0 = FFA_SUCCESS; + /* store the partitions count */ + res->a2 = (unsigned long) + (rxbuf_desc_info - (struct ffa_partition_info *) + sandbox_ffa_priv_data.pair.rxbuf); + + /* transfer ownership to the consumer: the non secure world */ + sandbox_ffa_priv_data.pair_info.rxbuf_owned = 1; + } else { + res->a2 = FFA_ERR_STAT_INVALID_PARAMETERS; + } + +cleanup: + + ffa_err("[Sandbox] FFA_PARTITION_INFO_GET (%ld)", res->a2); + + res->a1 = 0; + + /* w3-w7 MBZ */ + memset(FFA_W3_MBZ_REG_START, 0, FFA_W3W7_MBZ_CNT * sizeof(unsigned long)); + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * sandbox_ffa_rxtx_map - Emulated FFA_RXTX_MAP handler function + * @{a0-a7} , res: The SMC call arguments and return structure. + * + * This is the function that emulates FFA_RXTX_MAP FF-A function. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +SANDBOX_SMC_FFA_ABI(ffa_rxtx_map) +{ + res->a0 = FFA_ERROR; + + if (sandbox_ffa_priv_data.pair.txbuf && sandbox_ffa_priv_data.pair.rxbuf) { + res->a2 = FFA_ERR_STAT_DENIED; + goto feedback; + } + + if (a3 >= RXTX_BUFFERS_MIN_PAGES && a1 && a2) { + sandbox_ffa_priv_data.pair.txbuf = a1; + sandbox_ffa_priv_data.pair.rxbuf = a2; + sandbox_ffa_priv_data.pair_info.rxtx_buf_size = a3; + sandbox_ffa_priv_data.pair_info.rxbuf_mapped = 1; + res->a0 = FFA_SUCCESS; + res->a2 = 0; + goto feedback; + } + + if (!a1 || !a2) + res->a2 = FFA_ERR_STAT_INVALID_PARAMETERS; + else + res->a2 = FFA_ERR_STAT_NO_MEMORY; + + ffa_err("[Sandbox] error in FFA_RXTX_MAP arguments (%d)", (int)res->a2); + +feedback: + + res->a1 = 0; + + /* w3-w7 MBZ */ + memset(FFA_W3_MBZ_REG_START, + 0, FFA_W3W7_MBZ_CNT * sizeof(unsigned long)); + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * sandbox_ffa_rxtx_unmap - Emulated FFA_RXTX_UNMAP handler function + * @{a0-a7} , res: The SMC call arguments and return structure. + * + * This is the function that emulates FFA_RXTX_UNMAP FF-A function. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +SANDBOX_SMC_FFA_ABI(ffa_rxtx_unmap) +{ + res->a0 = FFA_ERROR; + res->a2 = FFA_ERR_STAT_INVALID_PARAMETERS; + + if (GET_NS_PHYS_ENDPOINT_ID(a1) != sandbox_ffa_priv_data.id) + goto feedback; + + if (sandbox_ffa_priv_data.pair.txbuf && sandbox_ffa_priv_data.pair.rxbuf) { + sandbox_ffa_priv_data.pair.txbuf = 0; + sandbox_ffa_priv_data.pair.rxbuf = 0; + sandbox_ffa_priv_data.pair_info.rxtx_buf_size = 0; + sandbox_ffa_priv_data.pair_info.rxbuf_mapped = 0; + res->a0 = FFA_SUCCESS; + res->a2 = 0; + goto feedback; + } + + ffa_err("[Sandbox] No buffer pair registered on behalf of the caller"); + +feedback: + + res->a1 = 0; + + /* w3-w7 MBZ */ + memset(FFA_W3_MBZ_REG_START, + 0, FFA_W3W7_MBZ_CNT * sizeof(unsigned long)); + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * sandbox_ffa_rx_release - Emulated FFA_RX_RELEASE handler function + * @{a0-a7} , res: The SMC call arguments and return structure. + * + * This is the function that emulates FFA_RX_RELEASE FF-A function. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +SANDBOX_SMC_FFA_ABI(ffa_rx_release) +{ + if (!sandbox_ffa_priv_data.pair_info.rxbuf_owned) { + res->a0 = FFA_ERROR; + res->a2 = FFA_ERR_STAT_DENIED; + } else { + sandbox_ffa_priv_data.pair_info.rxbuf_owned = 0; + res->a0 = FFA_SUCCESS; + res->a2 = 0; + } + + res->a1 = 0; + + /* w3-w7 MBZ */ + memset(FFA_W3_MBZ_REG_START, + 0, FFA_W3W7_MBZ_CNT * sizeof(unsigned long)); + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * sandbox_ffa_sp_valid - Checks SP validity + * @part_id: partition ID to check + * + * This is the function searches the input ID in the descriptors table. + * + * Return: + * + * 1 on success (Partition found). Otherwise, failure + */ +int sandbox_ffa_sp_valid(u16 part_id) +{ + u32 descs_cnt; + + for (descs_cnt = 0 ; descs_cnt < SANDBOX_PARTITIONS_CNT ; descs_cnt++) + if (sandbox_ffa_priv_data.partitions.descs[descs_cnt].info.id == part_id) + return 1; + + return 0; +} + +/** + * sandbox_ffa_msg_send_direct_req - Emulated FFA_MSG_SEND_DIRECT_{REQ,RESP} handler function + * @{a0-a7} , res: The SMC call arguments and return structure. + * + * This is the function that emulates FFA_MSG_SEND_DIRECT_{REQ,RESP} + * FF-A functions. + * + * Emulating interrupts is not supported. So, FFA_RUN and FFA_INTERRUPT are not supported. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +SANDBOX_SMC_FFA_ABI(ffa_msg_send_direct_req) +{ + u16 part_id; + + part_id = GET_DST_SP_ID(a1); + + if ((GET_NS_PHYS_ENDPOINT_ID(a1) != sandbox_ffa_priv_data.id) || + !sandbox_ffa_sp_valid(part_id) || + a2) { + res->a0 = FFA_ERROR; + res->a1 = 0; + res->a2 = FFA_ERR_STAT_INVALID_PARAMETERS; + + /* w3-w7 MBZ */ + memset(FFA_W3_MBZ_REG_START, + 0, FFA_W3W7_MBZ_CNT * sizeof(unsigned long)); + + return FFA_ERR_STAT_SUCCESS; + } + + res->a0 = FFA_MSG_SEND_DIRECT_RESP; + + res->a1 = PREP_SRC_SP_ID(part_id) | + PREP_NS_PHYS_ENDPOINT_ID(sandbox_ffa_priv_data.id); + + res->a2 = 0; + + /* + * return 0xff bytes as a response + */ + res->a3 = 0xffffffff; + res->a4 = 0xffffffff; + res->a5 = 0xffffffff; + res->a6 = 0xffffffff; + res->a7 = 0xffffffff; + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * sandbox_ffa_get_prv_data - Returns the pointer to FF-A core pivate data + * @func_data: Pointer to the FF-A function arguments container structure + * + * This is the handler that returns the address of the FF-A core pivate data. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +int sandbox_ffa_get_prv_data(struct ffa_interface_data *func_data) +{ + if (!func_data) + return -EINVAL; + + if (!func_data->data0 || func_data->data0_size != sizeof(struct ffa_prvdata **)) + return -EINVAL; + + if (!func_data->data1 || func_data->data1_size != sizeof(struct sandbox_ffa_prvdata **)) + return -EINVAL; + + *((struct ffa_prvdata **)func_data->data0) = &ffa_priv_data; + *((struct sandbox_ffa_prvdata **)func_data->data1) = &sandbox_ffa_priv_data; + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * sandbox_ffa_get_rxbuf_flags - Reading the mapping/ownership flags + * @queried_func_id: The FF-A function to be queried + * @func_data: Pointer to the FF-A function arguments container structure + * + * This is the handler that queries the status flags of the following emulated ABIs: + * FFA_RXTX_MAP, FFA_RXTX_UNMAP, FFA_RX_RELEASE + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +int sandbox_ffa_get_rxbuf_flags(u32 queried_func_id, struct ffa_interface_data *func_data) +{ + if (!func_data) + return -EINVAL; + + if (!func_data->data0 || func_data->data0_size != sizeof(u8)) + return -EINVAL; + + switch (queried_func_id) { + case FFA_RXTX_MAP: + case FFA_RXTX_UNMAP: + *((u8 *)func_data->data0) = sandbox_ffa_priv_data.pair_info.rxbuf_mapped; + return FFA_ERR_STAT_SUCCESS; + case FFA_RX_RELEASE: + *((u8 *)func_data->data0) = sandbox_ffa_priv_data.pair_info.rxbuf_owned; + return FFA_ERR_STAT_SUCCESS; + default: + ffa_err("[Sandbox] The querried FF-A interface flag (%d) undefined", + queried_func_id); + return -EINVAL; + } +} + +/** + * invoke_sandbox_ffa_drv_api - The driver dispatcher function + * @queried_func_id: The FF-A function to be queried + * @func_data: Pointer to the FF-A function arguments container structure + * + * The dispatcher function that selects the handler that queries the + * status of FF-A ABIs given in the input argument. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +int invoke_sandbox_ffa_drv_api(u32 queried_func_id, struct ffa_interface_data *func_data) +{ + switch (queried_func_id) { + case FFA_VERSION: + case FFA_ID_GET: + case FFA_FEATURES: + return sandbox_ffa_get_prv_data(func_data); + case FFA_RXTX_MAP: + case FFA_RXTX_UNMAP: + case FFA_RX_RELEASE: + return sandbox_ffa_get_rxbuf_flags(queried_func_id, func_data); + default: + ffa_err("[Sandbox] The querried FF-A interface (%d) undefined", queried_func_id); + return -EINVAL; + } +} + +/** + * sandbox_ffa_init_prv_data_from_dtb - init private data fields from DTB + * @dev: the sandbox_arm_ffa device + * + * The value of the conduit field in the private data structure is read from the DTB. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +static int sandbox_ffa_init_prv_data_from_dtb(struct udevice *dev) +{ + struct ffa_pdata *pdata = dev_get_plat(dev); + + sandbox_ffa_priv_data.conduit = pdata->conduit; + + if (sandbox_ffa_priv_data.conduit != FFA_CONDUIT_SMC) { + ffa_err("[Sandbox] Undefined FF-A conduit (%d)", sandbox_ffa_priv_data.conduit); + return -EINVAL; + } + + ffa_info("[Sandbox] Conduit is SMC"); + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * sandbox_arm_ffa_smccc_smc - FF-A SMC call emulation + * @dev: the SMC arguments to be passed to the FF-A ABI + * + * Sandbox driver emulates the FF-A ABIs SMC call using this function. + * The emulated FF-A ABI is identified and invoked. + * FF-A emulation is based on the FF-A specification 1.0 + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure. + * FF-A protocol error codes are returned using the registers arguments as described + * by the specification + */ +void sandbox_arm_ffa_smccc_smc(unsigned long a0, unsigned long a1, + unsigned long a2, unsigned long a3, unsigned long a4, + unsigned long a5, unsigned long a6, unsigned long a7, + struct arm_smccc_res *res) +{ + int ret = FFA_ERR_STAT_SUCCESS; + + switch (a0) { + case FFA_VERSION: + ret = sandbox_ffa_version(a0, a1, a2, a3, a4, a5, a6, a7, res); + break; + case FFA_PARTITION_INFO_GET: + ret = sandbox_ffa_partition_info_get(a0, a1, a2, a3, a4, a5, a6, a7, res); + break; + case FFA_RXTX_UNMAP: + ret = sandbox_ffa_rxtx_unmap(a0, a1, a2, a3, a4, a5, a6, a7, res); + break; + case FFA_MSG_SEND_DIRECT_REQ: + ret = sandbox_ffa_msg_send_direct_req(a0, a1, a2, a3, a4, a5, a6, a7, res); + break; + case FFA_ID_GET: + ret = sandbox_ffa_id_get(a0, a1, a2, a3, a4, a5, a6, a7, res); + break; + case FFA_FEATURES: + ret = sandbox_ffa_features(a0, a1, a2, a3, a4, a5, a6, a7, res); + break; + case FFA_RXTX_MAP: + ret = sandbox_ffa_rxtx_map(a0, a1, a2, a3, a4, a5, a6, a7, res); + break; + case FFA_RX_RELEASE: + ret = sandbox_ffa_rx_release(a0, a1, a2, a3, a4, a5, a6, a7, res); + break; + default: + ffa_err("[Sandbox] Undefined FF-A interface (0x%x)", (unsigned int)a0); + } + + if (ret != FFA_ERR_STAT_SUCCESS) + ffa_err("[Sandbox] FF-A ABI internal failure (%d)", ret); +} + +/** + * sandbox_ffa_bind - The driver bind function + * @dev: the arm_ffa device + * + * Called when the driver is bound with the device based on the DTB node. + * The private data structure is cleared before use. + * This makes sure that when the device added/removed multiple times the previous + * private structure is cleared. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS + */ +static int sandbox_ffa_bind(struct udevice *dev) +{ + memset(&sandbox_ffa_priv_data, 0, sizeof(sandbox_ffa_priv_data)); + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * sandbox_ffa_probe - The driver probe function + * @dev: the sandbox_arm_ffa device + * + * Probing is triggered by the uclass device discovery. + * At probe level the device tree conduit in the private structure + * is read from the DTB. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +static int sandbox_ffa_probe(struct udevice *dev) +{ + return sandbox_ffa_init_prv_data_from_dtb(dev); +} + +/** + * sandbox_ffa_of_to_plat - Reads the device tree node + * @dev: the sandbox_arm_ffa device + * + * This function reads data from the device tree node and populates + * the platform data structure + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +static int sandbox_ffa_of_to_plat(struct udevice *dev) +{ + struct ffa_pdata *pdata = dev_get_plat(dev); + const char *conduit; + + conduit = dev_read_string(dev, "method"); + + if (!conduit) { + ffa_err("[Sandbox] Failure to read the conduit from device tree"); + return -EINVAL; + } + + if (strcmp("smc", conduit)) { + ffa_err("[Sandbox] Unsupported conduit"); + return -EINVAL; + } + + pdata->conduit = FFA_CONDUIT_SMC; + + return FFA_ERR_STAT_SUCCESS; +} + +/** + * sandbox_ffa_drv_ops - The driver operations structure + * @invoke_func: The driver dispatcher + */ +struct ffa_ops sandbox_ffa_drv_ops = { + .invoke_func = invoke_sandbox_ffa_drv_api +}; + +/** + * sandbox_ffa_device_get_ops - driver operations getter + * + * Return: + * This function returns a pointer to the driver operations structure + */ +const struct ffa_ops *sandbox_ffa_device_get_ops(void) +{ + return &sandbox_ffa_drv_ops; +} + +/** + * Defining the device tree compatible string + */ +static const struct udevice_id sandbox_ffa_match_id[] = { + {"sandbox,ffa", 0}, + {}, +}; + +/** + * Declaring the sandbox_arm_ffa driver under UCLASS_FFA + */ +U_BOOT_DRIVER(sandbox_arm_ffa) = { + .name = "sandbox_arm_ffa", + .of_match = sandbox_ffa_match_id, + .id = UCLASS_FFA, + .of_to_plat = sandbox_ffa_of_to_plat, + .probe = sandbox_ffa_probe, + .bind = sandbox_ffa_bind, + .plat_auto = sizeof(struct ffa_pdata), +}; diff --git a/drivers/arm-ffa/sandbox_arm_ffa_prv.h b/drivers/arm-ffa/sandbox_arm_ffa_prv.h new file mode 100644 index 0000000000..9f5085f098 --- /dev/null +++ b/drivers/arm-ffa/sandbox_arm_ffa_prv.h @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2022 ARM Limited + * Abdellatif El Khlifi + */ + +#ifndef __SANDBOX_ARM_FFA_PRV_H +#define __SANDBOX_ARM_FFA_PRV_H + +#include "arm_ffa_prv.h" + +/* + * This header is private. It is exclusively used by the Sandbox FF-A driver + */ + +/* Non-secure physical FF-A instance */ +#define NS_PHYS_ENDPOINT_ID (0) + +#define GET_NS_PHYS_ENDPOINT_ID_MASK GENMASK(31, 16) +#define GET_NS_PHYS_ENDPOINT_ID(x) \ + ((u16)(FIELD_GET(GET_NS_PHYS_ENDPOINT_ID_MASK, (x)))) + +/* Helper macro for reading the destination partition ID */ +#define GET_DST_SP_ID_MASK GENMASK(15, 0) +#define GET_DST_SP_ID(x) \ + ((u16)(FIELD_GET(GET_DST_SP_ID_MASK, (x)))) + +/* Helper macro for setting the source partition ID */ +#define PREP_SRC_SP_ID_MASK GENMASK(31, 16) +#define PREP_SRC_SP_ID(x) \ + (FIELD_PREP(PREP_SRC_SP_ID_MASK, (x))) + +/* Helper macro for setting the destination endpoint ID */ +#define PREP_NS_PHYS_ENDPOINT_ID_MASK GENMASK(15, 0) +#define PREP_NS_PHYS_ENDPOINT_ID(x) \ + (FIELD_PREP(PREP_NS_PHYS_ENDPOINT_ID_MASK, (x))) + +/* RX/TX buffers minimum size */ +#define RXTX_BUFFERS_MIN_SIZE (RXTX_4K) +#define RXTX_BUFFERS_MIN_PAGES (1) + +/* MBZ registers info */ + +/* w1-w7 MBZ */ +#define FFA_W1W7_MBZ_CNT (7) +#define FFA_W1W7_MBZ_REG_START (&res->a1) + +/* w4-w7 MBZ */ +#define FFA_W4W7_MBZ_CNT (4) +#define FFA_W4W7_MBZ_REG_START (&res->a4) + +/* w3-w7 MBZ */ +#define FFA_W3W7_MBZ_CNT (5) +#define FFA_W3_MBZ_REG_START (&res->a3) + +/* secure partitions count */ +#define SANDBOX_PARTITIONS_CNT (4) + +/* service 1 UUID binary data (little-endian format) */ +#define SANDBOX_SERVICE1_UUID_DATA \ + 0xed, 0x32, 0xd5, 0x33, \ + 0x99, 0xe6, 0x42, 0x09, \ + 0x9c, 0xc0, 0x2d, 0x72, \ + 0xcd, 0xd9, 0x98, 0xa7 + +/* service 2 UUID binary data (little-endian format) */ +#define SANDBOX_SERVICE2_UUID_DATA \ + 0xab, 0xcd, 0xd5, 0x33, \ + 0x99, 0xe6, 0x42, 0x09, \ + 0x9c, 0xc0, 0x2d, 0x72, \ + 0xcd, 0xd9, 0x98, 0xa7 + +/** + * struct ffa_rxtxpair_info - structure hosting the RX/TX buffers flags + * @rxbuf_owned: RX buffer ownership flag (the owner is non secure world: the consumer) + * @rxbuf_mapped: RX buffer mapping flag + * @txbuf_owned TX buffer ownership flag + * @txbuf_mapped: TX buffer mapping flag + * @rxtx_buf_size: RX/TX buffers size as set by the FF-A core driver + * + * Data structure hosting the ownership/mapping flags of the RX/TX buffers + * When a buffer is owned/mapped its corresponding flag is set to 1 otherwise 0. + */ +struct ffa_rxtxpair_info { + u8 rxbuf_owned; + u8 rxbuf_mapped; + u8 txbuf_owned; + u8 txbuf_mapped; + u32 rxtx_buf_size; +}; + +/** + * struct sandbox_ffa_prvdata - the driver private data structure + * + * @dev: The arm_ffa device under u-boot driver model + * @fwk_version: FF-A framework version + * @id: u-boot endpoint ID + * @partitions: The partitions descriptors structure + * @pair: The RX/TX buffers pair + * @pair_info: The RX/TX buffers pair flags and size + * @conduit: The selected conduit + * + * The driver data structure hosting all the emulated secure world data. + */ +struct sandbox_ffa_prvdata { + struct udevice *dev; + u32 fwk_version; + u16 id; + struct ffa_partitions partitions; + struct ffa_rxtxpair pair; + struct ffa_rxtxpair_info pair_info; + enum ffa_conduit conduit; +}; + +void sandbox_arm_ffa_smccc_smc(unsigned long a0, unsigned long a1, + unsigned long a2, unsigned long a3, unsigned long a4, + unsigned long a5, unsigned long a6, unsigned long a7, + struct arm_smccc_res *res); + +#define SANDBOX_SMC_FFA_ABI(ffabi) static int sandbox_##ffabi(unsigned long a0, unsigned long a1, \ + unsigned long a2, unsigned long a3, unsigned long a4, \ + unsigned long a5, unsigned long a6, unsigned long a7, \ + struct arm_smccc_res *res) + +/* The core FF-A private data structure to inspect */ +extern struct ffa_prvdata ffa_priv_data; + +#endif diff --git a/include/arm_ffa.h b/include/arm_ffa.h index 5a2151f8e4..bff565f2af 100644 --- a/include/arm_ffa.h +++ b/include/arm_ffa.h @@ -22,6 +22,13 @@ #define ffa_info(fmt, ...) pr_info("[FFA] " fmt "\n", ##__VA_ARGS__) #define ffa_err(fmt, ...) pr_err("[FFA] " fmt "\n", ##__VA_ARGS__) +/* panic only on real HW. On sandbox mode return an error code */ +#if CONFIG_IS_ENABLED(SANDBOX_FFA) +#define ffa_panic(fmt, ...) ffa_err("[FFA] " fmt "\n", ##__VA_ARGS__) +#else +#define ffa_panic(fmt, ...) panic("[FFA] " fmt "\n", ##__VA_ARGS__) +#endif + /* * The driver operations success error code */ @@ -184,7 +191,7 @@ const struct ffa_ops * __ffa_runtime ffa_device_get_ops(void); int ffa_get_device(void); /** - * ffa_init_device - probes the arm_ffa device + * ffa_init_device - probes the arm_ffa and arm_ffa devices */ int ffa_init_device(void); #endif diff --git a/include/sandbox_arm_ffa.h b/include/sandbox_arm_ffa.h new file mode 100644 index 0000000000..fc681018ff --- /dev/null +++ b/include/sandbox_arm_ffa.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2022 ARM Limited + * Abdellatif El Khlifi + */ + +#ifndef __SANDBOX_ARM_FFA_H +#define __SANDBOX_ARM_FFA_H + +#include + +/** + * The device driver and the Uclass driver public functions + */ + +/** + * sandbox_ffa_get_invoke_func - performs a call to the Sandbox FF-A driver dispatcher + */ +int sandbox_ffa_get_invoke_func(u32 func_id, struct ffa_interface_data *func_data); + +/** + * sandbox_ffa_device_get_ops - driver operations getter + */ +const struct ffa_ops *sandbox_ffa_device_get_ops(void); + +/** + * sandbox_ffa_get_device - probes the sandbox_arm_ffa device + */ +int sandbox_ffa_get_device(void); + +#endif diff --git a/include/sandbox_arm_ffa_helper.h b/include/sandbox_arm_ffa_helper.h new file mode 100644 index 0000000000..f0fcd04536 --- /dev/null +++ b/include/sandbox_arm_ffa_helper.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2022 ARM Limited + * Abdellatif El Khlifi + */ + +#ifndef __SANDBOX_ARM_FFA_HELPER_H +#define __SANDBOX_ARM_FFA_HELPER_H + +#include +#include +#include "../drivers/arm-ffa/sandbox_arm_ffa_prv.h" + +/* + * This header is public. Including this header provides all FF-A Sandbox data structures + * It also provides the helper function allowing to pass data and invoke Sandbox FF-A functions + * used for testing the FF-A core driver + */ + +/** + * sandbox_ffa_helper_query_core_state - Wrapper function for + * reading the FF-A core driver data + */ +int sandbox_ffa_helper_query_core_state(u32 queried_func_id, struct ffa_interface_data *func_data); + +#endif diff --git a/lib/arm-ffa/Makefile b/lib/arm-ffa/Makefile index cba625fde4..04159da8eb 100644 --- a/lib/arm-ffa/Makefile +++ b/lib/arm-ffa/Makefile @@ -6,3 +6,4 @@ # This file only gets included when CONFIG_ARM_FFA_TRANSPORT_HELPERS is set obj-y += arm_ffa_helper.o +obj-$(CONFIG_SANDBOX_FFA) += sandbox_arm_ffa_helper.o diff --git a/lib/arm-ffa/arm_ffa_helper.c b/lib/arm-ffa/arm_ffa_helper.c index 67a3a4e9ab..32ee3b4486 100644 --- a/lib/arm-ffa/arm_ffa_helper.c +++ b/lib/arm-ffa/arm_ffa_helper.c @@ -105,10 +105,10 @@ int __ffa_runtime ffa_helper_msg_send_direct_req(struct ffa_interface_data } /** - * ffa_helper_init_device - Wrapper function for probing the arm_ffa device + * ffa_helper_init_device - Wrapper function for probing the arm_ffa and sandbox_arm_ffa devices * - * This boot time function should be called to probe the arm_ffa device so - * it becomes ready for use. + * This boot time function should be called to probe the arm_ffa and sandbox_arm_ffa devices so + * they become ready for use. * To achieve that, this function is called automatically at initcalls * level (after u-boot relocation). * diff --git a/lib/arm-ffa/sandbox_arm_ffa_helper.c b/lib/arm-ffa/sandbox_arm_ffa_helper.c new file mode 100644 index 0000000000..7859f30fc7 --- /dev/null +++ b/lib/arm-ffa/sandbox_arm_ffa_helper.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2022 ARM Limited + * Abdellatif El Khlifi + */ + +#include +#include + +/** + * sandbox_ffa_helper_query_core_state - Wrapper function for querying FF-A implementation + * + * A helper function used for querying the status of FF-A ABIs given in the input argument + * and the FF-A core driver. + * + * Return: + * + * FFA_ERR_STAT_SUCCESS on success. Otherwise, failure + */ +int sandbox_ffa_helper_query_core_state(u32 queried_func_id, struct ffa_interface_data *func_data) +{ + return sandbox_ffa_get_invoke_func(queried_func_id, func_data); +} diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index cffa2c69d6..12fc28fd82 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -2118,7 +2118,7 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, struct efi_event *evt, *next_event; efi_status_t ret = EFI_SUCCESS; -#if defined(CONFIG_ARM_FFA_TRANSPORT) +#if defined(CONFIG_ARM_FFA_TRANSPORT) && !defined(CONFIG_SANDBOX_FFA) int ffa_ret; #endif @@ -2182,7 +2182,7 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL); } -#if defined(CONFIG_ARM_FFA_TRANSPORT) +#if defined(CONFIG_ARM_FFA_TRANSPORT) && !defined(CONFIG_SANDBOX_FFA) /* unmap FF-A RX/TX buffers */ ffa_ret = ffa_helper_unmap_rxtx_buffers(); if (ffa_ret) From patchwork Tue Mar 29 15:16:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abdellatif El Khlifi X-Patchwork-Id: 1610731 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KSZRK03npz9sCq for ; Wed, 30 Mar 2022 03:15:24 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 08F8284025; Tue, 29 Mar 2022 18:14:55 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=fail (p=none dis=none) header.from=arm.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by phobos.denx.de (Postfix, from userid 109) id 17DA584015; Tue, 29 Mar 2022 17:17:26 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.2 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by phobos.denx.de (Postfix) with ESMTP id E153D84010 for ; Tue, 29 Mar 2022 17:17:18 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=abdellatif.elkhlifi@arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 443531477; Tue, 29 Mar 2022 08:17:18 -0700 (PDT) Received: from e121910.arm.com (unknown [10.57.40.79]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 1A48E3F73B; Tue, 29 Mar 2022 08:17:16 -0700 (PDT) From: abdellatif.elkhlifi@arm.com To: u-boot@lists.denx.de Cc: nd@arm.com, trini@konsulko.com, Abdellatif El Khlifi Subject: [PATCH 4/6] arm_ffa: introduce Sandbox test cases for UCLASS_FFA Date: Tue, 29 Mar 2022 16:16:57 +0100 Message-Id: <20220329151659.16894-5-abdellatif.elkhlifi@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220329151659.16894-1-abdellatif.elkhlifi@arm.com> References: <20220329151659.16894-1-abdellatif.elkhlifi@arm.com> X-Mailman-Approved-At: Tue, 29 Mar 2022 18:14:45 +0200 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.5 at phobos.denx.de X-Virus-Status: Clean From: Abdellatif El Khlifi Add functional test cases for the FF-A core driver These tests rely on the FF-A Sandbox driver which helps in inspecting the FF-A core driver. Signed-off-by: Abdellatif El Khlifi Cc: Tom Rini --- MAINTAINERS | 2 + test/dm/Makefile | 1 + test/dm/ffa.c | 424 +++++++++++++++++++++++++++++++++++++++++++++++ test/dm/ffa.h | 22 +++ 4 files changed, 449 insertions(+) create mode 100644 test/dm/ffa.c create mode 100644 test/dm/ffa.h diff --git a/MAINTAINERS b/MAINTAINERS index 84524d7caf..52274b2fac 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -242,6 +242,8 @@ F: include/arm_ffa_helper.h F: include/sandbox_arm_ffa.h F: include/sandbox_arm_ffa_helper.h F: lib/arm-ffa/ +F: test/dm/ffa.c +F: test/dm/ffa.h ARM FREESCALE IMX M: Stefano Babic diff --git a/test/dm/Makefile b/test/dm/Makefile index d46552fbf3..48eab1b1ff 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -79,6 +79,7 @@ obj-$(CONFIG_POWER_DOMAIN) += power-domain.o obj-$(CONFIG_ACPI_PMC) += pmc.o obj-$(CONFIG_DM_PMIC) += pmic.o obj-$(CONFIG_DM_PWM) += pwm.o +obj-$(CONFIG_SANDBOX_FFA) += ffa.o obj-$(CONFIG_QFW) += qfw.o obj-$(CONFIG_RAM) += ram.o obj-y += regmap.o diff --git a/test/dm/ffa.c b/test/dm/ffa.c new file mode 100644 index 0000000000..82875705c6 --- /dev/null +++ b/test/dm/ffa.c @@ -0,0 +1,424 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Functional tests for UCLASS_FFA class + * + * (C) Copyright 2022 ARM Limited + * Abdellatif El Khlifi + */ + +#include +#include +#include +#include +#include "ffa.h" +#include +#include +#include +#include + +/* Functional tests for the UCLASS_FFA */ + +int dm_test_ffa_log(struct unit_test_state *uts, char *msg) +{ + char cmd[LOG_CMD_SZ] = {0}; + + console_record_reset(); + + snprintf(cmd, LOG_CMD_SZ, "echo \"%s\"", msg); + run_command(cmd, 0); + + ut_assert_console_end(); + + return CMD_RET_SUCCESS; +} + +static int check_fwk_version(struct ffa_prvdata *prvdata, struct unit_test_state *uts) +{ + if (prvdata->fwk_version != SANDBOX_FWK_VERSION) { + char msg[LOG_MSG_SZ] = {0}; + + snprintf(msg, LOG_MSG_SZ, "[%s]: Error: prvdata->fwk_version = 0x%x", __func__, + prvdata->fwk_version); + dm_test_ffa_log(uts, msg); + return CMD_RET_FAILURE; + } + return CMD_RET_SUCCESS; +} + +static int check_endpoint_id(struct ffa_prvdata *prvdata, struct unit_test_state *uts) +{ + if (prvdata->id) { + char msg[LOG_MSG_SZ] = {0}; + + snprintf(msg, LOG_MSG_SZ, "[%s]: Error: prvdata->id = 0x%x", __func__, prvdata->id); + dm_test_ffa_log(uts, msg); + return CMD_RET_FAILURE; + } + return CMD_RET_SUCCESS; +} + +static int check_dev(struct ffa_prvdata *prvdata, struct unit_test_state *uts) +{ + if (!prvdata->dev) { + char msg[LOG_MSG_SZ] = {0}; + + snprintf(msg, LOG_MSG_SZ, "[%s]: Error: device = 0x%p", __func__, prvdata->dev); + dm_test_ffa_log(uts, msg); + return CMD_RET_FAILURE; + } + return CMD_RET_SUCCESS; +} + +static int check_prvdata_null(struct ffa_prvdata *prvdata) +{ + u32 idx; + u8 *byte = (u8 *)prvdata; + + for (idx = 0 ; idx < sizeof(struct ffa_prvdata) ; idx++) + if (*(byte++)) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; +} + +static int check_rxtxbuf(struct ffa_prvdata *prvdata, struct unit_test_state *uts) +{ + if (!prvdata->pair.rxbuf && prvdata->pair.txbuf) { + char msg[LOG_MSG_SZ] = {0}; + + snprintf(msg, LOG_MSG_SZ, "[%s]: Error: rxbuf = 0x%llx txbuf = 0x%llx", __func__, + prvdata->pair.rxbuf, + prvdata->pair.txbuf); + dm_test_ffa_log(uts, msg); + return CMD_RET_FAILURE; + } + return CMD_RET_SUCCESS; +} + +static int check_features(struct ffa_prvdata *prvdata, struct unit_test_state *uts) +{ + u32 desc_idx; + char msg[LOG_MSG_SZ] = {0}; + + snprintf(msg, + LOG_MSG_SZ, + "[%s]: Error: FFA_RXTX_MAP features not found", + __func__); + + for (desc_idx = 0; desc_idx < FFA_FEATURE_DESC_CNT ; desc_idx++) + if (prvdata->features[desc_idx].func_id == FFA_RXTX_MAP) { + if (prvdata->features[desc_idx].field1 != RXTX_4K && + prvdata->features[desc_idx].field1 != RXTX_16K && + prvdata->features[desc_idx].field1 != RXTX_64K) { + snprintf(msg, + LOG_MSG_SZ, + "[%s]: Error: FFA_RXTX_MAP features = 0x%x", + __func__, + prvdata->features[desc_idx].field1); + break; + } + return CMD_RET_SUCCESS; + } + + dm_test_ffa_log(uts, msg); + return CMD_RET_FAILURE; +} + +static int check_rxbuf_mapped_flag(u32 queried_func_id, + u8 rxbuf_mapped, + struct unit_test_state *uts) +{ + char msg[LOG_MSG_SZ] = {0}; + + switch (queried_func_id) { + case FFA_RXTX_MAP: + { + if (rxbuf_mapped) + return CMD_RET_SUCCESS; + break; + } + case FFA_RXTX_UNMAP: + { + if (!rxbuf_mapped) + return CMD_RET_SUCCESS; + break; + } + default: + return CMD_RET_FAILURE; + } + + snprintf(msg, LOG_MSG_SZ, "[%s]: Error: %s mapping issue", __func__, + (queried_func_id == FFA_RXTX_MAP ? "FFA_RXTX_MAP" : "FFA_RXTX_UNMAP")); + dm_test_ffa_log(uts, msg); + + return CMD_RET_FAILURE; +} + +static int check_rxbuf_release_flag(u8 rxbuf_owned, struct unit_test_state *uts) +{ + if (rxbuf_owned) { + char msg[LOG_MSG_SZ] = {0}; + + snprintf(msg, LOG_MSG_SZ, "[%s]: Error: RX buffer not released", __func__); + dm_test_ffa_log(uts, msg); + return CMD_RET_FAILURE; + } + return CMD_RET_SUCCESS; +} + +static int test_ffa_msg_send_direct_req(u16 part_id, struct unit_test_state *uts) +{ + struct ffa_interface_data func_data = {0}; + struct ffa_send_direct_data msg = {0}; + u32 pattern = 0xaabbccdd; + u8 cnt; + + /* + * telling the driver which partition to use + */ + func_data.data0_size = sizeof(part_id); + func_data.data0 = &part_id; + + /* + * filling the message data + */ + msg.a3 = pattern; + msg.a4 = pattern; + msg.a5 = pattern; + msg.a6 = pattern; + msg.a7 = pattern; + func_data.data1_size = sizeof(msg); + func_data.data1 = &msg; + + ut_assertok(ffa_helper_msg_send_direct_req(&func_data)); + + for (cnt = 0; cnt < sizeof(struct ffa_send_direct_data) / sizeof(u32); cnt++) + ut_assertok(((u32 *)&msg)[cnt] != 0xffffffff); + + return CMD_RET_SUCCESS; +} + +static int test_partitions_and_comms(union ffa_partition_uuid *service_uuid, + struct sandbox_ffa_prvdata *sdx_prvdata, + struct unit_test_state *uts) +{ + struct ffa_interface_data func_data = {0}; + u32 count = 0; + struct ffa_partition_info *parts_info; + u32 info_idx, exp_info_idx; + int ret; + + /* + * get from the driver the count of the SPs matching the UUID + */ + func_data.data0_size = sizeof(*service_uuid); + func_data.data0 = service_uuid; + func_data.data1_size = sizeof(count); + func_data.data1 = &count; + + ut_assertok(ffa_helper_get_partitions_info(&func_data)); + + /* make sure partitions are detected */ + ut_assertok(!count); + + /* + * pre-allocate a buffer to be filled by the driver + * with ffa_partition_info structs + */ + + parts_info = calloc(count, sizeof(struct ffa_partition_info)); + ut_assertok(!parts_info); + + func_data.data1_size = count * sizeof(struct ffa_partition_info); + func_data.data1 = parts_info; + + /* + * ask the driver to fill the buffer with the SPs info + */ + ret = ffa_helper_get_partitions_info(&func_data); + if (ret != FFA_ERR_STAT_SUCCESS) { + free(parts_info); + ut_assertok(ret != FFA_ERR_STAT_SUCCESS); + } + + /* + * SPs found , verify the partitions information + */ + + ret = CMD_RET_FAILURE; + + for (info_idx = 0; info_idx < count ; info_idx++) { + for (exp_info_idx = 0; + exp_info_idx < sdx_prvdata->partitions.count; + exp_info_idx++) { + if (parts_info[info_idx].id == + sdx_prvdata->partitions.descs[exp_info_idx].info.id) { + ret = memcmp(&parts_info[info_idx], + &sdx_prvdata->partitions.descs[exp_info_idx] + .info, + sizeof(struct ffa_partition_info)); + if (ret) + free(parts_info); + ut_assertok(ret != 0); + /* send and receive data from the current partition */ + test_ffa_msg_send_direct_req(parts_info[info_idx].id, uts); + } + ret = CMD_RET_SUCCESS; + } + } + + free(parts_info); + + /* Verify expected partitions found in the emulated secure world*/ + ut_assertok(ret != CMD_RET_SUCCESS); + + return CMD_RET_SUCCESS; +} + +static int dm_test_ffa_ack(struct unit_test_state *uts) +{ + struct ffa_prvdata *prvdata = NULL; + struct sandbox_ffa_prvdata *sdx_prvdata = NULL; + struct ffa_interface_data func_data = {0}; + u8 rxbuf_flag = 0; + union ffa_partition_uuid svc1_uuid = { .bytes = {SANDBOX_SERVICE1_UUID_DATA}}; + union ffa_partition_uuid svc2_uuid = { .bytes = {SANDBOX_SERVICE2_UUID_DATA}}; + int ret; + + /* get a pointer to the FF-A core and sandbox drivers private data */ + func_data.data0 = &prvdata; + func_data.data0_size = sizeof(prvdata); + func_data.data1 = &sdx_prvdata; + func_data.data1_size = sizeof(sdx_prvdata); + + ut_assertok(sandbox_ffa_helper_query_core_state(FFA_VERSION, &func_data)); + + /* make sure the core private data is cleared before use */ + ut_assertok(check_prvdata_null(prvdata)); + + /* test probing FF-A devices */ + ut_assertok(ffa_helper_init_device()); + ut_assertok(check_dev(prvdata, uts)); + + /* test FFA_VERSION */ + ut_assertok(check_fwk_version(prvdata, uts)); + + /* test FFA_ID_GET */ + ut_assertok(check_endpoint_id(prvdata, uts)); + + /* test FFA_FEATURES */ + ut_assertok(check_features(prvdata, uts)); + + /* test core RX/TX buffers */ + ut_assertok(check_rxtxbuf(prvdata, uts)); + + /* test FFA_RXTX_MAP */ + func_data.data0 = &rxbuf_flag; + func_data.data0_size = sizeof(rxbuf_flag); + + rxbuf_flag = 0; + ut_assertok(sandbox_ffa_helper_query_core_state(FFA_RXTX_MAP, &func_data)); + ut_assertok(check_rxbuf_mapped_flag(FFA_RXTX_MAP, rxbuf_flag, uts)); + + /* FFA_PARTITION_INFO_GET / FFA_MSG_SEND_DIRECT_REQ */ + ret = test_partitions_and_comms(&svc1_uuid, sdx_prvdata, uts); + ut_assertok(ret != CMD_RET_SUCCESS); + + /* test FFA_RX_RELEASE */ + rxbuf_flag = 1; + ut_assertok(sandbox_ffa_helper_query_core_state(FFA_RX_RELEASE, &func_data)); + ut_assertok(check_rxbuf_release_flag(rxbuf_flag, uts)); + + /* FFA_PARTITION_INFO_GET / FFA_MSG_SEND_DIRECT_REQ */ + ret = test_partitions_and_comms(&svc2_uuid, sdx_prvdata, uts); + ut_assertok(ret != CMD_RET_SUCCESS); + + /* test FFA_RX_RELEASE */ + rxbuf_flag = 1; + ut_assertok(sandbox_ffa_helper_query_core_state(FFA_RX_RELEASE, &func_data)); + ut_assertok(check_rxbuf_release_flag(rxbuf_flag, uts)); + + /* test FFA_RXTX_UNMAP */ + ut_assertok(ffa_helper_unmap_rxtx_buffers()); + + rxbuf_flag = 1; + ut_assertok(sandbox_ffa_helper_query_core_state(FFA_RXTX_UNMAP, &func_data)); + ut_assertok(check_rxbuf_mapped_flag(FFA_RXTX_UNMAP, rxbuf_flag, uts)); + + return CMD_RET_SUCCESS; +} + +DM_TEST(dm_test_ffa_ack, UT_TESTF_SCAN_FDT | UT_TESTF_CONSOLE_REC); + +static int dm_test_ffa_nack(struct unit_test_state *uts) +{ + struct ffa_prvdata *prvdata = NULL; + struct sandbox_ffa_prvdata *sdx_prvdata = NULL; + + struct ffa_interface_data func_data = {0}; + union ffa_partition_uuid valid_svc_uuid = { .bytes = {SANDBOX_SERVICE1_UUID_DATA}}; + union ffa_partition_uuid unvalid_svc_uuid = { .bytes = {SANDBOX_SERVICE3_UUID_DATA}}; + struct ffa_send_direct_data msg = {0}; + int ret; + u32 count = 0; + u16 part_id = 0; + + /* get partitions info before probing the core driver */ + func_data.data0_size = sizeof(union ffa_partition_uuid); + func_data.data0 = &unvalid_svc_uuid; + func_data.data1_size = sizeof(count); + func_data.data1 = &count; + + ret = ffa_helper_get_partitions_info(&func_data); + ut_assertok(ret != -ENODEV); + + /* get a pointer to the FF-A core and sandbox drivers private data */ + func_data.data0 = &prvdata; + func_data.data0_size = sizeof(prvdata); + func_data.data1 = &sdx_prvdata; + func_data.data1_size = sizeof(sdx_prvdata); + ut_assertok(sandbox_ffa_helper_query_core_state(FFA_VERSION, &func_data)); + + /* probing FF-A devices */ + ut_assertok(ffa_helper_init_device()); + ut_assertok(check_dev(prvdata, uts)); + + /* query partition info using invalid arguments */ + ret = ffa_helper_get_partitions_info(&func_data); + ut_assertok(ret != -EINVAL); + + /* query partition info using an invalid UUID */ + func_data.data0_size = sizeof(union ffa_partition_uuid); + func_data.data0 = &unvalid_svc_uuid; + func_data.data1_size = sizeof(count); + func_data.data1 = &count; + + ret = ffa_helper_get_partitions_info(&func_data); + ut_assertok(ret != -EPERM); + + /* query partition info using a valid UUID */ + func_data.data0 = &valid_svc_uuid; + count = 0; + ret = ffa_helper_get_partitions_info(&func_data); + /* make sure partitions are detected */ + ut_assertok(ret != FFA_ERR_STAT_SUCCESS); + ut_assertok(!count); + + /* send data to an invalid partition */ + func_data.data0_size = sizeof(part_id); + func_data.data0 = &part_id; + func_data.data1_size = sizeof(msg); + func_data.data1 = &msg; + + ret = ffa_helper_msg_send_direct_req(&func_data); + ut_assertok(ret != -EPERM); + + /* send data to a valid partition */ + part_id = ffa_priv_data.partitions.descs[0].info.id; + ret = ffa_helper_msg_send_direct_req(&func_data); + ut_assertok(ret != FFA_ERR_STAT_SUCCESS); + + return CMD_RET_SUCCESS; +} + +DM_TEST(dm_test_ffa_nack, UT_TESTF_SCAN_FDT | UT_TESTF_CONSOLE_REC); diff --git a/test/dm/ffa.h b/test/dm/ffa.h new file mode 100644 index 0000000000..11c7980fcf --- /dev/null +++ b/test/dm/ffa.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2022 ARM Limited + * Abdellatif El Khlifi + */ + +#ifndef __TEST_DM_FFA_H +#define __TEST_DM_FFA_H + +#define SANDBOX_FWK_VERSION (0x10000) + +#define LOG_MSG_SZ (100) +#define LOG_CMD_SZ (LOG_MSG_SZ * 2) + +/* service 3 UUID binary data (little-endian format) */ +#define SANDBOX_SERVICE3_UUID_DATA \ + 0xfd, 0x42, 0xd5, 0x33, \ + 0x19, 0xa6, 0x42, 0x09, \ + 0x9c, 0xc1, 0x2d, 0x72, \ + 0xcd, 0xd9, 0x98, 0x89 + +#endif /*__TEST_DM_FFA_H */ From patchwork Tue Mar 29 15:16:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abdellatif El Khlifi X-Patchwork-Id: 1610730 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KSZR56h5Xz9sCq for ; Wed, 30 Mar 2022 03:15:13 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 060478401E; Tue, 29 Mar 2022 18:14:52 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=fail (p=none dis=none) header.from=arm.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by phobos.denx.de (Postfix, from userid 109) id A77BC84015; Tue, 29 Mar 2022 17:17:24 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.2 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by phobos.denx.de (Postfix) with ESMTP id 834D684017 for ; Tue, 29 Mar 2022 17:17:20 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=abdellatif.elkhlifi@arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id CF3B614BF; Tue, 29 Mar 2022 08:17:19 -0700 (PDT) Received: from e121910.arm.com (unknown [10.57.40.79]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 9954D3F73B; Tue, 29 Mar 2022 08:17:18 -0700 (PDT) From: abdellatif.elkhlifi@arm.com To: u-boot@lists.denx.de Cc: nd@arm.com, trini@konsulko.com, Abdellatif El Khlifi Subject: [PATCH 5/6] arm_ffa: introduce armffa command Sandbox test Date: Tue, 29 Mar 2022 16:16:58 +0100 Message-Id: <20220329151659.16894-6-abdellatif.elkhlifi@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220329151659.16894-1-abdellatif.elkhlifi@arm.com> References: <20220329151659.16894-1-abdellatif.elkhlifi@arm.com> X-Mailman-Approved-At: Tue, 29 Mar 2022 18:14:45 +0200 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.5 at phobos.denx.de X-Virus-Status: Clean From: Abdellatif El Khlifi Add Sandbox test for the armffa command Signed-off-by: Abdellatif El Khlifi Cc: Tom Rini --- MAINTAINERS | 2 ++ test/cmd/Makefile | 1 + test/cmd/armffa.c | 33 +++++++++++++++++++++++++++++++++ test/cmd/armffa.h | 13 +++++++++++++ 4 files changed, 49 insertions(+) create mode 100644 test/cmd/armffa.c create mode 100644 test/cmd/armffa.h diff --git a/MAINTAINERS b/MAINTAINERS index 52274b2fac..9828095837 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -242,6 +242,8 @@ F: include/arm_ffa_helper.h F: include/sandbox_arm_ffa.h F: include/sandbox_arm_ffa_helper.h F: lib/arm-ffa/ +F: test/cmd/armffa.c +F: test/cmd/armffa.h F: test/dm/ffa.c F: test/dm/ffa.h diff --git a/test/cmd/Makefile b/test/cmd/Makefile index a59adb1e6d..d9dc0809d6 100644 --- a/test/cmd/Makefile +++ b/test/cmd/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_CMD_MEM_SEARCH) += mem_search.o obj-$(CONFIG_CMD_PINMUX) += pinmux.o obj-$(CONFIG_CMD_PWM) += pwm.o obj-$(CONFIG_CMD_SETEXPR) += setexpr.o +obj-$(CONFIG_SANDBOX_FFA) += armffa.o diff --git a/test/cmd/armffa.c b/test/cmd/armffa.c new file mode 100644 index 0000000000..d35032047b --- /dev/null +++ b/test/cmd/armffa.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for armffa command + * + * (C) Copyright 2022 ARM Limited + * Abdellatif El Khlifi + */ + +#include "armffa.h" +#include +#include +#include +#include +#include + +/* Basic test of 'armffa' command */ +static int dm_test_armffa_cmd(struct unit_test_state *uts) +{ + ut_assertok(ffa_helper_init_device()); + + /* armffa getpart */ + ut_assertok(run_command("armffa getpart " SE_PROXY_PARTITION_UUID, 0)); + + /* armffa ping */ + ut_assertok(run_command("armffa ping " SE_PROXY_PARTITION_ID, 0)); + + /* armffa devlist */ + ut_assertok(run_command("armffa devlist", 0)); + + return CMD_RET_SUCCESS; +} + +DM_TEST(dm_test_armffa_cmd, UT_TESTF_SCAN_FDT | UT_TESTF_CONSOLE_REC); diff --git a/test/cmd/armffa.h b/test/cmd/armffa.h new file mode 100644 index 0000000000..630dc75e25 --- /dev/null +++ b/test/cmd/armffa.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * (C) Copyright 2022 ARM Limited + * Abdellatif El Khlifi + */ + +#ifndef __TEST_CMD_FFA_H +#define __TEST_CMD_FFA_H + +#define SE_PROXY_PARTITION_ID "0x1245" +#define SE_PROXY_PARTITION_UUID "33d532ed-e699-0942-c09c-a798d9cd722d" + +#endif /*__TEST_CMD_FFA_H */ From patchwork Tue Mar 29 15:16:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Abdellatif El Khlifi X-Patchwork-Id: 1610733 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4KSZRq30tTz9sCq for ; Wed, 30 Mar 2022 03:15:51 +1100 (AEDT) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id BE27684030; Tue, 29 Mar 2022 18:15:02 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=fail (p=none dis=none) header.from=arm.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by phobos.denx.de (Postfix, from userid 109) id 94FC38400A; Tue, 29 Mar 2022 17:17:29 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.2 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by phobos.denx.de (Postfix) with ESMTP id 4839E84013 for ; Tue, 29 Mar 2022 17:17:22 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=abdellatif.elkhlifi@arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 8EEA023A; Tue, 29 Mar 2022 08:17:21 -0700 (PDT) Received: from e121910.arm.com (unknown [10.57.40.79]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 440413F73B; Tue, 29 Mar 2022 08:17:20 -0700 (PDT) From: abdellatif.elkhlifi@arm.com To: u-boot@lists.denx.de Cc: nd@arm.com, trini@konsulko.com, Abdellatif El Khlifi , Gowtham Suresh Kumar Subject: [PATCH 6/6] arm_ffa: introduce FF-A MM communication Date: Tue, 29 Mar 2022 16:16:59 +0100 Message-Id: <20220329151659.16894-7-abdellatif.elkhlifi@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20220329151659.16894-1-abdellatif.elkhlifi@arm.com> References: <20220329151659.16894-1-abdellatif.elkhlifi@arm.com> X-Mailman-Approved-At: Tue, 29 Mar 2022 18:14:45 +0200 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.5 at phobos.denx.de X-Virus-Status: Clean From: Abdellatif El Khlifi Add MM communication support using FF-A transport FF-A MM communication allows exchanging data with StandAlonneMM or smm-gateway secure partitions which run in OP-TEE. An MM shared buffer and a door bell event are used to exchange this data. The data is used by EFI services such as GetVariable()/SetVariable() and copied from the communication buffer to the MM shared buffer. The secure partition is notified about availability of data in the MM shared buffer by an FF-A message (door bell). On such event, MM SP can read the data and updates the MM shared buffer with the response data. The response data is copied back to the communication buffer and consumed by the EFI subsystem. Signed-off-by: Abdellatif El Khlifi Signed-off-by: Gowtham Suresh Kumar Cc: Tom Rini --- arch/arm/cpu/armv8/cache.S | 16 ++ arch/arm/cpu/armv8/cache_v8.c | 3 +- include/mm_communication.h | 4 +- lib/efi_loader/Kconfig | 14 +- lib/efi_loader/efi_variable_tee.c | 294 +++++++++++++++++++++++++++++- 5 files changed, 321 insertions(+), 10 deletions(-) diff --git a/arch/arm/cpu/armv8/cache.S b/arch/arm/cpu/armv8/cache.S index d1cee23437..bdbe89e0c5 100644 --- a/arch/arm/cpu/armv8/cache.S +++ b/arch/arm/cpu/armv8/cache.S @@ -21,7 +21,11 @@ * x1: 0 clean & invalidate, 1 invalidate only * x2~x9: clobbered */ +#ifdef CONFIG_ARM_FFA_TRANSPORT +.pushsection .text.efi_runtime, "ax" +#else .pushsection .text.__asm_dcache_level, "ax" +#endif ENTRY(__asm_dcache_level) lsl x12, x0, #1 msr csselr_el1, x12 /* select cache level */ @@ -65,7 +69,11 @@ ENDPROC(__asm_dcache_level) * * flush or invalidate all data cache by SET/WAY. */ +#ifdef CONFIG_ARM_FFA_TRANSPORT +.pushsection .text.efi_runtime, "ax" +#else .pushsection .text.__asm_dcache_all, "ax" +#endif ENTRY(__asm_dcache_all) mov x1, x0 dsb sy @@ -109,7 +117,11 @@ ENTRY(__asm_flush_dcache_all) ENDPROC(__asm_flush_dcache_all) .popsection +#ifdef CONFIG_ARM_FFA_TRANSPORT +.pushsection .text.efi_runtime, "ax" +#else .pushsection .text.__asm_invalidate_dcache_all, "ax" +#endif ENTRY(__asm_invalidate_dcache_all) mov x0, #0x1 b __asm_dcache_all @@ -182,7 +194,11 @@ ENTRY(__asm_invalidate_icache_all) ENDPROC(__asm_invalidate_icache_all) .popsection +#ifdef CONFIG_ARM_FFA_TRANSPORT +.pushsection .text.efi_runtime, "ax" +#else .pushsection .text.__asm_invalidate_l3_dcache, "ax" +#endif WEAK(__asm_invalidate_l3_dcache) mov x0, #0 /* return status as success */ ret diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c index 3de18c7675..187a4497a7 100644 --- a/arch/arm/cpu/armv8/cache_v8.c +++ b/arch/arm/cpu/armv8/cache_v8.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -425,7 +426,7 @@ __weak void mmu_setup(void) /* * Performs a invalidation of the entire data cache at all levels */ -void invalidate_dcache_all(void) +void __efi_runtime invalidate_dcache_all(void) { __asm_invalidate_dcache_all(); __asm_invalidate_l3_dcache(); diff --git a/include/mm_communication.h b/include/mm_communication.h index e65fbde60d..bb99190956 100644 --- a/include/mm_communication.h +++ b/include/mm_communication.h @@ -123,7 +123,7 @@ struct __packed efi_mm_communicate_header { * * Defined in EDK2 as SMM_VARIABLE_COMMUNICATE_HEADER. */ -struct smm_variable_communicate_header { +struct __packed smm_variable_communicate_header { efi_uintn_t function; efi_status_t ret_status; u8 data[]; @@ -145,7 +145,7 @@ struct smm_variable_communicate_header { * Defined in EDK2 as SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE. * */ -struct smm_variable_access { +struct __packed smm_variable_access { efi_guid_t guid; efi_uintn_t data_size; efi_uintn_t name_size; diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 28657f50c9..0d69133595 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -55,13 +55,23 @@ config EFI_VARIABLE_FILE_STORE stored as file /ubootefi.var on the EFI system partition. config EFI_MM_COMM_TEE - bool "UEFI variables storage service via OP-TEE" - depends on OPTEE + bool "UEFI variables storage service via the trusted world" + depends on OPTEE || ARM_FFA_TRANSPORT help + The MM SP (also called partition) can be StandAlonneMM or smm-gateway. + When using the u-boot OP-TEE driver, StandAlonneMM is supported. + When using the u-boot FF-A driver, StandAlonneMM and smm-gateway are supported. + If OP-TEE is present and running StandAloneMM, dispatch all UEFI variable related operations to that. The application will verify, authenticate and store the variables on an RPMB. + When ARM_FFA_TRANSPORT is used, dispatch all UEFI variable related + operations to the MM SP running under Optee in the trusted world. + A door bell mechanism is used to notify the SP when there is data in the shared + MM buffer. The data is copied by u-boot to the shared buffer before issuing + the door bell event. + endchoice config EFI_VARIABLES_PRESEED diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c index dfef18435d..3d01985662 100644 --- a/lib/efi_loader/efi_variable_tee.c +++ b/lib/efi_loader/efi_variable_tee.c @@ -15,6 +15,53 @@ #include #include +#if (IS_ENABLED(CONFIG_ARM_FFA_TRANSPORT)) + +#include +#include +#include + +#ifndef FFA_SHARED_MM_BUFFER_SIZE + +#include +#define FFA_SHARED_MM_BUFFER_SIZE SZ_4K /* 4 KB */ + +#endif + +#ifndef FFA_SHARED_MM_BUFFER_ADDR + +/* + * shared buffer physical address used for communication between + * u-boot and the MM SP + */ +#define FFA_SHARED_MM_BUFFER_ADDR (0x023F8000) + +#endif + +/* MM return codes */ +#define MM_SUCCESS (0) + +#define ARM_SVC_ID_SP_EVENT_COMPLETE_AARCH64 (0xC4000061) +#define ARM_SVC_ID_SP_EVENT_COMPLETE ARM_SVC_ID_SP_EVENT_COMPLETE_AARCH64 + +#ifndef MM_SP_UUID_DATA + +/* MM SP UUID binary data (little-endian format) */ +#define MM_SP_UUID_DATA \ + 0xed, 0x32, 0xd5, 0x33, \ + 0x99, 0xe6, 0x42, 0x09, \ + 0x9c, 0xc0, 0x2d, 0x72, \ + 0xcd, 0xd9, 0x98, 0xa7 + +#endif + +/* MM_SP_UUID_DATA defined by the platform */ +union ffa_partition_uuid mm_sp_svc_uuid = {.bytes = {MM_SP_UUID_DATA}}; + +static __efi_runtime_data 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 */ static efi_uintn_t max_payload_size; /* func + data */ @@ -24,6 +71,7 @@ struct mm_connection { u32 session; }; +#if (IS_ENABLED(CONFIG_OPTEE)) /** * get_connection() - Retrieve OP-TEE session for a specific UUID. * @@ -143,16 +191,238 @@ static efi_status_t optee_mm_communicate(void *comm_buf, ulong dsize) return ret; } +#endif + +#if (IS_ENABLED(CONFIG_ARM_FFA_TRANSPORT)) + +/** + * ffa_notify_mm_sp() - Announce there is data in the shared buffer + * + * Notifies 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 __efi_runtime ffa_notify_mm_sp(void) +{ + struct ffa_interface_data func_data = {0}; + struct ffa_send_direct_data msg = {0}; + int ret; + u32 sp_event_complete; + int sp_event_ret; + + func_data.data0_size = sizeof(mm_sp_id); + func_data.data0 = &mm_sp_id; + + msg.a3 = FFA_SHARED_MM_BUFFER_ADDR; + msg.a4 = FFA_SHARED_MM_BUFFER_SIZE; + func_data.data1_size = sizeof(msg); + func_data.data1 = &msg; + + ret = ffa_helper_msg_send_direct_req(&func_data); + if (ret != FFA_ERR_STAT_SUCCESS) + return ret; + + sp_event_complete = msg.a3; + sp_event_ret = (int)msg.a4; + + if (sp_event_complete == ARM_SVC_ID_SP_EVENT_COMPLETE && sp_event_ret == MM_SUCCESS) + return 0; + + /* + * Failure to notify the MM SP + */ + + return -EACCES; +} + +/** + * 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) +{ + struct ffa_interface_data func_data = {0}; + u32 count = 0; + int ret; + struct ffa_partition_info *parts_info; + + /* + * get from the driver the count of the SPs matching the UUID + */ + func_data.data0_size = sizeof(mm_sp_svc_uuid); + func_data.data0 = &mm_sp_svc_uuid; + func_data.data1_size = sizeof(count); + func_data.data1 = &count; + + ret = ffa_helper_get_partitions_info(&func_data); + if (ret != FFA_ERR_STAT_SUCCESS) { + log_err("EFI: Failure in querying partitions count (error code: %d)\n", ret); + return ret; + } + + if (!count) { + log_info("EFI: No MM partition found\n"); + return ret; + } + + /* + * pre-allocate a buffer to be filled by the driver + * with ffa_partition_info structs + */ + + parts_info = calloc(count, sizeof(struct ffa_partition_info)); + if (!parts_info) + return -EINVAL; + + log_info("EFI: Pre-allocating %d partition(s) info structures\n", count); + + func_data.data1_size = count * + sizeof(struct ffa_partition_info); + func_data.data1 = parts_info; + + /* + * ask the driver to fill the + * buffer with the SPs info + */ + ret = ffa_helper_get_partitions_info(&func_data); + if (ret != FFA_ERR_STAT_SUCCESS) { + log_err("EFI: Failure in querying partition(s) info (error code: %d)\n", ret); + free(parts_info); + return ret; + } + + /* + * MM SPs found , use the first one + */ + + mm_sp_id = parts_info[0].id; + + log_info("EFI: MM partition ID 0x%x\n", mm_sp_id); + + free(parts_info); + + 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 + * + * Issues 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 __efi_runtime ffa_mm_communicate(void *comm_buf, ulong comm_buf_size) +{ + ulong tx_data_size; + int ffa_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() != FFA_ERR_STAT_SUCCESS) { + log_err("EFI: Failure to discover MM partition ID at boot time\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 > FFA_SHARED_MM_BUFFER_SIZE) + return EFI_INVALID_PARAMETER; + + /* Copy the data to the shared buffer */ + + virt_shared_buf = (void *)map_sysmem((phys_addr_t)FFA_SHARED_MM_BUFFER_ADDR, 0); + efi_memcpy_runtime(virt_shared_buf, comm_buf, tx_data_size); + + /* + * The secure world has cache disabled for device region which we use for shared buffer. + * So, 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(); + if (ffa_ret) + unmap_sysmem(virt_shared_buf); + + 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_memcpy_runtime(comm_buf, virt_shared_buf, comm_buf_size); + unmap_sysmem(virt_shared_buf); + return EFI_BUFFER_TOO_SMALL; + } + + efi_memcpy_runtime(comm_buf, virt_shared_buf, rx_data_size); + unmap_sysmem(virt_shared_buf); + + return EFI_SUCCESS; + } + case -EINVAL: + return EFI_DEVICE_ERROR; + case -EPERM: + return EFI_INVALID_PARAMETER; + case -EACCES: + return EFI_ACCESS_DENIED; + case -EBUSY: + return EFI_OUT_OF_RESOURCES; + default: + return EFI_ACCESS_DENIED; + } +} +#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 MM SP (also called partition) can be 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, StandAlonneMM and smm-gateway are supported. + * * Return: status code */ -static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize) +static efi_status_t __efi_runtime mm_communicate(u8 *comm_buf, efi_uintn_t dsize) { efi_status_t ret; struct efi_mm_communicate_header *mm_hdr; @@ -162,9 +432,16 @@ static efi_status_t mm_communicate(u8 *comm_buf, efi_uintn_t dsize) mm_hdr = (struct efi_mm_communicate_header *)comm_buf; var_hdr = (struct smm_variable_communicate_header *)mm_hdr->data; + #if (IS_ENABLED(CONFIG_OPTEE)) ret = optee_mm_communicate(comm_buf, dsize); + #elif (IS_ENABLED(CONFIG_ARM_FFA_TRANSPORT)) + ret = ffa_mm_communicate(comm_buf, dsize); + #endif if (ret != EFI_SUCCESS) { - log_err("%s failed!\n", __func__); + /* No need for showing a log here. mm_communicate failure happens + * when getVariable() is called with data size set to 0. + * This is not expected so no log shown. + */ return ret; } @@ -258,6 +535,13 @@ efi_status_t EFIAPI get_max_payload(efi_uintn_t *size) goto out; } *size = var_payload->size; + + #if (IS_ENABLED(CONFIG_ARM_FFA_TRANSPORT)) + if (*size > FFA_SHARED_MM_BUFFER_SIZE) + *size = FFA_SHARED_MM_BUFFER_SIZE - MM_COMMUNICATE_HEADER_SIZE - + MM_VARIABLE_COMMUNICATE_SIZE; + #endif + /* * There seems to be a bug in EDK2 miscalculating the boundaries and * size checks, so deduct 2 more bytes to fulfill this requirement. Fix @@ -697,7 +981,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); /*