refactor(load): move memory mapping into own func
Create a helper function to map the memory regions to vms during load
to reduce the cognative complexity of the load_secondary function.
Signed-off-by: Daniel Boulby <daniel.boulby@arm.com>
Change-Id: I61e47faac9432d9600bd0d5c496c22f514ab4756
diff --git a/src/load.c b/src/load.c
index 75feb36..af3519a 100644
--- a/src/load.c
+++ b/src/load.c
@@ -500,6 +500,154 @@
return mode | MM_MODE_D;
}
+static bool ffa_map_memory_regions(const struct manifest_vm *manifest_vm,
+ const struct vm_locked vm_locked,
+ const struct vm_locked primary_vm_locked,
+ paddr_t mem_end, bool is_el0_partition,
+ struct mpool *ppool)
+{
+#if LOG_LEVEL >= LOG_LEVEL_WARNING
+ const char *error_string = " region security state ignored for ";
+#endif
+ int j = 0;
+ paddr_t region_begin;
+ paddr_t region_end;
+ paddr_t alloc_base = mem_end;
+ size_t size;
+ size_t total_alloc = 0;
+ uint32_t map_mode;
+ uint32_t attributes;
+
+ /* Map memory-regions */
+ while (j < manifest_vm->partition.mem_region_count) {
+ size = manifest_vm->partition.mem_regions[j].page_count *
+ PAGE_SIZE;
+ /*
+ * For memory-regions without base-address, memory
+ * should be allocated inside partition's page table.
+ * Start allocating memory regions in partition's
+ * page table, starting from the end.
+ * TODO: Add mechanism to let partition know of these
+ * memory regions
+ */
+ if (manifest_vm->partition.mem_regions[j].base_address ==
+ MANIFEST_INVALID_ADDRESS) {
+ total_alloc += size;
+ /* Don't go beyond half the VM's memory space */
+ if (total_alloc >
+ (manifest_vm->secondary.mem_size / 2)) {
+ dlog_error(
+ "Not enough space for memory-"
+ "region allocation");
+ return false;
+ }
+
+ region_end = alloc_base;
+ region_begin = pa_subtract(alloc_base, size);
+ alloc_base = region_begin;
+ } else {
+ /*
+ * Identity map memory region for both case,
+ * VA(S-EL0) or IPA(S-EL1).
+ */
+ region_begin =
+ pa_init(manifest_vm->partition.mem_regions[j]
+ .base_address);
+ region_end = pa_add(region_begin, size);
+ }
+
+ attributes = manifest_vm->partition.mem_regions[j].attributes;
+ if ((attributes & MANIFEST_REGION_ATTR_SECURITY) != 0) {
+ if (plat_ffa_is_vm_id(vm_locked.vm->id)) {
+ dlog_warning("Memory%sVMs\n", error_string);
+ attributes &= ~MANIFEST_REGION_ATTR_SECURITY;
+
+ } else if (!is_el0_partition) {
+ dlog_warning(
+ "Memory%sS-EL1 "
+ "partitions.\n",
+ error_string);
+ attributes &= ~MANIFEST_REGION_ATTR_SECURITY;
+ }
+ }
+
+ map_mode = memory_region_attributes_to_mode(attributes);
+
+ if (is_el0_partition) {
+ map_mode |= MM_MODE_USER | MM_MODE_NG;
+ }
+
+ if (!vm_identity_map(vm_locked, region_begin, region_end,
+ map_mode, ppool, NULL)) {
+ dlog_error(
+ "Unable to map secondary VM "
+ "memory-region.\n");
+ return false;
+ }
+
+ /* Deny the primary VM access to this memory */
+ if (!vm_unmap(primary_vm_locked, region_begin, region_end,
+ ppool)) {
+ dlog_error(
+ "Unable to unmap secondary VM memory-"
+ "region from primary VM.\n");
+ return false;
+ }
+
+ dlog_verbose("Memory region %#x - %#x allocated.\n",
+ region_begin, region_end);
+
+ j++;
+ }
+
+ /* Map device-regions */
+ j = 0;
+ while (j < manifest_vm->partition.dev_region_count) {
+ region_begin = pa_init(
+ manifest_vm->partition.dev_regions[j].base_address);
+ size = manifest_vm->partition.dev_regions[j].page_count *
+ PAGE_SIZE;
+ region_end = pa_add(region_begin, size);
+
+ attributes = manifest_vm->partition.dev_regions[j].attributes;
+ if ((attributes & MANIFEST_REGION_ATTR_SECURITY) != 0) {
+ if (plat_ffa_is_vm_id(vm_locked.vm->id)) {
+ dlog_warning("Device%sVMs\n", error_string);
+ attributes &= ~MANIFEST_REGION_ATTR_SECURITY;
+ } else if (!is_el0_partition) {
+ dlog_warning(
+ "Device%sS-EL1 "
+ "partitions.\n",
+ error_string);
+ attributes &= ~MANIFEST_REGION_ATTR_SECURITY;
+ }
+ }
+
+ map_mode = device_region_attributes_to_mode(attributes);
+ if (is_el0_partition) {
+ map_mode |= MM_MODE_USER | MM_MODE_NG;
+ }
+
+ if (!vm_identity_map(vm_locked, region_begin, region_end,
+ map_mode, ppool, NULL)) {
+ dlog_error(
+ "Unable to map secondary VM "
+ "device-region.\n");
+ return false;
+ }
+ /* Deny primary VM access to this region */
+ if (!vm_unmap(primary_vm_locked, region_begin, region_end,
+ ppool)) {
+ dlog_error(
+ "Unable to unmap secondary VM device-"
+ "region from primary VM.\n");
+ return false;
+ }
+ j++;
+ }
+ return true;
+}
+
/*
* Loads a secondary VM.
*/
@@ -509,9 +657,6 @@
const struct manifest_vm *manifest_vm,
const struct memiter *cpio, struct mpool *ppool)
{
-#if LOG_LEVEL >= LOG_LEVEL_WARNING
- const char *error_string = " region security state ignored for ";
-#endif
struct vm *vm;
struct vm_locked vm_locked;
struct vcpu_locked vcpu_locked;
@@ -523,6 +668,7 @@
size_t kernel_size = 0;
const size_t mem_size = pa_difference(mem_begin, mem_end);
uint32_t map_mode;
+ bool is_el0_partition = manifest_vm->partition.run_time_el == S_EL0;
/*
* Load the kernel if a filename is specified in the VM manifest.
@@ -572,11 +718,10 @@
* An S-EL0 partition must contain only 1 vCPU (UP migratable) per the
* FF-A 1.0 spec.
*/
- CHECK(manifest_vm->partition.run_time_el != S_EL0 ||
- manifest_vm->secondary.vcpu_count == 1);
+ CHECK(!is_el0_partition || manifest_vm->secondary.vcpu_count == 1);
if (!vm_init_next(manifest_vm->secondary.vcpu_count, ppool, &vm,
- (manifest_vm->partition.run_time_el == S_EL0))) {
+ is_el0_partition)) {
dlog_error("Unable to initialise VM.\n");
return false;
}
@@ -591,7 +736,7 @@
* expected to perform its owns relocations and call the FFA_MEM_PERM_*
* API's to change permissions on its image layout.
*/
- if (vm->el0_partition) {
+ if (is_el0_partition) {
map_mode = MM_MODE_R | MM_MODE_X | MM_MODE_USER | MM_MODE_NG;
} else {
map_mode = MM_MODE_R | MM_MODE_W | MM_MODE_X;
@@ -605,199 +750,11 @@
}
if (manifest_vm->is_ffa_partition) {
- int j = 0;
- paddr_t region_begin;
- paddr_t region_end;
- paddr_t alloc_base = mem_end;
- size_t size;
- size_t total_alloc = 0;
- uint32_t attributes;
-
- /* Map memory-regions */
- while (j < manifest_vm->partition.mem_region_count) {
- size = manifest_vm->partition.mem_regions[j]
- .page_count *
- PAGE_SIZE;
- /*
- * For memory-regions without base-address, memory
- * should be allocated inside partition's page table.
- * Start allocating memory regions in partition's
- * page table, starting from the end.
- * TODO: Add mechanism to let partition know of these
- * memory regions
- */
- if (manifest_vm->partition.mem_regions[j]
- .base_address == MANIFEST_INVALID_ADDRESS) {
- total_alloc += size;
- /* Don't go beyond half the VM's memory space */
- if (total_alloc >
- (manifest_vm->secondary.mem_size / 2)) {
- dlog_error(
- "Not enough space for memory-"
- "region allocation");
- ret = false;
- goto out;
- }
-
- region_end = alloc_base;
- region_begin = pa_subtract(alloc_base, size);
- alloc_base = region_begin;
-
- attributes =
- manifest_vm->partition.mem_regions[j]
- .attributes;
- if ((attributes &
- MANIFEST_REGION_ATTR_SECURITY) != 0) {
- if (plat_ffa_is_vm_id(
- vm_locked.vm->id)) {
- dlog_warning("Memory%sVMs\n",
- error_string);
- attributes &=
- ~MANIFEST_REGION_ATTR_SECURITY;
- } else if (!vm->el0_partition) {
- dlog_warning(
- "Memory%sS-EL1 "
- "partitions.\n",
- error_string);
- attributes &=
- ~MANIFEST_REGION_ATTR_SECURITY;
- }
- }
-
- map_mode = memory_region_attributes_to_mode(
- attributes);
- if (vm->el0_partition) {
- map_mode |= MM_MODE_USER | MM_MODE_NG;
- }
-
- if (!vm_identity_map(vm_locked, region_begin,
- region_end, map_mode,
- ppool, NULL)) {
- dlog_error(
- "Unable to map secondary VM "
- "memory-region.\n");
- ret = false;
- goto out;
- }
-
- dlog_verbose(
- " Memory region %#x - %#x allocated\n",
- region_begin, region_end);
- } else {
- /*
- * Identity map memory region for both case,
- * VA(S-EL0) or IPA(S-EL1).
- */
- region_begin = pa_init(
- manifest_vm->partition.mem_regions[j]
- .base_address);
- region_end = pa_add(region_begin, size);
-
- attributes =
- manifest_vm->partition.mem_regions[j]
- .attributes;
- if ((attributes &
- MANIFEST_REGION_ATTR_SECURITY) != 0) {
- if (plat_ffa_is_vm_id(
- vm_locked.vm->id)) {
- dlog_warning("Memory%sVMs\n",
- error_string);
- attributes &=
- ~MANIFEST_REGION_ATTR_SECURITY;
-
- } else if (!vm->el0_partition) {
- dlog_warning(
- "Memory%sS-EL1 "
- "partitions.\n",
- error_string);
- attributes &=
- ~MANIFEST_REGION_ATTR_SECURITY;
- }
- }
-
- map_mode = memory_region_attributes_to_mode(
- attributes);
- if (vm->el0_partition) {
- map_mode |= MM_MODE_USER | MM_MODE_NG;
- }
-
- if (!vm_identity_map(vm_locked, region_begin,
- region_end, map_mode,
- ppool, NULL)) {
- dlog_error(
- "Unable to map secondary VM "
- "memory-region.\n");
- ret = false;
- goto out;
- }
- }
-
- /* Deny the primary VM access to this memory */
- if (!vm_unmap(primary_vm_locked, region_begin,
- region_end, ppool)) {
- dlog_error(
- "Unable to unmap secondary VM memory-"
- "region from primary VM.\n");
- ret = false;
- goto out;
- }
-
- j++;
- }
-
- /* Map device-regions */
- j = 0;
- while (j < manifest_vm->partition.dev_region_count) {
- region_begin =
- pa_init(manifest_vm->partition.dev_regions[j]
- .base_address);
- size = manifest_vm->partition.dev_regions[j]
- .page_count *
- PAGE_SIZE;
- region_end = pa_add(region_begin, size);
-
- attributes = manifest_vm->partition.dev_regions[j]
- .attributes;
- if ((attributes & MANIFEST_REGION_ATTR_SECURITY) != 0) {
- if (plat_ffa_is_vm_id(vm_locked.vm->id)) {
- dlog_warning("Device%sVMs\n",
- error_string);
- attributes &=
- ~MANIFEST_REGION_ATTR_SECURITY;
- } else if (!vm->el0_partition) {
- dlog_warning(
- "Device%sS-EL1 "
- "partitions.\n",
- error_string);
- attributes &=
- ~MANIFEST_REGION_ATTR_SECURITY;
- }
- }
-
- map_mode = device_region_attributes_to_mode(attributes);
- if (vm->el0_partition) {
- map_mode |= MM_MODE_USER | MM_MODE_NG;
- }
-
- if (!vm_identity_map(vm_locked, region_begin,
- region_end, map_mode, ppool,
- NULL)) {
- dlog_error(
- "Unable to map secondary VM "
- "device-region.\n");
- ret = false;
- goto out;
- }
- /* Deny primary VM access to this region */
- if (!vm_unmap(primary_vm_locked, region_begin,
- region_end, ppool)) {
- dlog_error(
- "Unable to unmap secondary VM device-"
- "region from primary VM.\n");
- ret = false;
- goto out;
- }
- j++;
+ if (!ffa_map_memory_regions(manifest_vm, vm_locked,
+ primary_vm_locked, mem_end,
+ is_el0_partition, ppool)) {
+ ret = false;
+ goto out;
}
secondary_entry = ipa_add(secondary_entry,
@@ -812,7 +769,7 @@
* require and not the entire hypervisor. This helps with speculative
* side-channel attacks.
*/
- if (vm->el0_partition) {
+ if (is_el0_partition) {
CHECK(vm_identity_map(vm_locked, layout_text_begin(),
layout_text_end(), MM_MODE_X, ppool,
NULL));