143cbaf06SRoberto Vargas /*
2*4c700c15SGovindraj Raja * Copyright (c) 2017-2020, 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>
809d40e0eSAntonio Nino Diaz
9bd9344f6SAntonio Nino Diaz #include <common/debug.h>
1009d40e0eSAntonio Nino Diaz #include <lib/utils.h>
11bd9344f6SAntonio Nino Diaz #include <lib/xlat_tables/xlat_tables_compat.h>
1243cbaf06SRoberto Vargas
1343cbaf06SRoberto Vargas /*
1443cbaf06SRoberto Vargas * All the regions defined in mem_region_t must have the following properties
1543cbaf06SRoberto Vargas *
1643cbaf06SRoberto Vargas * - Any contiguous regions must be merged into a single entry.
1743cbaf06SRoberto Vargas * - The number of bytes of each region must be greater than zero.
1843cbaf06SRoberto Vargas * - The calculation of the highest address within the region (base + nbytes-1)
1943cbaf06SRoberto Vargas * doesn't produce an overflow.
2043cbaf06SRoberto Vargas *
2143cbaf06SRoberto Vargas * These conditions must be fulfilled by the caller and they aren't checked
2243cbaf06SRoberto Vargas * at runtime.
2343cbaf06SRoberto Vargas */
2443cbaf06SRoberto Vargas
2543cbaf06SRoberto Vargas /*
2643cbaf06SRoberto Vargas * zero_normalmem all the regions defined in tbl.
2743cbaf06SRoberto Vargas * It assumes that MMU is enabled and the memory is Normal memory.
2843cbaf06SRoberto Vargas * tbl must be a valid pointer to a memory mem_region_t array,
2943cbaf06SRoberto Vargas * nregions is the size of the array.
3043cbaf06SRoberto Vargas */
clear_mem_regions(mem_region_t * tbl,size_t nregions)3143cbaf06SRoberto Vargas void clear_mem_regions(mem_region_t *tbl, size_t nregions)
3243cbaf06SRoberto Vargas {
3343cbaf06SRoberto Vargas size_t i;
3443cbaf06SRoberto Vargas
35466bb285SZelalem assert(tbl != NULL);
36633fa4cdSjohpow01 assert(nregions > 0U);
3743cbaf06SRoberto Vargas
3843cbaf06SRoberto Vargas for (i = 0; i < nregions; i++) {
3943cbaf06SRoberto Vargas assert(tbl->nbytes > 0);
4043cbaf06SRoberto Vargas assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
4143cbaf06SRoberto Vargas zero_normalmem((void *) (tbl->base), tbl->nbytes);
4243cbaf06SRoberto Vargas tbl++;
4343cbaf06SRoberto Vargas }
4443cbaf06SRoberto Vargas }
4543cbaf06SRoberto Vargas
46638b034cSRoberto Vargas #if defined(PLAT_XLAT_TABLES_DYNAMIC)
47638b034cSRoberto Vargas /*
48638b034cSRoberto Vargas * zero_normalmem all the regions defined in regions.
49638b034cSRoberto Vargas * It assumes that MMU is enabled and the memory is Normal memory.
50638b034cSRoberto Vargas * regions must be a valid pointer to a memory mem_region_t array,
51638b034cSRoberto Vargas * nregions is the size of the array. va is the virtual address
52638b034cSRoberto Vargas * where we want to map the physical pages that are going to
53638b034cSRoberto Vargas * be cleared, and chunk is the amount of memory mapped and
54638b034cSRoberto Vargas * cleared in every iteration.
55638b034cSRoberto Vargas */
clear_map_dyn_mem_regions(struct mem_region * regions,size_t nregions,uintptr_t va,size_t chunk)56c96f297fSRoberto Vargas void clear_map_dyn_mem_regions(struct mem_region *regions,
57638b034cSRoberto Vargas size_t nregions,
58638b034cSRoberto Vargas uintptr_t va,
59638b034cSRoberto Vargas size_t chunk)
60638b034cSRoberto Vargas {
61638b034cSRoberto Vargas uintptr_t begin;
62638b034cSRoberto Vargas int r;
63638b034cSRoberto Vargas size_t size;
643a1b7b10SAntonio Nino Diaz const unsigned int attr = MT_MEMORY | MT_RW | MT_NS;
65638b034cSRoberto Vargas
66638b034cSRoberto Vargas assert(regions != NULL);
67633fa4cdSjohpow01 assert(nregions != 0U);
68633fa4cdSjohpow01 assert(chunk != 0U);
69638b034cSRoberto Vargas
70633fa4cdSjohpow01 for (unsigned int i = 0U; i < nregions; i++) {
71633fa4cdSjohpow01 begin = regions[i].base;
72633fa4cdSjohpow01 size = regions[i].nbytes;
73633fa4cdSjohpow01 if (((begin & (chunk-1U)) != 0U) ||
74633fa4cdSjohpow01 ((size & (chunk-1U)) != 0U)) {
75638b034cSRoberto Vargas INFO("PSCI: Not correctly aligned region\n");
76638b034cSRoberto Vargas panic();
77638b034cSRoberto Vargas }
78638b034cSRoberto Vargas
79633fa4cdSjohpow01 while (size > 0U) {
80638b034cSRoberto Vargas r = mmap_add_dynamic_region(begin, va, chunk, attr);
81638b034cSRoberto Vargas if (r != 0) {
82633fa4cdSjohpow01 INFO("PSCI: %s failed with %d\n",
83633fa4cdSjohpow01 "mmap_add_dynamic_region", r);
84638b034cSRoberto Vargas panic();
85638b034cSRoberto Vargas }
86638b034cSRoberto Vargas
87638b034cSRoberto Vargas zero_normalmem((void *)va, chunk);
88638b034cSRoberto Vargas
89638b034cSRoberto Vargas r = mmap_remove_dynamic_region(va, chunk);
90638b034cSRoberto Vargas if (r != 0) {
91633fa4cdSjohpow01 INFO("PSCI: %s failed with %d\n",
92633fa4cdSjohpow01 "mmap_remove_dynamic_region", r);
93638b034cSRoberto Vargas panic();
94638b034cSRoberto Vargas }
95638b034cSRoberto Vargas
96638b034cSRoberto Vargas begin += chunk;
97638b034cSRoberto Vargas size -= chunk;
98638b034cSRoberto Vargas }
99638b034cSRoberto Vargas }
100638b034cSRoberto Vargas }
101638b034cSRoberto Vargas #endif
102638b034cSRoberto Vargas
10343cbaf06SRoberto Vargas /*
10443cbaf06SRoberto Vargas * This function checks that a region (addr + nbytes-1) of memory is totally
10543cbaf06SRoberto Vargas * covered by one of the regions defined in tbl.
10643cbaf06SRoberto Vargas * tbl must be a valid pointer to a memory mem_region_t array, nregions
10743cbaf06SRoberto Vargas * is the size of the array and the region described by addr and nbytes must
10843cbaf06SRoberto Vargas * not generate an overflow.
10943cbaf06SRoberto Vargas * Returns:
11043cbaf06SRoberto Vargas * -1 means that the region is not covered by any of the regions
11143cbaf06SRoberto Vargas * described in tbl.
11243cbaf06SRoberto Vargas * 0 the region (addr + nbytes-1) is covered by one of the regions described
11343cbaf06SRoberto Vargas * in tbl
11443cbaf06SRoberto Vargas */
mem_region_in_array_chk(mem_region_t * tbl,size_t nregions,uintptr_t addr,size_t nbytes)11543cbaf06SRoberto Vargas int mem_region_in_array_chk(mem_region_t *tbl, size_t nregions,
11643cbaf06SRoberto Vargas uintptr_t addr, size_t nbytes)
11743cbaf06SRoberto Vargas {
11843cbaf06SRoberto Vargas uintptr_t region_start, region_end, start, end;
11943cbaf06SRoberto Vargas size_t i;
12043cbaf06SRoberto Vargas
121466bb285SZelalem assert(tbl != NULL);
122633fa4cdSjohpow01 assert(nbytes != 0U);
12343cbaf06SRoberto Vargas assert(!check_uptr_overflow(addr, nbytes-1));
12443cbaf06SRoberto Vargas
12543cbaf06SRoberto Vargas region_start = addr;
126633fa4cdSjohpow01 region_end = addr + (nbytes - 1U);
127633fa4cdSjohpow01 for (i = 0U; i < nregions; i++) {
12843cbaf06SRoberto Vargas assert(tbl->nbytes > 0);
12943cbaf06SRoberto Vargas assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
13043cbaf06SRoberto Vargas start = tbl->base;
13143cbaf06SRoberto Vargas end = start + (tbl->nbytes - 1);
132633fa4cdSjohpow01 if ((region_start >= start) && (region_end <= end)) {
13343cbaf06SRoberto Vargas return 0;
134633fa4cdSjohpow01 }
13543cbaf06SRoberto Vargas tbl++;
13643cbaf06SRoberto Vargas }
13743cbaf06SRoberto Vargas
13843cbaf06SRoberto Vargas return -1;
13943cbaf06SRoberto Vargas }
140