aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaghu Krishnamurthy <raghu.ncstate@gmail.com>2021-07-02 08:27:38 -0700
committerOlivier Deprez <olivier.deprez@arm.com>2022-01-05 16:08:48 +0100
commitb49549ea892ede95b428f91062b501e9a3f9eb6a (patch)
treec6ab31d9913d40383f492cc7e77998d627a7b543
parent048d63f30e4b766cc4fee2f14d1f3b2c9c7761db (diff)
downloadhafnium-b49549ea892ede95b428f91062b501e9a3f9eb6a.tar.gz
VHE: Tests: Allow FF-A partitions to be loaded by hafnium in NWd
This patch makes changes so that partitions (EL0 host applications or VMs) can be marked as an FF-A partition in their manifests and still be loaded. Today's design assumes that if a partition is an FF-A partition, it is pre-loaded by some other entity and hafnium does not need to load. This works well for the FVP where either trusted firmware or FVP command line options can be used to load FF-A partitions in memory prior to running code. On qemu, this capability does not exist today. To provide this ability in qemu, we can modify hftest.py and other test infrastructure to do the same thing as FVP and pre-load FF-A partitions into memory, but this patch uses a different approach. Here, we add a new flag that can be added in the hafnium/spmc manifest that indicates to hafnium that the partition and its manifest still need to be loaded from the initrd, like normal. When a partition is not an FF-A partition (marked by is_ffa_partition in the manifest), the loading rules of hafnium remain unchanged. When a partition is marked as an FF-A partition, it can either be pre-loaded (hyp_loaded not in manifest) or it can be explicitly loaded from the initrd by specifying hyp_loaded in the manifest for hafnium. Note that qemu currently only supports normal world, so this new field (hyp_loaded) is not expected to be used in the secure world. This patch also uses this new feature for all the normal world EL0 partition tests so that they can be marked as FF-A partitions and still be loaded by the hypervisor like normal. With this change, the main use case that is enabled is that an FF-A partition (EL1 VMs and EL0 host applications) can be loaded on qemu. Also the partition manifest can be compliant with FF-A, without having to extend or pollute hafniums default hypervisor manifest to include fields such as execution-ctx-count, memory regions etc. Signed-off-by: Raghu Krishnamurthy <raghu.ncstate@gmail.com> Change-Id: If98eb9b6cbd14fc30d6d4e78d2d260a6beb97aa9
-rw-r--r--inc/hf/arch/plat/ffa.h7
-rw-r--r--inc/hf/manifest.h5
-rw-r--r--src/arch/aarch64/plat/ffa/absent.c14
-rw-r--r--src/arch/aarch64/plat/ffa/hypervisor.c30
-rw-r--r--src/arch/aarch64/plat/ffa/spmc.c15
-rw-r--r--src/load.c11
-rw-r--r--src/manifest.c16
-rw-r--r--test/vmapi/el0_partitions/manifest.dts8
-rw-r--r--test/vmapi/el0_partitions/secondary.dts15
9 files changed, 110 insertions, 11 deletions
diff --git a/inc/hf/arch/plat/ffa.h b/inc/hf/arch/plat/ffa.h
index 44281741c..ee2a3ccbc 100644
--- a/inc/hf/arch/plat/ffa.h
+++ b/inc/hf/arch/plat/ffa.h
@@ -9,6 +9,7 @@
#pragma once
#include "hf/ffa.h"
+#include "hf/manifest.h"
#include "hf/vcpu.h"
#include "hf/vm.h"
@@ -226,3 +227,9 @@ void plat_ffa_partition_info_get_forward(const struct ffa_uuid *uuid,
const uint32_t flags,
struct ffa_partition_info *partitions,
ffa_vm_count_t *ret_count);
+
+void plat_ffa_parse_partition_manifest(struct mm_stage1_locked stage1_locked,
+ paddr_t fdt_addr,
+ size_t fdt_allocated_size,
+ const struct manifest_vm *manifest_vm,
+ struct mpool *ppool);
diff --git a/inc/hf/manifest.h b/inc/hf/manifest.h
index c045432a5..b77a09d8b 100644
--- a/inc/hf/manifest.h
+++ b/inc/hf/manifest.h
@@ -9,6 +9,7 @@
#pragma once
#include "hf/addr.h"
+#include "hf/fdt.h"
#include "hf/ffa.h"
#include "hf/memiter.h"
#include "hf/string.h"
@@ -187,6 +188,7 @@ struct manifest_vm {
struct string kernel_filename;
struct smc_whitelist smc_whitelist;
bool is_ffa_partition;
+ bool is_hyp_loaded;
struct partition_manifest partition;
union {
@@ -241,6 +243,9 @@ enum manifest_return_code manifest_init(struct mm_stage1_locked stage1_locked,
struct memiter *manifest_fdt,
struct mpool *ppool);
+enum manifest_return_code parse_ffa_manifest(struct fdt *fdt,
+ struct manifest_vm *vm);
+enum manifest_return_code sanity_check_ffa_manifest(struct manifest_vm *vm);
void manifest_dump(struct manifest_vm *vm);
const char *manifest_strerror(enum manifest_return_code ret_code);
diff --git a/src/arch/aarch64/plat/ffa/absent.c b/src/arch/aarch64/plat/ffa/absent.c
index 6f46cdd19..15fd84419 100644
--- a/src/arch/aarch64/plat/ffa/absent.c
+++ b/src/arch/aarch64/plat/ffa/absent.c
@@ -8,6 +8,7 @@
#include "hf/ffa.h"
#include "hf/ffa_internal.h"
+#include "hf/manifest.h"
#include "hf/vcpu.h"
#include "hf/vm.h"
@@ -308,3 +309,16 @@ bool plat_ffa_partition_info_get_forward(const struct ffa_uuid *uuid,
return false;
}
+
+void plat_ffa_parse_partition_manifest(struct mm_stage1_locked stage1_locked,
+ paddr_t fdt_addr,
+ size_t fdt_allocated_size,
+ const struct manifest_vm *manifest_vm,
+ struct mpool *ppool)
+{
+ (void)stage1_locked;
+ (void)fdt_addr;
+ (void)fdt_allocated_size;
+ (void)manifest_vm;
+ (void)ppool;
+}
diff --git a/src/arch/aarch64/plat/ffa/hypervisor.c b/src/arch/aarch64/plat/ffa/hypervisor.c
index 411bbdd30..d1f4607da 100644
--- a/src/arch/aarch64/plat/ffa/hypervisor.c
+++ b/src/arch/aarch64/plat/ffa/hypervisor.c
@@ -642,3 +642,33 @@ void plat_ffa_partition_info_get_forward(const struct ffa_uuid *uuid,
*ret_count = vm_count;
}
+
+void plat_ffa_parse_partition_manifest(struct mm_stage1_locked stage1_locked,
+ paddr_t fdt_addr,
+ size_t fdt_allocated_size,
+ const struct manifest_vm *manifest_vm,
+ struct mpool *ppool)
+{
+ struct fdt partition_fdt;
+
+ /*
+ * If the partition is an FF-A partition and is not
+ * hypervisor loaded, the manifest is passed in the
+ * partition package and is parsed during
+ * manifest_init() and secondary fdt should be empty.
+ */
+ CHECK(manifest_vm->is_hyp_loaded);
+ CHECK(mm_identity_map(stage1_locked, fdt_addr,
+ pa_add(fdt_addr, fdt_allocated_size), MM_MODE_R,
+ ppool) != NULL);
+ // NOLINTNEXTLINE(performance-no-int-to-ptr)
+ CHECK(fdt_init_from_ptr(&partition_fdt, (void *)pa_addr(fdt_addr),
+ fdt_allocated_size) == true);
+ CHECK(parse_ffa_manifest(&partition_fdt,
+ (struct manifest_vm *)manifest_vm) ==
+ MANIFEST_SUCCESS);
+ CHECK(sanity_check_ffa_manifest((struct manifest_vm *)manifest_vm) ==
+ MANIFEST_SUCCESS);
+ CHECK(mm_unmap(stage1_locked, fdt_addr,
+ pa_add(fdt_addr, fdt_allocated_size), ppool) == true);
+}
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index a7b9ba6ca..4e0074a9c 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -1237,3 +1237,18 @@ void plat_ffa_partition_info_get_forward( // NOLINTNEXTLINE
(void)partitions;
(void)ret_count;
}
+
+void plat_ffa_parse_partition_manifest(struct mm_stage1_locked stage1_locked,
+ paddr_t fdt_addr,
+ size_t fdt_allocated_size,
+ const struct manifest_vm *manifest_vm,
+ struct mpool *ppool)
+{
+ (void)stage1_locked;
+ (void)fdt_addr;
+ (void)fdt_allocated_size;
+ (void)manifest_vm;
+ (void)ppool;
+ /* should never be called in SPMC */
+ CHECK(false);
+}
diff --git a/src/load.c b/src/load.c
index 0aebb5446..0f80c122a 100644
--- a/src/load.c
+++ b/src/load.c
@@ -249,7 +249,7 @@ static bool load_primary(struct mm_stage1_locked stage1_locked,
size_t i;
bool ret;
- if (manifest_vm->is_ffa_partition) {
+ if (manifest_vm->is_ffa_partition && !manifest_vm->is_hyp_loaded) {
primary_begin = pa_init(manifest_vm->partition.load_addr);
primary_entry = ipa_add(ipa_from_pa(primary_begin),
manifest_vm->partition.ep_offset);
@@ -483,6 +483,12 @@ static bool load_secondary(struct mm_stage1_locked stage1_locked,
return false;
}
+ if (manifest_vm->is_ffa_partition) {
+ plat_ffa_parse_partition_manifest(
+ stage1_locked, fdt_addr, fdt_allocated_size,
+ manifest_vm, ppool);
+ }
+
if (!fdt_patch_mem(stage1_locked, fdt_addr, fdt_allocated_size,
mem_begin, mem_end, ppool)) {
dlog_error("Unable to patch FDT.\n");
@@ -887,7 +893,8 @@ bool load_vms(struct mm_stage1_locked stage1_locked,
mem_size = align_up(manifest_vm->secondary.mem_size, PAGE_SIZE);
- if (manifest_vm->is_ffa_partition) {
+ if (manifest_vm->is_ffa_partition &&
+ !manifest->vm[i].is_hyp_loaded) {
secondary_mem_begin =
pa_init(manifest_vm->partition.load_addr);
secondary_mem_end = pa_init(
diff --git a/src/manifest.c b/src/manifest.c
index 4699c201d..ceb47825b 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -12,7 +12,6 @@
#include "hf/assert.h"
#include "hf/check.h"
#include "hf/dlog.h"
-#include "hf/fdt.h"
#include "hf/static_assert.h"
#include "hf/std.h"
@@ -304,6 +303,8 @@ static enum manifest_return_code parse_vm_common(const struct fdt_node *node,
TRY(read_bool(node, "is_ffa_partition", &vm->is_ffa_partition));
+ TRY(read_bool(node, "hyp_loaded", &vm->is_hyp_loaded));
+
TRY(read_string(node, "debug_name", &vm->debug_name));
TRY(read_optional_uint32list(node, "smc_whitelist", &smcs));
@@ -540,8 +541,8 @@ static enum manifest_return_code parse_ffa_device_region_node(
return MANIFEST_SUCCESS;
}
-static enum manifest_return_code parse_ffa_manifest(struct fdt *fdt,
- struct manifest_vm *vm)
+enum manifest_return_code parse_ffa_manifest(struct fdt *fdt,
+ struct manifest_vm *vm)
{
unsigned int i = 0;
struct uint32list_iter uuid;
@@ -664,8 +665,7 @@ static enum manifest_return_code parse_ffa_manifest(struct fdt *fdt,
return MANIFEST_SUCCESS;
}
-static enum manifest_return_code sanity_check_ffa_manifest(
- struct manifest_vm *vm)
+enum manifest_return_code sanity_check_ffa_manifest(struct manifest_vm *vm)
{
uint16_t ffa_version_major;
uint16_t ffa_version_minor;
@@ -917,7 +917,11 @@ enum manifest_return_code manifest_init(struct mm_stage1_locked stage1_locked,
TRY(parse_vm_common(&vm_node, &manifest->vm[i], vm_id));
- if (manifest->vm[i].is_ffa_partition) {
+ CHECK(!manifest->vm[i].is_hyp_loaded ||
+ manifest->vm[i].is_ffa_partition);
+
+ if (manifest->vm[i].is_ffa_partition &&
+ !manifest->vm[i].is_hyp_loaded) {
TRY(parse_ffa_partition_package(stage1_locked, &vm_node,
&manifest->vm[i], vm_id,
ppool));
diff --git a/test/vmapi/el0_partitions/manifest.dts b/test/vmapi/el0_partitions/manifest.dts
index b22a20d73..e0dd138d5 100644
--- a/test/vmapi/el0_partitions/manifest.dts
+++ b/test/vmapi/el0_partitions/manifest.dts
@@ -17,6 +17,8 @@
};
vm2 {
+ is_ffa_partition;
+ hyp_loaded;
debug_name = "services1";
vcpu_count = <1>;
mem_size = <0x100000>;
@@ -26,6 +28,8 @@
};
vm3 {
+ is_ffa_partition;
+ hyp_loaded;
debug_name = "services2";
vcpu_count = <1>;
mem_size = <0x100000>;
@@ -35,10 +39,12 @@
};
vm4 {
+ is_ffa_partition;
+ hyp_loaded;
debug_name = "services3";
vcpu_count = <1>;
mem_size = <0x100000>;
- kernel_filename = "services2";
+ kernel_filename = "services3";
fdt_filename = "secondary.dtb";
exception-level = <1>;
};
diff --git a/test/vmapi/el0_partitions/secondary.dts b/test/vmapi/el0_partitions/secondary.dts
index 1e8ea16f4..19b1bfd36 100644
--- a/test/vmapi/el0_partitions/secondary.dts
+++ b/test/vmapi/el0_partitions/secondary.dts
@@ -6,9 +6,20 @@
* https://opensource.org/licenses/BSD-3-Clause.
*/
-/* A minimal FDT for the unit tests to work. */
-
/dts-v1/;
/ {
+ compatible = "arm,ffa-manifest-1.0";
+ debug_name = "partition-manifest";
+
+ /* Properties */
+ ffa-version = <0x00010000>; /* 31:16 - Major, 15:0 - Minor */
+ uuid = <0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>;
+ execution-ctx-count = <1>;
+ exception-level = <1>; /* S-EL0 */
+ execution-state = <0>; /* AARCH64 */
+ load-address = <0x90000000>;
+ entrypoint-offset = <0x0>;
+ xlat-granule = <0>; /* 4KiB */
+ messaging-method = <7>; /* Direct and indirect messaging */
};