PSA FF-A: add partition manifest parsing
Add PSA FF-A partition manifest structure to VM manifest. Add FF-A
partition package structure (comprises header + image dtb + image
payload). Parse FF-A partition manifest DT if requested by the
is_ffa_partition DTS boolean.
This assumes Hafnium entry point is directly fed with the hypervisor
manifest pointer address (rather than the initrd image).
For a regular VM, the entry point is the start address of the VM
workspace allocated by Hafnium from the mem ranges provided in
hypervisor manifest. If the VM is an FF-A compliant partition,
the VM entry point is extrapolated from the FF-A partition manifest
(start of the workspace as SP header load address plus entry point
offset from partition DTS).
Change-Id: I6947646d0cd6eb3c4d97a31aa589244b365c8486
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
Signed-off-by: Louis Mayencourt <louis.mayencourt@arm.com>
diff --git a/src/load.c b/src/load.c
index 259726e..606848e 100644
--- a/src/load.c
+++ b/src/load.c
@@ -73,11 +73,6 @@
{
struct memiter kernel;
- if (string_is_empty(&manifest_vm->kernel_filename)) {
- /* This signals the kernel has been preloaded. */
- return true;
- }
-
if (!cpio_get_file(cpio, &manifest_vm->kernel_filename, &kernel)) {
dlog_error("Could not find kernel file \"%s\".\n",
string_data(&manifest_vm->kernel_filename));
@@ -119,22 +114,41 @@
const struct memiter *cpio,
const struct boot_params *params, struct mpool *ppool)
{
+ paddr_t primary_begin;
+ ipaddr_t primary_entry;
struct vm *vm;
struct vm_locked vm_locked;
struct vcpu_locked vcpu_locked;
size_t i;
bool ret;
- paddr_t primary_begin =
- (manifest_vm->primary.boot_address == MANIFEST_INVALID_ADDRESS)
- ? layout_primary_begin()
- : pa_init(manifest_vm->primary.boot_address);
+ if (manifest_vm->is_ffa_partition) {
+ primary_begin = pa_init(manifest_vm->sp.load_addr);
+ primary_entry = ipa_add(ipa_from_pa(primary_begin),
+ manifest_vm->sp.ep_offset);
+ } else {
+ primary_begin =
+ (manifest_vm->primary.boot_address ==
+ MANIFEST_INVALID_ADDRESS)
+ ? layout_primary_begin()
+ : pa_init(manifest_vm->primary.boot_address);
+ primary_entry = ipa_from_pa(primary_begin);
+ }
+
paddr_t primary_end = pa_add(primary_begin, RSIZE_MAX);
- if (!load_kernel(stage1_locked, primary_begin, primary_end, manifest_vm,
- cpio, ppool)) {
- dlog_error("Unable to load primary kernel.\n");
- return false;
+ /*
+ * Load the kernel if a filename is specified in the VM manifest.
+ * For an FF-A partition, kernel_filename is undefined indicating
+ * the partition package has already been loaded prior to Hafnium
+ * booting.
+ */
+ if (!string_is_empty(&manifest_vm->kernel_filename)) {
+ if (!load_kernel(stage1_locked, primary_begin, primary_end,
+ manifest_vm, cpio, ppool)) {
+ dlog_error("Unable to load primary kernel.\n");
+ return false;
+ }
}
if (!vm_init_next(MAX_CPUS, ppool, &vm)) {
@@ -219,7 +233,7 @@
vm->vcpu_count, pa_addr(primary_begin));
vcpu_locked = vcpu_lock(vm_get_vcpu(vm, 0));
- vcpu_on(vcpu_locked, ipa_from_pa(primary_begin), params->kernel_arg);
+ vcpu_on(vcpu_locked, primary_entry, params->kernel_arg);
vcpu_unlock(&vcpu_locked);
ret = true;
@@ -243,10 +257,18 @@
ipaddr_t secondary_entry;
bool ret;
- if (!load_kernel(stage1_locked, mem_begin, mem_end, manifest_vm, cpio,
- ppool)) {
- dlog_error("Unable to load kernel.\n");
- return false;
+ /*
+ * Load the kernel if a filename is specified in the VM manifest.
+ * For an FF-A partition, kernel_filename is undefined indicating
+ * the partition package has already been loaded prior to Hafnium
+ * booting.
+ */
+ if (!string_is_empty(&manifest_vm->kernel_filename)) {
+ if (!load_kernel(stage1_locked, mem_begin, mem_end, manifest_vm,
+ cpio, ppool)) {
+ dlog_error("Unable to load kernel.\n");
+ return false;
+ }
}
if (!vm_init_next(manifest_vm->secondary.vcpu_count, ppool, &vm)) {
@@ -272,6 +294,11 @@
dlog_info("Loaded with %u vCPUs, entry at %#x.\n",
manifest_vm->secondary.vcpu_count, pa_addr(mem_begin));
+ if (manifest_vm->is_ffa_partition) {
+ secondary_entry =
+ ipa_add(secondary_entry, manifest_vm->sp.ep_offset);
+ }
+
vcpu = vm_get_vcpu(vm, 0);
vcpu_secondary_reset_and_start(vcpu, secondary_entry,
pa_difference(mem_begin, mem_end));
@@ -424,10 +451,16 @@
manifest_vm->debug_name);
mem_size = align_up(manifest_vm->secondary.mem_size, PAGE_SIZE);
- if (!carve_out_mem_range(mem_ranges_available,
- params->mem_ranges_count, mem_size,
- &secondary_mem_begin,
- &secondary_mem_end)) {
+
+ if (manifest_vm->is_ffa_partition) {
+ secondary_mem_begin =
+ pa_init(manifest_vm->sp.load_addr);
+ secondary_mem_end =
+ pa_init(manifest_vm->sp.load_addr + mem_size);
+ } else if (!carve_out_mem_range(mem_ranges_available,
+ params->mem_ranges_count,
+ mem_size, &secondary_mem_begin,
+ &secondary_mem_end)) {
dlog_error("Not enough memory (%u bytes).\n", mem_size);
continue;
}