1 /*
2  * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 
9 #include <common/debug.h>
10 #include <lib/utils.h>
11 #include <lib/xlat_tables/xlat_tables_compat.h>
12 
13 /*
14  * All the regions defined in mem_region_t must have the following properties
15  *
16  * - Any contiguous regions must be merged into a single entry.
17  * - The number of bytes of each region must be greater than zero.
18  * - The calculation of the highest address within the region (base + nbytes-1)
19  *   doesn't produce an overflow.
20  *
21  * These conditions must be fulfilled by the caller and they aren't checked
22  * at runtime.
23  */
24 
25 /*
26  * zero_normalmem all the regions defined in tbl.
27  * It assumes that MMU is enabled and the memory is Normal memory.
28  * tbl must be a valid pointer to a memory mem_region_t array,
29  * nregions is the size of the array.
30  */
clear_mem_regions(mem_region_t * tbl,size_t nregions)31 void clear_mem_regions(mem_region_t *tbl, size_t nregions)
32 {
33 	size_t i;
34 
35 	assert(tbl != NULL);
36 	assert(nregions > 0U);
37 
38 	for (i = 0; i < nregions; i++) {
39 		assert(tbl->nbytes > 0);
40 		assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
41 		zero_normalmem((void *) (tbl->base), tbl->nbytes);
42 		tbl++;
43 	}
44 }
45 
46 #if defined(PLAT_XLAT_TABLES_DYNAMIC)
47 /*
48  * zero_normalmem all the regions defined in regions.
49  * It assumes that MMU is enabled and the memory is Normal memory.
50  * regions must be a valid pointer to a memory mem_region_t array,
51  * nregions is the size of the array. va is the virtual address
52  * where we want to map the physical pages that are going to
53  * be cleared, and chunk is the amount of memory mapped and
54  * cleared in every iteration.
55  */
clear_map_dyn_mem_regions(struct mem_region * regions,size_t nregions,uintptr_t va,size_t chunk)56 void clear_map_dyn_mem_regions(struct mem_region *regions,
57 			       size_t nregions,
58 			       uintptr_t va,
59 			       size_t chunk)
60 {
61 	uintptr_t begin;
62 	int r;
63 	size_t size;
64 	const unsigned int attr = MT_MEMORY | MT_RW | MT_NS;
65 
66 	assert(regions != NULL);
67 	assert(nregions != 0U);
68 	assert(chunk != 0U);
69 
70 	for (unsigned int i = 0U; i < nregions; i++) {
71 		begin = regions[i].base;
72 		size = regions[i].nbytes;
73 		if (((begin & (chunk-1U)) != 0U) ||
74 				((size & (chunk-1U)) != 0U)) {
75 			INFO("PSCI: Not correctly aligned region\n");
76 			panic();
77 		}
78 
79 		while (size > 0U) {
80 			r = mmap_add_dynamic_region(begin, va, chunk, attr);
81 			if (r != 0) {
82 				INFO("PSCI: %s failed with %d\n",
83 					"mmap_add_dynamic_region", r);
84 				panic();
85 			}
86 
87 			zero_normalmem((void *)va, chunk);
88 
89 			r = mmap_remove_dynamic_region(va, chunk);
90 			if (r != 0) {
91 				INFO("PSCI: %s failed with %d\n",
92 					"mmap_remove_dynamic_region", r);
93 				panic();
94 			}
95 
96 			begin += chunk;
97 			size -= chunk;
98 		}
99 	}
100 }
101 #endif
102 
103 /*
104  * This function checks that a region (addr + nbytes-1) of memory is totally
105  * covered by one of the regions defined in tbl.
106  * tbl must be a valid pointer to a memory mem_region_t array, nregions
107  * is the size of the array and the region described by addr and nbytes must
108  * not generate an overflow.
109  * Returns:
110  *  -1 means that the region is not covered by any of the regions
111  *     described in tbl.
112  *   0 the region (addr + nbytes-1) is covered by one of the regions described
113  *     in tbl
114  */
mem_region_in_array_chk(mem_region_t * tbl,size_t nregions,uintptr_t addr,size_t nbytes)115 int mem_region_in_array_chk(mem_region_t *tbl, size_t nregions,
116 			    uintptr_t addr, size_t nbytes)
117 {
118 	uintptr_t region_start, region_end, start, end;
119 	size_t i;
120 
121 	assert(tbl != NULL);
122 	assert(nbytes != 0U);
123 	assert(!check_uptr_overflow(addr, nbytes-1));
124 
125 	region_start = addr;
126 	region_end = addr + (nbytes - 1U);
127 	for (i = 0U; i < nregions; i++) {
128 		assert(tbl->nbytes > 0);
129 		assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
130 		start = tbl->base;
131 		end = start + (tbl->nbytes - 1);
132 		if ((region_start >= start) && (region_end <= end)) {
133 			return 0;
134 		}
135 		tbl++;
136 	}
137 
138 	return -1;
139 }
140