Merge branch '2023-07-24-introduce-FF-A-suppport'

To quote the author:
Adding support for Arm FF-A v1.0 (Arm Firmware Framework for Armv8-A) [A].

FF-A specifies interfaces that enable a pair of software execution
environments aka partitions to communicate with each other. A partition
could be a VM in the Normal or Secure world, an application in S-EL0, or
a Trusted OS in S-EL1.

FF-A is a discoverable bus and similar to architecture features.
FF-A bus is discovered using ARM_SMCCC_FEATURES mechanism performed
by the PSCI driver.

   => dm tree

    Class     Index  Probed  Driver                Name
   -----------------------------------------------------------
   ...
    firmware      0  [ + ]   psci                      |-- psci
    ffa                   0  [   ]   arm_ffa               |   `-- arm_ffa
   ...

Clients are able to probe then use the FF-A bus by calling the DM class
searching APIs (e.g: uclass_first_device).

This implementation of the specification provides support for Aarch64.

The FF-A driver uses the SMC ABIs defined by the FF-A specification to:

    - Discover the presence of secure partitions (SPs) of interest
    - Access an SP's service through communication protocols
      (e.g: EFI MM communication protocol)

The FF-A support provides the following features:

    - Being generic by design and can be used by any Arm 64-bit platform
    - FF-A support can be compiled and used without EFI
    - Support for SMCCCv1.2 x0-x17 registers
    - Support for SMC32 calling convention
    - Support for 32-bit and 64-bit FF-A direct messaging
    - Support for FF-A MM communication (compatible with EFI boot time)
    - Enabling FF-A and MM communication in Corstone1000 platform as a use case
    - A Uclass driver providing generic FF-A methods.
    - An Arm FF-A device driver providing Arm-specific methods and
      reusing the Uclass methods.
    - A sandbox emulator for Arm FF-A, emulates the FF-A side of the
      Secure World and provides FF-A ABIs inspection methods.
    - An FF-A sandbox device driver for FF-A communication with the
      emulated Secure World.  The driver leverages the FF-A Uclass to
      establish FF-A communication.
    - Sandbox FF-A test cases.
    - A new command called armffa is provided as an example of how to
      access the FF-A bus

For more details about the FF-A support please refer to [B] and refer to [C] for
how to use the armffa command.

Please find at [D] an example of the expected boot logs when enabling
FF-A support for a platform. In this example the platform is
Corstone1000. But it can be any Arm 64-bit platform.

[A]: https://developer.arm.com/documentation/den0077/latest/
[B]: doc/arch/arm64.ffa.rst
[C]: doc/usage/cmd/armffa.rst
[D]: example of boot logs when enabling FF-A
This commit is contained in:
Tom Rini 2023-07-24 18:58:22 -04:00
commit d927d1a808
41 changed files with 4158 additions and 9 deletions

View file

@ -266,6 +266,19 @@ F: drivers/net/cortina_ni.h
F: drivers/net/phy/ca_phy.c
F: configs/cortina_presidio-asic-pnand_defconfig
ARM FF-A
M: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
S: Maintained
F: arch/sandbox/include/asm/sandbox_arm_ffa.h
F: arch/sandbox/include/asm/sandbox_arm_ffa_priv.h
F: cmd/armffa.c
F: doc/arch/arm64.ffa.rst
F: doc/usage/cmd/armffa.rst
F: drivers/firmware/arm-ffa/
F: include/arm_ffa.h
F: test/cmd/armffa.c
F: test/dm/ffa.c
ARM FREESCALE IMX
M: Stefano Babic <sbabic@denx.de>
M: Fabio Estevam <festevam@gmail.com>
@ -1634,3 +1647,8 @@ S: Maintained
F: arch/arm/dts/ls1021a-twr-u-boot.dtsi
F: drivers/crypto/fsl/
F: include/fsl_sec.h
UUID testing
M: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
S: Maintained
F: test/lib/uuid.c

View file

@ -1,7 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2015, Linaro Limited
*/
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#include <linux/linkage.h>
#include <linux/arm-smccc.h>
#include <generated/asm-offsets.h>
@ -45,3 +49,54 @@ ENDPROC(__arm_smccc_smc)
ENTRY(__arm_smccc_hvc)
SMCCC hvc
ENDPROC(__arm_smccc_hvc)
#ifdef CONFIG_ARM64
.macro SMCCC_1_2 instr
/* Save `res` and free a GPR that won't be clobbered */
stp x1, x19, [sp, #-16]!
/* Ensure `args` won't be clobbered while loading regs in next step */
mov x19, x0
/* Load the registers x0 - x17 from the struct arm_smccc_1_2_regs */
ldp x0, x1, [x19, #ARM_SMCCC_1_2_REGS_X0_OFFS]
ldp x2, x3, [x19, #ARM_SMCCC_1_2_REGS_X2_OFFS]
ldp x4, x5, [x19, #ARM_SMCCC_1_2_REGS_X4_OFFS]
ldp x6, x7, [x19, #ARM_SMCCC_1_2_REGS_X6_OFFS]
ldp x8, x9, [x19, #ARM_SMCCC_1_2_REGS_X8_OFFS]
ldp x10, x11, [x19, #ARM_SMCCC_1_2_REGS_X10_OFFS]
ldp x12, x13, [x19, #ARM_SMCCC_1_2_REGS_X12_OFFS]
ldp x14, x15, [x19, #ARM_SMCCC_1_2_REGS_X14_OFFS]
ldp x16, x17, [x19, #ARM_SMCCC_1_2_REGS_X16_OFFS]
\instr #0
/* Load the `res` from the stack */
ldr x19, [sp]
/* Store the registers x0 - x17 into the result structure */
stp x0, x1, [x19, #ARM_SMCCC_1_2_REGS_X0_OFFS]
stp x2, x3, [x19, #ARM_SMCCC_1_2_REGS_X2_OFFS]
stp x4, x5, [x19, #ARM_SMCCC_1_2_REGS_X4_OFFS]
stp x6, x7, [x19, #ARM_SMCCC_1_2_REGS_X6_OFFS]
stp x8, x9, [x19, #ARM_SMCCC_1_2_REGS_X8_OFFS]
stp x10, x11, [x19, #ARM_SMCCC_1_2_REGS_X10_OFFS]
stp x12, x13, [x19, #ARM_SMCCC_1_2_REGS_X12_OFFS]
stp x14, x15, [x19, #ARM_SMCCC_1_2_REGS_X14_OFFS]
stp x16, x17, [x19, #ARM_SMCCC_1_2_REGS_X16_OFFS]
/* Restore original x19 */
ldp xzr, x19, [sp], #16
ret
.endm
/*
* void arm_smccc_1_2_smc(const struct arm_smccc_1_2_regs *args,
* struct arm_smccc_1_2_regs *res);
*/
ENTRY(arm_smccc_1_2_smc)
SMCCC_1_2 smc
ENDPROC(arm_smccc_1_2_smc)
#endif

View file

@ -9,6 +9,11 @@
* generate asm statements containing #defines,
* compile this file to assembler, and then extract the
* #defines from the assembly-language output.
*
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#include <common.h>
@ -90,6 +95,17 @@ int main(void)
DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2));
DEFINE(ARM_SMCCC_QUIRK_ID_OFFS, offsetof(struct arm_smccc_quirk, id));
DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS, offsetof(struct arm_smccc_quirk, state));
#ifdef CONFIG_ARM64
DEFINE(ARM_SMCCC_1_2_REGS_X0_OFFS, offsetof(struct arm_smccc_1_2_regs, a0));
DEFINE(ARM_SMCCC_1_2_REGS_X2_OFFS, offsetof(struct arm_smccc_1_2_regs, a2));
DEFINE(ARM_SMCCC_1_2_REGS_X4_OFFS, offsetof(struct arm_smccc_1_2_regs, a4));
DEFINE(ARM_SMCCC_1_2_REGS_X6_OFFS, offsetof(struct arm_smccc_1_2_regs, a6));
DEFINE(ARM_SMCCC_1_2_REGS_X8_OFFS, offsetof(struct arm_smccc_1_2_regs, a8));
DEFINE(ARM_SMCCC_1_2_REGS_X10_OFFS, offsetof(struct arm_smccc_1_2_regs, a10));
DEFINE(ARM_SMCCC_1_2_REGS_X12_OFFS, offsetof(struct arm_smccc_1_2_regs, a12));
DEFINE(ARM_SMCCC_1_2_REGS_X14_OFFS, offsetof(struct arm_smccc_1_2_regs, a14));
DEFINE(ARM_SMCCC_1_2_REGS_X16_OFFS, offsetof(struct arm_smccc_1_2_regs, a16));
#endif
#endif
return 0;

View file

@ -451,6 +451,15 @@
thermal {
compatible = "sandbox,thermal";
};
arm-ffa-emul {
compatible = "sandbox,arm-ffa-emul";
sandbox-arm-ffa {
compatible = "sandbox,arm-ffa";
};
};
};
&cros_ec {

View file

@ -1831,6 +1831,14 @@
extcon {
compatible = "sandbox,extcon";
};
arm-ffa-emul {
compatible = "sandbox,arm-ffa-emul";
sandbox-arm-ffa {
compatible = "sandbox,arm-ffa";
};
};
};
#include "sandbox_pmic.dtsi"

View file

@ -0,0 +1,72 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#ifndef __SANDBOX_ARM_FFA_H
#define __SANDBOX_ARM_FFA_H
#include <arm_ffa.h>
/*
* This header provides public sandbox FF-A emulator declarations
* and declarations needed by FF-A sandbox clients
*/
/* UUIDs strings of the emulated services */
#define SANDBOX_SERVICE1_UUID "ed32d533-4209-99e6-2d72-cdd998a79cc0"
#define SANDBOX_SERVICE2_UUID "ed32d544-4209-99e6-2d72-cdd998a79cc0"
/* IDs of the emulated secure partitions (SPs) */
#define SANDBOX_SP1_ID 0x1245
#define SANDBOX_SP2_ID 0x9836
#define SANDBOX_SP3_ID 0x6452
#define SANDBOX_SP4_ID 0x7814
/* Invalid service UUID (no matching SP) */
#define SANDBOX_SERVICE3_UUID "55d532ed-0942-e699-722d-c09ca798d9cd"
/* Invalid service UUID (invalid UUID string format) */
#define SANDBOX_SERVICE4_UUID "32ed-0942-e699-722d-c09ca798d9cd"
/* Number of valid services */
#define SANDBOX_SP_COUNT_PER_VALID_SERVICE 2
/**
* struct ffa_sandbox_data - query ABI state data structure
* @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
*
* Used to pass various types of data with different sizes between
* the test cases and the sandbox emulator.
* The data is for querying FF-A ABIs state.
*/
struct ffa_sandbox_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 */
};
/* The sandbox FF-A emulator public functions */
/**
* sandbox_query_ffa_emul_state() - Inspect the FF-A ABIs
* @queried_func_id: The FF-A function to be queried
* @func_data: Pointer to the FF-A function arguments container structure
*
* Query the status of FF-A ABI specified in the input argument.
*
* Return:
*
* 0 on success. Otherwise, failure
*/
int sandbox_query_ffa_emul_state(u32 queried_func_id,
struct ffa_sandbox_data *func_data);
#endif

View file

@ -0,0 +1,121 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#ifndef __SANDBOX_ARM_FFA_PRV_H
#define __SANDBOX_ARM_FFA_PRV_H
#include <arm_ffa_priv.h>
/* This header is exclusively used by the Sandbox FF-A driver and emulator */
/* 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 */
/* x1-x7 MBZ */
#define FFA_X1X7_MBZ_CNT (7)
#define FFA_X1X7_MBZ_REG_START (&res->a1)
/* x4-x7 MBZ */
#define FFA_X4X7_MBZ_CNT (4)
#define FFA_X4X7_MBZ_REG_START (&res->a4)
/* x3-x7 MBZ */
#define FFA_X3X7_MBZ_CNT (5)
#define FFA_X3_MBZ_REG_START (&res->a3)
/* number of emulated FF-A secure partitions (SPs) */
#define SANDBOX_PARTITIONS_CNT (4)
/* Binary data of the emulated services UUIDs */
/* service 1 UUID binary data (little-endian format) */
#define SANDBOX_SERVICE1_UUID_A1 0xed32d533
#define SANDBOX_SERVICE1_UUID_A2 0x99e64209
#define SANDBOX_SERVICE1_UUID_A3 0x9cc02d72
#define SANDBOX_SERVICE1_UUID_A4 0xcdd998a7
/* service 2 UUID binary data (little-endian format) */
#define SANDBOX_SERVICE2_UUID_A1 0xed32d544
#define SANDBOX_SERVICE2_UUID_A2 0x99e64209
#define SANDBOX_SERVICE2_UUID_A3 0x9cc02d72
#define SANDBOX_SERVICE2_UUID_A4 0xcdd998a7
/**
* struct ffa_rxtxpair_info - structure hosting the RX/TX buffers flags
* @rxbuf_owned: RX buffer ownership flag (the owner is non secure world)
* @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
*
* Hosts 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_emul - emulator data
*
* @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
* @test_ffa_data: The data of the FF-A bus under test
*
* Hosts all the emulated secure world data.
*/
struct sandbox_ffa_emul {
u32 fwk_version;
u16 id;
struct ffa_partitions partitions;
struct ffa_rxtxpair pair;
struct ffa_rxtxpair_info pair_info;
};
/**
* ffa_emul_find() - Finds the FF-A emulator
* @dev: the sandbox FF-A device (sandbox-arm-ffa)
* @emulp: the FF-A emulator device (sandbox-ffa-emul)
* Return:
* 0 on success. Otherwise, failure
*/
int ffa_emul_find(struct udevice *dev, struct udevice **emulp);
#endif

View file

@ -952,6 +952,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 FF-A support
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"

View file

@ -12,6 +12,7 @@ obj-y += panic.o
obj-y += version.o
# command
obj-$(CONFIG_CMD_ARMFFA) += armffa.o
obj-$(CONFIG_CMD_2048) += 2048.o
obj-$(CONFIG_CMD_ACPI) += acpi.o
obj-$(CONFIG_CMD_ADDRMAP) += addrmap.o

202
cmd/armffa.c Normal file
View file

@ -0,0 +1,202 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#include <common.h>
#include <arm_ffa.h>
#include <command.h>
#include <dm.h>
#include <mapmem.h>
#include <stdlib.h>
#include <asm/io.h>
/* Select the right physical address formatting according to the platform */
#ifdef CONFIG_PHYS_64BIT
#define PhysAddrLength "ll"
#else
#define PhysAddrLength ""
#endif
#define PHYS_ADDR_LN "%" PhysAddrLength "x"
/**
* ffa_get_dev() - Return the FF-A device
* @devp: pointer to the FF-A device
*
* Search for the FF-A device.
*
* Return:
* 0 on success. Otherwise, failure
*/
static int ffa_get_dev(struct udevice **devp)
{
int ret;
ret = uclass_first_device_err(UCLASS_FFA, devp);
if (ret) {
log_err("Cannot find FF-A bus device\n");
return ret;
}
return 0;
}
/**
* do_ffa_getpart() - implementation of the getpart subcommand
* @cmdtp: Command Table
* @flag: flags
* @argc: number of arguments
* @argv: arguments
*
* Query a secure partition information. The secure partition UUID is provided
* as an argument. The function uses the arm_ffa driver
* partition_info_get operation which implements FFA_PARTITION_INFO_GET
* ABI 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_getpart(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
u32 count = 0;
int ret;
struct ffa_partition_desc *descs;
u32 i;
struct udevice *dev;
if (argc != 2) {
log_err("Missing argument\n");
return CMD_RET_USAGE;
}
ret = ffa_get_dev(&dev);
if (ret)
return CMD_RET_FAILURE;
/* Ask the driver to fill the buffer with the SPs info */
ret = ffa_partition_info_get(dev, argv[1], &count, &descs);
if (ret) {
log_err("Failure in querying partition(s) info (error code: %d)\n", ret);
return CMD_RET_FAILURE;
}
/* SPs found , show the partition information */
for (i = 0; i < count ; i++) {
log_info("Partition: id = %x , exec_ctxt %x , properties %x\n",
descs[i].info.id,
descs[i].info.exec_ctxt,
descs[i].info.properties);
}
return CMD_RET_SUCCESS;
}
/**
* do_ffa_ping() - implementation of the ping subcommand
* @cmdtp: Command Table
* @flag: flags
* @argc: number of arguments
* @argv: arguments
*
* Send data to a secure partition. The secure partition UUID is provided
* as an argument. Use the arm_ffa driver sync_send_receive operation
* which implements FFA_MSG_SEND_DIRECT_{REQ,RESP} ABIs to send/receive data.
*
* Return:
*
* CMD_RET_SUCCESS: on success, otherwise failure
*/
static int do_ffa_ping(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
struct ffa_send_direct_data msg = {
.data0 = 0xaaaaaaaa,
.data1 = 0xbbbbbbbb,
.data2 = 0xcccccccc,
.data3 = 0xdddddddd,
.data4 = 0xeeeeeeee,
};
u16 part_id;
int ret;
struct udevice *dev;
if (argc != 2) {
log_err("Missing argument\n");
return CMD_RET_USAGE;
}
part_id = strtoul(argv[1], NULL, 16);
if (!part_id) {
log_err("Partition ID can not be 0\n");
return CMD_RET_USAGE;
}
ret = ffa_get_dev(&dev);
if (ret)
return CMD_RET_FAILURE;
ret = ffa_sync_send_receive(dev, part_id, &msg, 1);
if (!ret) {
u8 cnt;
log_info("SP response:\n[LSB]\n");
for (cnt = 0;
cnt < sizeof(struct ffa_send_direct_data) / sizeof(u64);
cnt++)
log_info("%llx\n", ((u64 *)&msg)[cnt]);
return CMD_RET_SUCCESS;
}
log_err("Sending direct request error (%d)\n", ret);
return CMD_RET_FAILURE;
}
/**
*do_ffa_devlist() - implementation of the devlist subcommand
* @cmdtp: [in] Command Table
* @flag: flags
* @argc: number of arguments
* @argv: arguments
*
* Query the device belonging to the UCLASS_FFA
* class.
*
* Return:
*
* CMD_RET_SUCCESS: on success, otherwise failure
*/
static int do_ffa_devlist(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
struct udevice *dev;
int ret;
ret = ffa_get_dev(&dev);
if (ret)
return CMD_RET_FAILURE;
log_info("device %s, addr " PHYS_ADDR_LN ", driver %s, ops " PHYS_ADDR_LN "\n",
dev->name,
map_to_sysmem(dev),
dev->driver->name,
map_to_sysmem(dev->driver->ops));
return CMD_RET_SUCCESS;
}
static char armffa_help_text[] =
"getpart <partition UUID>\n"
" - lists the partition(s) info\n"
"ping <partition ID>\n"
" - sends a data pattern to the specified partition\n"
"devlist\n"
" - displays information about the FF-A device/driver\n";
U_BOOT_CMD_WITH_SUBCMDS(armffa, "Arm FF-A test command", armffa_help_text,
U_BOOT_SUBCMD_MKENT(getpart, 2, 1, do_ffa_getpart),
U_BOOT_SUBCMD_MKENT(ping, 2, 1, do_ffa_ping),
U_BOOT_SUBCMD_MKENT(devlist, 1, 1, do_ffa_devlist));

View file

@ -64,3 +64,7 @@ CONFIG_EFI_CAPSULE_ON_DISK=y
CONFIG_EFI_IGNORE_OSINDICATIONS=y
CONFIG_FWU_MULTI_BANK_UPDATE=y
CONFIG_ERRNO_STR=y
CONFIG_EFI_MM_COMM_TEE=y
CONFIG_FFA_SHARED_MM_BUF_SIZE=4096
CONFIG_FFA_SHARED_MM_BUF_OFFSET=0
CONFIG_FFA_SHARED_MM_BUF_ADDR=0x02000000

View file

@ -261,3 +261,4 @@ CONFIG_FWU_MULTI_BANK_UPDATE=y
CONFIG_UNIT_TEST=y
CONFIG_UT_TIME=y
CONFIG_UT_DM=y
CONFIG_ARM_FFA_TRANSPORT=y

View file

@ -347,3 +347,4 @@ CONFIG_TEST_FDTDEC=y
CONFIG_UNIT_TEST=y
CONFIG_UT_TIME=y
CONFIG_UT_DM=y
CONFIG_ARM_FFA_TRANSPORT=y

261
doc/arch/arm64.ffa.rst Normal file
View file

@ -0,0 +1,261 @@
.. SPDX-License-Identifier: GPL-2.0+
Arm FF-A Support
================
Summary
-------
FF-A stands for Firmware Framework for Arm A-profile processors.
FF-A specifies interfaces that enable a pair of software execution environments aka partitions to
communicate with each other. A partition could be a VM in the Normal or Secure world, an
application in S-EL0, or a Trusted OS in S-EL1.
The U-Boot FF-A support (the bus) implements the interfaces to communicate
with partitions in the Secure world aka Secure partitions (SPs).
The FF-A support specifically focuses on communicating with SPs that
isolate portions of EFI runtime services that must run in a protected
environment which is inaccessible by the Host OS or Hypervisor.
Examples of such services are set/get variables.
The FF-A support uses the SMC ABIs defined by the FF-A specification to:
- Discover the presence of SPs of interest
- Access an SP's service through communication protocols
e.g. EFI MM communication protocol
At this stage of development only EFI boot-time services are supported.
Runtime support will be added in future developments.
The U-Boot FF-A support provides the following parts:
- A Uclass driver providing generic FF-A methods.
- An Arm FF-A device driver providing Arm-specific methods and reusing the Uclass methods.
- A sandbox emulator for Arm FF-A, emulates the FF-A side of the Secure World and provides
FF-A ABIs inspection methods.
- An FF-A sandbox device driver for FF-A communication with the emulated Secure World.
The driver leverages the FF-A Uclass to establish FF-A communication.
- Sandbox FF-A test cases.
FF-A and SMC specifications
-------------------------------------------
The current implementation of the U-Boot FF-A support relies on
`FF-A v1.0 specification`_ and uses SMC32 calling convention which
means using the first 32-bit data of the Xn registers.
At this stage we only need the FF-A v1.0 features.
The FF-A support has been tested with OP-TEE which supports SMC32 calling
convention.
Hypervisors are supported if they are configured to trap SMC calls.
The FF-A support uses 64-bit registers as per `SMC Calling Convention v1.2 specification`_.
Supported hardware
--------------------------------
Aarch64 plaforms
Configuration
----------------------
CONFIG_ARM_FFA_TRANSPORT
Enables the FF-A support. Turn this on if you want to use FF-A
communication.
When using an Arm 64-bit platform, the Arm FF-A driver will be used.
When using sandbox, the sandbox FF-A emulator and FF-A sandbox driver will be used.
FF-A ABIs under the hood
---------------------------------------
Invoking an FF-A ABI involves providing to the secure world/hypervisor the
expected arguments from the ABI.
On an Arm 64-bit platform, the ABI arguments are stored in x0 to x7 registers.
Then, an SMC instruction is executed.
At the secure side level or hypervisor the ABI is handled at a higher exception
level and the arguments are read and processed.
The response is put back through x0 to x7 registers and control is given back
to the U-Boot Arm FF-A driver (non-secure world).
The driver reads the response and processes it accordingly.
This methodology applies to all the FF-A ABIs.
FF-A bus discovery on Arm 64-bit platforms
---------------------------------------------
When CONFIG_ARM_FFA_TRANSPORT is enabled, the FF-A bus is considered as
an architecture feature and discovered using ARM_SMCCC_FEATURES mechanism.
This discovery mechanism is performed by the PSCI driver.
The PSCI driver comes with a PSCI device tree node which is the root node for all
architecture features including FF-A bus.
::
=> dm tree
Class Index Probed Driver Name
-----------------------------------------------------------
firmware 0 [ + ] psci |-- psci
ffa 0 [ ] arm_ffa | `-- arm_ffa
The PSCI driver is bound to the PSCI device and when probed it tries to discover
the architecture features by calling a callback the features drivers provide.
In case of FF-A, the callback is arm_ffa_is_supported() which tries to discover the
FF-A framework by querying the FF-A framework version from secure world using
FFA_VERSION ABI. When discovery is successful, the ARM_SMCCC_FEATURES
mechanism creates a U-Boot device for the FF-A bus and binds the Arm FF-A driver
with the device using device_bind_driver().
At this stage the FF-A bus is registered with the DM and can be interacted with using
the DM APIs.
Clients are able to probe then use the FF-A bus by calling uclass_first_device().
Please refer to the armffa command implementation as an example of how to probe
and interact with the FF-A bus.
When calling uclass_first_device(), the FF-A driver is probed and ends up calling
ffa_do_probe() provided by the Uclass which does the following:
- saving the FF-A framework version in uc_priv
- querying from secure world the u-boot endpoint ID
- querying from secure world the supported features of FFA_RXTX_MAP
- mapping the RX/TX buffers
- querying from secure world all the partitions information
When one of the above actions fails, probing fails and the driver stays not active
and can be probed again if needed.
Requirements for clients
-------------------------------------
When using the FF-A bus with EFI, clients must query the SPs they are looking for
during EFI boot-time mode using the service UUID.
The RX/TX buffers are only available at EFI boot-time. Querying partitions is
done at boot time and data is cached for future use.
RX/TX buffers should be unmapped before EFI runtime mode starts.
The driver provides a bus operation for that called ffa_rxtx_unmap().
The user should call ffa_rxtx_unmap() to unmap the RX/TX buffers when required
(e.g: at efi_exit_boot_services()).
The Linux kernel allocates its own RX/TX buffers. To be able to register these kernel buffers
with secure world, the U-Boot's RX/TX buffers should be unmapped before EFI runtime starts.
When invoking FF-A direct messaging, clients should specify which ABI protocol
they want to use (32-bit vs 64-bit). Selecting the protocol means using
the 32-bit or 64-bit version of FFA_MSG_SEND_DIRECT_{REQ, RESP}.
The calling convention between U-Boot and the secure world stays the same: SMC32.
Requirements for user drivers
-------------------------------------
Users who want to implement their custom FF-A device driver while reusing the FF-A Uclass can do so
by implementing their own invoke_ffa_fn() in the user driver.
The bus driver layer
------------------------------
FF-A support comes on top of the SMCCC layer and is implemented by the FF-A Uclass drivers/firmware/arm-ffa/arm-ffa-uclass.c
The following features are provided:
- Support for the 32-bit version of the following ABIs:
- FFA_VERSION
- FFA_ID_GET
- FFA_FEATURES
- FFA_PARTITION_INFO_GET
- FFA_RXTX_UNMAP
- FFA_RX_RELEASE
- FFA_RUN
- FFA_ERROR
- FFA_SUCCESS
- FFA_INTERRUPT
- FFA_MSG_SEND_DIRECT_REQ
- FFA_MSG_SEND_DIRECT_RESP
- Support for the 64-bit version of the following ABIs:
- FFA_RXTX_MAP
- FFA_MSG_SEND_DIRECT_REQ
- FFA_MSG_SEND_DIRECT_RESP
- Processing the received data from the secure world/hypervisor and caching it
- Hiding from upper layers the FF-A protocol and registers details. Upper
layers focus on exchanged data, FF-A support takes care of how to transport
that to the secure world/hypervisor using FF-A
- FF-A support provides driver operations to be used by upper layers:
- ffa_partition_info_get
- ffa_sync_send_receive
- ffa_rxtx_unmap
- FF-A bus discovery makes sure FF-A framework is responsive and compatible
with the driver
- FF-A bus can be compiled and used without EFI
Relationship between the sandbox emulator and the FF-A device
---------------------------------------------------------------
::
=> dm tree
Class Index Probed Driver Name
-----------------------------------------------------------
ffa_emul 0 [ + ] sandbox_ffa_emul `-- arm-ffa-emul
ffa 0 [ ] sandbox_arm_ffa `-- sandbox-arm-ffa
The armffa command
-----------------------------------
armffa is a command showcasing how to use the FF-A bus and how to invoke the driver operations.
Please refer the command documentation at :doc:`../usage/cmd/armffa`
Example of boot logs with FF-A enabled
--------------------------------------
For example, when using FF-A with Corstone-1000 the logs are as follows:
::
U-Boot 2023.01 (May 10 2023 - 11:08:07 +0000) corstone1000 aarch64
DRAM: 2 GiB
Arm FF-A framework discovery
FF-A driver 1.0
FF-A framework 1.0
FF-A versions are compatible
...
FF-A driver 1.0
FF-A framework 1.0
FF-A versions are compatible
EFI: MM partition ID 0x8003
...
EFI stub: Booting Linux Kernel...
...
Linux version 6.1.9-yocto-standard (oe-user@oe-host) (aarch64-poky-linux-musl-gcc (GCC) 12.2.0, GNU ld (GNU Binutils) 2.40.202301193
Machine model: ARM Corstone1000 FPGA MPS3 board
Contributors
------------
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
.. _`FF-A v1.0 specification`: https://documentation-service.arm.com/static/5fb7e8a6ca04df4095c1d65e
.. _`SMC Calling Convention v1.2 specification`: https://documentation-service.arm.com/static/5f8edaeff86e16515cdbe4c6

View file

@ -8,6 +8,7 @@ Architecture-specific doc
arc
arm64
arm64.ffa
m68k
mips
nios2

View file

@ -200,6 +200,7 @@ Supported Drivers
U-Boot sandbox supports these emulations:
- Arm FF-A
- Block devices
- Chrome OS EC
- GPIO

93
doc/usage/cmd/armffa.rst Normal file
View file

@ -0,0 +1,93 @@
.. SPDX-License-Identifier: GPL-2.0+:
armffa command
==============
Synopsis
--------
::
armffa [sub-command] [arguments]
sub-commands:
getpart [partition UUID]
lists the partition(s) info
ping [partition ID]
sends a data pattern to the specified partition
devlist
displays information about the FF-A device/driver
Description
-----------
armffa is a command showcasing how to use the FF-A bus and how to invoke its operations.
This provides a guidance to the client developers on how to call the FF-A bus interfaces.
The command also allows to gather secure partitions information and ping these partitions.
The command is also helpful in testing the communication with secure partitions.
Example
-------
The following examples are run on Corstone-1000 platform.
* ping
::
corstone1000# armffa ping 0x8003
SP response:
[LSB]
fffffffe
0
0
0
0
* ping (failure case)
::
corstone1000# armffa ping 0
Sending direct request error (-22)
* getpart
::
corstone1000# armffa getpart 33d532ed-e699-0942-c09c-a798d9cd722d
Partition: id = 8003 , exec_ctxt 1 , properties 3
* getpart (failure case)
::
corstone1000# armffa getpart 33d532ed-e699-0942-c09c-a798d9cd7221
INVALID_PARAMETERS: Unrecognized UUID
Failure in querying partitions count (error code: -22)
* devlist
::
corstone1000# armffa devlist
device name arm_ffa, dev 00000000fdf41c30, driver name arm_ffa, ops 00000000fffc0e98
Configuration
-------------
The command is available if CONFIG_CMD_ARMFFA=y and CONFIG_ARM_FFA_TRANSPORT=y.
Return value
------------
The return value $? is 0 (true) on success, 1 (false) on failure.

View file

@ -22,6 +22,7 @@ Shell commands
cmd/acpi
cmd/addrmap
cmd/armffa
cmd/askenv
cmd/base
cmd/bdinfo

View file

@ -115,6 +115,7 @@ obj-y += iommu/
obj-y += smem/
obj-y += thermal/
obj-$(CONFIG_TEE) += tee/
obj-$(CONFIG_ARM_FFA_TRANSPORT) += firmware/arm-ffa/
obj-y += axi/
obj-y += ufs/
obj-$(CONFIG_W1) += w1/

View file

@ -45,4 +45,5 @@ config ARM_SMCCC_FEATURES
the PSCI driver is always probed and binds dirvers registered to the Arm SMCCC
services if any and reported as supported by the SMCCC firmware.
source "drivers/firmware/arm-ffa/Kconfig"
source "drivers/firmware/scmi/Kconfig"

View file

@ -0,0 +1,42 @@
# SPDX-License-Identifier: GPL-2.0
config ARM_FFA_TRANSPORT
bool "Enable Arm Firmware Framework for Armv8-A driver"
depends on DM && (ARM64 || SANDBOX)
select ARM_SMCCC if !SANDBOX
select ARM_SMCCC_FEATURES if !SANDBOX
imply CMD_ARMFFA
select LIB_UUID
select DEVRES
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.
The FF-A support in U-Boot 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, FF-A is considered as a discoverable bus.
FF-A bus is discovered using ARM_SMCCC_FEATURES mechanism performed
by the PSCI driver.
The Secure World is considered as one entity to communicate with
using the FF-A bus.
FF-A communication is handled by one device and one instance (the bus).
The FF-A support on U-Boot takes care of all the interactions between Normal
world and Secure World.
Generic FF-A methods are implemented in the Uclass (arm-ffa-uclass.c).
Arm specific methods are implemented in the Arm driver (arm-ffa.c).
FF-A sandbox is provided to run FF-A under sandbox and allows to test the FF-A Uclass.
Sandbox support includes an emulator for Arm FF-A which emulates the FF-A side of
the Secure World and provides FF-A ABIs inspection methods (ffa-emul-uclass.c).
An FF-A sandbox driver is also provided for FF-A communication with the emulated
Secure World (sandbox_ffa.c).
For more details about the FF-A support, please refer to doc/arch/arm64.ffa.rst

View file

@ -0,0 +1,16 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
#
# Authors:
# Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
# build the generic FF-A methods
obj-y += arm-ffa-uclass.o
ifeq ($(CONFIG_SANDBOX),y)
# build the FF-A sandbox emulator and driver
obj-y += ffa-emul-uclass.o sandbox_ffa.o
else
# build the Arm64 FF-A driver
obj-y += arm-ffa.o
endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,104 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#include <common.h>
#include <arm_ffa.h>
#include <arm_ffa_priv.h>
#include <dm.h>
#include <log.h>
#include <asm/global_data.h>
#include <dm/device-internal.h>
#include <linux/errno.h>
DECLARE_GLOBAL_DATA_PTR;
/**
* invoke_ffa_fn() - SMC wrapper
* @args: FF-A ABI arguments to be copied to Xn registers
* @res: FF-A ABI return data to be copied from Xn registers
*
* Calls low level SMC assembly function
*/
void invoke_ffa_fn(ffa_value_t args, ffa_value_t *res)
{
arm_smccc_1_2_smc(&args, res);
}
/**
* arm_ffa_discover() - perform FF-A discovery
* @dev: The Arm FF-A bus device (arm_ffa)
* Try to discover the FF-A framework. Discovery is performed by
* querying the FF-A framework version from secure world using the FFA_VERSION ABI.
* Return:
*
* true on success. Otherwise, false.
*/
static bool arm_ffa_discover(struct udevice *dev)
{
int ret;
log_info("Arm FF-A framework discovery\n");
ret = ffa_get_version_hdlr(dev);
if (ret)
return false;
return true;
}
/**
* arm_ffa_is_supported() - FF-A bus discovery callback
* @invoke_fn: legacy SMC invoke function (not used)
*
* Perform FF-A discovery by calling arm_ffa_discover().
* Discovery is performed by querying the FF-A framework version from
* secure world using the FFA_VERSION ABI.
*
* The FF-A driver is registered as an SMCCC feature driver. So, features discovery
* callbacks are called by the PSCI driver (PSCI device is the SMCCC features
* root device).
*
* The FF-A driver supports the SMCCCv1.2 extended input/output registers.
* So, the legacy SMC invocation is not used.
*
* Return:
*
* 0 on success. Otherwise, failure
*/
static bool arm_ffa_is_supported(void (*invoke_fn)(ulong a0, ulong a1,
ulong a2, ulong a3,
ulong a4, ulong a5,
ulong a6, ulong a7,
struct arm_smccc_res *res))
{
return arm_ffa_discover(NULL);
}
/* Arm FF-A driver operations */
static const struct ffa_bus_ops ffa_ops = {
.partition_info_get = ffa_get_partitions_info_hdlr,
.sync_send_receive = ffa_msg_send_direct_req_hdlr,
.rxtx_unmap = ffa_unmap_rxtx_buffers_hdlr,
};
/* Registering the FF-A driver as an SMCCC feature driver */
ARM_SMCCC_FEATURE_DRIVER(arm_ffa) = {
.driver_name = FFA_DRV_NAME,
.is_supported = arm_ffa_is_supported,
};
/* Declaring the FF-A driver under UCLASS_FFA */
U_BOOT_DRIVER(arm_ffa) = {
.name = FFA_DRV_NAME,
.id = UCLASS_FFA,
.flags = DM_REMOVE_OS_PREPARE,
.ops = &ffa_ops,
};

View file

@ -0,0 +1,720 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#include <common.h>
#include <dm.h>
#include <mapmem.h>
#include <string.h>
#include <asm/global_data.h>
#include <asm/sandbox_arm_ffa.h>
#include <asm/sandbox_arm_ffa_priv.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
#include <dm/root.h>
#include <linux/errno.h>
#include <linux/sizes.h>
DECLARE_GLOBAL_DATA_PTR;
/* The partitions (SPs) table */
static struct ffa_partition_desc sandbox_partitions[SANDBOX_PARTITIONS_CNT] = {
{
.info = { .id = SANDBOX_SP1_ID, .exec_ctxt = 0x5687, .properties = 0x89325621 },
.sp_uuid = {
.a1 = SANDBOX_SERVICE1_UUID_A1,
.a2 = SANDBOX_SERVICE1_UUID_A2,
.a3 = SANDBOX_SERVICE1_UUID_A3,
.a4 = SANDBOX_SERVICE1_UUID_A4,
}
},
{
.info = { .id = SANDBOX_SP3_ID, .exec_ctxt = 0x7687, .properties = 0x23325621 },
.sp_uuid = {
.a1 = SANDBOX_SERVICE2_UUID_A1,
.a2 = SANDBOX_SERVICE2_UUID_A2,
.a3 = SANDBOX_SERVICE2_UUID_A3,
.a4 = SANDBOX_SERVICE2_UUID_A4,
}
},
{
.info = { .id = SANDBOX_SP2_ID, .exec_ctxt = 0x9587, .properties = 0x45325621 },
.sp_uuid = {
.a1 = SANDBOX_SERVICE1_UUID_A1,
.a2 = SANDBOX_SERVICE1_UUID_A2,
.a3 = SANDBOX_SERVICE1_UUID_A3,
.a4 = SANDBOX_SERVICE1_UUID_A4,
}
},
{
.info = { .id = SANDBOX_SP4_ID, .exec_ctxt = 0x1487, .properties = 0x70325621 },
.sp_uuid = {
.a1 = SANDBOX_SERVICE2_UUID_A1,
.a2 = SANDBOX_SERVICE2_UUID_A2,
.a3 = SANDBOX_SERVICE2_UUID_A3,
.a4 = SANDBOX_SERVICE2_UUID_A4,
}
}
};
/* The emulator functions */
/**
* sandbox_ffa_version() - Emulated FFA_VERSION handler function
* @emul: The sandbox FF-A emulator device
* @pargs: The SMC call input arguments a0-a7
* @res: The SMC return data
*
* Emulate FFA_VERSION FF-A function.
*
* Return:
*
* 0 on success. Otherwise, failure
*/
static int sandbox_ffa_version(struct udevice *emul, ffa_value_t *pargs, ffa_value_t *res)
{
struct sandbox_ffa_emul *priv = dev_get_priv(emul);
priv->fwk_version = FFA_VERSION_1_0;
res->a0 = priv->fwk_version;
/* x1-x7 MBZ */
memset(FFA_X1X7_MBZ_REG_START, 0, FFA_X1X7_MBZ_CNT * sizeof(ulong));
return 0;
}
/**
* sandbox_ffa_id_get() - Emulated FFA_ID_GET handler function
* @emul: The sandbox FF-A emulator device
* @pargs: The SMC call input arguments a0-a7
* @res: The SMC return data
*
* Emulate FFA_ID_GET FF-A function.
*
* Return:
*
* 0 on success. Otherwise, failure
*/
static int sandbox_ffa_id_get(struct udevice *emul, ffa_value_t *pargs, ffa_value_t *res)
{
struct sandbox_ffa_emul *priv = dev_get_priv(emul);
res->a0 = FFA_SMC_32(FFA_SUCCESS);
res->a1 = 0;
priv->id = NS_PHYS_ENDPOINT_ID;
res->a2 = priv->id;
/* x3-x7 MBZ */
memset(FFA_X3_MBZ_REG_START, 0, FFA_X3X7_MBZ_CNT * sizeof(ulong));
return 0;
}
/**
* sandbox_ffa_features() - Emulated FFA_FEATURES handler function
* @pargs: The SMC call input arguments a0-a7
* @res: The SMC return data
*
* Emulate FFA_FEATURES FF-A function.
*
* Return:
*
* 0 on success. Otherwise, failure
*/
static int sandbox_ffa_features(ffa_value_t *pargs, ffa_value_t *res)
{
res->a1 = 0;
if (pargs->a1 == FFA_SMC_64(FFA_RXTX_MAP)) {
res->a0 = FFA_SMC_32(FFA_SUCCESS);
res->a2 = RXTX_BUFFERS_MIN_SIZE;
res->a3 = 0;
/* x4-x7 MBZ */
memset(FFA_X4X7_MBZ_REG_START, 0, FFA_X4X7_MBZ_CNT * sizeof(ulong));
return 0;
}
res->a0 = FFA_SMC_32(FFA_ERROR);
res->a2 = -NOT_SUPPORTED;
/* x3-x7 MBZ */
memset(FFA_X3_MBZ_REG_START, 0, FFA_X3X7_MBZ_CNT * sizeof(ulong));
log_err("FF-A interface %lx not implemented\n", pargs->a1);
return ffa_to_std_errmap[NOT_SUPPORTED];
}
/**
* sandbox_ffa_partition_info_get() - Emulated FFA_PARTITION_INFO_GET handler
* @emul: The sandbox FF-A emulator device
* @pargs: The SMC call input arguments a0-a7
* @res: The SMC return data
*
* Emulate FFA_PARTITION_INFO_GET FF-A function.
*
* Return:
*
* 0 on success. Otherwise, failure
*/
static int sandbox_ffa_partition_info_get(struct udevice *emul, ffa_value_t *pargs,
ffa_value_t *res)
{
struct ffa_partition_info *rxbuf_desc_info = NULL;
u32 descs_cnt;
u32 descs_size_bytes;
int ret;
struct sandbox_ffa_emul *priv = dev_get_priv(emul);
res->a0 = FFA_SMC_32(FFA_ERROR);
if (!priv->pair.rxbuf) {
res->a2 = -DENIED;
ret = ffa_to_std_errmap[DENIED];
goto cleanup;
}
if (priv->pair_info.rxbuf_owned) {
res->a2 = -BUSY;
ret = ffa_to_std_errmap[BUSY];
goto cleanup;
}
if (!priv->partitions.descs) {
priv->partitions.descs = sandbox_partitions;
priv->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 descs buffer size */
if ((priv->pair_info.rxtx_buf_size * SZ_4K) < descs_size_bytes) {
res->a2 = -NO_MEMORY;
ret = ffa_to_std_errmap[NO_MEMORY];
goto cleanup;
}
rxbuf_desc_info = priv->pair.rxbuf;
/* No UUID specified. Return the information of all partitions */
if (!pargs->a1 && !pargs->a2 && !pargs->a3 && !pargs->a4) {
for (descs_cnt = 0; descs_cnt < SANDBOX_PARTITIONS_CNT; descs_cnt++)
*(rxbuf_desc_info++) = priv->partitions.descs[descs_cnt].info;
res->a0 = FFA_SMC_32(FFA_SUCCESS);
res->a2 = SANDBOX_PARTITIONS_CNT;
/* Transfer ownership to the consumer: the non secure world */
priv->pair_info.rxbuf_owned = 1;
ret = 0;
goto cleanup;
}
/* A UUID specified. Return the info of all SPs matching the UUID */
for (descs_cnt = 0 ; descs_cnt < SANDBOX_PARTITIONS_CNT ; descs_cnt++)
if (pargs->a1 == priv->partitions.descs[descs_cnt].sp_uuid.a1 &&
pargs->a2 == priv->partitions.descs[descs_cnt].sp_uuid.a2 &&
pargs->a3 == priv->partitions.descs[descs_cnt].sp_uuid.a3 &&
pargs->a4 == priv->partitions.descs[descs_cnt].sp_uuid.a4) {
*(rxbuf_desc_info++) = priv->partitions.descs[descs_cnt].info;
}
if (rxbuf_desc_info != priv->pair.rxbuf) {
res->a0 = FFA_SMC_32(FFA_SUCCESS);
/* Store the partitions count */
res->a2 = (ulong)
(rxbuf_desc_info - (struct ffa_partition_info *)
priv->pair.rxbuf);
ret = 0;
/* Transfer ownership to the consumer: the non secure world */
priv->pair_info.rxbuf_owned = 1;
} else {
/* Unrecognized UUID */
res->a2 = -INVALID_PARAMETERS;
ret = ffa_to_std_errmap[INVALID_PARAMETERS];
}
cleanup:
log_err("FFA_PARTITION_INFO_GET (%ld)\n", res->a2);
res->a1 = 0;
/* x3-x7 MBZ */
memset(FFA_X3_MBZ_REG_START, 0, FFA_X3X7_MBZ_CNT * sizeof(ulong));
return ret;
}
/**
* sandbox_ffa_rxtx_map() - Emulated FFA_RXTX_MAP handler
* @emul: The sandbox FF-A emulator device
* @pargs: The SMC call input arguments a0-a7
* @res: The SMC return data
*
* Emulate FFA_RXTX_MAP FF-A function.
*
* Return:
*
* 0 on success. Otherwise, failure
*/
static int sandbox_ffa_rxtx_map(struct udevice *emul, ffa_value_t *pargs, ffa_value_t *res)
{
int ret;
struct sandbox_ffa_emul *priv = dev_get_priv(emul);
res->a0 = FFA_SMC_32(FFA_ERROR);
if (priv->pair.txbuf && priv->pair.rxbuf) {
res->a2 = -DENIED;
ret = ffa_to_std_errmap[DENIED];
goto feedback;
}
if (pargs->a3 >= RXTX_BUFFERS_MIN_PAGES && pargs->a1 && pargs->a2) {
priv->pair.txbuf = map_sysmem(pargs->a1, 0);
priv->pair.rxbuf = map_sysmem(pargs->a2, 0);
priv->pair_info.rxtx_buf_size = pargs->a3;
priv->pair_info.rxbuf_mapped = 1;
res->a0 = FFA_SMC_32(FFA_SUCCESS);
res->a2 = 0;
ret = 0;
goto feedback;
}
if (!pargs->a1 || !pargs->a2) {
res->a2 = -INVALID_PARAMETERS;
ret = ffa_to_std_errmap[INVALID_PARAMETERS];
} else {
res->a2 = -NO_MEMORY;
ret = ffa_to_std_errmap[NO_MEMORY];
}
log_err("Error in FFA_RXTX_MAP arguments (%d)\n",
(int)res->a2);
feedback:
res->a1 = 0;
/* x3-x7 MBZ */
memset(FFA_X3_MBZ_REG_START, 0, FFA_X3X7_MBZ_CNT * sizeof(ulong));
return ret;
}
/**
* sandbox_ffa_rxtx_unmap() - Emulated FFA_RXTX_UNMAP handler
* @emul: The sandbox FF-A emulator device
* @pargs: The SMC call input arguments a0-a7
* @res: The SMC return data
*
* Emulate FFA_RXTX_UNMAP FF-A function.
*
* Return:
*
* 0 on success. Otherwise, failure
*/
static int sandbox_ffa_rxtx_unmap(struct udevice *emul, ffa_value_t *pargs, ffa_value_t *res)
{
int ret;
struct sandbox_ffa_emul *priv = dev_get_priv(emul);
res->a0 = FFA_SMC_32(FFA_ERROR);
res->a2 = -INVALID_PARAMETERS;
ret = ffa_to_std_errmap[INVALID_PARAMETERS];
if (GET_NS_PHYS_ENDPOINT_ID(pargs->a1) != priv->id)
goto feedback;
if (priv->pair.txbuf && priv->pair.rxbuf) {
priv->pair.txbuf = 0;
priv->pair.rxbuf = 0;
priv->pair_info.rxtx_buf_size = 0;
priv->pair_info.rxbuf_mapped = 0;
res->a0 = FFA_SMC_32(FFA_SUCCESS);
res->a2 = 0;
ret = 0;
goto feedback;
}
log_err("No buffer pair registered on behalf of the caller\n");
feedback:
res->a1 = 0;
/* x3-x7 MBZ */
memset(FFA_X3_MBZ_REG_START, 0, FFA_X3X7_MBZ_CNT * sizeof(ulong));
return ret;
}
/**
* sandbox_ffa_rx_release() - Emulated FFA_RX_RELEASE handler
* @emul: The sandbox FF-A emulator device
* @pargs: The SMC call input arguments a0-a7
* @res: The SMC return data
*
* Emulate FFA_RX_RELEASE FF-A function.
*
* Return:
*
* 0 on success. Otherwise, failure
*/
static int sandbox_ffa_rx_release(struct udevice *emul, ffa_value_t *pargs, ffa_value_t *res)
{
int ret;
struct sandbox_ffa_emul *priv = dev_get_priv(emul);
if (!priv->pair_info.rxbuf_owned) {
res->a0 = FFA_SMC_32(FFA_ERROR);
res->a2 = -DENIED;
ret = ffa_to_std_errmap[DENIED];
} else {
priv->pair_info.rxbuf_owned = 0;
res->a0 = FFA_SMC_32(FFA_SUCCESS);
res->a2 = 0;
ret = 0;
}
res->a1 = 0;
/* x3-x7 MBZ */
memset(FFA_X3_MBZ_REG_START, 0, FFA_X3X7_MBZ_CNT * sizeof(ulong));
return ret;
}
/**
* sandbox_ffa_sp_valid() - Check SP validity
* @emul: The sandbox FF-A emulator device
* @part_id: partition ID to check
*
* Search the input ID in the descriptors table.
*
* Return:
*
* 1 on success (Partition found). Otherwise, failure
*/
static int sandbox_ffa_sp_valid(struct udevice *emul, u16 part_id)
{
u32 descs_cnt;
struct sandbox_ffa_emul *priv = dev_get_priv(emul);
for (descs_cnt = 0 ; descs_cnt < SANDBOX_PARTITIONS_CNT ; descs_cnt++)
if (priv->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
* @emul: The sandbox FF-A emulator device
* @pargs: The SMC call input arguments a0-a7
* @res: The SMC return data
*
* Emulate FFA_MSG_SEND_DIRECT_{REQ,RESP} FF-A ABIs.
* Only SMC 64-bit is supported in Sandbox.
*
* Emulating interrupts is not supported. So, FFA_RUN and FFA_INTERRUPT are not
* supported. In case of success FFA_MSG_SEND_DIRECT_RESP is returned with
* default pattern data (0xff).
*
* Return:
*
* 0 on success. Otherwise, failure
*/
static int sandbox_ffa_msg_send_direct_req(struct udevice *emul,
ffa_value_t *pargs, ffa_value_t *res)
{
u16 part_id;
struct sandbox_ffa_emul *priv = dev_get_priv(emul);
part_id = GET_DST_SP_ID(pargs->a1);
if (GET_NS_PHYS_ENDPOINT_ID(pargs->a1) != priv->id ||
!sandbox_ffa_sp_valid(emul, part_id) || pargs->a2) {
res->a0 = FFA_SMC_32(FFA_ERROR);
res->a1 = 0;
res->a2 = -INVALID_PARAMETERS;
/* x3-x7 MBZ */
memset(FFA_X3_MBZ_REG_START, 0, FFA_X3X7_MBZ_CNT * sizeof(ulong));
return ffa_to_std_errmap[INVALID_PARAMETERS];
}
res->a0 = FFA_SMC_64(FFA_MSG_SEND_DIRECT_RESP);
res->a1 = PREP_SRC_SP_ID(part_id) |
PREP_NS_PHYS_ENDPOINT_ID(priv->id);
res->a2 = 0;
/* Return 0xff bytes as a response */
res->a3 = -1UL;
res->a4 = -1UL;
res->a5 = -1UL;
res->a6 = -1UL;
res->a7 = -1UL;
return 0;
}
/**
* sandbox_ffa_get_rxbuf_flags() - Read the mapping/ownership flags
* @emul: The sandbox FF-A emulator device
* @queried_func_id: The FF-A function to be queried
* @func_data: Pointer to the FF-A function arguments container structure
*
* Query the status flags of the following emulated
* ABIs: FFA_RXTX_MAP, FFA_RXTX_UNMAP, FFA_RX_RELEASE.
*
* Return:
*
* 0 on success. Otherwise, failure
*/
static int sandbox_ffa_get_rxbuf_flags(struct udevice *emul, u32 queried_func_id,
struct ffa_sandbox_data *func_data)
{
struct sandbox_ffa_emul *priv = dev_get_priv(emul);
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) = priv->pair_info.rxbuf_mapped;
return 0;
case FFA_RX_RELEASE:
*((u8 *)func_data->data0) = priv->pair_info.rxbuf_owned;
return 0;
default:
log_err("The querried FF-A interface flag (%d) undefined\n",
queried_func_id);
return -EINVAL;
}
}
/**
* sandbox_ffa_get_fwk_version() - Return the FFA framework version
* @emul: The sandbox FF-A emulator device
* @func_data: Pointer to the FF-A function arguments container structure
*
* Return the FFA framework version read from the FF-A emulator data.
*
* Return:
*
* 0 on success. Otherwise, failure
*/
static int sandbox_ffa_get_fwk_version(struct udevice *emul, struct ffa_sandbox_data *func_data)
{
struct sandbox_ffa_emul *priv = dev_get_priv(emul);
if (!func_data)
return -EINVAL;
if (!func_data->data0 ||
func_data->data0_size != sizeof(priv->fwk_version))
return -EINVAL;
*((u32 *)func_data->data0) = priv->fwk_version;
return 0;
}
/**
* sandbox_ffa_get_parts() - Return the address of partitions data
* @emul: The sandbox FF-A emulator device
* @func_data: Pointer to the FF-A function arguments container structure
*
* Return the address of partitions data read from the FF-A emulator data.
*
* Return:
*
* 0 on success. Otherwise, failure
*/
static int sandbox_ffa_get_parts(struct udevice *emul, struct ffa_sandbox_data *func_data)
{
struct sandbox_ffa_emul *priv = dev_get_priv(emul);
if (!func_data)
return -EINVAL;
if (!func_data->data0 ||
func_data->data0_size != sizeof(struct ffa_partitions *))
return -EINVAL;
*((struct ffa_partitions **)func_data->data0) = &priv->partitions;
return 0;
}
/**
* sandbox_query_ffa_emul_state() - Inspect the FF-A ABIs
* @queried_func_id: The FF-A function to be queried
* @func_data: Pointer to the FF-A function arguments container structure
*
* Query the status of FF-A ABI specified in the input argument.
*
* Return:
*
* 0 on success. Otherwise, failure
*/
int sandbox_query_ffa_emul_state(u32 queried_func_id,
struct ffa_sandbox_data *func_data)
{
struct udevice *emul;
int ret;
ret = uclass_first_device_err(UCLASS_FFA_EMUL, &emul);
if (ret) {
log_err("Cannot find FF-A emulator during querying state\n");
return ret;
}
switch (queried_func_id) {
case FFA_RXTX_MAP:
case FFA_RXTX_UNMAP:
case FFA_RX_RELEASE:
return sandbox_ffa_get_rxbuf_flags(emul, queried_func_id, func_data);
case FFA_VERSION:
return sandbox_ffa_get_fwk_version(emul, func_data);
case FFA_PARTITION_INFO_GET:
return sandbox_ffa_get_parts(emul, func_data);
default:
log_err("Undefined FF-A interface (%d)\n",
queried_func_id);
return -EINVAL;
}
}
/**
* sandbox_arm_ffa_smccc_smc() - FF-A SMC call emulation
* @args: the SMC call arguments
* @res: the SMC call returned data
*
* Emulate the FF-A ABIs SMC call.
* The emulated FF-A ABI is identified and invoked.
* FF-A emulation is based on the FF-A specification 1.0
*
* Return:
*
* 0 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(ffa_value_t *args, ffa_value_t *res)
{
int ret = 0;
struct udevice *emul;
ret = uclass_first_device_err(UCLASS_FFA_EMUL, &emul);
if (ret) {
log_err("Cannot find FF-A emulator during SMC emulation\n");
return;
}
switch (args->a0) {
case FFA_SMC_32(FFA_VERSION):
ret = sandbox_ffa_version(emul, args, res);
break;
case FFA_SMC_32(FFA_PARTITION_INFO_GET):
ret = sandbox_ffa_partition_info_get(emul, args, res);
break;
case FFA_SMC_32(FFA_RXTX_UNMAP):
ret = sandbox_ffa_rxtx_unmap(emul, args, res);
break;
case FFA_SMC_64(FFA_MSG_SEND_DIRECT_REQ):
ret = sandbox_ffa_msg_send_direct_req(emul, args, res);
break;
case FFA_SMC_32(FFA_ID_GET):
ret = sandbox_ffa_id_get(emul, args, res);
break;
case FFA_SMC_32(FFA_FEATURES):
ret = sandbox_ffa_features(args, res);
break;
case FFA_SMC_64(FFA_RXTX_MAP):
ret = sandbox_ffa_rxtx_map(emul, args, res);
break;
case FFA_SMC_32(FFA_RX_RELEASE):
ret = sandbox_ffa_rx_release(emul, args, res);
break;
default:
log_err("Undefined FF-A interface (%lx)\n",
args->a0);
}
if (ret != 0)
log_err("FF-A ABI internal failure (%d)\n", ret);
}
/**
* invoke_ffa_fn() - SMC wrapper
* @args: FF-A ABI arguments to be copied to Xn registers
* @res: FF-A ABI return data to be copied from Xn registers
*
* Calls the emulated SMC call.
*/
void invoke_ffa_fn(ffa_value_t args, ffa_value_t *res)
{
sandbox_arm_ffa_smccc_smc(&args, res);
}
/**
* ffa_emul_find() - Find the FF-A emulator
* @dev: the sandbox FF-A device (sandbox-arm-ffa)
* @emulp: the FF-A emulator device (sandbox-ffa-emul)
*
* Search for the FF-A emulator and returns its device pointer.
*
* Return:
* 0 on success. Otherwise, failure
*/
int ffa_emul_find(struct udevice *dev, struct udevice **emulp)
{
int ret;
ret = uclass_first_device_err(UCLASS_FFA_EMUL, emulp);
if (ret) {
log_err("Cannot find FF-A emulator\n");
return ret;
}
log_info("FF-A emulator ready to use\n");
return 0;
}
UCLASS_DRIVER(ffa_emul) = {
.name = "ffa_emul",
.id = UCLASS_FFA_EMUL,
.post_bind = dm_scan_fdt_dev,
};
static const struct udevice_id sandbox_ffa_emul_ids[] = {
{ .compatible = "sandbox,arm-ffa-emul" },
{ }
};
/* Declaring the sandbox FF-A emulator under UCLASS_FFA_EMUL */
U_BOOT_DRIVER(sandbox_ffa_emul) = {
.name = "sandbox_ffa_emul",
.id = UCLASS_FFA_EMUL,
.of_match = sandbox_ffa_emul_ids,
.priv_auto = sizeof(struct sandbox_ffa_emul),
};

View file

@ -0,0 +1,110 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#include <common.h>
#include <arm_ffa.h>
#include <dm.h>
#include <log.h>
#include <asm/global_data.h>
#include <asm/sandbox_arm_ffa_priv.h>
#include <dm/device-internal.h>
#include <linux/errno.h>
DECLARE_GLOBAL_DATA_PTR;
/**
* sandbox_ffa_discover() - perform sandbox FF-A discovery
* @dev: The sandbox FF-A bus device
* Try to discover the FF-A framework. Discovery is performed by
* querying the FF-A framework version from secure world using the FFA_VERSION ABI.
* Return:
*
* 0 on success. Otherwise, failure
*/
static int sandbox_ffa_discover(struct udevice *dev)
{
int ret;
struct udevice *emul;
log_info("Emulated FF-A framework discovery\n");
ret = ffa_emul_find(dev, &emul);
if (ret) {
log_err("Cannot find FF-A emulator\n");
return ret;
}
ret = ffa_get_version_hdlr(dev);
if (ret)
return ret;
return 0;
}
/**
* sandbox_ffa_probe() - The sandbox FF-A driver probe function
* @dev: the sandbox-arm-ffa device
* Save the emulator device in uc_priv.
* Return:
*
* 0 on success.
*/
static int sandbox_ffa_probe(struct udevice *dev)
{
int ret;
struct ffa_priv *uc_priv = dev_get_uclass_priv(dev);
ret = uclass_first_device_err(UCLASS_FFA_EMUL, &uc_priv->emul);
if (ret) {
log_err("Cannot find FF-A emulator\n");
return ret;
}
return 0;
}
/**
* sandbox_ffa_bind() - The sandbox FF-A driver bind function
* @dev: the sandbox-arm-ffa device
* Try to discover the emulated FF-A bus.
* Return:
*
* 0 on success.
*/
static int sandbox_ffa_bind(struct udevice *dev)
{
int ret;
ret = sandbox_ffa_discover(dev);
if (ret)
return ret;
return 0;
}
/* Sandbox Arm FF-A emulator operations */
static const struct ffa_bus_ops sandbox_ffa_ops = {
.partition_info_get = ffa_get_partitions_info_hdlr,
.sync_send_receive = ffa_msg_send_direct_req_hdlr,
.rxtx_unmap = ffa_unmap_rxtx_buffers_hdlr,
};
static const struct udevice_id sandbox_ffa_id[] = {
{ "sandbox,arm-ffa", 0 },
{ },
};
/* Declaring the sandbox FF-A driver under UCLASS_FFA */
U_BOOT_DRIVER(sandbox_arm_ffa) = {
.name = "sandbox_arm_ffa",
.of_match = sandbox_ffa_id,
.id = UCLASS_FFA,
.bind = sandbox_ffa_bind,
.probe = sandbox_ffa_probe,
.ops = &sandbox_ffa_ops,
};

213
include/arm_ffa.h Normal file
View file

@ -0,0 +1,213 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#ifndef __ARM_FFA_H
#define __ARM_FFA_H
#include <linux/printk.h>
/*
* This header is public. It can be used by clients to access
* data structures and definitions they need
*/
/*
* 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 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_partition_uuid - 16 bytes UUID transmitted by FFA_PARTITION_INFO_GET
* @a1-4: 32-bit words access to the UUID data
*
*/
struct ffa_partition_uuid {
u32 a1; /* w1 */
u32 a2; /* w2 */
u32 a3; /* w3 */
u32 a4; /* w4 */
};
/**
* struct ffa_partition_desc - the secure partition descriptor
* @info: partition information
* @sp_uuid: the secure partition UUID
*
* Each partition has its descriptor containing the partitions information and the UUID
*/
struct ffa_partition_desc {
struct ffa_partition_info info;
struct ffa_partition_uuid sp_uuid;
};
/*
* struct ffa_send_direct_data - Data structure hosting the data
* used by FFA_MSG_SEND_DIRECT_{REQ,RESP}
* @data0-4: Data read/written from/to x3-x7 registers
*
* Data structure containing the data to be sent by FFA_MSG_SEND_DIRECT_REQ
* or read from FFA_MSG_SEND_DIRECT_RESP
*/
/* For use with FFA_MSG_SEND_DIRECT_{REQ,RESP} which pass data via registers */
struct ffa_send_direct_data {
ulong data0; /* w3/x3 */
ulong data1; /* w4/x4 */
ulong data2; /* w5/x5 */
ulong data3; /* w6/x6 */
ulong data4; /* w7/x7 */
};
struct udevice;
/**
* struct ffa_bus_ops - Operations for FF-A
* @partition_info_get: callback for the FFA_PARTITION_INFO_GET
* @sync_send_receive: callback for the FFA_MSG_SEND_DIRECT_REQ
* @rxtx_unmap: callback for the FFA_RXTX_UNMAP
*
* The data structure providing all the operations supported by the driver.
* This structure is EFI runtime resident.
*/
struct ffa_bus_ops {
int (*partition_info_get)(struct udevice *dev, const char *uuid_str,
u32 *sp_count, struct ffa_partition_desc **sp_descs);
int (*sync_send_receive)(struct udevice *dev, u16 dst_part_id,
struct ffa_send_direct_data *msg,
bool is_smc64);
int (*rxtx_unmap)(struct udevice *dev);
};
#define ffa_get_ops(dev) ((struct ffa_bus_ops *)(dev)->driver->ops)
/**
* ffa_rxtx_unmap() - FFA_RXTX_UNMAP driver operation
* Please see ffa_unmap_rxtx_buffers_hdlr() description for more details.
*/
int ffa_rxtx_unmap(struct udevice *dev);
/**
* ffa_unmap_rxtx_buffers_hdlr() - FFA_RXTX_UNMAP handler function
* @dev: The arm_ffa bus device
*
* This function implements FFA_RXTX_UNMAP FF-A function
* to unmap the RX/TX buffers
*
* Return:
*
* 0 on success. Otherwise, failure
*/
int ffa_unmap_rxtx_buffers_hdlr(struct udevice *dev);
/**
* ffa_sync_send_receive() - FFA_MSG_SEND_DIRECT_{REQ,RESP} driver operation
* Please see ffa_msg_send_direct_req_hdlr() description for more details.
*/
int ffa_sync_send_receive(struct udevice *dev, u16 dst_part_id,
struct ffa_send_direct_data *msg, bool is_smc64);
/**
* ffa_msg_send_direct_req_hdlr() - FFA_MSG_SEND_DIRECT_{REQ,RESP} handler function
* @dev: The arm_ffa bus device
* @dst_part_id: destination partition ID
* @msg: pointer to the message data preallocated by the client (in/out)
* @is_smc64: select 64-bit or 32-bit FF-A ABI
*
* This function 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 40 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:
*
* 0 on success. Otherwise, failure
*/
int ffa_msg_send_direct_req_hdlr(struct udevice *dev, u16 dst_part_id,
struct ffa_send_direct_data *msg, bool is_smc64);
/**
* ffa_partition_info_get() - FFA_PARTITION_INFO_GET driver operation
* Please see ffa_get_partitions_info_hdlr() description for more details.
*/
int ffa_partition_info_get(struct udevice *dev, const char *uuid_str,
u32 *sp_count, struct ffa_partition_desc **sp_descs);
/**
* ffa_get_partitions_info_hdlr() - FFA_PARTITION_INFO_GET handler function
* @uuid_str: pointer to the UUID string
* @sp_count: address of the variable containing the number of partitions matching the UUID
* The variable is set by the driver
* @sp_descs: address of the descriptors of the partitions matching the UUID
* The address is set by the driver
*
* Return the number of partitions and their descriptors matching the UUID
*
* Query the secure partition data from uc_priv.
* If not found, invoke 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_hdlr() 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().
*
* Return:
*
* @sp_count: the number of partitions
* @sp_descs: address of the partitions descriptors
*
* On success 0 is returned. Otherwise, failure
*/
int ffa_get_partitions_info_hdlr(struct udevice *dev, const char *uuid_str,
u32 *sp_count, struct ffa_partition_desc **sp_descs);
struct ffa_priv;
/**
* ffa_set_smc_conduit() - Set the SMC conduit
* @dev: The FF-A bus device
*
* Selects the SMC conduit by setting the FF-A ABI invoke function.
*
* Return:
*
* 0 on success. Otherwise, failure
*/
int ffa_set_smc_conduit(struct udevice *dev);
#endif

246
include/arm_ffa_priv.h Normal file
View file

@ -0,0 +1,246 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#ifndef __ARM_FFA_PRV_H
#define __ARM_FFA_PRV_H
#include <mapmem.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
/* This header is exclusively used by the FF-A Uclass and FF-A driver(s) */
/* Arm FF-A driver name */
#define FFA_DRV_NAME "arm_ffa"
/* The FF-A SMC function definitions */
#if CONFIG_IS_ENABLED(SANDBOX)
/* Providing Arm SMCCC declarations to sandbox */
/**
* struct sandbox_smccc_1_2_regs - emulated SMC call arguments or results
* @a0-a17 argument values from registers 0 to 17
*/
struct sandbox_smccc_1_2_regs {
ulong a0;
ulong a1;
ulong a2;
ulong a3;
ulong a4;
ulong a5;
ulong a6;
ulong a7;
ulong a8;
ulong a9;
ulong a10;
ulong a11;
ulong a12;
ulong a13;
ulong a14;
ulong a15;
ulong a16;
ulong a17;
};
typedef struct sandbox_smccc_1_2_regs ffa_value_t;
#define ARM_SMCCC_FAST_CALL 1UL
#define ARM_SMCCC_OWNER_STANDARD 4
#define ARM_SMCCC_SMC_32 0
#define ARM_SMCCC_SMC_64 1
#define ARM_SMCCC_TYPE_SHIFT 31
#define ARM_SMCCC_CALL_CONV_SHIFT 30
#define ARM_SMCCC_OWNER_MASK 0x3f
#define ARM_SMCCC_OWNER_SHIFT 24
#define ARM_SMCCC_FUNC_MASK 0xffff
#define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \
(((type) << ARM_SMCCC_TYPE_SHIFT) | \
((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \
(((owner) & ARM_SMCCC_OWNER_MASK) << ARM_SMCCC_OWNER_SHIFT) | \
((func_num) & ARM_SMCCC_FUNC_MASK))
#else
/* CONFIG_ARM64 */
#include <linux/arm-smccc.h>
typedef struct arm_smccc_1_2_regs ffa_value_t;
#endif
/* Defining the function pointer type for the function executing the FF-A ABIs */
typedef void (*invoke_ffa_fn_t)(ffa_value_t args, ffa_value_t *res);
/* 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)))
/* 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_SMC_64(func_num) FFA_SMC(ARM_SMCCC_SMC_64, (func_num))
enum ffa_abis {
FFA_ERROR = 0x60,
FFA_SUCCESS = 0x61,
FFA_INTERRUPT = 0x62,
FFA_VERSION = 0x63,
FFA_FEATURES = 0x64,
FFA_RX_RELEASE = 0x65,
FFA_RXTX_MAP = 0x66,
FFA_RXTX_UNMAP = 0x67,
FFA_PARTITION_INFO_GET = 0x68,
FFA_ID_GET = 0x69,
FFA_RUN = 0x6d,
FFA_MSG_SEND_DIRECT_REQ = 0x6f,
FFA_MSG_SEND_DIRECT_RESP = 0x70,
/* To be updated when adding new FFA IDs */
FFA_FIRST_ID = FFA_ERROR, /* Lowest number ID */
FFA_LAST_ID = FFA_MSG_SEND_DIRECT_RESP, /* Highest number ID */
};
enum ffa_abi_errcode {
NOT_SUPPORTED = 1,
INVALID_PARAMETERS,
NO_MEMORY,
BUSY,
INTERRUPTED,
DENIED,
RETRY,
ABORTED,
MAX_NUMBER_FFA_ERR
};
extern int ffa_to_std_errmap[MAX_NUMBER_FFA_ERR];
/* Container structure and helper macros to map between an FF-A error and relevant error log */
struct ffa_abi_errmap {
char *err_str[MAX_NUMBER_FFA_ERR];
};
#define FFA_ERRMAP_COUNT (FFA_LAST_ID - FFA_FIRST_ID + 1)
#define FFA_ID_TO_ERRMAP_ID(ffa_id) ((ffa_id) - FFA_FIRST_ID)
/**
* enum ffa_rxtx_buf_sizes - minimum sizes supported
* for the RX/TX buffers
*/
enum ffa_rxtx_buf_sizes {
RXTX_4K,
RXTX_64K,
RXTX_16K
};
/**
* struct ffa_rxtxpair - Hosts the RX/TX buffers virtual addresses
* @rxbuf: virtual address of the RX buffer
* @txbuf: virtual address of the TX buffer
* @rxtx_min_pages: RX/TX buffers minimum size in pages
*
* Hosts 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 {
void *rxbuf; /* Virtual address returned by memalign */
void *txbuf; /* Virtual address returned by memalign */
size_t rxtx_min_pages; /* Minimum number of pages in each of the RX/TX buffers */
};
struct ffa_partition_desc;
/**
* struct ffa_partitions - descriptors for all secure partitions
* @count: The number of partitions descriptors
* @descs The partitions descriptors table
*
* Contains the partitions descriptors table
*/
struct ffa_partitions {
u32 count;
struct ffa_partition_desc *descs; /* Virtual address */
};
/**
* struct ffa_priv - the driver private data structure
*
* @fwk_version: FF-A framework version
* @emul: FF-A sandbox emulator
* @id: u-boot endpoint ID
* @partitions: The partitions descriptors structure
* @pair: The RX/TX buffers pair
*
* The device private data structure containing all the
* data read from secure world.
*/
struct ffa_priv {
u32 fwk_version;
struct udevice *emul;
u16 id;
struct ffa_partitions partitions;
struct ffa_rxtxpair pair;
};
/**
* ffa_get_version_hdlr() - FFA_VERSION handler function
* @dev: The FF-A bus device
*
* Implement FFA_VERSION FF-A function
* to get from the secure world the FF-A framework version
* FFA_VERSION is used to discover the FF-A framework.
*
* Return:
*
* 0 on success. Otherwise, failure
*/
int ffa_get_version_hdlr(struct udevice *dev);
/**
* invoke_ffa_fn() - SMC wrapper
* @args: FF-A ABI arguments to be copied to Xn registers
* @res: FF-A ABI return data to be copied from Xn registers
*
* Calls low level SMC implementation.
* This function should be implemented by the user driver.
*/
void invoke_ffa_fn(ffa_value_t args, ffa_value_t *res);
#endif

View file

@ -4,6 +4,11 @@
*
* (C) Copyright 2012
* Pavel Herrmann <morpheus.ibis@gmail.com>
*
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#ifndef _DM_UCLASS_ID_H
@ -57,6 +62,8 @@ enum uclass_id {
UCLASS_ETH, /* Ethernet device */
UCLASS_ETH_PHY, /* Ethernet PHY device */
UCLASS_EXTCON, /* External Connector Class */
UCLASS_FFA, /* Arm Firmware Framework for Armv8-A */
UCLASS_FFA_EMUL, /* sandbox FF-A device emulator */
UCLASS_FIRMWARE, /* Firmware */
UCLASS_FPGA, /* FPGA device */
UCLASS_FUZZING_ENGINE, /* Fuzzing engine */

View file

@ -1,6 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2015, Linaro Limited
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#ifndef __LINUX_ARM_SMCCC_H
#define __LINUX_ARM_SMCCC_H
@ -70,6 +74,47 @@ struct arm_smccc_res {
unsigned long a3;
};
#ifdef CONFIG_ARM64
/**
* struct arm_smccc_1_2_regs - Arguments for or Results from SMC call
* @a0-a17 argument values from registers 0 to 17
*/
struct arm_smccc_1_2_regs {
unsigned long a0;
unsigned long a1;
unsigned long a2;
unsigned long a3;
unsigned long a4;
unsigned long a5;
unsigned long a6;
unsigned long a7;
unsigned long a8;
unsigned long a9;
unsigned long a10;
unsigned long a11;
unsigned long a12;
unsigned long a13;
unsigned long a14;
unsigned long a15;
unsigned long a16;
unsigned long a17;
};
/**
* arm_smccc_1_2_smc() - make SMC calls
* @args: arguments passed via struct arm_smccc_1_2_regs
* @res: result values via struct arm_smccc_1_2_regs
*
* This function is used to make SMC calls following SMC Calling Convention
* v1.2 or above. The content of the supplied param are copied from the
* structure to registers prior to the SMC instruction. The return values
* are updated with the content from registers on return from the SMC
* instruction.
*/
asmlinkage void arm_smccc_1_2_smc(const struct arm_smccc_1_2_regs *args,
struct arm_smccc_1_2_regs *res);
#endif
/**
* struct arm_smccc_quirk - Contains quirk information
* @id: quirk identification

View file

@ -6,6 +6,9 @@
* Copyright (c) 2017, Intel Corporation. All rights reserved.
* Copyright (C) 2020 Linaro Ltd. <sughosh.ganu@linaro.org>
* Copyright (C) 2020 Linaro Ltd. <ilias.apalodimas@linaro.org>
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#ifndef _MM_COMMUNICATION_H_
@ -13,6 +16,9 @@
#include <part_efi.h>
/* MM service UUID string (big-endian format). This UUID is common across all MM SPs */
#define MM_SP_UUID "33d532ed-e699-0942-c09c-a798d9cd722d"
/*
* Interface to the pseudo Trusted Application (TA), which provides a
* communication channel with the Standalone MM (Management Mode)
@ -248,4 +254,11 @@ struct smm_variable_var_check_property {
u16 name[];
};
/* supported MM transports */
enum mm_comms_select {
MM_COMMS_UNDEFINED,
MM_COMMS_FFA,
MM_COMMS_OPTEE
};
#endif /* _MM_COMMUNICATION_H_ */

View file

@ -2,6 +2,10 @@
/*
* Copyright (C) 2014 Samsung Electronics
* Przemyslaw Marczak <p.marczak@samsung.com>
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#ifndef __UUID_H__
#define __UUID_H__
@ -44,4 +48,15 @@ int uuid_guid_get_bin(const char *guid_str, unsigned char *guid_bin);
const char *uuid_guid_get_str(const unsigned char *guid_bin);
void gen_rand_uuid(unsigned char *uuid_bin);
void gen_rand_uuid_str(char *uuid_str, int str_format);
/**
* uuid_str_to_le_bin() - Convert string UUID to little endian binary data.
* @uuid_str: pointer to UUID string
* @uuid_bin: pointer to allocated array for little endian output [16B]
* Return:
* uuid_bin filled with little endian UUID data
* On success 0 is returned. Otherwise, failure code.
*/
int uuid_str_to_le_bin(const char *uuid_str, unsigned char *uuid_bin);
#endif

View file

@ -55,13 +55,55 @@ 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"
select ARM_FFA_TRANSPORT
select TEE
select OPTEE
help
Allowing access to the MM SP services (SPs such as StandAlonneMM, smm-gateway).
When using the u-boot OP-TEE driver, StandAlonneMM is supported.
When using the u-boot FF-A driver any MM SP is 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 in the secure 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.
config FFA_SHARED_MM_BUF_SIZE
int "Memory size of the shared MM communication buffer"
default 0
depends on EFI_MM_COMM_TEE
help
This defines the size in bytes of the memory area reserved for the shared
buffer used for communication between the MM feature in U-Boot and
the MM SP in secure world.
The size of the memory region must be a multiple of the size of the maximum
translation granule size that is specified in the ID_AA64MMFR0_EL1 System register.
It is assumed that the MM SP knows the size of the shared MM communication buffer.
config FFA_SHARED_MM_BUF_OFFSET
int "Data offset in the shared MM communication buffer"
default 0
depends on EFI_MM_COMM_TEE
help
This defines the offset in bytes of the data read or written to in the shared
buffer by the MM SP.
config FFA_SHARED_MM_BUF_ADDR
hex "Define the address of the shared MM communication buffer"
default 0x0
depends on EFI_MM_COMM_TEE
help
This defines the address of the shared MM communication buffer
used for communication between the MM feature in U-Boot and
the MM SP in secure world.
It is assumed that the MM SP knows the address of the shared MM communication buffer.
config EFI_VARIABLE_NO_STORE
bool "Don't persist non-volatile UEFI variables"
help

View file

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

View file

@ -1,6 +1,10 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright 2011 Calxeda, Inc.
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#include <common.h>
@ -354,6 +358,50 @@ int uuid_str_to_bin(const char *uuid_str, unsigned char *uuid_bin,
return 0;
}
/**
* uuid_str_to_le_bin() - Convert string UUID to little endian binary data.
* @uuid_str: pointer to UUID string
* @uuid_bin: pointer to allocated array for little endian output [16B]
*
* UUID string is 36 characters (36 bytes):
*
* xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
*
* where x is a hexadecimal character. Fields are separated by '-'s.
* When converting to a little endian binary UUID, the string fields are reversed.
*
* Return:
*
* uuid_bin filled with little endian UUID data
* On success 0 is returned. Otherwise, failure code.
*/
int uuid_str_to_le_bin(const char *uuid_str, unsigned char *uuid_bin)
{
u16 tmp16;
u32 tmp32;
u64 tmp64;
if (!uuid_str_valid(uuid_str) || !uuid_bin)
return -EINVAL;
tmp32 = cpu_to_le32(hextoul(uuid_str, NULL));
memcpy(uuid_bin, &tmp32, 4);
tmp16 = cpu_to_le16(hextoul(uuid_str + 9, NULL));
memcpy(uuid_bin + 4, &tmp16, 2);
tmp16 = cpu_to_le16(hextoul(uuid_str + 14, NULL));
memcpy(uuid_bin + 6, &tmp16, 2);
tmp16 = cpu_to_le16(hextoul(uuid_str + 19, NULL));
memcpy(uuid_bin + 8, &tmp16, 2);
tmp64 = cpu_to_le64(simple_strtoull(uuid_str + 24, NULL, 16));
memcpy(uuid_bin + 10, &tmp64, 6);
return 0;
}
/*
* uuid_bin_to_str() - convert big endian binary data to string UUID or GUID.
*

View file

@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (c) 2013 Google, Inc
# Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
ifdef CONFIG_HUSH_PARSER
obj-$(CONFIG_CONSOLE_RECORD) += test_echo.o
@ -24,6 +25,7 @@ obj-$(CONFIG_CMD_SEAMA) += seama.o
ifdef CONFIG_SANDBOX
obj-$(CONFIG_CMD_READ) += rw.o
obj-$(CONFIG_CMD_SETEXPR) += setexpr.o
obj-$(CONFIG_ARM_FFA_TRANSPORT) += armffa.o
endif
obj-$(CONFIG_CMD_TEMPERATURE) += temperature.o
obj-$(CONFIG_CMD_WGET) += wget.o

33
test/cmd/armffa.c Normal file
View file

@ -0,0 +1,33 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Test for armffa command
*
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#include <common.h>
#include <string.h>
#include <asm/sandbox_arm_ffa.h>
#include <dm/test.h>
#include <test/test.h>
#include <test/ut.h>
/* Basic test of 'armffa' command */
static int dm_test_armffa_cmd(struct unit_test_state *uts)
{
/* armffa getpart <UUID> */
ut_assertok(run_command("armffa getpart " SANDBOX_SERVICE1_UUID, 0));
/* armffa ping <ID> */
ut_assertok(run_commandf("armffa ping 0x%x", SANDBOX_SP1_ID));
/* armffa devlist */
ut_assertok(run_command("armffa devlist", 0));
return 0;
}
DM_TEST(dm_test_armffa_cmd, UT_TESTF_SCAN_FDT | UT_TESTF_CONSOLE_REC);

View file

@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (c) 2013 Google, Inc
# Copyright 2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
# Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
obj-$(CONFIG_UT_DM) += test-dm.o
@ -92,6 +92,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_ARM_FFA_TRANSPORT) += ffa.o
obj-$(CONFIG_QFW) += qfw.o
obj-$(CONFIG_RAM) += ram.o
obj-y += regmap.o

261
test/dm/ffa.c Normal file
View file

@ -0,0 +1,261 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Functional tests for UCLASS_FFA class
*
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#include <common.h>
#include <console.h>
#include <dm.h>
#include <asm/sandbox_arm_ffa.h>
#include <asm/sandbox_arm_ffa_priv.h>
#include <dm/test.h>
#include <test/test.h>
#include <test/ut.h>
/* Functional tests for the UCLASS_FFA */
static int check_fwk_version(struct ffa_priv *uc_priv, struct unit_test_state *uts)
{
struct ffa_sandbox_data func_data;
u32 fwk_version = 0;
func_data.data0 = &fwk_version;
func_data.data0_size = sizeof(fwk_version);
ut_assertok(sandbox_query_ffa_emul_state(FFA_VERSION, &func_data));
ut_asserteq(uc_priv->fwk_version, fwk_version);
return 0;
}
static int check_endpoint_id(struct ffa_priv *uc_priv, struct unit_test_state *uts)
{
ut_asserteq(0, uc_priv->id);
return 0;
}
static int check_rxtxbuf(struct ffa_priv *uc_priv, struct unit_test_state *uts)
{
ut_assertnonnull(uc_priv->pair.rxbuf);
ut_assertnonnull(uc_priv->pair.txbuf);
return 0;
}
static int check_features(struct ffa_priv *uc_priv, struct unit_test_state *uts)
{
ut_assert(uc_priv->pair.rxtx_min_pages == RXTX_4K ||
uc_priv->pair.rxtx_min_pages == RXTX_16K ||
uc_priv->pair.rxtx_min_pages == RXTX_64K);
return 0;
}
static int check_rxbuf_mapped_flag(u32 queried_func_id,
u8 rxbuf_mapped,
struct unit_test_state *uts)
{
switch (queried_func_id) {
case FFA_RXTX_MAP:
ut_asserteq(1, rxbuf_mapped);
break;
case FFA_RXTX_UNMAP:
ut_asserteq(0, rxbuf_mapped);
break;
default:
ut_assert(false);
}
return 0;
}
static int check_rxbuf_release_flag(u8 rxbuf_owned, struct unit_test_state *uts)
{
ut_asserteq(0, rxbuf_owned);
return 0;
}
static int test_ffa_msg_send_direct_req(u16 part_id, struct unit_test_state *uts)
{
struct ffa_send_direct_data msg;
u8 cnt;
struct udevice *dev;
ut_assertok(uclass_first_device_err(UCLASS_FFA, &dev));
ut_assertok(ffa_sync_send_receive(dev, part_id, &msg, 1));
for (cnt = 0; cnt < sizeof(struct ffa_send_direct_data) / sizeof(u64); cnt++)
ut_asserteq_64(-1UL, ((u64 *)&msg)[cnt]);
return 0;
}
static int test_partitions_and_comms(const char *service_uuid,
struct unit_test_state *uts)
{
struct ffa_partition_desc *descs;
u32 count, i, j, valid_sps = 0;
struct udevice *dev;
struct ffa_sandbox_data func_data;
struct ffa_partitions *partitions;
ut_assertok(uclass_first_device_err(UCLASS_FFA, &dev));
/* Get from the driver the count and information of the SPs matching the UUID */
ut_assertok(ffa_partition_info_get(dev, service_uuid, &count, &descs));
/* Make sure the count is correct */
ut_asserteq(SANDBOX_SP_COUNT_PER_VALID_SERVICE, count);
/* SPs found , verify the partitions information */
func_data.data0 = &partitions;
func_data.data0_size = sizeof(struct ffa_partitions *);
ut_assertok(sandbox_query_ffa_emul_state(FFA_PARTITION_INFO_GET, &func_data));
for (i = 0; i < count ; i++) {
for (j = 0;
j < partitions->count;
j++) {
if (descs[i].info.id ==
partitions->descs[j].info.id) {
valid_sps++;
ut_asserteq_mem(&descs[i],
&partitions->descs[j],
sizeof(struct ffa_partition_desc));
/* Send and receive data from the current partition */
test_ffa_msg_send_direct_req(descs[i].info.id, uts);
}
}
}
/* Verify expected partitions found in the emulated secure world */
ut_asserteq(SANDBOX_SP_COUNT_PER_VALID_SERVICE, valid_sps);
return 0;
}
static int dm_test_ffa_ack(struct unit_test_state *uts)
{
struct ffa_priv *uc_priv;
struct ffa_sandbox_data func_data;
u8 rxbuf_flag = 0;
const char *svc1_uuid = SANDBOX_SERVICE1_UUID;
const char *svc2_uuid = SANDBOX_SERVICE2_UUID;
struct udevice *dev;
/* Test probing the sandbox FF-A bus */
ut_assertok(uclass_first_device_err(UCLASS_FFA, &dev));
/* Get a pointer to the sandbox FF-A bus private data */
uc_priv = dev_get_uclass_priv(dev);
/* Make sure the private data pointer is retrieved */
ut_assertnonnull(uc_priv);
/* Test FFA_VERSION */
check_fwk_version(uc_priv, uts);
/* Test FFA_ID_GET */
check_endpoint_id(uc_priv, uts);
/* Test FFA_FEATURES */
check_features(uc_priv, uts);
/* Test RX/TX buffers */
check_rxtxbuf(uc_priv, uts);
/* Test FFA_RXTX_MAP */
func_data.data0 = &rxbuf_flag;
func_data.data0_size = sizeof(rxbuf_flag);
rxbuf_flag = 0;
sandbox_query_ffa_emul_state(FFA_RXTX_MAP, &func_data);
check_rxbuf_mapped_flag(FFA_RXTX_MAP, rxbuf_flag, uts);
/* FFA_PARTITION_INFO_GET / FFA_MSG_SEND_DIRECT_REQ */
test_partitions_and_comms(svc1_uuid, uts);
/* Test FFA_RX_RELEASE */
rxbuf_flag = 1;
sandbox_query_ffa_emul_state(FFA_RX_RELEASE, &func_data);
check_rxbuf_release_flag(rxbuf_flag, uts);
/* FFA_PARTITION_INFO_GET / FFA_MSG_SEND_DIRECT_REQ */
test_partitions_and_comms(svc2_uuid, uts);
/* Test FFA_RX_RELEASE */
rxbuf_flag = 1;
ut_assertok(sandbox_query_ffa_emul_state(FFA_RX_RELEASE, &func_data));
check_rxbuf_release_flag(rxbuf_flag, uts);
return 0;
}
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_priv *uc_priv;
const char *valid_svc_uuid = SANDBOX_SERVICE1_UUID;
const char *unvalid_svc_uuid = SANDBOX_SERVICE3_UUID;
const char *unvalid_svc_uuid_str = SANDBOX_SERVICE4_UUID;
struct ffa_send_direct_data msg;
int ret;
u32 count;
u16 part_id = 0;
struct udevice *dev;
struct ffa_partition_desc *descs = NULL;
/* Test probing the sandbox FF-A bus */
ut_assertok(uclass_first_device_err(UCLASS_FFA, &dev));
/* Get a pointer to the sandbox FF-A bus private data */
uc_priv = dev_get_uclass_priv(dev);
/* Make sure the private data pointer is retrieved */
ut_assertnonnull(uc_priv);
/* Query partitions count using invalid arguments */
ret = ffa_partition_info_get(dev, NULL, NULL, NULL);
ut_asserteq(-EINVAL, ret);
ret = ffa_partition_info_get(dev, unvalid_svc_uuid, NULL, NULL);
ut_asserteq(-EINVAL, ret);
ret = ffa_partition_info_get(dev, unvalid_svc_uuid, &count, NULL);
ut_asserteq(-EINVAL, ret);
/* Query partitions count using an invalid UUID string */
ret = ffa_partition_info_get(dev, unvalid_svc_uuid_str, &count, &descs);
ut_asserteq(-EINVAL, ret);
/* Query partitions count using an invalid UUID (no matching SP) */
count = 0;
ret = ffa_partition_info_get(dev, unvalid_svc_uuid, &count, &descs);
ut_asserteq(0, count);
/* Query partitions data using a valid UUID */
count = 0;
ut_assertok(ffa_partition_info_get(dev, valid_svc_uuid, &count, &descs));
/* Make sure partitions are detected */
ut_asserteq(SANDBOX_SP_COUNT_PER_VALID_SERVICE, count);
ut_assertnonnull(descs);
/* Send data to an invalid partition */
ret = ffa_sync_send_receive(dev, part_id, &msg, 1);
ut_asserteq(-EINVAL, ret);
/* Send data to a valid partition */
part_id = uc_priv->partitions.descs[0].info.id;
ut_assertok(ffa_sync_send_receive(dev, part_id, &msg, 1));
return 0;
}
DM_TEST(dm_test_ffa_nack, UT_TESTF_SCAN_FDT | UT_TESTF_CONSOLE_REC);

View file

@ -22,6 +22,7 @@ obj-$(CONFIG_AES) += test_aes.o
obj-$(CONFIG_GETOPT) += getopt.o
obj-$(CONFIG_CRC8) += test_crc8.o
obj-$(CONFIG_UT_LIB_CRYPT) += test_crypt.o
obj-$(CONFIG_LIB_UUID) += uuid.o
else
obj-$(CONFIG_SANDBOX) += kconfig_spl.o
endif

41
test/lib/uuid.c Normal file
View file

@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Functional tests for UCLASS_FFA class
*
* Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
*
* Authors:
* Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
*/
#include <common.h>
#include <uuid.h>
#include <test/lib.h>
#include <test/test.h>
#include <test/ut.h>
/* test UUID */
#define TEST_SVC_UUID "ed32d533-4209-99e6-2d72-cdd998a79cc0"
#define UUID_SIZE 16
/* The UUID binary data (little-endian format) */
static const u8 ref_uuid_bin[UUID_SIZE] = {
0x33, 0xd5, 0x32, 0xed,
0x09, 0x42, 0xe6, 0x99,
0x72, 0x2d, 0xc0, 0x9c,
0xa7, 0x98, 0xd9, 0xcd
};
static int lib_test_uuid_to_le(struct unit_test_state *uts)
{
const char *uuid_str = TEST_SVC_UUID;
u8 ret_uuid_bin[UUID_SIZE] = {0};
ut_assertok(uuid_str_to_le_bin(uuid_str, ret_uuid_bin));
ut_asserteq_mem(ref_uuid_bin, ret_uuid_bin, UUID_SIZE);
return 0;
}
LIB_TEST(lib_test_uuid_to_le, 0);