[PATCH 0/8] arm_ffa: Add FFA_MEM_SHARE and FFA_MEM_RECLAIM support

From: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com
Add to the FF-A bus FFA_MEM_SHARE and FFA_MEM_RECLAIM ABIs.
These FF-A ABIs are for memory management. They are used for sharing memory between U-Boot and secure world.
FFA_MEM_SHARE starts a transaction to grant access to a memory region to one or more Borrowers (aka Secure Partitions or endpoints). FFA_MEM_RECLAIM restores exclusive access to a memory region back to its Owner (U-Boot).
For more details about these ABIs please refer to the FF-A v1.0 specification [1]. For more details about FF-A in U-Boot please refer to the readme [2].
This work is based on the implementation in Linux kernel [3].
This work is provided with sandbox support (emulation and test cases).
[1]: https://developer.arm.com/documentation/den0077/a/?lang=en [2]: doc/arch/arm64.ffa.rst [3]: commit cc2195fe536c28e192df5d07e6dd277af36814b4 Files: drivers/firmware/arm_ffa/driver.c , include/linux/arm_ffa.h
Cc: Tom Rini trini@konsulko.com Cc: Simon Glass sjg@chromium.org Cc: Ilias Apalodimas ilias.apalodimas@linaro.org Cc: Jens Wiklander jens.wiklander@linaro.org Cc: Achin Gupta achin.gupta@arm.com Cc: Drew Reed Drew.Reed@arm.com Cc: Hugues Kamba Mpiana Hugues.KambaMpiana@arm.com
Cheers, Abdellatif
Abdellatif El Khlifi (8): arm_ffa: Add NULL pointer check to the driver operations arm_ffa: Add FFA_MEM_SHARE support arm_ffa: Add FFA_MEM_RECLAIM support arm_ffa: sandbox: Replace the emulator error log with debug log arm_ffa: sandbox: Add FFA_MEM_SHARE emulation arm_ffa: sandbox: Add FFA_MEM_SHARE tests arm_ffa: sandbox: Add FFA_MEM_RECLAIM emulation arm_ffa: sandbox: Add FFA_MEM_RECLAIM tests
.../include/asm/sandbox_arm_ffa_priv.h | 5 +- doc/arch/arm64.ffa.rst | 4 + drivers/firmware/arm-ffa/arm-ffa-uclass.c | 286 +++++++++++++++++- drivers/firmware/arm-ffa/arm-ffa.c | 4 +- drivers/firmware/arm-ffa/ffa-emul-uclass.c | 92 +++++- drivers/firmware/arm-ffa/sandbox_ffa.c | 4 +- include/arm_ffa.h | 111 ++++++- include/arm_ffa_priv.h | 143 ++++++++- test/dm/ffa.c | 73 ++++- 9 files changed, 707 insertions(+), 15 deletions(-)
base-commit: 28dc47038edc4e93f32d75a357131bcf01a18d85

