mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-30 07:39:24 +00:00
Merge changes from topic "ffa_el3_spmc" into integration
* changes: feat(spmc): enable the SPMC to pass the linear core ID in a register feat(spmc): add FFA_RX_RELEASE handler feat(spmc): add FFA_RUN handler feat(spmc): support FFA_ID_GET ABI feat(spmc): add FFA_FEATURES handler feat(spmc): add FFA_PARTITION_INFO_GET handler feat(spmc): enable handling FF-A RX/TX Mapping ABIs docs(maintainers): introduce SPMC maintainer section
This commit is contained in:
commit
c8113bf77c
7 changed files with 720 additions and 8 deletions
|
@ -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
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -132,3 +132,27 @@ int read_uuid(uint8_t *dest, char *uuid)
|
||||||
return 0;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -89,8 +89,14 @@ Trusted Boot
|
||||||
:|G|: `ManishVB-Arm`_
|
:|G|: `ManishVB-Arm`_
|
||||||
:|F|: drivers/auth/
|
:|F|: drivers/auth/
|
||||||
|
|
||||||
Secure Partition Manager (SPM)
|
Secure Partition Manager Core (EL3 FF-A SPMC)
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
:|M|: Marc Bonnici <marc.bonnici@arm.com>
|
||||||
|
:|G|: `marcbonnici`_
|
||||||
|
:|F|: services/std_svc/spm/el3_spmc/\*
|
||||||
|
|
||||||
|
Secure Partition Manager Dispatcher (SPMD)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
:|M|: Olivier Deprez <olivier.deprez@arm.com>
|
:|M|: Olivier Deprez <olivier.deprez@arm.com>
|
||||||
:|G|: `odeprez`_
|
:|G|: `odeprez`_
|
||||||
:|M|: Manish Pandey <manish.pandey2@arm.com>
|
:|M|: Manish Pandey <manish.pandey2@arm.com>
|
||||||
|
@ -99,7 +105,7 @@ Secure Partition Manager (SPM)
|
||||||
:|G|: `max-shvetsov`_
|
:|G|: `max-shvetsov`_
|
||||||
:|M|: Joao Alves <Joao.Alves@arm.com>
|
:|M|: Joao Alves <Joao.Alves@arm.com>
|
||||||
:|G|: `J-Alves`_
|
:|G|: `J-Alves`_
|
||||||
:|F|: services/std_svc/spm\*
|
:|F|: services/std_svc/spmd/\*
|
||||||
|
|
||||||
Exception Handling Framework (EHF)
|
Exception Handling Framework (EHF)
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -908,5 +914,6 @@ Conventional Changelog Extensions
|
||||||
.. _JiafeiPan: https://github.com/JiafeiPan
|
.. _JiafeiPan: https://github.com/JiafeiPan
|
||||||
.. _arve-android: https://github.com/arve-android
|
.. _arve-android: https://github.com/arve-android
|
||||||
.. _marcone: https://github.com/marcone
|
.. _marcone: https://github.com/marcone
|
||||||
|
.. _marcbonnici: https://github.com/marcbonnici
|
||||||
|
|
||||||
.. _Project Maintenance Process: https://developer.trustedfirmware.org/w/collaboration/project-maintenance-process/
|
.. _Project Maintenance Process: https://developer.trustedfirmware.org/w/collaboration/project-maintenance-process/
|
||||||
|
|
|
@ -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
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef UUID_H
|
#ifndef UUID_COMMON_H
|
||||||
#define UUID_H
|
#define UUID_COMMON_H
|
||||||
|
|
||||||
#define UUID_BYTES_LENGTH 16
|
#define UUID_BYTES_LENGTH 16
|
||||||
#define UUID_STRING_LENGTH 36
|
#define UUID_STRING_LENGTH 36
|
||||||
|
|
||||||
int read_uuid(uint8_t *dest, char *uuid);
|
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 */
|
||||||
|
|
|
@ -195,6 +195,11 @@
|
||||||
#define SPMC_SECURE_ID_MASK U(1)
|
#define SPMC_SECURE_ID_MASK U(1)
|
||||||
#define SPMC_SECURE_ID_SHIFT U(15)
|
#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
|
* Mask for source and destination endpoint id in
|
||||||
* a direct message request/response.
|
* a direct message request/response.
|
||||||
|
|
|
@ -37,6 +37,22 @@
|
||||||
#define FFA_WB_TYPE_S2RAM 0
|
#define FFA_WB_TYPE_S2RAM 0
|
||||||
#define FFA_WB_TYPE_NOTS2RAM 1
|
#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.
|
* 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;
|
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. */
|
/* Setup Function for different SP types. */
|
||||||
void spmc_sp_common_setup(struct secure_partition_desc *sp,
|
void spmc_sp_common_setup(struct secure_partition_desc *sp,
|
||||||
entry_point_info_t *ep_info);
|
entry_point_info_t *ep_info);
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <common/debug.h>
|
#include <common/debug.h>
|
||||||
#include <common/fdt_wrappers.h>
|
#include <common/fdt_wrappers.h>
|
||||||
#include <common/runtime_svc.h>
|
#include <common/runtime_svc.h>
|
||||||
|
#include <common/uuid.h>
|
||||||
#include <lib/el3_runtime/context_mgmt.h>
|
#include <lib/el3_runtime/context_mgmt.h>
|
||||||
#include <lib/smccc.h>
|
#include <lib/smccc.h>
|
||||||
#include <lib/utils.h>
|
#include <lib/utils.h>
|
||||||
|
@ -27,6 +28,9 @@
|
||||||
|
|
||||||
#include <platform_def.h>
|
#include <platform_def.h>
|
||||||
|
|
||||||
|
/* 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
|
* Allocate a secure partition descriptor to describe each SP in the system that
|
||||||
* does not reside at EL3.
|
* 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
|
* This function will parse the Secure Partition Manifest. From manifest, it
|
||||||
* will fetch details for preparing Secure partition image context and secure
|
* 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,
|
return ffa_version_handler(smc_fid, secure_origin, x1, x2, x3,
|
||||||
x4, cookie, handle, flags);
|
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_SMC32:
|
||||||
case FFA_MSG_SEND_DIRECT_REQ_SMC64:
|
case FFA_MSG_SEND_DIRECT_REQ_SMC64:
|
||||||
return direct_req_smc_handler(smc_fid, secure_origin, x1, x2,
|
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,
|
return direct_resp_smc_handler(smc_fid, secure_origin, x1, x2,
|
||||||
x3, x4, cookie, handle, flags);
|
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:
|
case FFA_MSG_WAIT:
|
||||||
return msg_wait_handler(smc_fid, secure_origin, x1, x2, x3, x4,
|
return msg_wait_handler(smc_fid, secure_origin, x1, x2, x3, x4,
|
||||||
cookie, handle, flags);
|
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,
|
return ffa_error_handler(smc_fid, secure_origin, x1, x2, x3, x4,
|
||||||
cookie, handle, flags);
|
cookie, handle, flags);
|
||||||
|
|
||||||
|
case FFA_MSG_RUN:
|
||||||
|
return ffa_run_handler(smc_fid, secure_origin, x1, x2, x3, x4,
|
||||||
|
cookie, handle, flags);
|
||||||
default:
|
default:
|
||||||
WARN("Unsupported FF-A call 0x%08x.\n", smc_fid);
|
WARN("Unsupported FF-A call 0x%08x.\n", smc_fid);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -43,6 +43,12 @@ void spmc_el1_sp_setup(struct secure_partition_desc *sp,
|
||||||
ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
|
ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
|
||||||
DISABLE_ALL_EXCEPTIONS);
|
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
|
* Check whether setup is being performed for the primary or a secondary
|
||||||
* execution context. In the latter case, indicate to the SP that this
|
* execution context. In the latter case, indicate to the SP that this
|
||||||
|
|
Loading…
Add table
Reference in a new issue