summaryrefslogtreecommitdiffstats
path: root/lib/utils/mem_region.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/utils/mem_region.c')
-rw-r--r--lib/utils/mem_region.c139
1 files changed, 139 insertions, 0 deletions
diff --git a/lib/utils/mem_region.c b/lib/utils/mem_region.c
new file mode 100644
index 0000000..fec086b
--- /dev/null
+++ b/lib/utils/mem_region.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_compat.h>
+
+/*
+ * All the regions defined in mem_region_t must have the following properties
+ *
+ * - Any contiguous regions must be merged into a single entry.
+ * - The number of bytes of each region must be greater than zero.
+ * - The calculation of the highest address within the region (base + nbytes-1)
+ * doesn't produce an overflow.
+ *
+ * These conditions must be fulfilled by the caller and they aren't checked
+ * at runtime.
+ */
+
+/*
+ * zero_normalmem all the regions defined in tbl.
+ * It assumes that MMU is enabled and the memory is Normal memory.
+ * tbl must be a valid pointer to a memory mem_region_t array,
+ * nregions is the size of the array.
+ */
+void clear_mem_regions(mem_region_t *tbl, size_t nregions)
+{
+ size_t i;
+
+ assert(tbl != NULL);
+ assert(nregions > 0U);
+
+ for (i = 0; i < nregions; i++) {
+ assert(tbl->nbytes > 0);
+ assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
+ zero_normalmem((void *) (tbl->base), tbl->nbytes);
+ tbl++;
+ }
+}
+
+#if defined(PLAT_XLAT_TABLES_DYNAMIC)
+/*
+ * zero_normalmem all the regions defined in regions.
+ * It assumes that MMU is enabled and the memory is Normal memory.
+ * regions must be a valid pointer to a memory mem_region_t array,
+ * nregions is the size of the array. va is the virtual address
+ * where we want to map the physical pages that are going to
+ * be cleared, and chunk is the amount of memory mapped and
+ * cleared in every iteration.
+ */
+void clear_map_dyn_mem_regions(struct mem_region *regions,
+ size_t nregions,
+ uintptr_t va,
+ size_t chunk)
+{
+ uintptr_t begin;
+ int r;
+ size_t size;
+ const unsigned int attr = MT_MEMORY | MT_RW | MT_NS;
+
+ assert(regions != NULL);
+ assert(nregions != 0U);
+ assert(chunk != 0U);
+
+ for (unsigned int i = 0U; i < nregions; i++) {
+ begin = regions[i].base;
+ size = regions[i].nbytes;
+ if (((begin & (chunk-1U)) != 0U) ||
+ ((size & (chunk-1U)) != 0U)) {
+ INFO("PSCI: Not correctly aligned region\n");
+ panic();
+ }
+
+ while (size > 0U) {
+ r = mmap_add_dynamic_region(begin, va, chunk, attr);
+ if (r != 0) {
+ INFO("PSCI: %s failed with %d\n",
+ "mmap_add_dynamic_region", r);
+ panic();
+ }
+
+ zero_normalmem((void *)va, chunk);
+
+ r = mmap_remove_dynamic_region(va, chunk);
+ if (r != 0) {
+ INFO("PSCI: %s failed with %d\n",
+ "mmap_remove_dynamic_region", r);
+ panic();
+ }
+
+ begin += chunk;
+ size -= chunk;
+ }
+ }
+}
+#endif
+
+/*
+ * This function checks that a region (addr + nbytes-1) of memory is totally
+ * covered by one of the regions defined in tbl.
+ * tbl must be a valid pointer to a memory mem_region_t array, nregions
+ * is the size of the array and the region described by addr and nbytes must
+ * not generate an overflow.
+ * Returns:
+ * -1 means that the region is not covered by any of the regions
+ * described in tbl.
+ * 0 the region (addr + nbytes-1) is covered by one of the regions described
+ * in tbl
+ */
+int mem_region_in_array_chk(mem_region_t *tbl, size_t nregions,
+ uintptr_t addr, size_t nbytes)
+{
+ uintptr_t region_start, region_end, start, end;
+ size_t i;
+
+ assert(tbl != NULL);
+ assert(nbytes != 0U);
+ assert(!check_uptr_overflow(addr, nbytes-1));
+
+ region_start = addr;
+ region_end = addr + (nbytes - 1U);
+ for (i = 0U; i < nregions; i++) {
+ assert(tbl->nbytes > 0);
+ assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
+ start = tbl->base;
+ end = start + (tbl->nbytes - 1);
+ if ((region_start >= start) && (region_end <= end)) {
+ return 0;
+ }
+ tbl++;
+ }
+
+ return -1;
+}