From: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com
Add NULL pointer check for ops
Signed-off-by: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com --- drivers/firmware/arm-ffa/arm-ffa-uclass.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c index 96c64964bb7..5ec7654ed1c 100644 --- a/drivers/firmware/arm-ffa/arm-ffa-uclass.c +++ b/drivers/firmware/arm-ffa/arm-ffa-uclass.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright 2022-2023 Arm Limited and/or its affiliates open-source-office@arm.com + * Copyright 2022-2024 Arm Limited and/or its affiliates open-source-office@arm.com * * Authors: * Abdellatif El Khlifi abdellatif.elkhlifi@arm.com @@ -954,7 +954,7 @@ int ffa_partition_info_get(struct udevice *dev, const char *uuid_str, { struct ffa_bus_ops *ops = ffa_get_ops(dev);
- if (!ops->partition_info_get) + if (!ops || !ops->partition_info_get) return -ENOSYS;
return ops->partition_info_get(dev, uuid_str, sp_count, sp_descs); @@ -979,7 +979,7 @@ int ffa_sync_send_receive(struct udevice *dev, u16 dst_part_id, { struct ffa_bus_ops *ops = ffa_get_ops(dev);
- if (!ops->sync_send_receive) + if (!ops || !ops->sync_send_receive) return -ENOSYS;
return ops->sync_send_receive(dev, dst_part_id, msg, is_smc64); @@ -1000,7 +1000,7 @@ int ffa_rxtx_unmap(struct udevice *dev) { struct ffa_bus_ops *ops = ffa_get_ops(dev);
- if (!ops->rxtx_unmap) + if (!ops || !ops->rxtx_unmap) return -ENOSYS;
return ops->rxtx_unmap(dev);

Hi Abdellatif,
Something is wrong on your setup and you only cc'ed people on the cover letter.
On Fri, Nov 01, 2024 at 02:20:10PM +0000, abdellatif.elkhlifi@arm.com wrote:
From: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com
Add NULL pointer check for ops
Signed-off-by: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com
drivers/firmware/arm-ffa/arm-ffa-uclass.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c index 96c64964bb7..5ec7654ed1c 100644 --- a/drivers/firmware/arm-ffa/arm-ffa-uclass.c +++ b/drivers/firmware/arm-ffa/arm-ffa-uclass.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /*
- Copyright 2022-2023 Arm Limited and/or its affiliates open-source-office@arm.com
- Copyright 2022-2024 Arm Limited and/or its affiliates open-source-office@arm.com
- Authors:
- Abdellatif El Khlifi abdellatif.elkhlifi@arm.com
@@ -954,7 +954,7 @@ int ffa_partition_info_get(struct udevice *dev, const char *uuid_str, { struct ffa_bus_ops *ops = ffa_get_ops(dev);
- if (!ops->partition_info_get)
if (!ops || !ops->partition_info_get) return -ENOSYS;
return ops->partition_info_get(dev, uuid_str, sp_count, sp_descs);
@@ -979,7 +979,7 @@ int ffa_sync_send_receive(struct udevice *dev, u16 dst_part_id, { struct ffa_bus_ops *ops = ffa_get_ops(dev);
- if (!ops->sync_send_receive)
if (!ops || !ops->sync_send_receive) return -ENOSYS;
return ops->sync_send_receive(dev, dst_part_id, msg, is_smc64);
@@ -1000,7 +1000,7 @@ int ffa_rxtx_unmap(struct udevice *dev) { struct ffa_bus_ops *ops = ffa_get_ops(dev);
- if (!ops->rxtx_unmap)
if (!ops || !ops->rxtx_unmap) return -ENOSYS;
return ops->rxtx_unmap(dev);
-- 2.25.1
Reviewed-by: Ilias Apalodimas ilias.apalodimas@linaro.org

On Fri, Nov 1, 2024 at 3:20 PM abdellatif.elkhlifi@arm.com wrote:
From: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com
Add NULL pointer check for ops
Signed-off-by: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com
drivers/firmware/arm-ffa/arm-ffa-uclass.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
Looks good. Reviewed-by: Jens Wiklander jens.wiklander@linaro.org
Cheers, Jens
diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c index 96c64964bb7..5ec7654ed1c 100644 --- a/drivers/firmware/arm-ffa/arm-ffa-uclass.c +++ b/drivers/firmware/arm-ffa/arm-ffa-uclass.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /*
- Copyright 2022-2023 Arm Limited and/or its affiliates open-source-office@arm.com
- Copyright 2022-2024 Arm Limited and/or its affiliates open-source-office@arm.com
- Authors:
- Abdellatif El Khlifi abdellatif.elkhlifi@arm.com
@@ -954,7 +954,7 @@ int ffa_partition_info_get(struct udevice *dev, const char *uuid_str, { struct ffa_bus_ops *ops = ffa_get_ops(dev);
if (!ops->partition_info_get)
if (!ops || !ops->partition_info_get) return -ENOSYS; return ops->partition_info_get(dev, uuid_str, sp_count, sp_descs);
@@ -979,7 +979,7 @@ int ffa_sync_send_receive(struct udevice *dev, u16 dst_part_id, { struct ffa_bus_ops *ops = ffa_get_ops(dev);
if (!ops->sync_send_receive)
if (!ops || !ops->sync_send_receive) return -ENOSYS; return ops->sync_send_receive(dev, dst_part_id, msg, is_smc64);
@@ -1000,7 +1000,7 @@ int ffa_rxtx_unmap(struct udevice *dev) { struct ffa_bus_ops *ops = ffa_get_ops(dev);
if (!ops->rxtx_unmap)
if (!ops || !ops->rxtx_unmap) return -ENOSYS; return ops->rxtx_unmap(dev);
-- 2.25.1

From: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com
Add to the FF-A bus FFA_MEM_SHARE ABI
The FFA_MEM_SHARE is a memory management ABI described in the FF-A v1.0 specification [1].
This ABI starts a transaction to grant access to a memory region to one or more Borrowers (aka Secure Partitions or endpoints).
This work is based on the implementation in Linux kernel [2].
[1]: https://developer.arm.com/documentation/den0077/a/?lang=en [2]: commit cc2195fe536c28e192df5d07e6dd277af36814b4 Files: drivers/firmware/arm_ffa/driver.c , include/linux/arm_ffa.h
Signed-off-by: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com --- doc/arch/arm64.ffa.rst | 2 + drivers/firmware/arm-ffa/arm-ffa-uclass.c | 208 ++++++++++++++++++++++ drivers/firmware/arm-ffa/arm-ffa.c | 3 +- include/arm_ffa.h | 86 ++++++++- include/arm_ffa_priv.h | 142 ++++++++++++++- 5 files changed, 437 insertions(+), 4 deletions(-)
diff --git a/doc/arch/arm64.ffa.rst b/doc/arch/arm64.ffa.rst index f966f8ba6af..3eec735d741 100644 --- a/doc/arch/arm64.ffa.rst +++ b/doc/arch/arm64.ffa.rst @@ -185,6 +185,7 @@ The following features are provided: - FFA_INTERRUPT - FFA_MSG_SEND_DIRECT_REQ - FFA_MSG_SEND_DIRECT_RESP + - FFA_MEM_SHARE
- Support for the 64-bit version of the following ABIs:
@@ -203,6 +204,7 @@ The following features are provided: - ffa_partition_info_get - ffa_sync_send_receive - ffa_rxtx_unmap + - ffa_memory_share
- FF-A bus discovery makes sure FF-A framework is responsive and compatible with the driver diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c index 5ec7654ed1c..8ff666c3757 100644 --- a/drivers/firmware/arm-ffa/arm-ffa-uclass.c +++ b/drivers/firmware/arm-ffa/arm-ffa-uclass.c @@ -95,6 +95,20 @@ static struct ffa_abi_errmap err_msg_map[FFA_ERRMAP_COUNT] = { "DENIED: Buffer pair already registered", }, }, + [FFA_ID_TO_ERRMAP_ID(FFA_MEM_SHARE)] = { + { + [ABORTED] = + "ABORTED: Failure in the transmission of fragments or in time slicing", + [INVALID_PARAMETERS] = + "INVALID_PARAMETERS: Validation failed for the Memory Transaction or the Endpoint memory access descriptor", + [NO_MEMORY] = + "NO_MEMORY: Insufficient memory to complete this operation", + [BUSY] = + "BUSY: The TX buffer is busy", + [DENIED] = + "DENIED: Memory region ownership, permission, access or attributes error", + }, + }, };
/** @@ -929,6 +943,178 @@ int ffa_msg_send_direct_req_hdlr(struct udevice *dev, u16 dst_part_id, return ffa_to_std_errno(ffa_errno); }
+/** + * ffa_mem_desc_offset() - helper for descriptors offset calculation + * @count: The number of Endpoint memory access descriptors + * + * Calculate the offset of the Endpoint memory access descriptor and + * the Composite memory region descriptor. + * + * Return: + * + * The descriptor offset. + */ +static inline u32 ffa_mem_desc_offset(int count) +{ + u32 offset = count * sizeof(struct ffa_mem_region_attributes); + + offset += sizeof(struct ffa_mem_region); + + return offset; +} + +/** + * ffa_setup_and_transmit() - setup the memory region and invoke the memory ABI + * @dev: The FF-A bus device + * @func_id: The FF-A memory ABI (currently we support FFA_MEM_SHARE only) + * @buffer: The TX buffer + * @args: The user arguments + * + * Setup the memory transaction related to the access to a specified + * memory region. + * + * Return: + * + * 0 on success. . Otherwise, failure + */ +static int ffa_setup_and_transmit(struct udevice *dev, u32 func_id, + void *buffer, struct ffa_mem_ops_args *args) +{ + ffa_value_t res = {0}; + int ffa_errno; + u32 composite_offset; + u32 total_length; + struct ffa_mem_region *mem_region = buffer; + struct ffa_composite_mem_region *composite; + struct ffa_mem_region_addr_range *constituent; + struct ffa_mem_region_attributes *ep_mem_access; + u32 idx; + struct ffa_priv *uc_priv; + + if (!buffer || !args->attrs || !args->address) + return -EINVAL; + + uc_priv = dev_get_uclass_priv(dev); + + mem_region->tag = args->tag; + mem_region->flags = args->flags; + mem_region->sender_id = uc_priv->id; + + /* + * These attributes are only valid for FFA_MEM_SHARE. + * They are not valid for FFA_MEM_LEND (no implemented). + */ + if (func_id == FFA_MEM_SHARE) + mem_region->attributes = FFA_MEM_NORMAL | FFA_MEM_WRITE_BACK + | FFA_MEM_INNER_SHAREABLE; + else + mem_region->attributes = 0; + + mem_region->handle = 0; + mem_region->ep_count = args->nattrs; + mem_region->reserved1 = 0; + mem_region->reserved2 = 0; + + ep_mem_access = buffer + ffa_mem_desc_offset(0); + + composite_offset = ffa_mem_desc_offset(args->nattrs); + + /* Multiple borrowers supported */ + for (idx = 0; idx < args->nattrs; idx++, ep_mem_access++) { + ep_mem_access->receiver = args->attrs[idx].receiver; + ep_mem_access->attrs = args->attrs[idx].attrs; + ep_mem_access->composite_off = composite_offset; + ep_mem_access->flag = 0; + ep_mem_access->reserved = 0; + } + + /* Only one Composite and one Constituent memory region supported */ + composite = buffer + composite_offset; + composite->total_pg_cnt = args->pg_cnt; + composite->addr_range_cnt = FFA_MEM_CONSTITUENTS; + composite->reserved = 0; + + constituent = &composite->constituents[0]; + constituent->address = map_to_sysmem(args->address); + constituent->pg_cnt = args->pg_cnt; + constituent->reserved = 0; + + total_length = composite_offset + sizeof(*composite) + + sizeof(*constituent); + + /* + * Note: Time slicing is not supported. + * It's only available to EL1 and S-EL1 endpoints. + */ + + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_SMC_32(func_id), + .a1 = total_length, + .a2 = total_length, + .a3 = 0, /* the TX buffer is used */ + .a4 = 0, /* the TX buffer is used */ + }, + &res + ); + + if (res.a0 != FFA_SMC_32(FFA_SUCCESS)) { + ffa_errno = res.a2; + ffa_print_error_log(func_id, ffa_errno); + return ffa_to_std_errno(ffa_errno); + } + + args->g_handle = PACK_HANDLE(res.a2, res.a3); + return 0; +} + +/** + * ffa_memory_ops() - wrapper for the memory management ABIs + * @dev: The FF-A bus device + * @func_id: The FF-A memory ABI (currently we support FFA_MEM_SHARE only) + * @args: The user arguments + * + * Verify the use of the TX buffer then call ffa_setup_and_transmit(). + * + * Return: + * + * 0 on success. Otherwise, failure + */ +static int ffa_memory_ops(struct udevice *dev, u32 func_id, + struct ffa_mem_ops_args *args) +{ + void *buffer; + struct ffa_priv *uc_priv = dev_get_uclass_priv(dev); + + if (!args->use_txbuf) { + log_err("only TX buffer supported\n"); + return -EPROTONOSUPPORT; + } + + buffer = uc_priv->pair.txbuf; + + return ffa_setup_and_transmit(dev, func_id, buffer, args); +} + +/** + * ffa_memory_share_hdlr() - FFA_MEM_SHARE handler function + * @dev: The FF-A bus device + * @args: The arguments needed by FFA_MEM_SHARE + * + * Implement FFA_MEM_SHARE FF-A function + * to grant access to a memory region to one or more Borrowers. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +int ffa_memory_share_hdlr(struct udevice *dev, struct ffa_mem_ops_args *args) +{ + if (!args) + return -EINVAL; + + return ffa_memory_ops(dev, FFA_MEM_SHARE, args); +} + /* FF-A driver operations (used by clients for communicating with FF-A)*/
/** @@ -1006,6 +1192,28 @@ int ffa_rxtx_unmap(struct udevice *dev) return ops->rxtx_unmap(dev); }
+/** + * ffa_memory_share() - FFA_MEM_SHARE driver operation + * @dev: The FF-A bus device + * @args: the arguments needed by FFA_MEM_SHARE + * + * Driver operation for FFA_MEM_SHARE. + * Please see ffa_memory_share_hdlr() description for more details. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +int ffa_memory_share(struct udevice *dev, struct ffa_mem_ops_args *args) +{ + struct ffa_bus_ops *ops = ffa_get_ops(dev); + + if (!ops || !ops->memory_share) + return -ENOSYS; + + return ops->memory_share(dev, args); +} + /** * ffa_do_probe() - probing FF-A framework * @dev: the FF-A bus device (arm_ffa) diff --git a/drivers/firmware/arm-ffa/arm-ffa.c b/drivers/firmware/arm-ffa/arm-ffa.c index 94e6105cb38..c4211c953ef 100644 --- a/drivers/firmware/arm-ffa/arm-ffa.c +++ b/drivers/firmware/arm-ffa/arm-ffa.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright 2022-2023 Arm Limited and/or its affiliates open-source-office@arm.com + * Copyright 2022-2024 Arm Limited and/or its affiliates open-source-office@arm.com * * Authors: * Abdellatif El Khlifi abdellatif.elkhlifi@arm.com @@ -84,6 +84,7 @@ 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, + .memory_share = ffa_memory_share_hdlr, };
/* Registering the FF-A driver as an SMCCC feature driver */ diff --git a/include/arm_ffa.h b/include/arm_ffa.h index db9b1be995e..ce4a3d7f440 100644 --- a/include/arm_ffa.h +++ b/include/arm_ffa.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * Copyright 2022-2023 Arm Limited and/or its affiliates open-source-office@arm.com + * Copyright 2022-2024 Arm Limited and/or its affiliates open-source-office@arm.com * * Authors: * Abdellatif El Khlifi abdellatif.elkhlifi@arm.com @@ -81,11 +81,74 @@ struct ffa_send_direct_data {
struct udevice;
+/** + * struct ffa_mem_region_attributes - Endpoint memory access descriptor + * + * The data structure used in memory management transactions to create an + * association between an endpoint, memory access permissions and a composite + * memory region description. + * + * For more details, please refer to Table 5.16 and Table 5.15 in the FF-A + * specification v1.0. + * + * This structure was taken from Linux. + */ +struct ffa_mem_region_attributes { + /* The ID of the VM to which the memory is being given or shared. */ + u16 receiver; + /* + * The permissions with which the memory region should be mapped in the + * receiver's page table. + */ +#define FFA_MEM_EXEC BIT(3) +#define FFA_MEM_NO_EXEC BIT(2) +#define FFA_MEM_RW BIT(1) +#define FFA_MEM_RO BIT(0) + u8 attrs; + /* + * Flags used during FFA_MEM_RETRIEVE_REQ and FFA_MEM_RETRIEVE_RESP + * for memory regions with multiple borrowers. + */ +#define FFA_MEM_RETRIEVE_SELF_BORROWER BIT(0) + u8 flag; + /* + * Offset in bytes from the start of the outer `ffa_memory_region` to + * an `struct ffa_mem_region_addr_range`. + */ + u32 composite_off; + u64 reserved; +}; + +/** + * struct ffa_mem_ops_args - User arguments to the memory management ABIs + * @use_txbuf: Whether to use the TX buffer for the memory transaction + * @nattrs: Number of the borrowers + * @flags: Memory transaction flags + * @tag: The tag associated with the transaction + * @g_handle: Globally unique Handle to identify the memory region (out) + * @address: Virtual address of the memory region + * @attrs: Memory access permissions of each borrower + * + * The structured filled by the user and passed to the memory + * management ABIs (e.g: FFA_MEM_SHARE) + */ +struct ffa_mem_ops_args { + bool use_txbuf; + u32 nattrs; + u32 flags; + u64 tag; + u64 g_handle; + void *address; + u32 pg_cnt; + struct ffa_mem_region_attributes *attrs; +}; + /** * 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 + * @memory_share: callback for the FFA_MEM_SHARE * * The data structure providing all the operations supported by the driver. * This structure is EFI runtime resident. @@ -97,6 +160,7 @@ struct ffa_bus_ops { struct ffa_send_direct_data *msg, bool is_smc64); int (*rxtx_unmap)(struct udevice *dev); + int (*memory_share)(struct udevice *dev, struct ffa_mem_ops_args *args); };
#define ffa_get_ops(dev) ((struct ffa_bus_ops *)(dev)->driver->ops) @@ -196,6 +260,26 @@ int ffa_partition_info_get(struct udevice *dev, const char *uuid_str, int ffa_get_partitions_info_hdlr(struct udevice *dev, const char *uuid_str, u32 *sp_count, struct ffa_partition_desc **sp_descs);
+/** + * ffa_memory_share() - FFA_MEM_SHARE driver operation + * Please see ffa_memory_share_hdlr() description for more details. + */ +int ffa_memory_share(struct udevice *dev, struct ffa_mem_ops_args *args); + +/** + * ffa_memory_share_hdlr() - FFA_MEM_SHARE handler function + * @dev: The FF-A bus device + * @args: the arguments needed by FFA_MEM_SHARE + * + * Implement FFA_MEM_SHARE FF-A function + * to grant access to a memory region to one or more Borrowers. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +int ffa_memory_share_hdlr(struct udevice *dev, struct ffa_mem_ops_args *args); + struct ffa_priv;
/** diff --git a/include/arm_ffa_priv.h b/include/arm_ffa_priv.h index d564c33c647..02e2cd89937 100644 --- a/include/arm_ffa_priv.h +++ b/include/arm_ffa_priv.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * Copyright 2022-2023 Arm Limited and/or its affiliates open-source-office@arm.com + * Copyright 2022-2024 Arm Limited and/or its affiliates open-source-office@arm.com * * Authors: * Abdellatif El Khlifi abdellatif.elkhlifi@arm.com @@ -132,10 +132,11 @@ enum ffa_abis { FFA_RUN = 0x6d, FFA_MSG_SEND_DIRECT_REQ = 0x6f, FFA_MSG_SEND_DIRECT_RESP = 0x70, + FFA_MEM_SHARE = 0x73,
/* 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 */ + FFA_LAST_ID = FFA_MEM_SHARE, /* Highest number ID */ };
enum ffa_abi_errcode { @@ -219,6 +220,143 @@ struct ffa_priv { struct ffa_rxtxpair pair; };
+/* FF-A memory management ABIs data structures */ + +/** + * struct ffa_mem_region - Lend, donate or share memory transaction descriptor + * + * Specifies the data structure that must be used by the Owner/Lender and a + * Borrower/Receiver in a transaction to donate, lend or share a memory region. + * It specifies the memory region description, properties and other transaction + * attributes in an invocation of the following ABIs. + * + * FFA_MEM_DONATE. + * FFA_MEM_LEND. + * FFA_MEM_SHARE. + * FFA_MEM_RETRIEVE_REQ. + * FFA_MEM_RETRIEVE_RESP. + * + * For more details, please refer to the Table 5.19 in the FF-A specification + * v1.0. + * + * The interpretation of some fields depends on the ABI this structure is used + * with. This variance in behavior is also specified in the Table 5.19. + * + * This structure was taken from Linux and adapted to FF-A v1.0. + */ +struct ffa_mem_region { + /* The ID of the VM/owner which originally sent the memory region */ + u16 sender_id; +#define FFA_MEM_NORMAL BIT(5) +#define FFA_MEM_DEVICE BIT(4) + +#define FFA_MEM_WRITE_BACK (3 << 2) +#define FFA_MEM_NON_CACHEABLE BIT(2) + +#define FFA_DEV_nGnRnE (0 << 2) +#define FFA_DEV_nGnRE BIT(2) +#define FFA_DEV_nGRE (2 << 2) +#define FFA_DEV_GRE (3 << 2) + +#define FFA_MEM_NON_SHAREABLE (0) +#define FFA_MEM_OUTER_SHAREABLE (2) +#define FFA_MEM_INNER_SHAREABLE (3) + /* Memory region attributes */ + u8 attributes; + + u8 reserved1; + +/* + * Clear memory region contents after unmapping it from the sender and + * before mapping it for any receiver. + */ +#define FFA_MEM_CLEAR BIT(0) +/* + * Whether the hypervisor may time slice the memory sharing or retrieval + * operation. + */ +#define FFA_TIME_SLICE_ENABLE BIT(1) + +#define FFA_MEM_RETRIEVE_TYPE_IN_RESP (0 << 3) +#define FFA_MEM_RETRIEVE_TYPE_SHARE BIT(3) +#define FFA_MEM_RETRIEVE_TYPE_LEND (2 << 3) +#define FFA_MEM_RETRIEVE_TYPE_DONATE (3 << 3) + +#define FFA_MEM_RETRIEVE_ADDR_ALIGN_HINT BIT(9) +#define FFA_MEM_RETRIEVE_ADDR_ALIGN(x) ((x) << 5) + /* Flags to control behaviour of the transaction. */ + u32 flags; +#define HANDLE_LOW_MASK GENMASK_ULL(31, 0) +#define HANDLE_HIGH_MASK GENMASK_ULL(63, 32) +#define HANDLE_LOW(x) ((u32)(FIELD_GET(HANDLE_LOW_MASK, (x)))) +#define HANDLE_HIGH(x) ((u32)(FIELD_GET(HANDLE_HIGH_MASK, (x)))) + +#define PACK_HANDLE(l, h) \ + (FIELD_PREP(HANDLE_LOW_MASK, (l)) | FIELD_PREP(HANDLE_HIGH_MASK, (h))) + /* + * A globally-unique ID assigned by the hypervisor for a region + * of memory being sent between VMs. + */ + u64 handle; + /* + * An implementation defined value associated with the receiver and the + * memory region. + */ + u64 tag; + + u32 reserved2; + + /* + * The number of `ffa_mem_region_attributes` entries included in this + * transaction. + */ + u32 ep_count; +}; + +/** + * struct ffa_mem_region_addr_range - Constituent memory region descriptor + * + * Each descriptor specifies the base address and size of a virtually or + * physically contiguous memory region. + * + * For more details, please refer to Table 5.14 in the FF-A + * specification v1.0. + * + * This structure was taken from Linux. + */ +struct ffa_mem_region_addr_range { + /* The base IPA of the constituent memory region, aligned to 4 kiB */ + u64 address; + /* The number of 4 kiB pages in the constituent memory region. */ + u32 pg_cnt; + u32 reserved; +}; + +/** + * struct ffa_composite_mem_region - Composite memory region descriptor + * + * For more details, please refer to Table 5.13 in the FF-A + * specification v1.0. + * + * This structure was taken from Linux. + */ +struct ffa_composite_mem_region { + /* + * The total number of 4 kiB pages included in this memory region. This + * must be equal to the sum of page counts specified in each + * `struct ffa_mem_region_addr_range`. + */ + u32 total_pg_cnt; + /* The number of constituents included in this memory region range */ +#define FFA_MEM_CONSTITUENTS (1) + u32 addr_range_cnt; + u64 reserved; + /** An array of `addr_range_cnt` memory region constituents. */ + struct ffa_mem_region_addr_range constituents[]; +}; + +/* Functions prototypes */ + /** * ffa_get_version_hdlr() - FFA_VERSION handler function * @dev: The FF-A bus device

From: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com
Add to the FF-A bus FFA_MEM_RECLAIM ABI
The FFA_MEM_RECLAIM is a memory management ABI described in the FF-A v1.0 specification [1].
This ABI restores exclusive access to a memory region back to its Owner.
This work is based on the implementation in Linux [2].
[1]: https://developer.arm.com/documentation/den0077/a/?lang=en [2]: commit cc2195fe536c28e192df5d07e6dd277af36814b4 File: drivers/firmware/arm_ffa/driver.c
Signed-off-by: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com --- doc/arch/arm64.ffa.rst | 2 + drivers/firmware/arm-ffa/arm-ffa-uclass.c | 70 +++++++++++++++++++++++ drivers/firmware/arm-ffa/arm-ffa.c | 1 + include/arm_ffa.h | 25 +++++++- include/arm_ffa_priv.h | 3 +- 5 files changed, 99 insertions(+), 2 deletions(-)
diff --git a/doc/arch/arm64.ffa.rst b/doc/arch/arm64.ffa.rst index 3eec735d741..d2c4fb49f79 100644 --- a/doc/arch/arm64.ffa.rst +++ b/doc/arch/arm64.ffa.rst @@ -186,6 +186,7 @@ The following features are provided: - FFA_MSG_SEND_DIRECT_REQ - FFA_MSG_SEND_DIRECT_RESP - FFA_MEM_SHARE + - FFA_MEM_RECLAIM
- Support for the 64-bit version of the following ABIs:
@@ -205,6 +206,7 @@ The following features are provided: - ffa_sync_send_receive - ffa_rxtx_unmap - ffa_memory_share + - ffa_memory_reclaim
- FF-A bus discovery makes sure FF-A framework is responsive and compatible with the driver diff --git a/drivers/firmware/arm-ffa/arm-ffa-uclass.c b/drivers/firmware/arm-ffa/arm-ffa-uclass.c index 8ff666c3757..5eae28386ae 100644 --- a/drivers/firmware/arm-ffa/arm-ffa-uclass.c +++ b/drivers/firmware/arm-ffa/arm-ffa-uclass.c @@ -109,6 +109,18 @@ static struct ffa_abi_errmap err_msg_map[FFA_ERRMAP_COUNT] = { "DENIED: Memory region ownership, permission, access or attributes error", }, }, + [FFA_ID_TO_ERRMAP_ID(FFA_MEM_RECLAIM)] = { + { + [ABORTED] = + "ABORTED: ABI invocation failure", + [INVALID_PARAMETERS] = + "INVALID_PARAMETERS: Invalid handle or flags", + [NO_MEMORY] = + "NO_MEMORY: Failure to create the Owner's mapping", + [DENIED] = + "DENIED: Memory region state issue", + }, + }, };
/** @@ -1115,6 +1127,41 @@ int ffa_memory_share_hdlr(struct udevice *dev, struct ffa_mem_ops_args *args) return ffa_memory_ops(dev, FFA_MEM_SHARE, args); }
+/** + * ffa_memory_reclaim_hdlr() - FFA_MEM_RECLAIM handler function + * @dev: The FF-A bus device + * @g_handle: The memory region globally unique Handle + * @flags: Zero memory and time slicing flags + * + * Implement FFA_MEM_RECLAIM FF-A function + * to restore exclusive access to a memory region back to its Owner. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +int ffa_memory_reclaim_hdlr(struct udevice *dev, u64 g_handle, u32 flags) +{ + ffa_value_t res; + int ffa_errno; + + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_SMC_32(FFA_MEM_RECLAIM), + .a1 = HANDLE_LOW(g_handle), .a2 = HANDLE_HIGH(g_handle), + .a3 = flags, + }, + &res + ); + + if (res.a0 != FFA_SMC_32(FFA_SUCCESS)) { + ffa_errno = res.a2; + ffa_print_error_log(FFA_MEM_RECLAIM, ffa_errno); + return ffa_to_std_errno(ffa_errno); + } + + return 0; +} + /* FF-A driver operations (used by clients for communicating with FF-A)*/
/** @@ -1214,6 +1261,29 @@ int ffa_memory_share(struct udevice *dev, struct ffa_mem_ops_args *args) return ops->memory_share(dev, args); }
+/** + * ffa_memory_reclaim() - FFA_MEM_RECLAIM driver operation + * @dev: The FF-A bus device + * @g_handle: The memory region globally unique Handle + * @flags: Zero memory and time slicing flags + * + * Driver operation for FFA_MEM_RECLAIM. + * Please see ffa_memory_reclaim_hdlr() description for more details. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +int ffa_memory_reclaim(struct udevice *dev, u64 g_handle, u32 flags) +{ + struct ffa_bus_ops *ops = ffa_get_ops(dev); + + if (!ops || !ops->memory_reclaim) + return -ENOSYS; + + return ops->memory_reclaim(dev, g_handle, flags); +} + /** * ffa_do_probe() - probing FF-A framework * @dev: the FF-A bus device (arm_ffa) diff --git a/drivers/firmware/arm-ffa/arm-ffa.c b/drivers/firmware/arm-ffa/arm-ffa.c index c4211c953ef..b7e751e3821 100644 --- a/drivers/firmware/arm-ffa/arm-ffa.c +++ b/drivers/firmware/arm-ffa/arm-ffa.c @@ -85,6 +85,7 @@ static const struct ffa_bus_ops ffa_ops = { .sync_send_receive = ffa_msg_send_direct_req_hdlr, .rxtx_unmap = ffa_unmap_rxtx_buffers_hdlr, .memory_share = ffa_memory_share_hdlr, + .memory_reclaim = ffa_memory_reclaim_hdlr, };
/* Registering the FF-A driver as an SMCCC feature driver */ diff --git a/include/arm_ffa.h b/include/arm_ffa.h index ce4a3d7f440..965139b166a 100644 --- a/include/arm_ffa.h +++ b/include/arm_ffa.h @@ -147,8 +147,9 @@ struct ffa_mem_ops_args { * 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 + * @rxtx_unmap: callback for the FFA_RXTX_UNMAP * @memory_share: callback for the FFA_MEM_SHARE + * @memory_reclaim: callback for the FFA_MEM_RECLAIM * * The data structure providing all the operations supported by the driver. * This structure is EFI runtime resident. @@ -161,6 +162,7 @@ struct ffa_bus_ops { bool is_smc64); int (*rxtx_unmap)(struct udevice *dev); int (*memory_share)(struct udevice *dev, struct ffa_mem_ops_args *args); + int (*memory_reclaim)(struct udevice *dev, u64 g_handle, u32 flags); };
#define ffa_get_ops(dev) ((struct ffa_bus_ops *)(dev)->driver->ops) @@ -280,6 +282,27 @@ int ffa_memory_share(struct udevice *dev, struct ffa_mem_ops_args *args); */ int ffa_memory_share_hdlr(struct udevice *dev, struct ffa_mem_ops_args *args);
+/** + * ffa_memory_reclaim() - FFA_MEM_RECLAIM driver operation + * Please see ffa_memory_reclaim_hdlr() description for more details. + */ +int ffa_memory_reclaim(struct udevice *dev, u64 g_handle, u32 flags); + +/** + * ffa_memory_reclaim_hdlr() - FFA_MEM_RECLAIM handler function + * @dev: The FF-A bus device + * @g_handle: The memory region globally unique Handle + * @flags: Zero memory and time slicing flags + * + * Implement FFA_MEM_RECLAIM FF-A function + * to restore exclusive access to a memory region back to its Owner. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +int ffa_memory_reclaim_hdlr(struct udevice *dev, u64 g_handle, u32 flags); + struct ffa_priv;
/** diff --git a/include/arm_ffa_priv.h b/include/arm_ffa_priv.h index 02e2cd89937..09205f40907 100644 --- a/include/arm_ffa_priv.h +++ b/include/arm_ffa_priv.h @@ -133,10 +133,11 @@ enum ffa_abis { FFA_MSG_SEND_DIRECT_REQ = 0x6f, FFA_MSG_SEND_DIRECT_RESP = 0x70, FFA_MEM_SHARE = 0x73, + FFA_MEM_RECLAIM = 0x77,
/* To be updated when adding new FFA IDs */ FFA_FIRST_ID = FFA_ERROR, /* Lowest number ID */ - FFA_LAST_ID = FFA_MEM_SHARE, /* Highest number ID */ + FFA_LAST_ID = FFA_MEM_RECLAIM, /* Highest number ID */ };
enum ffa_abi_errcode {

[...]
}
+/**
- ffa_memory_reclaim_hdlr() - FFA_MEM_RECLAIM handler function
- @dev: The FF-A bus device
- @g_handle: The memory region globally unique Handle
- @flags: Zero memory and time slicing flags
- Implement FFA_MEM_RECLAIM FF-A function
- to restore exclusive access to a memory region back to its Owner.
- Return:
- 0 on success. Otherwise, failure
- */
+int ffa_memory_reclaim_hdlr(struct udevice *dev, u64 g_handle, u32 flags) +{
- ffa_value_t res;
- int ffa_errno;
- invoke_ffa_fn((ffa_value_t){
.a0 = FFA_SMC_32(FFA_MEM_RECLAIM),
.a1 = HANDLE_LOW(g_handle), .a2 = HANDLE_HIGH(g_handle),
.a3 = flags,
},
&res
- );
- if (res.a0 != FFA_SMC_32(FFA_SUCCESS)) {
ffa_errno = res.a2;
ffa_print_error_log(FFA_MEM_RECLAIM, ffa_errno);
return ffa_to_std_errno(ffa_errno);
- }
- return 0;
+}
Is there a reason you have to define both ffa_memory_reclaim_hdlr() and ffa_memory_reclaim()? Can't you just move the checks of ffa_memory_reclaim() to ffa_memory_reclaim_hdlr()?
/* FF-A driver operations (used by clients for communicating with FF-A)*/
/** @@ -1214,6 +1261,29 @@ int ffa_memory_share(struct udevice *dev, struct ffa_mem_ops_args *args) return ops->memory_share(dev, args); }
+/**
- ffa_memory_reclaim() - FFA_MEM_RECLAIM driver operation
- @dev: The FF-A bus device
- @g_handle: The memory region globally unique Handle
- @flags: Zero memory and time slicing flags
- Driver operation for FFA_MEM_RECLAIM.
- Please see ffa_memory_reclaim_hdlr() description for more details.
- Return:
- 0 on success. Otherwise, failure
- */
+int ffa_memory_reclaim(struct udevice *dev, u64 g_handle, u32 flags) +{
- struct ffa_bus_ops *ops = ffa_get_ops(dev);
- if (!ops || !ops->memory_reclaim)
return -ENOSYS;
- return ops->memory_reclaim(dev, g_handle, flags);
+}
/**
- ffa_do_probe() - probing FF-A framework
- @dev: the FF-A bus device (arm_ffa)
diff --git a/drivers/firmware/arm-ffa/arm-ffa.c b/drivers/firmware/arm-ffa/arm-ffa.c index c4211c953ef..b7e751e3821 100644 --- a/drivers/firmware/arm-ffa/arm-ffa.c +++ b/drivers/firmware/arm-ffa/arm-ffa.c @@ -85,6 +85,7 @@ static const struct ffa_bus_ops ffa_ops = { .sync_send_receive = ffa_msg_send_direct_req_hdlr, .rxtx_unmap = ffa_unmap_rxtx_buffers_hdlr, .memory_share = ffa_memory_share_hdlr,
- .memory_reclaim = ffa_memory_reclaim_hdlr,
};
[...]
Thanks /Ilias

Hi Ilias,
+/**
- ffa_memory_reclaim_hdlr() - FFA_MEM_RECLAIM handler function
- @dev: The FF-A bus device
- @g_handle: The memory region globally unique Handle
- @flags: Zero memory and time slicing flags
- Implement FFA_MEM_RECLAIM FF-A function
- to restore exclusive access to a memory region back to its Owner.
- Return:
- 0 on success. Otherwise, failure
- */
+int ffa_memory_reclaim_hdlr(struct udevice *dev, u64 g_handle, u32 flags) +{
- ffa_value_t res;
- int ffa_errno;
- invoke_ffa_fn((ffa_value_t){
.a0 = FFA_SMC_32(FFA_MEM_RECLAIM),
.a1 = HANDLE_LOW(g_handle), .a2 = HANDLE_HIGH(g_handle),
.a3 = flags,
},
&res
- );
- if (res.a0 != FFA_SMC_32(FFA_SUCCESS)) {
ffa_errno = res.a2;
ffa_print_error_log(FFA_MEM_RECLAIM, ffa_errno);
return ffa_to_std_errno(ffa_errno);
- }
- return 0;
+}
Is there a reason you have to define both ffa_memory_reclaim_hdlr() and ffa_memory_reclaim()? Can't you just move the checks of ffa_memory_reclaim() to ffa_memory_reclaim_hdlr()?
Yes, ffa_memory_reclaim() is the FF-A bus operation which is called by upper layers (clients).
ffa_memory_reclaim_hdlr() is the low level handler called by the operation.
The handler is set by the driver (e.g: Arm driver, sandbox driver) in the driver's ops structure [5].
So, the driver can set the handler and define its own if needed.
The client doesn't know which handler to use. It just calls the driver operation.
This design was followed in the other ABIs already merged. For example [1][2][3][4].
[1]: ffa_rxtx_unmap() operation: drivers/firmware/arm-ffa/arm-ffa-uclass.c#L999 [2]: ffa_unmap_rxtx_buffers_hdlr() handler: drivers/firmware/arm-ffa/arm-ffa-uclass.c#L999 [3]: rxtx_unmap ops callback in sandbox driver: drivers/firmware/arm-ffa/sandbox_ffa.c#L93 [4]: rxtx_unmap ops callback in Arm driver: drivers/firmware/arm-ffa/arm-ffa.c#L86 [5]: Arm's driver ops structure: drivers/firmware/arm-ffa/arm-ffa.c#L83
/* FF-A driver operations (used by clients for communicating with FF-A)*/ ... +/**
- ffa_memory_reclaim() - FFA_MEM_RECLAIM driver operation
- @dev: The FF-A bus device
- @g_handle: The memory region globally unique Handle
- @flags: Zero memory and time slicing flags
- Driver operation for FFA_MEM_RECLAIM.
- Please see ffa_memory_reclaim_hdlr() description for more details.
- Return:
- 0 on success. Otherwise, failure
- */
+int ffa_memory_reclaim(struct udevice *dev, u64 g_handle, u32 flags) +{
- struct ffa_bus_ops *ops = ffa_get_ops(dev);
- if (!ops || !ops->memory_reclaim)
return -ENOSYS;
- return ops->memory_reclaim(dev, g_handle, flags);
+}
Cheers, Abdellatif

From: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com
Set the log to a debug log and reformulate the message
The message is about showing what the emulated FF-A ABI decided based on the user arguments. The log is just for information purposes and helpful when debugging.
Signed-off-by: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com --- drivers/firmware/arm-ffa/ffa-emul-uclass.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/firmware/arm-ffa/ffa-emul-uclass.c b/drivers/firmware/arm-ffa/ffa-emul-uclass.c index 1521d9b66ac..3e8b5288d3b 100644 --- a/drivers/firmware/arm-ffa/ffa-emul-uclass.c +++ b/drivers/firmware/arm-ffa/ffa-emul-uclass.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright 2022-2023 Arm Limited and/or its affiliates open-source-office@arm.com + * Copyright 2022-2024 Arm Limited and/or its affiliates open-source-office@arm.com * * Authors: * Abdellatif El Khlifi abdellatif.elkhlifi@arm.com @@ -658,8 +658,7 @@ void sandbox_arm_ffa_smccc_smc(ffa_value_t *args, ffa_value_t *res) args->a0); }
- if (ret != 0) - log_err("FF-A ABI internal failure (%d)\n", ret); + log_debug("Emulated FF-A ABI feedback (%d)\n", ret); }
/**

On Fri, Nov 01, 2024 at 02:20:13PM +0000, abdellatif.elkhlifi@arm.com wrote:
From: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com
Set the log to a debug log and reformulate the message
The message is about showing what the emulated FF-A ABI decided based on the user arguments. The log is just for information purposes and helpful when debugging.
Signed-off-by: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com
drivers/firmware/arm-ffa/ffa-emul-uclass.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/firmware/arm-ffa/ffa-emul-uclass.c b/drivers/firmware/arm-ffa/ffa-emul-uclass.c index 1521d9b66ac..3e8b5288d3b 100644 --- a/drivers/firmware/arm-ffa/ffa-emul-uclass.c +++ b/drivers/firmware/arm-ffa/ffa-emul-uclass.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /*
- Copyright 2022-2023 Arm Limited and/or its affiliates open-source-office@arm.com
- Copyright 2022-2024 Arm Limited and/or its affiliates open-source-office@arm.com
- Authors:
- Abdellatif El Khlifi abdellatif.elkhlifi@arm.com
@@ -658,8 +658,7 @@ void sandbox_arm_ffa_smccc_smc(ffa_value_t *args, ffa_value_t *res) args->a0); }
- if (ret != 0)
log_err("FF-A ABI internal failure (%d)\n", ret);
- log_debug("Emulated FF-A ABI feedback (%d)\n", ret);
}
/**
2.25.1
Reviewed-by: Ilias Apalodimas ilias.apalodimas@linaro.org

From: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com
Add FFA_MEM_SHARE support to the FF-A emulator
Signed-off-by: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com --- .../include/asm/sandbox_arm_ffa_priv.h | 5 ++- drivers/firmware/arm-ffa/ffa-emul-uclass.c | 44 +++++++++++++++++++ drivers/firmware/arm-ffa/sandbox_ffa.c | 3 +- 3 files changed, 50 insertions(+), 2 deletions(-)
diff --git a/arch/sandbox/include/asm/sandbox_arm_ffa_priv.h b/arch/sandbox/include/asm/sandbox_arm_ffa_priv.h index b0881822d78..8d04efc32d6 100644 --- a/arch/sandbox/include/asm/sandbox_arm_ffa_priv.h +++ b/arch/sandbox/include/asm/sandbox_arm_ffa_priv.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * Copyright 2022-2023 Arm Limited and/or its affiliates open-source-office@arm.com + * Copyright 2022-2024 Arm Limited and/or its affiliates open-source-office@arm.com * * Authors: * Abdellatif El Khlifi abdellatif.elkhlifi@arm.com @@ -70,6 +70,9 @@ #define SANDBOX_SERVICE2_UUID_A3 0x9cc02d72 #define SANDBOX_SERVICE2_UUID_A4 0xcdd998a7
+/* Globally unique Handle to identify the shared memory region */ +#define SANDBOX_MEM_HANDLE 0xffffffff + /** * struct ffa_rxtxpair_info - structure hosting the RX/TX buffers flags * @rxbuf_owned: RX buffer ownership flag (the owner is non secure world) diff --git a/drivers/firmware/arm-ffa/ffa-emul-uclass.c b/drivers/firmware/arm-ffa/ffa-emul-uclass.c index 3e8b5288d3b..a859d2e26cc 100644 --- a/drivers/firmware/arm-ffa/ffa-emul-uclass.c +++ b/drivers/firmware/arm-ffa/ffa-emul-uclass.c @@ -563,6 +563,47 @@ static int sandbox_ffa_get_parts(struct udevice *emul, struct ffa_sandbox_data * return 0; }
+/** + * sandbox_ffa_memory_share() - Emulated FFA_MEM_SHARE handler + * @emul: The sandbox FF-A emulator device + * @pargs: The SMC call input arguments a0-a7 + * @res: The SMC return data + * + * Emulate FFA_MEM_SHARE FF-A function. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +static int sandbox_ffa_memory_share(struct udevice *emul, ffa_value_t *pargs, + ffa_value_t *res) +{ + int ret; + + res->a0 = FFA_SMC_32(FFA_ERROR); + res->a3 = 0; + + if (!pargs->a1 || (pargs->a1 > (RXTX_BUFFERS_MIN_PAGES * SZ_4K))) { + res->a2 = -INVALID_PARAMETERS; + ret = ffa_to_std_errmap[INVALID_PARAMETERS]; + goto feedback; + } + + res->a0 = FFA_SMC_32(FFA_SUCCESS); + res->a2 = SANDBOX_MEM_HANDLE; + res->a3 = SANDBOX_MEM_HANDLE; + ret = 0; + +feedback: + + res->a1 = 0; + + /* x4-x7 MBZ */ + memset(FFA_X4X7_MBZ_REG_START, 0, FFA_X4X7_MBZ_CNT * sizeof(ulong)); + + return ret; +} + /** * sandbox_query_ffa_emul_state() - Inspect the FF-A ABIs * @queried_func_id: The FF-A function to be queried @@ -653,6 +694,9 @@ void sandbox_arm_ffa_smccc_smc(ffa_value_t *args, ffa_value_t *res) case FFA_SMC_32(FFA_RX_RELEASE): ret = sandbox_ffa_rx_release(emul, args, res); break; + case FFA_SMC_32(FFA_MEM_SHARE): + ret = sandbox_ffa_memory_share(emul, args, res); + break; default: log_err("Undefined FF-A interface (%lx)\n", args->a0); diff --git a/drivers/firmware/arm-ffa/sandbox_ffa.c b/drivers/firmware/arm-ffa/sandbox_ffa.c index 44b32a829dd..a81455ce5ff 100644 --- a/drivers/firmware/arm-ffa/sandbox_ffa.c +++ b/drivers/firmware/arm-ffa/sandbox_ffa.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright 2022-2023 Arm Limited and/or its affiliates open-source-office@arm.com + * Copyright 2022-2024 Arm Limited and/or its affiliates open-source-office@arm.com * * Authors: * Abdellatif El Khlifi abdellatif.elkhlifi@arm.com @@ -91,6 +91,7 @@ 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, + .memory_share = ffa_memory_share_hdlr, };
static const struct udevice_id sandbox_ffa_id[] = {

From: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com
Add positive and negative test cases
Signed-off-by: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com --- test/dm/ffa.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-)
diff --git a/test/dm/ffa.c b/test/dm/ffa.c index 593b7177fce..4fd21ac3d72 100644 --- a/test/dm/ffa.c +++ b/test/dm/ffa.c @@ -2,7 +2,7 @@ /* * Functional tests for UCLASS_FFA class * - * Copyright 2022-2023 Arm Limited and/or its affiliates open-source-office@arm.com + * Copyright 2022-2024 Arm Limited and/or its affiliates open-source-office@arm.com * * Authors: * Abdellatif El Khlifi abdellatif.elkhlifi@arm.com @@ -13,6 +13,7 @@ #include <asm/sandbox_arm_ffa.h> #include <asm/sandbox_arm_ffa_priv.h> #include <dm/test.h> +#include <linux/sizes.h> #include <test/test.h> #include <test/ut.h>
@@ -141,6 +142,43 @@ static int test_partitions_and_comms(const char *service_uuid, return 0; }
+static int test_ffa_memory_share(bool test_ack, struct unit_test_state *uts) +{ + struct ffa_mem_ops_args args = {0}; + struct ffa_mem_region_attributes attrs = {0}; + static u8 buf[SZ_4K]; + int ret; + struct udevice *dev; + + ut_assertok(uclass_first_device_err(UCLASS_FFA, &dev)); + + args.attrs = &attrs; + args.nattrs = 1; + args.address = buf; + args.pg_cnt = 1; + + if (test_ack) { + args.use_txbuf = true; + + ut_assertok(ffa_memory_share(dev, &args)); + ut_asserteq(HANDLE_LOW(args.g_handle), SANDBOX_MEM_HANDLE); + ut_asserteq(HANDLE_HIGH(args.g_handle), SANDBOX_MEM_HANDLE); + } else { + /* Do not use the TX buffer as a transaction buffer */ + args.use_txbuf = false; + ret = ffa_memory_share(dev, &args); + ut_asserteq(-EPROTONOSUPPORT, ret); + + /* No memory region address given */ + args.use_txbuf = true; + args.address = NULL; + ret = ffa_memory_share(dev, &args); + ut_asserteq(-EINVAL, ret); + } + + return 0; +} + static int dm_test_ffa_ack(struct unit_test_state *uts) { struct ffa_priv *uc_priv; @@ -195,6 +233,9 @@ static int dm_test_ffa_ack(struct unit_test_state *uts) ut_assertok(sandbox_query_ffa_emul_state(FFA_RX_RELEASE, &func_data)); check_rxbuf_release_flag(rxbuf_flag, uts);
+ /* Test FFA_MEM_SHARE */ + test_ffa_memory_share(true, uts); + return 0; } DM_TEST(dm_test_ffa_ack, UTF_SCAN_FDT | UTF_CONSOLE); @@ -253,6 +294,9 @@ static int dm_test_ffa_nack(struct unit_test_state *uts) part_id = uc_priv->partitions.descs[0].info.id; ut_assertok(ffa_sync_send_receive(dev, part_id, &msg, 1));
+ /* Test FFA_MEM_SHARE */ + test_ffa_memory_share(false, uts); + return 0; } DM_TEST(dm_test_ffa_nack, UTF_SCAN_FDT | UTF_CONSOLE);

