143cbaf06SRoberto Vargas /* 2638b034cSRoberto 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 43638b034cSRoberto Vargas #if defined(PLAT_XLAT_TABLES_DYNAMIC) 44638b034cSRoberto Vargas /* 45638b034cSRoberto Vargas * zero_normalmem all the regions defined in regions. 46638b034cSRoberto Vargas * It assumes that MMU is enabled and the memory is Normal memory. 47638b034cSRoberto Vargas * regions must be a valid pointer to a memory mem_region_t array, 48638b034cSRoberto Vargas * nregions is the size of the array. va is the virtual address 49638b034cSRoberto Vargas * where we want to map the physical pages that are going to 50638b034cSRoberto Vargas * be cleared, and chunk is the amount of memory mapped and 51638b034cSRoberto Vargas * cleared in every iteration. 52638b034cSRoberto Vargas */ 53638b034cSRoberto Vargas void clear_map_dyn_mem_regions(mem_region_t *regions, 54638b034cSRoberto Vargas size_t nregions, 55638b034cSRoberto Vargas uintptr_t va, 56638b034cSRoberto Vargas size_t chunk) 57638b034cSRoberto Vargas { 58638b034cSRoberto Vargas uintptr_t begin; 59638b034cSRoberto Vargas int r; 60638b034cSRoberto Vargas size_t size; 61*3a1b7b10SAntonio Nino Diaz const unsigned int attr = MT_MEMORY | MT_RW | MT_NS; 62638b034cSRoberto Vargas 63638b034cSRoberto Vargas assert(regions != NULL); 64638b034cSRoberto Vargas assert(nregions > 0 && chunk > 0); 65638b034cSRoberto Vargas 66638b034cSRoberto Vargas for ( ; nregions--; regions++) { 67638b034cSRoberto Vargas begin = regions->base; 68638b034cSRoberto Vargas size = regions->nbytes; 69638b034cSRoberto Vargas if ((begin & (chunk-1)) != 0 || (size & (chunk-1)) != 0) { 70638b034cSRoberto Vargas INFO("PSCI: Not correctly aligned region\n"); 71638b034cSRoberto Vargas panic(); 72638b034cSRoberto Vargas } 73638b034cSRoberto Vargas 74638b034cSRoberto Vargas while (size > 0) { 75638b034cSRoberto Vargas r = mmap_add_dynamic_region(begin, va, chunk, attr); 76638b034cSRoberto Vargas if (r != 0) { 77638b034cSRoberto Vargas INFO("PSCI: mmap_add_dynamic_region failed with %d\n", r); 78638b034cSRoberto Vargas panic(); 79638b034cSRoberto Vargas } 80638b034cSRoberto Vargas 81638b034cSRoberto Vargas zero_normalmem((void *) va, chunk); 82638b034cSRoberto Vargas 83638b034cSRoberto Vargas r = mmap_remove_dynamic_region(va, chunk); 84638b034cSRoberto Vargas if (r != 0) { 85638b034cSRoberto Vargas INFO("PSCI: mmap_remove_dynamic_region failed with %d\n", r); 86638b034cSRoberto Vargas panic(); 87638b034cSRoberto Vargas } 88638b034cSRoberto Vargas 89638b034cSRoberto Vargas begin += chunk; 90638b034cSRoberto Vargas size -= chunk; 91638b034cSRoberto Vargas } 92638b034cSRoberto Vargas } 93638b034cSRoberto Vargas } 94638b034cSRoberto Vargas #endif 95638b034cSRoberto 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