diff --git a/common/uuid.c b/common/uuid.c index ac6db50a0..3e47eb4ba 100644 --- a/common/uuid.c +++ b/common/uuid.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -132,3 +132,27 @@ int read_uuid(uint8_t *dest, char *uuid) return 0; } +/* + * Helper function to check if 2 UUIDs match. + */ +bool uuid_match(uint32_t *uuid1, uint32_t *uuid2) +{ + return !memcmp(uuid1, uuid2, sizeof(uint32_t) * 4); +} + +/* + * Helper function to copy from one UUID struct to another. + */ +void copy_uuid(uint32_t *to_uuid, uint32_t *from_uuid) +{ + to_uuid[0] = from_uuid[0]; + to_uuid[1] = from_uuid[1]; + to_uuid[2] = from_uuid[2]; + to_uuid[3] = from_uuid[3]; +} + +bool is_null_uuid(uint32_t *uuid) +{ + return (uuid[0] == 0 && uuid[1] == 0 && + uuid[2] == 0 && uuid[3] == 0); +} diff --git a/docs/about/maintainers.rst b/docs/about/maintainers.rst index c62a6beb2..5d2173448 100644 --- a/docs/about/maintainers.rst +++ b/docs/about/maintainers.rst @@ -89,8 +89,14 @@ Trusted Boot :|G|: `ManishVB-Arm`_ :|F|: drivers/auth/ -Secure Partition Manager (SPM) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Secure Partition Manager Core (EL3 FF-A SPMC) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +:|M|: Marc Bonnici +:|G|: `marcbonnici`_ +:|F|: services/std_svc/spm/el3_spmc/\* + +Secure Partition Manager Dispatcher (SPMD) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :|M|: Olivier Deprez :|G|: `odeprez`_ :|M|: Manish Pandey @@ -99,7 +105,7 @@ Secure Partition Manager (SPM) :|G|: `max-shvetsov`_ :|M|: Joao Alves :|G|: `J-Alves`_ -:|F|: services/std_svc/spm\* +:|F|: services/std_svc/spmd/\* Exception Handling Framework (EHF) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -908,5 +914,6 @@ Conventional Changelog Extensions .. _JiafeiPan: https://github.com/JiafeiPan .. _arve-android: https://github.com/arve-android .. _marcone: https://github.com/marcone +.. _marcbonnici: https://github.com/marcbonnici .. _Project Maintenance Process: https://developer.trustedfirmware.org/w/collaboration/project-maintenance-process/ diff --git a/include/common/uuid.h b/include/common/uuid.h index 5651d0d58..c8dd68197 100644 --- a/include/common/uuid.h +++ b/include/common/uuid.h @@ -1,15 +1,18 @@ /* - * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved. + * Copyright (c) 2021-2022, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ -#ifndef UUID_H -#define UUID_H +#ifndef UUID_COMMON_H +#define UUID_COMMON_H #define UUID_BYTES_LENGTH 16 #define UUID_STRING_LENGTH 36 int read_uuid(uint8_t *dest, char *uuid); +bool uuid_match(uint32_t *uuid1, uint32_t *uuid2); +void copy_uuid(uint32_t *to_uuid, uint32_t *from_uuid); +bool is_null_uuid(uint32_t *uuid); -#endif /* UUID_H */ +#endif /* UUID_COMMON_H */ diff --git a/include/services/ffa_svc.h b/include/services/ffa_svc.h index 08365796c..153d206b9 100644 --- a/include/services/ffa_svc.h +++ b/include/services/ffa_svc.h @@ -195,6 +195,11 @@ #define SPMC_SECURE_ID_MASK U(1) #define SPMC_SECURE_ID_SHIFT U(15) +/* + * Partition Count Flag in FFA_PARTITION_INFO_GET. + */ +#define FFA_PARTITION_INFO_GET_COUNT_FLAG_MASK U(1 << 0) + /* * Mask for source and destination endpoint id in * a direct message request/response. diff --git a/services/std_svc/spm/el3_spmc/spmc.h b/services/std_svc/spm/el3_spmc/spmc.h index faa604f53..5f397338f 100644 --- a/services/std_svc/spm/el3_spmc/spmc.h +++ b/services/std_svc/spm/el3_spmc/spmc.h @@ -37,6 +37,22 @@ #define FFA_WB_TYPE_S2RAM 0 #define FFA_WB_TYPE_NOTS2RAM 1 +/* FF-A Related helper macros. */ +#define FFA_ID_MASK U(0xFFFF) +#define FFA_PARTITION_ID_SHIFT U(16) +#define FFA_FEATURES_BIT31_MASK U(0x1u << 31) + +#define FFA_RUN_EP_ID(ep_vcpu_ids) \ + ((ep_vcpu_ids >> FFA_PARTITION_ID_SHIFT) & FFA_ID_MASK) +#define FFA_RUN_VCPU_ID(ep_vcpu_ids) \ + (ep_vcpu_ids & FFA_ID_MASK) + +#define FFA_PAGE_SIZE (4096) +#define FFA_RXTX_PAGE_COUNT_MASK 0x1F + +/* Ensure that the page size used by TF-A is 4k aligned. */ +CASSERT((PAGE_SIZE % FFA_PAGE_SIZE) == 0, assert_aligned_page_size); + /* * Runtime states of an execution context as per the FF-A v1.1 specification. */ @@ -178,6 +194,24 @@ struct ns_endpoint_desc { uint32_t ffa_version; }; +/** + * Holds information returned for each partition by the FFA_PARTITION_INFO_GET + * interface. + */ +struct ffa_partition_info_v1_0 { + uint16_t ep_id; + uint16_t execution_ctx_count; + uint32_t properties; +}; + +/* Extended structure for v1.1. */ +struct ffa_partition_info_v1_1 { + uint16_t ep_id; + uint16_t execution_ctx_count; + uint32_t properties; + uint32_t uuid[4]; +}; + /* Setup Function for different SP types. */ void spmc_sp_common_setup(struct secure_partition_desc *sp, entry_point_info_t *ep_info); diff --git a/services/std_svc/spm/el3_spmc/spmc_main.c b/services/std_svc/spm/el3_spmc/spmc_main.c index 33a25a262..5dbc48d67 100644 --- a/services/std_svc/spm/el3_spmc/spmc_main.c +++ b/services/std_svc/spm/el3_spmc/spmc_main.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,9 @@ #include +/* Declare the maximum number of SPs and El3 LPs. */ +#define MAX_SP_LP_PARTITIONS SECURE_PARTITION_COUNT + MAX_EL3_LP_DESCS_COUNT + /* * Allocate a secure partition descriptor to describe each SP in the system that * does not reside at EL3. @@ -567,6 +571,606 @@ uint32_t get_partition_ffa_version(bool secure_origin) } } +static uint64_t rxtx_map_handler(uint32_t smc_fid, + bool secure_origin, + uint64_t x1, + uint64_t x2, + uint64_t x3, + uint64_t x4, + void *cookie, + void *handle, + uint64_t flags) +{ + int ret; + uint32_t error_code; + uint32_t mem_atts = secure_origin ? MT_SECURE : MT_NS; + struct mailbox *mbox; + uintptr_t tx_address = x1; + uintptr_t rx_address = x2; + uint32_t page_count = x3 & FFA_RXTX_PAGE_COUNT_MASK; /* Bits [5:0] */ + uint32_t buf_size = page_count * FFA_PAGE_SIZE; + + /* + * The SPMC does not support mapping of VM RX/TX pairs to facilitate + * indirect messaging with SPs. Check if the Hypervisor has invoked this + * ABI on behalf of a VM and reject it if this is the case. + */ + if (tx_address == 0 || rx_address == 0) { + WARN("Mapping RX/TX Buffers on behalf of VM not supported.\n"); + return spmc_ffa_error_return(handle, + FFA_ERROR_INVALID_PARAMETER); + } + + /* Ensure the specified buffers are not the same. */ + if (tx_address == rx_address) { + WARN("TX Buffer must not be the same as RX Buffer.\n"); + return spmc_ffa_error_return(handle, + FFA_ERROR_INVALID_PARAMETER); + } + + /* Ensure the buffer size is not 0. */ + if (buf_size == 0U) { + WARN("Buffer size must not be 0\n"); + return spmc_ffa_error_return(handle, + FFA_ERROR_INVALID_PARAMETER); + } + + /* + * Ensure the buffer size is a multiple of the translation granule size + * in TF-A. + */ + if (buf_size % PAGE_SIZE != 0U) { + WARN("Buffer size must be aligned to translation granule.\n"); + return spmc_ffa_error_return(handle, + FFA_ERROR_INVALID_PARAMETER); + } + + /* Obtain the RX/TX buffer pair descriptor. */ + mbox = spmc_get_mbox_desc(secure_origin); + + spin_lock(&mbox->lock); + + /* Check if buffers have already been mapped. */ + if (mbox->rx_buffer != 0 || mbox->tx_buffer != 0) { + WARN("RX/TX Buffers already mapped (%p/%p)\n", + (void *) mbox->rx_buffer, (void *)mbox->tx_buffer); + error_code = FFA_ERROR_DENIED; + goto err; + } + + /* memmap the TX buffer as read only. */ + ret = mmap_add_dynamic_region(tx_address, /* PA */ + tx_address, /* VA */ + buf_size, /* size */ + mem_atts | MT_RO_DATA); /* attrs */ + if (ret != 0) { + /* Return the correct error code. */ + error_code = (ret == -ENOMEM) ? FFA_ERROR_NO_MEMORY : + FFA_ERROR_INVALID_PARAMETER; + WARN("Unable to map TX buffer: %d\n", error_code); + goto err; + } + + /* memmap the RX buffer as read write. */ + ret = mmap_add_dynamic_region(rx_address, /* PA */ + rx_address, /* VA */ + buf_size, /* size */ + mem_atts | MT_RW_DATA); /* attrs */ + + if (ret != 0) { + error_code = (ret == -ENOMEM) ? FFA_ERROR_NO_MEMORY : + FFA_ERROR_INVALID_PARAMETER; + WARN("Unable to map RX buffer: %d\n", error_code); + /* Unmap the TX buffer again. */ + mmap_remove_dynamic_region(tx_address, buf_size); + goto err; + } + + mbox->tx_buffer = (void *) tx_address; + mbox->rx_buffer = (void *) rx_address; + mbox->rxtx_page_count = page_count; + spin_unlock(&mbox->lock); + + SMC_RET1(handle, FFA_SUCCESS_SMC32); + /* Execution stops here. */ +err: + spin_unlock(&mbox->lock); + return spmc_ffa_error_return(handle, error_code); +} + +static uint64_t rxtx_unmap_handler(uint32_t smc_fid, + bool secure_origin, + uint64_t x1, + uint64_t x2, + uint64_t x3, + uint64_t x4, + void *cookie, + void *handle, + uint64_t flags) +{ + struct mailbox *mbox = spmc_get_mbox_desc(secure_origin); + uint32_t buf_size = mbox->rxtx_page_count * FFA_PAGE_SIZE; + + /* + * The SPMC does not support mapping of VM RX/TX pairs to facilitate + * indirect messaging with SPs. Check if the Hypervisor has invoked this + * ABI on behalf of a VM and reject it if this is the case. + */ + if (x1 != 0UL) { + return spmc_ffa_error_return(handle, + FFA_ERROR_INVALID_PARAMETER); + } + + spin_lock(&mbox->lock); + + /* Check if buffers are currently mapped. */ + if (mbox->rx_buffer == 0 || mbox->tx_buffer == 0) { + spin_unlock(&mbox->lock); + return spmc_ffa_error_return(handle, + FFA_ERROR_INVALID_PARAMETER); + } + + /* Unmap RX Buffer */ + if (mmap_remove_dynamic_region((uintptr_t) mbox->rx_buffer, + buf_size) != 0) { + WARN("Unable to unmap RX buffer!\n"); + } + + mbox->rx_buffer = 0; + + /* Unmap TX Buffer */ + if (mmap_remove_dynamic_region((uintptr_t) mbox->tx_buffer, + buf_size) != 0) { + WARN("Unable to unmap TX buffer!\n"); + } + + mbox->tx_buffer = 0; + mbox->rxtx_page_count = 0; + + spin_unlock(&mbox->lock); + SMC_RET1(handle, FFA_SUCCESS_SMC32); +} + +/* + * Collate the partition information in a v1.1 partition information + * descriptor format, this will be converter later if required. + */ +static int partition_info_get_handler_v1_1(uint32_t *uuid, + struct ffa_partition_info_v1_1 + *partitions, + uint32_t max_partitions, + uint32_t *partition_count) +{ + uint32_t index; + struct ffa_partition_info_v1_1 *desc; + bool null_uuid = is_null_uuid(uuid); + struct el3_lp_desc *el3_lp_descs = get_el3_lp_array(); + + /* Deal with Logical Partitions. */ + for (index = 0U; index < EL3_LP_DESCS_COUNT; index++) { + if (null_uuid || uuid_match(uuid, el3_lp_descs[index].uuid)) { + /* Found a matching UUID, populate appropriately. */ + if (*partition_count >= max_partitions) { + return FFA_ERROR_NO_MEMORY; + } + + desc = &partitions[*partition_count]; + desc->ep_id = el3_lp_descs[index].sp_id; + desc->execution_ctx_count = PLATFORM_CORE_COUNT; + desc->properties = el3_lp_descs[index].properties; + if (null_uuid) { + copy_uuid(desc->uuid, el3_lp_descs[index].uuid); + } + (*partition_count)++; + } + } + + /* Deal with physical SP's. */ + for (index = 0U; index < SECURE_PARTITION_COUNT; index++) { + if (null_uuid || uuid_match(uuid, sp_desc[index].uuid)) { + /* Found a matching UUID, populate appropriately. */ + if (*partition_count >= max_partitions) { + return FFA_ERROR_NO_MEMORY; + } + + desc = &partitions[*partition_count]; + desc->ep_id = sp_desc[index].sp_id; + /* + * Execution context count must match No. cores for + * S-EL1 SPs. + */ + desc->execution_ctx_count = PLATFORM_CORE_COUNT; + desc->properties = sp_desc[index].properties; + if (null_uuid) { + copy_uuid(desc->uuid, sp_desc[index].uuid); + } + (*partition_count)++; + } + } + return 0; +} + +/* + * Handle the case where that caller only wants the count of partitions + * matching a given UUID and does not want the corresponding descriptors + * populated. + */ +static uint32_t partition_info_get_handler_count_only(uint32_t *uuid) +{ + uint32_t index = 0; + uint32_t partition_count = 0; + bool null_uuid = is_null_uuid(uuid); + struct el3_lp_desc *el3_lp_descs = get_el3_lp_array(); + + /* Deal with Logical Partitions. */ + for (index = 0U; index < EL3_LP_DESCS_COUNT; index++) { + if (null_uuid || + uuid_match(uuid, el3_lp_descs[index].uuid)) { + (partition_count)++; + } + } + + /* Deal with physical SP's. */ + for (index = 0U; index < SECURE_PARTITION_COUNT; index++) { + if (null_uuid || uuid_match(uuid, sp_desc[index].uuid)) { + (partition_count)++; + } + } + return partition_count; +} + +/* + * If the caller of the PARTITION_INFO_GET ABI was a v1.0 caller, populate + * the coresponding descriptor format from the v1.1 descriptor array. + */ +static uint64_t partition_info_populate_v1_0(struct ffa_partition_info_v1_1 + *partitions, + struct mailbox *mbox, + int partition_count) +{ + uint32_t index; + uint32_t buf_size; + uint32_t descriptor_size; + struct ffa_partition_info_v1_0 *v1_0_partitions = + (struct ffa_partition_info_v1_0 *) mbox->rx_buffer; + + buf_size = mbox->rxtx_page_count * FFA_PAGE_SIZE; + descriptor_size = partition_count * + sizeof(struct ffa_partition_info_v1_0); + + if (descriptor_size > buf_size) { + return FFA_ERROR_NO_MEMORY; + } + + for (index = 0U; index < partition_count; index++) { + v1_0_partitions[index].ep_id = partitions[index].ep_id; + v1_0_partitions[index].execution_ctx_count = + partitions[index].execution_ctx_count; + v1_0_partitions[index].properties = + partitions[index].properties; + } + return 0; +} + +/* + * Main handler for FFA_PARTITION_INFO_GET which supports both FF-A v1.1 and + * v1.0 implementations. + */ +static uint64_t partition_info_get_handler(uint32_t smc_fid, + bool secure_origin, + uint64_t x1, + uint64_t x2, + uint64_t x3, + uint64_t x4, + void *cookie, + void *handle, + uint64_t flags) +{ + int ret; + uint32_t partition_count = 0; + uint32_t size = 0; + uint32_t ffa_version = get_partition_ffa_version(secure_origin); + struct mailbox *mbox; + uint64_t info_get_flags; + bool count_only; + uint32_t uuid[4]; + + uuid[0] = x1; + uuid[1] = x2; + uuid[2] = x3; + uuid[3] = x4; + + /* Determine if the Partition descriptors should be populated. */ + info_get_flags = SMC_GET_GP(handle, CTX_GPREG_X5); + count_only = (info_get_flags & FFA_PARTITION_INFO_GET_COUNT_FLAG_MASK); + + /* Handle the case where we don't need to populate the descriptors. */ + if (count_only) { + partition_count = partition_info_get_handler_count_only(uuid); + if (partition_count == 0) { + return spmc_ffa_error_return(handle, + FFA_ERROR_INVALID_PARAMETER); + } + } else { + struct ffa_partition_info_v1_1 partitions[MAX_SP_LP_PARTITIONS]; + + /* + * Handle the case where the partition descriptors are required, + * check we have the buffers available and populate the + * appropriate structure version. + */ + + /* Obtain the v1.1 format of the descriptors. */ + ret = partition_info_get_handler_v1_1(uuid, partitions, + MAX_SP_LP_PARTITIONS, + &partition_count); + + /* Check if an error occurred during discovery. */ + if (ret != 0) { + goto err; + } + + /* If we didn't find any matches the UUID is unknown. */ + if (partition_count == 0) { + ret = FFA_ERROR_INVALID_PARAMETER; + goto err; + } + + /* Obtain the partition mailbox RX/TX buffer pair descriptor. */ + mbox = spmc_get_mbox_desc(secure_origin); + + /* + * If the caller has not bothered registering its RX/TX pair + * then return an error code. + */ + spin_lock(&mbox->lock); + if (mbox->rx_buffer == NULL) { + ret = FFA_ERROR_BUSY; + goto err_unlock; + } + + /* Ensure the RX buffer is currently free. */ + if (mbox->state != MAILBOX_STATE_EMPTY) { + ret = FFA_ERROR_BUSY; + goto err_unlock; + } + + /* Zero the RX buffer before populating. */ + (void)memset(mbox->rx_buffer, 0, + mbox->rxtx_page_count * FFA_PAGE_SIZE); + + /* + * Depending on the FF-A version of the requesting partition + * we may need to convert to a v1.0 format otherwise we can copy + * directly. + */ + if (ffa_version == MAKE_FFA_VERSION(U(1), U(0))) { + ret = partition_info_populate_v1_0(partitions, + mbox, + partition_count); + if (ret != 0) { + goto err_unlock; + } + } else { + uint32_t buf_size = mbox->rxtx_page_count * + FFA_PAGE_SIZE; + + /* Ensure the descriptor will fit in the buffer. */ + size = sizeof(struct ffa_partition_info_v1_1); + if (partition_count * size > buf_size) { + ret = FFA_ERROR_NO_MEMORY; + goto err_unlock; + } + memcpy(mbox->rx_buffer, partitions, + partition_count * size); + } + + mbox->state = MAILBOX_STATE_FULL; + spin_unlock(&mbox->lock); + } + SMC_RET4(handle, FFA_SUCCESS_SMC32, 0, partition_count, size); + +err_unlock: + spin_unlock(&mbox->lock); +err: + return spmc_ffa_error_return(handle, ret); +} + +static uint64_t ffa_features_handler(uint32_t smc_fid, + bool secure_origin, + uint64_t x1, + uint64_t x2, + uint64_t x3, + uint64_t x4, + void *cookie, + void *handle, + uint64_t flags) +{ + uint32_t function_id = (uint32_t) x1; + uint32_t input_properties = (uint32_t) x2; + + /* + * We don't currently support any additional input properties + * for any ABI therefore ensure this value is always set to 0. + */ + if (input_properties != 0) { + return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED); + } + + /* Check if a Feature ID was requested. */ + if ((function_id & FFA_FEATURES_BIT31_MASK) == 0U) { + /* We currently don't support any additional features. */ + return spmc_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED); + } + + /* Report if an FF-A ABI is supported. */ + switch (function_id) { + /* Supported features from both worlds. */ + case FFA_ERROR: + case FFA_SUCCESS_SMC32: + case FFA_ID_GET: + case FFA_FEATURES: + case FFA_VERSION: + case FFA_RX_RELEASE: + case FFA_MSG_SEND_DIRECT_REQ_SMC32: + case FFA_MSG_SEND_DIRECT_REQ_SMC64: + case FFA_PARTITION_INFO_GET: + case FFA_RXTX_MAP_SMC32: + case FFA_RXTX_MAP_SMC64: + case FFA_RXTX_UNMAP: + case FFA_MSG_RUN: + + /* + * We are relying on the fact that the other registers + * will be set to 0 as these values align with the + * currently implemented features of the SPMC. If this + * changes this function must be extended to handle + * reporting the additional functionality. + */ + + SMC_RET1(handle, FFA_SUCCESS_SMC32); + /* Execution stops here. */ + + /* Supported ABIs only from the secure world. */ + case FFA_MSG_SEND_DIRECT_RESP_SMC32: + case FFA_MSG_SEND_DIRECT_RESP_SMC64: + case FFA_MSG_WAIT: + + if (!secure_origin) { + return spmc_ffa_error_return(handle, + FFA_ERROR_NOT_SUPPORTED); + } + SMC_RET1(handle, FFA_SUCCESS_SMC32); + /* Execution stops here. */ + + default: + return spmc_ffa_error_return(handle, + FFA_ERROR_NOT_SUPPORTED); + } +} + +static uint64_t ffa_id_get_handler(uint32_t smc_fid, + bool secure_origin, + uint64_t x1, + uint64_t x2, + uint64_t x3, + uint64_t x4, + void *cookie, + void *handle, + uint64_t flags) +{ + if (secure_origin) { + SMC_RET3(handle, FFA_SUCCESS_SMC32, 0x0, + spmc_get_current_sp_ctx()->sp_id); + } else { + SMC_RET3(handle, FFA_SUCCESS_SMC32, 0x0, + spmc_get_hyp_ctx()->ns_ep_id); + } +} + +static uint64_t ffa_run_handler(uint32_t smc_fid, + bool secure_origin, + uint64_t x1, + uint64_t x2, + uint64_t x3, + uint64_t x4, + void *cookie, + void *handle, + uint64_t flags) +{ + struct secure_partition_desc *sp; + uint16_t target_id = FFA_RUN_EP_ID(x1); + uint16_t vcpu_id = FFA_RUN_VCPU_ID(x1); + unsigned int idx; + unsigned int *rt_state; + unsigned int *rt_model; + + /* Can only be called from the normal world. */ + if (secure_origin) { + ERROR("FFA_RUN can only be called from NWd.\n"); + return spmc_ffa_error_return(handle, + FFA_ERROR_INVALID_PARAMETER); + } + + /* Cannot run a Normal world partition. */ + if (ffa_is_normal_world_id(target_id)) { + ERROR("Cannot run a NWd partition (0x%x).\n", target_id); + return spmc_ffa_error_return(handle, + FFA_ERROR_INVALID_PARAMETER); + } + + /* Check that the target SP exists. */ + sp = spmc_get_sp_ctx(target_id); + ERROR("Unknown partition ID (0x%x).\n", target_id); + if (sp == NULL) { + return spmc_ffa_error_return(handle, + FFA_ERROR_INVALID_PARAMETER); + } + + idx = get_ec_index(sp); + if (idx != vcpu_id) { + ERROR("Cannot run vcpu %d != %d.\n", idx, vcpu_id); + return spmc_ffa_error_return(handle, + FFA_ERROR_INVALID_PARAMETER); + } + rt_state = &((sp->ec[idx]).rt_state); + rt_model = &((sp->ec[idx]).rt_model); + if (*rt_state == RT_STATE_RUNNING) { + ERROR("Partition (0x%x) is already running.\n", target_id); + return spmc_ffa_error_return(handle, FFA_ERROR_BUSY); + } + + /* + * Sanity check that if the execution context was not waiting then it + * was either in the direct request or the run partition runtime model. + */ + if (*rt_state == RT_STATE_PREEMPTED || *rt_state == RT_STATE_BLOCKED) { + assert(*rt_model == RT_MODEL_RUN || + *rt_model == RT_MODEL_DIR_REQ); + } + + /* + * If the context was waiting then update the partition runtime model. + */ + if (*rt_state == RT_STATE_WAITING) { + *rt_model = RT_MODEL_RUN; + } + + /* + * Forward the request to the correct SP vCPU after updating + * its state. + */ + *rt_state = RT_STATE_RUNNING; + + return spmc_smc_return(smc_fid, secure_origin, x1, 0, 0, 0, + handle, cookie, flags, target_id); +} + +static uint64_t rx_release_handler(uint32_t smc_fid, + bool secure_origin, + uint64_t x1, + uint64_t x2, + uint64_t x3, + uint64_t x4, + void *cookie, + void *handle, + uint64_t flags) +{ + struct mailbox *mbox = spmc_get_mbox_desc(secure_origin); + + spin_lock(&mbox->lock); + + if (mbox->state != MAILBOX_STATE_FULL) { + spin_unlock(&mbox->lock); + return spmc_ffa_error_return(handle, FFA_ERROR_DENIED); + } + + mbox->state = MAILBOX_STATE_EMPTY; + spin_unlock(&mbox->lock); + + SMC_RET1(handle, FFA_SUCCESS_SMC32); +} + /******************************************************************************* * This function will parse the Secure Partition Manifest. From manifest, it * will fetch details for preparing Secure partition image context and secure @@ -963,6 +1567,14 @@ uint64_t spmc_smc_handler(uint32_t smc_fid, return ffa_version_handler(smc_fid, secure_origin, x1, x2, x3, x4, cookie, handle, flags); + case FFA_ID_GET: + return ffa_id_get_handler(smc_fid, secure_origin, x1, x2, x3, + x4, cookie, handle, flags); + + case FFA_FEATURES: + return ffa_features_handler(smc_fid, secure_origin, x1, x2, x3, + x4, cookie, handle, flags); + case FFA_MSG_SEND_DIRECT_REQ_SMC32: case FFA_MSG_SEND_DIRECT_REQ_SMC64: return direct_req_smc_handler(smc_fid, secure_origin, x1, x2, @@ -973,6 +1585,24 @@ uint64_t spmc_smc_handler(uint32_t smc_fid, return direct_resp_smc_handler(smc_fid, secure_origin, x1, x2, x3, x4, cookie, handle, flags); + case FFA_RXTX_MAP_SMC32: + case FFA_RXTX_MAP_SMC64: + return rxtx_map_handler(smc_fid, secure_origin, x1, x2, x3, x4, + cookie, handle, flags); + + case FFA_RXTX_UNMAP: + return rxtx_unmap_handler(smc_fid, secure_origin, x1, x2, x3, + x4, cookie, handle, flags); + + case FFA_PARTITION_INFO_GET: + return partition_info_get_handler(smc_fid, secure_origin, x1, + x2, x3, x4, cookie, handle, + flags); + + case FFA_RX_RELEASE: + return rx_release_handler(smc_fid, secure_origin, x1, x2, x3, + x4, cookie, handle, flags); + case FFA_MSG_WAIT: return msg_wait_handler(smc_fid, secure_origin, x1, x2, x3, x4, cookie, handle, flags); @@ -981,6 +1611,9 @@ uint64_t spmc_smc_handler(uint32_t smc_fid, return ffa_error_handler(smc_fid, secure_origin, x1, x2, x3, x4, cookie, handle, flags); + case FFA_MSG_RUN: + return ffa_run_handler(smc_fid, secure_origin, x1, x2, x3, x4, + cookie, handle, flags); default: WARN("Unsupported FF-A call 0x%08x.\n", smc_fid); break; diff --git a/services/std_svc/spm/el3_spmc/spmc_setup.c b/services/std_svc/spm/el3_spmc/spmc_setup.c index 7b23c9e3b..af5219d02 100644 --- a/services/std_svc/spm/el3_spmc/spmc_setup.c +++ b/services/std_svc/spm/el3_spmc/spmc_setup.c @@ -43,6 +43,12 @@ void spmc_el1_sp_setup(struct secure_partition_desc *sp, ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); + /* + * TF-A Implementation defined behaviour to provide the linear + * core ID in the x4 register. + */ + ep_info->args.arg4 = (uintptr_t) plat_my_core_pos(); + /* * Check whether setup is being performed for the primary or a secondary * execution context. In the latter case, indicate to the SP that this