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