feat(manifest): check SPs don't overlap mem regions
Add check that memory regions defined in the partition manifest
do not overlap.
Since the size of the allocated_fields struct could increase
greatly if MAX_VMs was increased, this patch allocates the number
of entries from the mpool required according to the size of the
allocated_fields struct, helping scaling in the future.
Signed-off-by: Daniel Boulby <daniel.boulby@arm.com>
Change-Id: I5559166c3c94783471bdc3c8bb53f3338c4547a1
diff --git a/src/manifest.c b/src/manifest.c
index cd70e11..58a2ff2 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -44,15 +44,22 @@
*/
struct allocated_fields {
uint32_t intids[HF_NUM_INTIDS / INTERRUPT_REGISTER_BITS];
+ struct {
+ uintptr_t base;
+ uintptr_t limit;
+ } mem_regions[PARTITION_MAX_MEMORY_REGIONS * MAX_VMS];
};
-
/**
- * Ensure the allocated_fields struct will fit in the entry allocated from
- * the mpool.
+ * Calculate the number of entries in the ppool that are required to
+ * store the allocated_fields struct.
*/
-static_assert(sizeof(struct allocated_fields) < MM_PPOOL_ENTRY_SIZE,
- "More space required for the allocated_fields struct.");
+static size_t allocated_fields_ppool_entries =
+ (align_up(sizeof(struct allocated_fields), MM_PPOOL_ENTRY_SIZE) /
+ MM_PPOOL_ENTRY_SIZE);
+
static struct allocated_fields *allocated_fields;
+/* Index used the track the number of memory regions allocted. */
+static size_t allocated_mem_regions_index = 0;
/**
* Allocates memory for the allocated fields struct in the given memory
@@ -61,7 +68,9 @@
*/
static bool manifest_allocated_fields_init(struct mpool *ppool)
{
- allocated_fields = (struct allocated_fields *)mpool_alloc(ppool);
+ allocated_fields = (struct allocated_fields *)mpool_alloc_contiguous(
+ ppool, allocated_fields_ppool_entries, 1);
+
return allocated_fields != NULL;
}
@@ -71,7 +80,17 @@
*/
static void manifest_allocated_fields_deinit(struct mpool *ppool)
{
- mpool_free(ppool, allocated_fields);
+ /**
+ * Return the memory used for the allocated_fields struct to the
+ * memory pool
+ */
+ mpool_add_chunk(ppool, allocated_fields,
+ allocated_fields_ppool_entries);
+ /**
+ * Reset the index used for tracking the number of memory regions
+ * allocated.
+ */
+ allocated_mem_regions_index = 0;
}
static inline size_t count_digits(ffa_vm_id_t vm_id)
@@ -391,6 +410,39 @@
return MANIFEST_SUCCESS;
}
+static bool check_and_record_mem_regions(uintptr_t base_address,
+ uint32_t page_count)
+{
+ uintptr_t limit = base_address + page_count * PAGE_SIZE;
+
+ for (size_t i = 0; i < allocated_mem_regions_index; i++) {
+ uintptr_t mem_region_base =
+ allocated_fields->mem_regions[i].base;
+ uintptr_t mem_region_limit =
+ allocated_fields->mem_regions[i].limit;
+
+ if ((base_address >= mem_region_base &&
+ base_address < mem_region_limit) ||
+ (limit < mem_region_limit && limit >= mem_region_base)) {
+ dlog_error(
+ "Overlapping memory regions\n"
+ "New Region %#x - %#x\n"
+ "Overlapping region %#x - %#x\n",
+ base_address, limit, mem_region_base,
+ mem_region_limit);
+ return false;
+ }
+ }
+
+ allocated_fields->mem_regions[allocated_mem_regions_index].base =
+ base_address;
+ allocated_fields->mem_regions[allocated_mem_regions_index].limit =
+ limit;
+ allocated_mem_regions_index++;
+
+ return true;
+}
+
static enum manifest_return_code parse_ffa_memory_region_node(
struct fdt_node *mem_node, struct memory_region *mem_regions,
uint16_t *count, struct rx_tx *rxtx)
@@ -427,6 +479,11 @@
dlog_verbose(" Pages_count: %u\n",
mem_regions[i].page_count);
+ if (!check_and_record_mem_regions(mem_regions[i].base_address,
+ mem_regions[i].page_count)) {
+ return MANIFEST_ERROR_MEM_REGION_OVERLAP;
+ }
+
TRY(read_uint32(mem_node, "attributes",
&mem_regions[i].attributes));
@@ -1078,6 +1135,8 @@
return "Device-region node should have at least one entry";
case MANIFEST_ERROR_RXTX_SIZE_MISMATCH:
return "RX and TX buffers should be of same size";
+ case MANIFEST_ERROR_MEM_REGION_OVERLAP:
+ return "Memory region overlaps with one already allocated";
case MANIFEST_ERROR_INVALID_MEM_PERM:
return "Memory permission should be RO, RW or RX";
case MANIFEST_ERROR_ARGUMENTS_LIST_EMPTY: