| // 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 <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_debug("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), | |
| }; |