From: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com
Add FFA_MEM_RECLAIM support to the FF-A emulator
Signed-off-by: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com --- drivers/firmware/arm-ffa/ffa-emul-uclass.c | 43 ++++++++++++++++++++++ drivers/firmware/arm-ffa/sandbox_ffa.c | 1 + 2 files changed, 44 insertions(+)
diff --git a/drivers/firmware/arm-ffa/ffa-emul-uclass.c b/drivers/firmware/arm-ffa/ffa-emul-uclass.c index a859d2e26cc..b628e2c5c63 100644 --- a/drivers/firmware/arm-ffa/ffa-emul-uclass.c +++ b/drivers/firmware/arm-ffa/ffa-emul-uclass.c @@ -604,6 +604,46 @@ feedback: return ret; }
+/** + * sandbox_ffa_memory_reclaim() - Emulated FFA_MEM_RECLAIM handler + * @emul: The sandbox FF-A emulator device + * @pargs: The SMC call input arguments a0-a7 + * @res: The SMC return data + * + * Emulate FFA_MEM_RECLAIM FF-A function. + * + * Return: + * + * 0 on success. Otherwise, failure + */ +static int sandbox_ffa_memory_reclaim(struct udevice *emul, ffa_value_t *pargs, + ffa_value_t *res) +{ + int ret; + + if (pargs->a1 != SANDBOX_MEM_HANDLE || + pargs->a2 != SANDBOX_MEM_HANDLE) { + res->a0 = FFA_SMC_32(FFA_ERROR); + res->a2 = -INVALID_PARAMETERS; + ret = ffa_to_std_errmap[INVALID_PARAMETERS]; + goto feedback; + } + + res->a0 = FFA_SMC_32(FFA_SUCCESS); + res->a2 = 0; + ret = 0; + +feedback: + + res->a1 = 0; + res->a3 = 0; + + /* x4-x7 MBZ */ + memset(FFA_X4X7_MBZ_REG_START, 0, FFA_X4X7_MBZ_CNT * sizeof(ulong)); + + return ret; +} + /** * sandbox_query_ffa_emul_state() - Inspect the FF-A ABIs * @queried_func_id: The FF-A function to be queried @@ -697,6 +737,9 @@ void sandbox_arm_ffa_smccc_smc(ffa_value_t *args, ffa_value_t *res) case FFA_SMC_32(FFA_MEM_SHARE): ret = sandbox_ffa_memory_share(emul, args, res); break; + case FFA_SMC_32(FFA_MEM_RECLAIM): + ret = sandbox_ffa_memory_reclaim(emul, args, res); + break; default: log_err("Undefined FF-A interface (%lx)\n", args->a0); diff --git a/drivers/firmware/arm-ffa/sandbox_ffa.c b/drivers/firmware/arm-ffa/sandbox_ffa.c index a81455ce5ff..8af9c8ac005 100644 --- a/drivers/firmware/arm-ffa/sandbox_ffa.c +++ b/drivers/firmware/arm-ffa/sandbox_ffa.c @@ -92,6 +92,7 @@ static const struct ffa_bus_ops sandbox_ffa_ops = { .sync_send_receive = ffa_msg_send_direct_req_hdlr, .rxtx_unmap = ffa_unmap_rxtx_buffers_hdlr, .memory_share = ffa_memory_share_hdlr, + .memory_reclaim = ffa_memory_reclaim_hdlr, };
static const struct udevice_id sandbox_ffa_id[] = {

From: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com
Add FFA_MEM_RECLAIM positive and negative test cases
Signed-off-by: Abdellatif El Khlifi abdellatif.elkhlifi@arm.com --- test/dm/ffa.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
diff --git a/test/dm/ffa.c b/test/dm/ffa.c index 4fd21ac3d72..c481964c758 100644 --- a/test/dm/ffa.c +++ b/test/dm/ffa.c @@ -179,6 +179,27 @@ static int test_ffa_memory_share(bool test_ack, struct unit_test_state *uts) return 0; }
+static int test_ffa_memory_reclaim(bool test_ack, struct unit_test_state *uts) +{ + int ret; + u64 g_handle; + struct udevice *dev; + + ut_assertok(uclass_first_device_err(UCLASS_FFA, &dev)); + + if (test_ack) { + g_handle = PACK_HANDLE(SANDBOX_MEM_HANDLE, SANDBOX_MEM_HANDLE); + ut_assertok(ffa_memory_reclaim(dev, g_handle, 0)); + } else { + /* Provide a wrong handle */ + g_handle = PACK_HANDLE(SANDBOX_MEM_HANDLE, 0); + ret = ffa_memory_reclaim(dev, g_handle, 0); + ut_asserteq(-EINVAL, ret); + } + + return 0; +} + static int dm_test_ffa_ack(struct unit_test_state *uts) { struct ffa_priv *uc_priv; @@ -236,6 +257,9 @@ static int dm_test_ffa_ack(struct unit_test_state *uts) /* Test FFA_MEM_SHARE */ test_ffa_memory_share(true, uts);
+ /* Test FFA_MEM_RECLAIM */ + test_ffa_memory_reclaim(true, uts); + return 0; } DM_TEST(dm_test_ffa_ack, UTF_SCAN_FDT | UTF_CONSOLE); @@ -297,6 +321,9 @@ static int dm_test_ffa_nack(struct unit_test_state *uts) /* Test FFA_MEM_SHARE */ test_ffa_memory_share(false, uts);
+ /* Test FFA_MEM_RECLAIM */ + test_ffa_memory_reclaim(false, uts); + return 0; } DM_TEST(dm_test_ffa_nack, UTF_SCAN_FDT | UTF_CONSOLE);

