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