blob: cbe66ce8e49a339ee899404990dfa0dd25d062af [file] [log] [blame]
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (c) 2020-2023, Arm Limited and Contributors. All rights reserved.
*/
#include "sp_discovery.h"
#include "ffa_api.h"
#include "sp_rxtx.h"
#include "util.h"
#include <string.h>
static const struct sp_uuid uuid_nil = { 0 };
sp_result sp_discovery_ffa_version_get(uint16_t *major, uint16_t *minor)
{
uint32_t version = 0;
ffa_result ffa_res = FFA_OK;
ffa_res = ffa_version(&version);
if (ffa_res != FFA_OK) {
*major = UINT16_C(0);
*minor = UINT16_C(0);
return SP_RESULT_FFA(ffa_res);
}
*major = (version >> FFA_VERSION_MAJOR_SHIFT) & FFA_VERSION_MAJOR_MASK;
*minor = (version >> FFA_VERSION_MINOR_SHIFT) & FFA_VERSION_MINOR_MASK;
return SP_RESULT_OK;
}
sp_result sp_discovery_own_id_get(uint16_t *id)
{
ffa_result ffa_res = FFA_OK;
ffa_res = ffa_id_get(id);
return SP_RESULT_FFA(ffa_res);
}
static void unpack_ffa_info(const struct ffa_partition_information *ffa_info,
struct sp_partition_info *sp_info)
{
uint32_t props = ffa_info->partition_properties;
sp_info->partition_id = ffa_info->partition_id;
sp_info->execution_context_count = ffa_info->execution_context_count;
sp_info->supports_direct_requests =
props & FFA_PARTITION_SUPPORTS_DIRECT_REQUESTS;
sp_info->can_send_direct_requests =
props & FFA_PARTITION_CAN_SEND_DIRECT_REQUESTS;
sp_info->supports_indirect_requests =
props & FFA_PARTITION_SUPPORTS_INDIRECT_REQUESTS;
#if CFG_FFA_VERSION >= FFA_VERSION_1_1
sp_info->partition_id_type =
(props >> FFA_PARTITION_PART_ID_SHIFT) & FFA_PARTITION_PART_ID_MASK;
sp_info->inform_vm_create = props & FFA_PARTITION_INFORM_VM_CREATE;
sp_info->inform_vm_destroy = props & FFA_PARTITION_INFORM_VM_DESTROY;
if (props & FFA_PARTITION_AARCH64_EXECUTION_STATE)
sp_info->execution_state = sp_execution_state_aarch64;
else
sp_info->execution_state = sp_execution_state_aarch32;
memcpy(sp_info->uuid.uuid, ffa_info->uuid.uuid, sizeof(sp_info->uuid.uuid));
#endif /* CFG_FFA_VERSION */
}
static sp_result partition_info_get(const struct sp_uuid *uuid, struct sp_partition_info info[],
uint32_t *count, bool allow_nil_uuid)
{
const struct ffa_partition_information *ffa_info = NULL;
uint32_t ffa_count = 0;
uint32_t i = 0;
sp_result sp_res = SP_RESULT_OK;
const void *buffer = NULL;
size_t buffer_size = 0;
struct ffa_uuid ffa_uuid = { 0 };
ffa_result ffa_res = FFA_OK;
uint32_t __maybe_unused ffa_size = 0;
if (count == NULL)
return SP_RESULT_INVALID_PARAMETERS;
if (info == NULL) {
*count = UINT32_C(0);
return SP_RESULT_INVALID_PARAMETERS;
}
if (uuid == NULL || (!allow_nil_uuid &&
memcmp(&uuid_nil, uuid, sizeof(struct sp_uuid)) == 0)) {
sp_res = SP_RESULT_INVALID_PARAMETERS;
goto out;
}
sp_res = sp_rxtx_buffer_rx_get(&buffer, &buffer_size);
if (sp_res != SP_RESULT_OK) {
goto out;
}
/* Safely convert to FF-A UUID format */
memcpy(&ffa_uuid.uuid, uuid->uuid, sizeof(ffa_uuid.uuid));
#if CFG_FFA_VERSION == FFA_VERSION_1_0
ffa_res = ffa_partition_info_get(&ffa_uuid, &ffa_count);
if (ffa_res != FFA_OK) {
sp_res = SP_RESULT_FFA(ffa_res);
goto out;
}
#elif CFG_FFA_VERSION >= FFA_VERSION_1_1
ffa_res = ffa_partition_info_get(&ffa_uuid, 0, &ffa_count, &ffa_size);
if (ffa_res != FFA_OK) {
sp_res = SP_RESULT_FFA(ffa_res);
goto out;
}
if (ffa_size != sizeof(struct ffa_partition_information)) {
/* Non-matching structure size, this may happen in future FF-A versions */
sp_res = SP_RESULT_INTERNAL_ERROR;
goto out;
}
#endif
if ((ffa_count * sizeof(struct ffa_partition_information)) > buffer_size) {
/* The indicated amount of info structures doesn't fit into the RX buffer */
sp_res = SP_RESULT_INTERNAL_ERROR;
goto out;
}
ffa_info = (const struct ffa_partition_information *)buffer;
if (ffa_count == 0) {
sp_res = SP_RESULT_NOT_FOUND;
goto out;
}
*count = MIN(*count, ffa_count);
for (i = 0; i < *count; i++)
unpack_ffa_info(&ffa_info[i], &info[i]);
return SP_RESULT_OK;
out:
for (i = 0; i < *count; i++)
info[i] = (struct sp_partition_info){ 0 };
*count = UINT32_C(0);
return sp_res;
}
sp_result sp_discovery_partition_id_get(const struct sp_uuid *uuid,
uint16_t *id)
{
struct sp_partition_info sp_info = { 0 };
sp_result sp_res = SP_RESULT_OK;
uint32_t count = 1;
if (id == NULL)
return SP_RESULT_INVALID_PARAMETERS;
*id = FFA_ID_GET_ID_MASK;
if (uuid == NULL || memcmp(&uuid_nil, uuid, sizeof(struct sp_uuid)) == 0)
return SP_RESULT_INVALID_PARAMETERS;
sp_res = partition_info_get(uuid, &sp_info, &count, false);
if (sp_res != SP_RESULT_OK)
return sp_res;
*id = sp_info.partition_id;
return SP_RESULT_OK;
}
sp_result sp_discovery_partition_info_get(const struct sp_uuid *uuid,
struct sp_partition_info info[],
uint32_t *count)
{
return partition_info_get(uuid, info, count, false);
}
sp_result sp_discovery_partition_info_get_all(struct sp_partition_info info[],
uint32_t *count)
{
return partition_info_get(&uuid_nil, info, count, true);
}
#if CFG_FFA_VERSION >= FFA_VERSION_1_1
sp_result sp_discovery_partition_info_get_count(const struct sp_uuid *uuid, uint32_t *count)
{
struct ffa_uuid ffa_uuid = { 0 };
ffa_result ffa_res = FFA_OK;
uint32_t ffa_size = 0;
if (count == NULL)
return SP_RESULT_INVALID_PARAMETERS;
*count = 0;
if (uuid == NULL)
return SP_RESULT_INVALID_PARAMETERS;
/* Safely convert to FF-A UUID format */
memcpy(&ffa_uuid.uuid, uuid->uuid, sizeof(ffa_uuid.uuid));
ffa_res = ffa_partition_info_get(&ffa_uuid, FFA_PARTITION_INFO_GET_FLAG_COUNT_ONLY, count,
&ffa_size);
if (ffa_res != FFA_OK)
return SP_RESULT_FFA(ffa_res);
if (ffa_size != 0)
/* Size is MBZ if FFA_PARTITION_INFO_GET_FLAG_COUNT_ONLY is set */
return SP_RESULT_INTERNAL_ERROR;
return SP_RESULT_OK;
}
#endif /* CFG_FFA_VERSION */