Hi Simon, Tom,
Add to the FF-A bus FFA_MEM_SHARE and FFA_MEM_RECLAIM ABIs.
These FF-A ABIs are for memory management. They are used for sharing memory between U-Boot and secure world.
FFA_MEM_SHARE starts a transaction to grant access to a memory region to one or more Borrowers (aka Secure Partitions or endpoints). FFA_MEM_RECLAIM restores exclusive access to a memory region back to its Owner (U-Boot).
For more details about these ABIs please refer to the FF-A v1.0 specification [1]. For more details about FF-A in U-Boot please refer to the readme [2].
This work is based on the implementation in Linux kernel [3].
This work is provided with sandbox support (emulation and test cases).
[3]: commit cc2195fe536c28e192df5d07e6dd277af36814b4 Files: drivers/firmware/arm_ffa/driver.c , include/linux/arm_ffa.h
Cc: Tom Rini trini@konsulko.com Cc: Simon Glass sjg@chromium.org Cc: Ilias Apalodimas ilias.apalodimas@linaro.org Cc: Jens Wiklander jens.wiklander@linaro.org Cc: Achin Gupta achin.gupta@arm.com Cc: Drew Reed Drew.Reed@arm.com Cc: Hugues Kamba Mpiana Hugues.KambaMpiana@arm.com
Cheers, Abdellatif
Abdellatif El Khlifi (8): arm_ffa: Add NULL pointer check to the driver operations arm_ffa: Add FFA_MEM_SHARE support arm_ffa: Add FFA_MEM_RECLAIM support arm_ffa: sandbox: Replace the emulator error log with debug log arm_ffa: sandbox: Add FFA_MEM_SHARE emulation arm_ffa: sandbox: Add FFA_MEM_SHARE tests arm_ffa: sandbox: Add FFA_MEM_RECLAIM emulation arm_ffa: sandbox: Add FFA_MEM_RECLAIM tests
A gentle reminder please. Your comments are welcome.
Cheers, Abdellatif

