xref: /rk3399_ARM-atf/lib/utils/mem_region.c (revision 665e71b8ea28162ec7737c1411bca3ea89e5957e)
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  */
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 > 0);
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  */
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 > 0 && chunk > 0);
68 
69 	for ( ; nregions--; regions++) {
70 		begin = regions->base;
71 		size = regions->nbytes;
72 		if ((begin & (chunk-1)) != 0 || (size & (chunk-1)) != 0) {
73 			INFO("PSCI: Not correctly aligned region\n");
74 			panic();
75 		}
76 
77 		while (size > 0) {
78 			r = mmap_add_dynamic_region(begin, va, chunk, attr);
79 			if (r != 0) {
80 				INFO("PSCI: mmap_add_dynamic_region failed with %d\n", r);
81 				panic();
82 			}
83 
84 			zero_normalmem((void *) va, chunk);
85 
86 			r = mmap_remove_dynamic_region(va, chunk);
87 			if (r != 0) {
88 				INFO("PSCI: mmap_remove_dynamic_region failed with %d\n", r);
89 				panic();
90 			}
91 
92 			begin += chunk;
93 			size -= chunk;
94 		}
95 	}
96 }
97 #endif
98 
99 /*
100  * This function checks that a region (addr + nbytes-1) of memory is totally
101  * covered by one of the regions defined in tbl.
102  * tbl must be a valid pointer to a memory mem_region_t array, nregions
103  * is the size of the array and the region described by addr and nbytes must
104  * not generate an overflow.
105  * Returns:
106  *  -1 means that the region is not covered by any of the regions
107  *     described in tbl.
108  *   0 the region (addr + nbytes-1) is covered by one of the regions described
109  *     in tbl
110  */
111 int mem_region_in_array_chk(mem_region_t *tbl, size_t nregions,
112 			    uintptr_t addr, size_t nbytes)
113 {
114 	uintptr_t region_start, region_end, start, end;
115 	size_t i;
116 
117 	assert(tbl != NULL);
118 	assert(nbytes > 0);
119 	assert(!check_uptr_overflow(addr, nbytes-1));
120 
121 	region_start = addr;
122 	region_end = addr + (nbytes - 1);
123 	for (i = 0; i < nregions; i++) {
124 		assert(tbl->nbytes > 0);
125 		assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
126 		start = tbl->base;
127 		end = start + (tbl->nbytes - 1);
128 		if (region_start >= start && region_end <= end)
129 			return 0;
130 		tbl++;
131 	}
132 
133 	return -1;
134 }
135