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