Hi Tom,
I'm happy to address your review comments and make the patchset meets your expectations.
Please feel free to give a feedback and I'll be addressing that ASAP.
Cheers Abdellatif
On Thu, Nov 07, 2024 at 03:33:11PM +0000, Abdellatif El Khlifi wrote:
Hi Simon, Tom,
Add to the FF-A bus FFA_MEM_SHARE and FFA_MEM_RECLAIM ABIs.
These FF-A ABIs are for memory management. They are used for sharing memory between U-Boot and secure world.
FFA_MEM_SHARE starts a transaction to grant access to a memory region to one or more Borrowers (aka Secure Partitions or endpoints). FFA_MEM_RECLAIM restores exclusive access to a memory region back to its Owner (U-Boot).
For more details about these ABIs please refer to the FF-A v1.0 specification [1]. For more details about FF-A in U-Boot please refer to the readme [2].
This work is based on the implementation in Linux kernel [3].
This work is provided with sandbox support (emulation and test cases).
[3]: commit cc2195fe536c28e192df5d07e6dd277af36814b4 Files: drivers/firmware/arm_ffa/driver.c , include/linux/arm_ffa.h
Cc: Tom Rini trini@konsulko.com Cc: Simon Glass sjg@chromium.org Cc: Ilias Apalodimas ilias.apalodimas@linaro.org Cc: Jens Wiklander jens.wiklander@linaro.org Cc: Achin Gupta achin.gupta@arm.com Cc: Drew Reed Drew.Reed@arm.com Cc: Hugues Kamba Mpiana Hugues.KambaMpiana@arm.com
Cheers, Abdellatif
Abdellatif El Khlifi (8): arm_ffa: Add NULL pointer check to the driver operations arm_ffa: Add FFA_MEM_SHARE support arm_ffa: Add FFA_MEM_RECLAIM support arm_ffa: sandbox: Replace the emulator error log with debug log arm_ffa: sandbox: Add FFA_MEM_SHARE emulation arm_ffa: sandbox: Add FFA_MEM_SHARE tests arm_ffa: sandbox: Add FFA_MEM_RECLAIM emulation arm_ffa: sandbox: Add FFA_MEM_RECLAIM tests
A gentle reminder please. Your comments are welcome.
Cheers, Abdellatif
participants (4)
-
Abdellatif El Khlifi
-
abdellatif.elkhlifi@arm.com
-
Ilias Apalodimas
-
Jens Wiklander