
Hi Abdellatif,
On Mon, 1 Aug 2022 at 20:21, Abdellatif El Khlifi abdellatif.elkhlifi@arm.com wrote:
Add the driver implementing Arm Firmware Framework for Armv8-A v1.0
The Firmware Framework for Arm A-profile processors (FF-A) describes interfaces (ABIs) that standardize communication between the Secure World and Normal World leveraging TrustZone technology.
This driver uses 64-bit registers as per SMCCCv1.2 spec and comes on top of the SMCCC layer. The driver provides the FF-A ABIs needed for querying the FF-A framework from the secure world.
32-bit version of the ABIs is supported and 64-bit version of FFA_RXTX_MAP and FFA_MSG_SEND_DIRECT_{REQ, RESP}.
In u-boot FF-A design, FF-A is considered as a discoverable bus. 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). This FF-A driver takes care of all the interactions between Normal world and Secure World.
The driver exports its operations to be used by upper layers.
Exported operations:
- partition_info_get
- sync_send_receive
- rxtx_unmap
This implementation provides an optional feature to copy the driver data to EFI runtime area.
[...]
+config ARM_FFA_TRANSPORT
bool "Enable Arm Firmware Framework for Armv8-A driver"
depends on DM && ARM64
select ARM_SMCCC
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.
This driver is based on FF-A specification v1.0 and uses SMC32
calling convention.
FF-A specification:
https://developer.arm.com/documentation/den0077/a/?lang=en
In u-boot FF-A design, FF-A is considered as a discoverable bus.
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).
This FF-A driver takes care of all the interactions between Normal world
and Secure World.
+config ARM_FFA_EFI_RUNTIME_MODE
bool "Enable EFI runtime support for FF-A data and code "
depends on ARM_FFA_TRANSPORT && EFI_LOADER
help
Allows FF-A driver data structures and code to be accessible at EFI runtime
Is there a reason we want to opt-in on that? What prevents it from always being there?
[...]
+/* 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))
+#define FFA_VERSION FFA_SMC_32(0x63) +#define FFA_ID_GET FFA_SMC_32(0x69) +#define FFA_FEATURES FFA_SMC_32(0x64) +#define FFA_PARTITION_INFO_GET FFA_SMC_32(0x68) +#define FFA_RXTX_UNMAP FFA_SMC_32(0x67) +#define FFA_RX_RELEASE FFA_SMC_32(0x65) +#define FFA_RUN FFA_SMC_32(0x6D) +#define FFA_ERROR FFA_SMC_32(0x60) +#define FFA_SUCCESS FFA_SMC_32(0x61) +#define FFA_INTERRUPT FFA_SMC_32(0x62) +#define FFA_RXTX_MAP FFA_SMC_64(0x66) +#define FFA_MSG_SEND_DIRECT_REQ FFA_SMC_64(0x6F) +#define FFA_MSG_SEND_DIRECT_RESP FFA_SMC_64(0x70)
+/* The FF-A SMC function definitions */
+typedef struct arm_smccc_1_2_regs ffa_value_t; +typedef void (*invoke_ffa_fn_t)(ffa_value_t args, ffa_value_t *res);
+/* FF-A error codes */ +#define FFA_ERR_STAT_NOT_SUPPORTED (-1) +#define FFA_ERR_STAT_INVALID_PARAMETERS (-2) +#define FFA_ERR_STAT_NO_MEMORY (-3) +#define FFA_ERR_STAT_BUSY (-4) +#define FFA_ERR_STAT_INTERRUPTED (-5) +#define FFA_ERR_STAT_DENIED (-6) +#define FFA_ERR_STAT_RETRY (-7) +#define FFA_ERR_STAT_ABORTED (-8)
+/* UUID data size */ +#define UUID_SIZE (16)
Please drop () on these
+/*
- union ffa_partition_uuid - Data union hosting the UUID
transmitted by FFA_PARTITION_INFO_GET
- @words: data structure giving 32-bit words access to the UUID data
- @bytes: data structure giving byte access to the UUID data
- The structure holds little-endian UUID data.
- */
+union ffa_partition_uuid {
struct __packed words {
u32 a1; /* w1 */
u32 a2; /* w2 */
u32 a3; /* w3 */
u32 a4; /* w4 */
} words;
u8 bytes[UUID_SIZE];
+};
is the bytes field used anywhere?
[...]
- Each partition has its descriptor containing the partitions information and the UUID
- */
+struct ffa_partition_desc {
struct ffa_partition_info info;
union ffa_partition_uuid UUID;
lower case please and perhaps a better name e.g partition_uuid
+};
+/**
- struct ffa_partitions - descriptors for all secure partitions
- @count: The number of partitions descriptors
- @descs The partitions descriptors table
- This data structure contains the partitions descriptors table
- */
+struct ffa_partitions {
u32 count;
struct ffa_partition_desc *descs; /* virtual address */
+};
+/**
- struct ffa_prvdata - the driver private data structure
- @dev: The arm_ffa device under u-boot driver model
- @ffa_ops: The driver operations structure
- @fwk_version: FF-A framework version
- @id: u-boot endpoint ID
- @partitions: The partitions descriptors structure
- @pair: The RX/TX buffers pair
- @invoke_ffa_fn: The function executing the FF-A function
- @features: Table of the FF-A functions having features
- The driver data structure hosting all resident data.
- */
+struct ffa_prvdata {
struct udevice *dev;
struct ffa_bus_ops ffa_ops;
u32 fwk_version;
u16 id;
struct ffa_partitions partitions;
struct ffa_rxtxpair pair;
invoke_ffa_fn_t invoke_ffa_fn;
struct ffa_features_desc features[FFA_FEATURE_DESC_CNT];
+};
+/**
- ffa_device_get - create, bind and probe the arm_ffa device
- */
+int ffa_device_get(void);
+/**
- ffa_bus_prvdata_get - bus driver private data getter
- */
+struct ffa_prvdata **ffa_bus_prvdata_get(void);
+#endif diff --git a/drivers/arm-ffa/core.c b/drivers/arm-ffa/core.c new file mode 100644 index 0000000000..40d140fc3e --- /dev/null +++ b/drivers/arm-ffa/core.c @@ -0,0 +1,1338 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- (C) Copyright 2022 ARM Limited
- Abdellatif El Khlifi abdellatif.elkhlifi@arm.com
- */
+#include "arm_ffa_prv.h" +#include <asm/global_data.h> +#include <common.h> +#include <dm.h> +#include <dm/device-internal.h> +#include <dm/devres.h> +#include <dm/root.h> +#include <linux/errno.h> +#include <linux/sizes.h> +#include <log.h> +#include <malloc.h> +#include <string.h> +#include <uuid.h>
+DECLARE_GLOBAL_DATA_PTR;
+/**
- The device private data structure containing all the resident
- data read from secure world
- */
+__ffa_runtime_data struct ffa_prvdata *ffa_priv_data;
I think it's better if we just keep this as efi_runtime, especially since the rest of the declarations you use are marked as efi_*
[...]
+/**
- ffa_device_get - create, bind and probe the arm_ffa device
- This boot time function makes sure the arm_ffa device is
- created, bound to this driver, probed and ready to use.
- Arm FF-A transport is implemented through a single u-boot
- device managing the FF-A bus (arm_ffa).
- Return:
- FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
- */
+int ffa_device_get(void) +{
int ret;
struct udevice *dev = NULL;
if (ffa_priv_data && ffa_priv_data->dev)
return FFA_ERR_STAT_SUCCESS;
ret = device_bind(dm_root(),
DM_DRIVER_GET(arm_ffa),
FFA_DRV_NAME,
NULL,
ofnode_null(),
&dev);
if (ret)
return ret;
/* The FF-A bus discovery succeeds when probing is successful */
ret = device_probe(dev);
if (ret) {
ffa_err("arm_ffa device probing failed");
ffa_remove_device(dev);
return ret;
}
return FFA_ERR_STAT_SUCCESS;
The return values in most of the functions are confusing. I think you should just get rid of FFA_ERR_STAT_SUCCESS and just return 0
[...]
if (!ffa_priv_data->invoke_ffa_fn)
panic("[FFA] no private data found\n");
Get rid of all the panicking please. We've discussed this on a previous email. Isn't an error message enough?
[...]
- ffa_map_rxtx_buffers - FFA_RXTX_MAP handler function
- @buf_4k_pages: the minimum number of pages in each of the RX/TX
buffers
- This is the boot time function that implements FFA_RXTX_MAP FF-A function
- to map the RX/TX buffers
- Return:
- FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
- */
+static int ffa_map_rxtx_buffers(size_t buf_4k_pages) +{
int ret;
ffa_value_t res = {0};
if (!ffa_priv_data->invoke_ffa_fn)
panic("[FFA] no private data found\n");
ret = ffa_alloc_rxtx_buffers(buf_4k_pages);
if (ret != FFA_ERR_STAT_SUCCESS)
return ret;
/*
* we need to pass the physical addresses of the RX/TX buffers
* in u-boot physical/virtual mapping is 1:1
*no need to convert from virtual to physical
*/
ffa_priv_data->invoke_ffa_fn((ffa_value_t){
.a0 = FFA_RXTX_MAP,
.a1 = ffa_priv_data->pair.txbuf,
.a2 = ffa_priv_data->pair.rxbuf,
.a3 = buf_4k_pages,
.a4 = 0, .a5 = 0, .a6 = 0, .a7 = 0,
}, &res);
switch (res.a0) {
case FFA_ERROR:
{
There are comments in v2 that are ignored throughout the patchset. Please check the remarks in v2 before sending a new patchset
switch (((int)res.a2)) {
case FFA_ERR_STAT_INVALID_PARAMETERS:
ffa_err("One or more fields in input parameters is incorrectly encoded");
ret = -EPERM;
break;
case FFA_ERR_STAT_NO_MEMORY:
ffa_err("Not enough memory");
ret = -ENOMEM;
break;
case FFA_ERR_STAT_DENIED:
ffa_err("Buffer pair already registered");
ret = -EACCES;
break;
case FFA_ERR_STAT_NOT_SUPPORTED:
ffa_err("This function is not implemented at this FF-A instance");
ret = -EOPNOTSUPP;
break;
default:
ffa_err("Undefined error (%d)",
((int)res.a2));
ret = -EINVAL;
}
break;
}
case FFA_SUCCESS:
ffa_info("RX/TX buffers mapped");
return FFA_ERR_STAT_SUCCESS;
default:
ffa_err("Undefined response function (0x%lx)",
res.a0);
ret = -EINVAL;
}
ffa_free_rxtx_buffers();
return ret;
+}
+/**
[...]
Regards /Ilias
+/**
- Declaring the arm_ffa driver under UCLASS_FFA
- */
+U_BOOT_DRIVER(arm_ffa) = {
.name = FFA_DRV_NAME,
.id = UCLASS_FFA,
.probe = ffa_probe,
+}; diff --git a/drivers/arm-ffa/efi_ffa_runtime_data_mgr.c b/drivers/arm-ffa/efi_ffa_runtime_data_mgr.c new file mode 100644 index 0000000000..942601a7ba --- /dev/null +++ b/drivers/arm-ffa/efi_ffa_runtime_data_mgr.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- (C) Copyright 2022 ARM Limited
- Abdellatif El Khlifi abdellatif.elkhlifi@arm.com
- */
+#include "arm_ffa_prv.h"
+/**
- ffa_copy_runtime_data - copy the private data structure to the runtime area
- This boot time function copies the arm_ffa driver data structures including
- partitions data to the EFI runtime data section.
- Return:
- FFA_ERR_STAT_SUCCESS on success. Otherwise, failure
- */
+efi_status_t ffa_copy_runtime_data(void) +{
efi_status_t efi_ret;
efi_uintn_t prvdata_pages;
efi_uintn_t descs_pages;
struct ffa_prvdata **prvdata = NULL; /* Pointer to the current structure */
struct ffa_prvdata *runtime_prvdata = NULL; /* Pointer to the structure runtime copy */
u64 runtime_descs = 0;
prvdata = ffa_bus_prvdata_get();
printf("INFO: EFI: FFA: prv data area at 0x%llx\n", (u64)prvdata);
/* allocate private data runtime area */
prvdata_pages = efi_size_in_pages(sizeof(struct ffa_prvdata));
efi_ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
EFI_RUNTIME_SERVICES_DATA,
prvdata_pages,
(u64 *)&runtime_prvdata);
if (efi_ret != EFI_SUCCESS) {
printf("ERROR: EFI: FFA: allocating runtime data (err: 0x%lx, addr 0x%llx)\n",
efi_ret, (u64)runtime_prvdata);
return efi_ret;
}
printf("INFO: EFI: FFA: runtime data area at 0x%llx\n", (u64)runtime_prvdata);
if (!runtime_prvdata)
return EFI_INVALID_PARAMETER;
/* allocate the partition data runtime area */
descs_pages = efi_size_in_pages((*prvdata)->partitions.count *
sizeof(struct ffa_partition_desc));
efi_ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
EFI_RUNTIME_SERVICES_DATA,
descs_pages,
&runtime_descs);
if (efi_ret != EFI_SUCCESS) {
printf("ERROR: EFI: FFA: allocating runtime SPs data (err: 0x%lx, addr 0x%llx)\n",
efi_ret, runtime_descs);
efi_free_pages((u64)runtime_prvdata, prvdata_pages);
return efi_ret;
}
printf("INFO: EFI: FFA: SPs runtime area at 0x%llx\n", (u64)runtime_descs);
if (!runtime_descs)
return EFI_INVALID_PARAMETER;
*runtime_prvdata = **prvdata;
runtime_prvdata->dev = NULL;
runtime_prvdata->ffa_ops.partition_info_get = NULL;
runtime_prvdata->ffa_ops.rxtx_unmap = NULL;
runtime_prvdata->partitions.descs = (struct ffa_partition_desc *)runtime_descs;
runtime_prvdata->pair.rxbuf = 0;
runtime_prvdata->pair.txbuf = 0;
/*
* Update the private data structure pointer in the driver
* no need to free the old structure. devm takes care of that
*/
*prvdata = runtime_prvdata;
printf("INFO: EFI: FFA: runtime prv data now at 0x%llx , SPs count %d\n",
(u64)*prvdata, (*prvdata)->partitions.count);
return FFA_ERR_STAT_SUCCESS;
+} diff --git a/include/arm_ffa.h b/include/arm_ffa.h new file mode 100644 index 0000000000..ee9ce2d99d --- /dev/null +++ b/include/arm_ffa.h @@ -0,0 +1,132 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- (C) Copyright 2022 ARM Limited
- 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
- */
+/*
- Macros for displaying logs
- */
+#define ffa_info(fmt, ...) pr_info("[FFA] " fmt "\n", ##__VA_ARGS__) +#define ffa_err(fmt, ...) pr_err("[FFA] " fmt "\n", ##__VA_ARGS__)
+/*
- The driver operations success error code
- */
+#define FFA_ERR_STAT_SUCCESS (0)
+/*
- struct ffa_partition_info - Partition information descriptor
- @id: Partition ID
- @exec_ctxt: Execution context count
- @properties: Partition properties
- Data structure containing information about partitions instantiated in the system
- This structure is filled with the data queried by FFA_PARTITION_INFO_GET
- */
+struct __packed ffa_partition_info {
u16 id;
u16 exec_ctxt;
+/* partition supports receipt of direct requests */ +#define FFA_PARTITION_DIRECT_RECV BIT(0) +/* partition can send direct requests. */ +#define FFA_PARTITION_DIRECT_SEND BIT(1) +/* partition can send and receive indirect messages. */ +#define FFA_PARTITION_INDIRECT_MSG BIT(2)
u32 properties;
+};
+/*
- struct ffa_send_direct_data - Data structure hosting the data
used by FFA_MSG_SEND_DIRECT_{REQ,RESP}
- @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 __packed ffa_send_direct_data {
unsigned long data0; /* w3/x3 */
unsigned long data1; /* w4/x4 */
unsigned long data2; /* w5/x5 */
unsigned long data3; /* w6/x6 */
unsigned long data4; /* w7/x7 */
+};
+#if CONFIG_IS_ENABLED(ARM_FFA_EFI_RUNTIME_MODE)
+#include <efi_loader.h>
+/*
- __ffa_runtime - controls whether functions are
- available after calling the EFI ExitBootServices service.
- Functions tagged with these keywords are resident (available at boot time and
- at runtime)
- */
+#define __ffa_runtime_data __efi_runtime_data +#define __ffa_runtime __efi_runtime
+#else
+/*
- The FF-A driver is independent from EFI
- */
+#define __ffa_runtime_data +#define __ffa_runtime
+#endif
+/**
- struct ffa_bus_ops - The driver operations structure
- @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)(const char *uuid_str,
u32 *parts_size, struct ffa_partition_info *buffer);
int (*sync_send_receive)(u16 dst_part_id, struct ffa_send_direct_data *msg);
int (*rxtx_unmap)(void);
+};
+/**
- The device driver and the Uclass driver public functions
- */
+/**
- ffa_bus_ops_get - driver operations getter
- */
+const struct ffa_bus_ops * __ffa_runtime ffa_bus_ops_get(void);
+/**
- ffa_bus_discover - discover FF-A bus and probes the arm_ffa device
- */
+int ffa_bus_discover(void);
+#if CONFIG_IS_ENABLED(ARM_FFA_EFI_RUNTIME_MODE)
+/**
- ffa_copy_runtime_data - copy the private data structure and the SPs data to the runtime area
- */
+efi_status_t ffa_copy_runtime_data(void);
+#endif
+#endif diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index a432e43871..6eebbe9c7d 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -55,6 +55,7 @@ enum uclass_id { UCLASS_EFI_MEDIA, /* Devices provided by UEFI firmware */ UCLASS_ETH, /* Ethernet device */ UCLASS_ETH_PHY, /* Ethernet PHY device */
UCLASS_FFA, /* Arm Firmware Framework for Armv8-A */ UCLASS_FIRMWARE, /* Firmware */ UCLASS_FUZZING_ENGINE, /* Fuzzing engine */ UCLASS_FS_FIRMWARE_LOADER, /* Generic loader */
diff --git a/include/uuid.h b/include/uuid.h index 4a4883d3b5..789f8e0f15 100644 --- a/include/uuid.h +++ b/include/uuid.h @@ -44,4 +44,12 @@ 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);
+#ifdef CONFIG_ARM_FFA_TRANSPORT +/**
- ffa_uuid_str_to_bin - Converts a big endian UUID string to a little endian buffer
- */
+int ffa_uuid_str_to_bin(const char *uuid_str, unsigned char *uuid_bin); +#endif
#endif diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 4da64b5d29..e02bb445f5 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -23,6 +23,10 @@ #include <asm/setjmp.h> #include <linux/libfdt_env.h>
+#if defined(CONFIG_ARM_FFA_TRANSPORT) +#include <arm_ffa.h> +#endif
DECLARE_GLOBAL_DATA_PTR;
/* Task priority level */ @@ -2113,6 +2117,10 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, struct efi_event *evt, *next_event; efi_status_t ret = EFI_SUCCESS;
+#if defined(CONFIG_ARM_FFA_TRANSPORT)
int ffa_ret;
+#endif
EFI_ENTRY("%p, %zx", image_handle, map_key); /* Check that the caller has read the current memory map */
@@ -2173,6 +2181,15 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL); }
+#if defined(CONFIG_ARM_FFA_TRANSPORT)
/* unmap FF-A RX/TX buffers */
ffa_ret = ffa_bus_ops_get()->rxtx_unmap();
if (ffa_ret)
debug("[efi_boottime][ERROR]: can not unmap FF-A RX/TX buffers\n");
else
debug("[efi_boottime][INFO]: FF-A RX/TX buffers unmapped\n");
+#endif
/* Patch out unsupported runtime function */ efi_runtime_detach();
diff --git a/lib/uuid.c b/lib/uuid.c index 284f8113ff..50b3e61d59 100644 --- a/lib/uuid.c +++ b/lib/uuid.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /*
- Copyright 2011 Calxeda, Inc.
*/
- Copyright 2022 ARM Limited
#include <common.h> @@ -342,6 +343,70 @@ int uuid_str_to_bin(const char *uuid_str, unsigned char *uuid_bin, return 0; }
+#ifdef CONFIG_ARM_FFA_TRANSPORT +/**
- ffa_uuid_str_to_bin - Converts a big endian UUID string to a little endian buffer
- @uuid_str: UUID string in big endian format (36 bytes wide + '/0')
- @uuid_bin: preallocated 16 bytes UUID buffer in little endian format
- UUID string is 36 characters (36 bytes):
- xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
- be be be be be
- where x is a hexadecimal character. Fields are separated by '-'s.
- When converting to a binary UUID, these endianness rules apply:
be: means the field in the string is considered a big endian hex number
and should be converted to little endian binary format
- Return:
- uuid_bin filled with little endian UUID data
- On success 0 is returned. Otherwise, failure code.
- */
+int ffa_uuid_str_to_bin(const char *uuid_str, unsigned char *uuid_bin) +{
u16 tmp16 = 0;
u32 tmp32 = 0;
u64 tmp64 = 0;
if (!uuid_str_valid(uuid_str) || !uuid_bin)
return -EINVAL;
/*
* reverse bytes from big to little endian
*/
tmp32 = simple_strtoul(uuid_str, NULL, 16);
memcpy(uuid_bin, &tmp32, 4);
/*
* reverse bytes from big to little endian
*/
tmp16 = simple_strtoul(uuid_str + 9, NULL, 16);
memcpy(uuid_bin + 4, &tmp16, 2);
/*
* reverse bytes from big to little endian
*/
tmp16 = simple_strtoul(uuid_str + 14, NULL, 16);
memcpy(uuid_bin + 6, &tmp16, 2);
/*
* reverse bytes from big to little endian
*/
tmp16 = simple_strtoul(uuid_str + 19, NULL, 16);
memcpy(uuid_bin + 8, &tmp16, 2);
/*
* reverse bytes from big to little endian
*/
tmp64 = simple_strtoull(uuid_str + 24, NULL, 16);
memcpy(uuid_bin + 10, (char *)&tmp64, 6);
return 0;
+} +#endif
/*
- uuid_bin_to_str() - convert big endian binary data to string UUID or GUID.
-- 2.17.1