refactor: forward ABI to secure world
Forward FFA_PARTITION_INFO_GET_REGS from normal world to secure world to
get information for all partitions. With this patch, normal world
partitions can get information for SPs as well.
Signed-off-by: Raghu Krishnamurthy <raghu.ncstate@gmail.com>
Change-Id: Id4f51d72f4c97d40ca15101ad9df616f75999cce
diff --git a/inc/hf/arch/plat/ffa.h b/inc/hf/arch/plat/ffa.h
index 5fa8c2e..5a9ff82 100644
--- a/inc/hf/arch/plat/ffa.h
+++ b/inc/hf/arch/plat/ffa.h
@@ -273,6 +273,11 @@
struct vcpu_locked next_locked, struct vcpu *current,
struct vm_locked receiver_locked);
+bool plat_ffa_partition_info_get_regs_forward(
+ const struct ffa_uuid *uuid, const uint16_t start_index,
+ const uint16_t tag, struct ffa_partition_info *partitions,
+ uint16_t partitions_len, ffa_vm_count_t *ret_count);
+
void plat_ffa_partition_info_get_forward(const struct ffa_uuid *uuid,
const uint32_t flags,
struct ffa_partition_info *partitions,
diff --git a/src/api.c b/src/api.c
index de5b03c..623111f 100644
--- a/src/api.c
+++ b/src/api.c
@@ -471,7 +471,7 @@
const uint16_t tag)
{
struct vm *current_vm = current->vm;
- static struct ffa_partition_info partitions[MAX_VMS];
+ static struct ffa_partition_info partitions[2 * MAX_VMS];
bool uuid_is_null = ffa_uuid_is_null(uuid);
ffa_vm_count_t vm_count = 0;
struct ffa_value ret = ffa_error(FFA_INVALID_PARAMETERS);
@@ -513,13 +513,32 @@
/* If UUID is Null vm_count must not be zero at this stage. */
CHECK(!uuid_is_null || vm_count != 0);
- /* TODO: Forward to secure world */
+ /*
+ * When running the Hypervisor:
+ * - If UUID is Null the Hypervisor forwards the query to the SPMC for
+ * it to fill with secure partitions information.
+ * TODO: Note that for this ABI, forwarding on every invocation when
+ * uuid is Null is inefficient,and if performance becomes a problem,
+ * this would be a good place to optimize using strategies such as
+ * caching info etc. For now, assuming this inefficiency is not a major
+ * issue.
+ * - If UUID is non-Null vm_count may be zero because the UUID matches
+ * a secure partition and the query is forwarded to the SPMC.
+ * When running the SPMC:
+ * - If UUID is non-Null and vm_count is zero it means there is no such
+ * partition identified in the system.
+ */
+ if (!plat_ffa_partition_info_get_regs_forward(
+ uuid, start_index, tag, partitions, ARRAY_SIZE(partitions),
+ &vm_count)) {
+ return ffa_error(FFA_DENIED);
+ }
/*
* Unrecognized UUID: does not match any of the VMs (or SPs)
* and is not Null.
*/
- if (vm_count == 0 || vm_count > vm_get_count()) {
+ if (vm_count == 0 || vm_count > ARRAY_SIZE(partitions)) {
return ffa_error(FFA_INVALID_PARAMETERS);
}
diff --git a/src/arch/aarch64/plat/ffa/absent.c b/src/arch/aarch64/plat/ffa/absent.c
index 4f440d8..5699c22 100644
--- a/src/arch/aarch64/plat/ffa/absent.c
+++ b/src/arch/aarch64/plat/ffa/absent.c
@@ -432,6 +432,23 @@
return false;
}
+bool plat_ffa_partition_info_get_regs_forward( // NOLINTNEXTLINE
+ const struct ffa_uuid *uuid,
+ const uint16_t start_index, // NOLINTNEXTLINE
+ const uint16_t tag,
+ struct ffa_partition_info *partitions, // NOLINTNEXTLINE
+ uint16_t partitions_len, ffa_vm_count_t *ret_count) // NOLINTNEXTLINE
+{
+ (void)uuid;
+ (void)start_index;
+ (void)tag;
+ (void)partitions;
+ (void)partitions_len;
+ (void)ret_count;
+
+ return true;
+}
+
void plat_ffa_parse_partition_manifest(struct mm_stage1_locked stage1_locked,
paddr_t fdt_addr,
size_t fdt_allocated_size,
diff --git a/src/arch/aarch64/plat/ffa/hypervisor.c b/src/arch/aarch64/plat/ffa/hypervisor.c
index 11d5c79..7a5924d 100644
--- a/src/arch/aarch64/plat/ffa/hypervisor.c
+++ b/src/arch/aarch64/plat/ffa/hypervisor.c
@@ -852,6 +852,139 @@
return false;
}
+static struct ffa_value plat_ffa_partition_info_get_regs(
+ const struct ffa_uuid *uuid, const uint16_t start_index,
+ const uint16_t tag)
+{
+ uint64_t arg1 = (uint64_t)uuid->uuid[1] << 32 | uuid->uuid[0];
+ uint64_t arg2 = (uint64_t)uuid->uuid[3] << 32 | uuid->uuid[2];
+ uint64_t arg3 = start_index | (uint64_t)tag << 16;
+
+ return arch_other_world_call((struct ffa_value){
+ .func = FFA_PARTITION_INFO_GET_REGS_64,
+ .arg1 = arg1,
+ .arg2 = arg2,
+ .arg3 = arg3,
+ });
+}
+
+static bool plat_ffa_fill_partition_info_from_regs(
+ struct ffa_value ret, uint16_t start_index,
+ struct ffa_partition_info *partitions, uint16_t partitions_len,
+ ffa_vm_count_t *ret_count)
+{
+ uint16_t vm_count = *ret_count;
+ uint16_t curr_index = 0;
+ uint8_t num_entries = 0;
+ uint8_t idx = 0;
+ /* list of pointers to args in return value */
+ uint64_t *arg_ptrs[15] = {
+ &ret.arg3,
+ &ret.arg4,
+ &ret.arg5,
+ &ret.arg6,
+ &ret.arg7,
+ &ret.extended_val.arg8,
+ &ret.extended_val.arg9,
+ &ret.extended_val.arg10,
+ &ret.extended_val.arg11,
+ &ret.extended_val.arg12,
+ &ret.extended_val.arg13,
+ &ret.extended_val.arg14,
+ &ret.extended_val.arg15,
+ &ret.extended_val.arg16,
+ &ret.extended_val.arg17,
+ };
+
+ if (vm_count > partitions_len) {
+ return false;
+ }
+ assert(ffa_partition_info_regs_get_tag(ret) == 0);
+ assert(ffa_partition_info_regs_get_desc_size(ret) ==
+ sizeof(struct ffa_partition_info));
+
+ curr_index = ffa_partition_info_regs_get_curr_idx(ret);
+ assert(start_index <= curr_index);
+
+ num_entries = curr_index - start_index + 1;
+ if (num_entries > (partitions_len - vm_count) || num_entries > 5) {
+ return false;
+ }
+
+ while (num_entries) {
+ uint64_t info = *(arg_ptrs[(idx * 3)]);
+ uint64_t uuid_lo = *(arg_ptrs[(idx * 3) + 1]);
+ uint64_t uuid_high = *(arg_ptrs[(idx * 3) + 2]);
+
+ partitions[vm_count].vm_id = info & 0xFFFF;
+ partitions[vm_count].vcpu_count = (info >> 16) & 0xFFFF;
+ partitions[vm_count].properties = (info >> 32);
+ partitions[vm_count].uuid.uuid[0] = uuid_lo & 0xFFFFFFFF;
+ partitions[vm_count].uuid.uuid[1] =
+ (uuid_lo >> 32) & 0xFFFFFFFF;
+ partitions[vm_count].uuid.uuid[2] = uuid_high & 0xFFFFFFFF;
+ partitions[vm_count].uuid.uuid[3] =
+ (uuid_high >> 32) & 0xFFFFFFFF;
+ vm_count++;
+ idx++;
+ num_entries--;
+ }
+
+ *ret_count = vm_count;
+ return true;
+}
+
+bool plat_ffa_partition_info_get_regs_forward(
+ const struct ffa_uuid *uuid, const uint16_t start_index,
+ const uint16_t tag, struct ffa_partition_info *partitions,
+ uint16_t partitions_len, ffa_vm_count_t *ret_count)
+{
+ (void)start_index;
+ (void)tag;
+ struct ffa_value ret;
+ uint16_t last_index = 0;
+ uint16_t curr_index = 0;
+ uint16_t swd_start_index = 0;
+
+ /*
+ * Allow forwarding from the Hypervisor if TEE or SPMC exists and
+ * declared as such in the Hypervisor manifest.
+ */
+ if (!ffa_tee_enabled) {
+ return true;
+ }
+
+ ret = plat_ffa_partition_info_get_regs(uuid, swd_start_index, 0);
+ if (ffa_func_id(ret) != FFA_SUCCESS_64) {
+ return false;
+ }
+
+ if (!plat_ffa_fill_partition_info_from_regs(ret, swd_start_index,
+ partitions, partitions_len,
+ ret_count)) {
+ return false;
+ }
+
+ last_index = ffa_partition_info_regs_get_last_idx(ret);
+ curr_index = ffa_partition_info_regs_get_curr_idx(ret);
+ swd_start_index = curr_index + 1;
+ while (swd_start_index <= last_index) {
+ ret = plat_ffa_partition_info_get_regs(uuid, swd_start_index,
+ 0);
+ if (ffa_func_id(ret) != FFA_SUCCESS_32) {
+ return false;
+ }
+
+ if (!plat_ffa_fill_partition_info_from_regs(
+ ret, swd_start_index, partitions, partitions_len,
+ ret_count)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
/*
* Forward helper for FFA_PARTITION_INFO_GET.
* Emits FFA_PARTITION_INFO_GET from Hypervisor to SPMC if allowed.
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index 28f077b..ddf9c22 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -1953,6 +1953,22 @@
return ret;
}
+bool plat_ffa_partition_info_get_regs_forward( // NOLINTNEXTLINE
+ const struct ffa_uuid *uuid,
+ const uint16_t start_index, // NOLINTNEXTLINE
+ const uint16_t tag,
+ struct ffa_partition_info *partitions, // NOLINTNEXTLINE
+ uint16_t partitions_len, ffa_vm_count_t *ret_count)
+{
+ (void)uuid;
+ (void)start_index;
+ (void)tag;
+ (void)partitions;
+ (void)partitions_len;
+ (void)ret_count;
+ return true;
+}
+
/** Forward helper for FFA_PARTITION_INFO_GET. */
void plat_ffa_partition_info_get_forward( // NOLINTNEXTLINE
const struct ffa_uuid *uuid, // NOLINTNEXTLINE
diff --git a/src/arch/fake/hypervisor/ffa.c b/src/arch/fake/hypervisor/ffa.c
index 9ce473d..b6a6a1a 100644
--- a/src/arch/fake/hypervisor/ffa.c
+++ b/src/arch/fake/hypervisor/ffa.c
@@ -393,6 +393,22 @@
return false;
}
+bool plat_ffa_partition_info_get_regs_forward( // NOLINTNEXTLINE
+ const struct ffa_uuid *uuid,
+ const uint16_t start_index, // NOLINTNEXTLINE
+ const uint16_t tag,
+ struct ffa_partition_info *partitions, // NOLINTNEXTLINE
+ uint16_t partitions_len, ffa_vm_count_t *ret_count)
+{
+ (void)uuid;
+ (void)start_index;
+ (void)tag;
+ (void)partitions;
+ (void)partitions_len;
+ (void)ret_count;
+ return true;
+}
+
void plat_ffa_partition_info_get_forward( // NOLINTNEXTLINE
const struct ffa_uuid *uuid, // NOLINTNEXTLINE
const uint32_t flags, // NOLINTNEXTLINE