xref: /rk3399_ARM-atf/lib/utils/mem_region.c (revision 638b034cc34ecdc54b9c790d5192229a027c8156)
143cbaf06SRoberto Vargas /*
2*638b034cSRoberto Vargas  * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
343cbaf06SRoberto Vargas  *
443cbaf06SRoberto Vargas  * SPDX-License-Identifier: BSD-3-Clause
543cbaf06SRoberto Vargas  */
643cbaf06SRoberto Vargas 
743cbaf06SRoberto Vargas #include <assert.h>
843cbaf06SRoberto Vargas #include <utils.h>
943cbaf06SRoberto Vargas 
1043cbaf06SRoberto Vargas /*
1143cbaf06SRoberto Vargas  * All the regions defined in mem_region_t must have the following properties
1243cbaf06SRoberto Vargas  *
1343cbaf06SRoberto Vargas  * - Any contiguous regions must be merged into a single entry.
1443cbaf06SRoberto Vargas  * - The number of bytes of each region must be greater than zero.
1543cbaf06SRoberto Vargas  * - The calculation of the highest address within the region (base + nbytes-1)
1643cbaf06SRoberto Vargas  *   doesn't produce an overflow.
1743cbaf06SRoberto Vargas  *
1843cbaf06SRoberto Vargas  * These conditions must be fulfilled by the caller and they aren't checked
1943cbaf06SRoberto Vargas  * at runtime.
2043cbaf06SRoberto Vargas  */
2143cbaf06SRoberto Vargas 
2243cbaf06SRoberto Vargas /*
2343cbaf06SRoberto Vargas  * zero_normalmem all the regions defined in tbl.
2443cbaf06SRoberto Vargas  * It assumes that MMU is enabled and the memory is Normal memory.
2543cbaf06SRoberto Vargas  * tbl must be a valid pointer to a memory mem_region_t array,
2643cbaf06SRoberto Vargas  * nregions is the size of the array.
2743cbaf06SRoberto Vargas  */
2843cbaf06SRoberto Vargas void clear_mem_regions(mem_region_t *tbl, size_t nregions)
2943cbaf06SRoberto Vargas {
3043cbaf06SRoberto Vargas 	size_t i;
3143cbaf06SRoberto Vargas 
3243cbaf06SRoberto Vargas 	assert(tbl);
3343cbaf06SRoberto Vargas 	assert(nregions > 0);
3443cbaf06SRoberto Vargas 
3543cbaf06SRoberto Vargas 	for (i = 0; i < nregions; i++) {
3643cbaf06SRoberto Vargas 		assert(tbl->nbytes > 0);
3743cbaf06SRoberto Vargas 		assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
3843cbaf06SRoberto Vargas 		zero_normalmem((void *) (tbl->base), tbl->nbytes);
3943cbaf06SRoberto Vargas 		tbl++;
4043cbaf06SRoberto Vargas 	}
4143cbaf06SRoberto Vargas }
4243cbaf06SRoberto Vargas 
43*638b034cSRoberto Vargas #if defined(PLAT_XLAT_TABLES_DYNAMIC)
44*638b034cSRoberto Vargas /*
45*638b034cSRoberto Vargas  * zero_normalmem all the regions defined in regions.
46*638b034cSRoberto Vargas  * It assumes that MMU is enabled and the memory is Normal memory.
47*638b034cSRoberto Vargas  * regions must be a valid pointer to a memory mem_region_t array,
48*638b034cSRoberto Vargas  * nregions is the size of the array. va is the virtual address
49*638b034cSRoberto Vargas  * where we want to map the physical pages that are going to
50*638b034cSRoberto Vargas  * be cleared, and chunk is the amount of memory mapped and
51*638b034cSRoberto Vargas  * cleared in every iteration.
52*638b034cSRoberto Vargas  */
53*638b034cSRoberto Vargas void clear_map_dyn_mem_regions(mem_region_t *regions,
54*638b034cSRoberto Vargas 			       size_t nregions,
55*638b034cSRoberto Vargas 			       uintptr_t va,
56*638b034cSRoberto Vargas 			       size_t chunk)
57*638b034cSRoberto Vargas {
58*638b034cSRoberto Vargas 	uintptr_t begin;
59*638b034cSRoberto Vargas 	int r;
60*638b034cSRoberto Vargas 	size_t size;
61*638b034cSRoberto Vargas 	const mmap_attr_t attr = MT_MEMORY|MT_RW|MT_NS;
62*638b034cSRoberto Vargas 
63*638b034cSRoberto Vargas 	assert(regions != NULL);
64*638b034cSRoberto Vargas 	assert(nregions > 0 && chunk > 0);
65*638b034cSRoberto Vargas 
66*638b034cSRoberto Vargas 	for ( ; nregions--; regions++) {
67*638b034cSRoberto Vargas 		begin = regions->base;
68*638b034cSRoberto Vargas 		size = regions->nbytes;
69*638b034cSRoberto Vargas 		if ((begin & (chunk-1)) != 0 || (size & (chunk-1)) != 0) {
70*638b034cSRoberto Vargas 			INFO("PSCI: Not correctly aligned region\n");
71*638b034cSRoberto Vargas 			panic();
72*638b034cSRoberto Vargas 		}
73*638b034cSRoberto Vargas 
74*638b034cSRoberto Vargas 		while (size > 0) {
75*638b034cSRoberto Vargas 			r = mmap_add_dynamic_region(begin, va, chunk, attr);
76*638b034cSRoberto Vargas 			if (r != 0) {
77*638b034cSRoberto Vargas 				INFO("PSCI: mmap_add_dynamic_region failed with %d\n", r);
78*638b034cSRoberto Vargas 				panic();
79*638b034cSRoberto Vargas 			}
80*638b034cSRoberto Vargas 
81*638b034cSRoberto Vargas 			zero_normalmem((void *) va, chunk);
82*638b034cSRoberto Vargas 
83*638b034cSRoberto Vargas 			r = mmap_remove_dynamic_region(va, chunk);
84*638b034cSRoberto Vargas 			if (r != 0) {
85*638b034cSRoberto Vargas 				INFO("PSCI: mmap_remove_dynamic_region failed with %d\n", r);
86*638b034cSRoberto Vargas 				panic();
87*638b034cSRoberto Vargas 			}
88*638b034cSRoberto Vargas 
89*638b034cSRoberto Vargas 			begin += chunk;
90*638b034cSRoberto Vargas 			size -= chunk;
91*638b034cSRoberto Vargas 		}
92*638b034cSRoberto Vargas 	}
93*638b034cSRoberto Vargas }
94*638b034cSRoberto Vargas #endif
95*638b034cSRoberto Vargas 
9643cbaf06SRoberto Vargas /*
9743cbaf06SRoberto Vargas  * This function checks that a region (addr + nbytes-1) of memory is totally
9843cbaf06SRoberto Vargas  * covered by one of the regions defined in tbl.
9943cbaf06SRoberto Vargas  * tbl must be a valid pointer to a memory mem_region_t array, nregions
10043cbaf06SRoberto Vargas  * is the size of the array and the region described by addr and nbytes must
10143cbaf06SRoberto Vargas  * not generate an overflow.
10243cbaf06SRoberto Vargas  * Returns:
10343cbaf06SRoberto Vargas  *  -1 means that the region is not covered by any of the regions
10443cbaf06SRoberto Vargas  *     described in tbl.
10543cbaf06SRoberto Vargas  *   0 the region (addr + nbytes-1) is covered by one of the regions described
10643cbaf06SRoberto Vargas  *     in tbl
10743cbaf06SRoberto Vargas  */
10843cbaf06SRoberto Vargas int mem_region_in_array_chk(mem_region_t *tbl, size_t nregions,
10943cbaf06SRoberto Vargas 			    uintptr_t addr, size_t nbytes)
11043cbaf06SRoberto Vargas {
11143cbaf06SRoberto Vargas 	uintptr_t region_start, region_end, start, end;
11243cbaf06SRoberto Vargas 	size_t i;
11343cbaf06SRoberto Vargas 
11443cbaf06SRoberto Vargas 	assert(tbl);
11543cbaf06SRoberto Vargas 	assert(nbytes > 0);
11643cbaf06SRoberto Vargas 	assert(!check_uptr_overflow(addr, nbytes-1));
11743cbaf06SRoberto Vargas 
11843cbaf06SRoberto Vargas 	region_start = addr;
11943cbaf06SRoberto Vargas 	region_end = addr + (nbytes - 1);
12043cbaf06SRoberto Vargas 	for (i = 0; i < nregions; i++) {
12143cbaf06SRoberto Vargas 		assert(tbl->nbytes > 0);
12243cbaf06SRoberto Vargas 		assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
12343cbaf06SRoberto Vargas 		start = tbl->base;
12443cbaf06SRoberto Vargas 		end = start + (tbl->nbytes - 1);
12543cbaf06SRoberto Vargas 		if (region_start >= start && region_end <= end)
12643cbaf06SRoberto Vargas 			return 0;
12743cbaf06SRoberto Vargas 		tbl++;
12843cbaf06SRoberto Vargas 	}
12943cbaf06SRoberto Vargas 
13043cbaf06SRoberto Vargas 	return -1;
13143cbaf06SRoberto Vargas }
132