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> 8*09d40e0eSAntonio Nino Diaz 9*09d40e0eSAntonio Nino Diaz #include <lib/utils.h> 1043cbaf06SRoberto Vargas 1143cbaf06SRoberto Vargas /* 1243cbaf06SRoberto Vargas * All the regions defined in mem_region_t must have the following properties 1343cbaf06SRoberto Vargas * 1443cbaf06SRoberto Vargas * - Any contiguous regions must be merged into a single entry. 1543cbaf06SRoberto Vargas * - The number of bytes of each region must be greater than zero. 1643cbaf06SRoberto Vargas * - The calculation of the highest address within the region (base + nbytes-1) 1743cbaf06SRoberto Vargas * doesn't produce an overflow. 1843cbaf06SRoberto Vargas * 1943cbaf06SRoberto Vargas * These conditions must be fulfilled by the caller and they aren't checked 2043cbaf06SRoberto Vargas * at runtime. 2143cbaf06SRoberto Vargas */ 2243cbaf06SRoberto Vargas 2343cbaf06SRoberto Vargas /* 2443cbaf06SRoberto Vargas * zero_normalmem all the regions defined in tbl. 2543cbaf06SRoberto Vargas * It assumes that MMU is enabled and the memory is Normal memory. 2643cbaf06SRoberto Vargas * tbl must be a valid pointer to a memory mem_region_t array, 2743cbaf06SRoberto Vargas * nregions is the size of the array. 2843cbaf06SRoberto Vargas */ 2943cbaf06SRoberto Vargas void clear_mem_regions(mem_region_t *tbl, size_t nregions) 3043cbaf06SRoberto Vargas { 3143cbaf06SRoberto Vargas size_t i; 3243cbaf06SRoberto Vargas 3343cbaf06SRoberto Vargas assert(tbl); 3443cbaf06SRoberto Vargas assert(nregions > 0); 3543cbaf06SRoberto Vargas 3643cbaf06SRoberto Vargas for (i = 0; i < nregions; i++) { 3743cbaf06SRoberto Vargas assert(tbl->nbytes > 0); 3843cbaf06SRoberto Vargas assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1)); 3943cbaf06SRoberto Vargas zero_normalmem((void *) (tbl->base), tbl->nbytes); 4043cbaf06SRoberto Vargas tbl++; 4143cbaf06SRoberto Vargas } 4243cbaf06SRoberto Vargas } 4343cbaf06SRoberto Vargas 44638b034cSRoberto Vargas #if defined(PLAT_XLAT_TABLES_DYNAMIC) 45638b034cSRoberto Vargas /* 46638b034cSRoberto Vargas * zero_normalmem all the regions defined in regions. 47638b034cSRoberto Vargas * It assumes that MMU is enabled and the memory is Normal memory. 48638b034cSRoberto Vargas * regions must be a valid pointer to a memory mem_region_t array, 49638b034cSRoberto Vargas * nregions is the size of the array. va is the virtual address 50638b034cSRoberto Vargas * where we want to map the physical pages that are going to 51638b034cSRoberto Vargas * be cleared, and chunk is the amount of memory mapped and 52638b034cSRoberto Vargas * cleared in every iteration. 53638b034cSRoberto Vargas */ 54c96f297fSRoberto Vargas void clear_map_dyn_mem_regions(struct mem_region *regions, 55638b034cSRoberto Vargas size_t nregions, 56638b034cSRoberto Vargas uintptr_t va, 57638b034cSRoberto Vargas size_t chunk) 58638b034cSRoberto Vargas { 59638b034cSRoberto Vargas uintptr_t begin; 60638b034cSRoberto Vargas int r; 61638b034cSRoberto Vargas size_t size; 623a1b7b10SAntonio Nino Diaz const unsigned int attr = MT_MEMORY | MT_RW | MT_NS; 63638b034cSRoberto Vargas 64638b034cSRoberto Vargas assert(regions != NULL); 65638b034cSRoberto Vargas assert(nregions > 0 && chunk > 0); 66638b034cSRoberto Vargas 67638b034cSRoberto Vargas for ( ; nregions--; regions++) { 68638b034cSRoberto Vargas begin = regions->base; 69638b034cSRoberto Vargas size = regions->nbytes; 70638b034cSRoberto Vargas if ((begin & (chunk-1)) != 0 || (size & (chunk-1)) != 0) { 71638b034cSRoberto Vargas INFO("PSCI: Not correctly aligned region\n"); 72638b034cSRoberto Vargas panic(); 73638b034cSRoberto Vargas } 74638b034cSRoberto Vargas 75638b034cSRoberto Vargas while (size > 0) { 76638b034cSRoberto Vargas r = mmap_add_dynamic_region(begin, va, chunk, attr); 77638b034cSRoberto Vargas if (r != 0) { 78638b034cSRoberto Vargas INFO("PSCI: mmap_add_dynamic_region failed with %d\n", r); 79638b034cSRoberto Vargas panic(); 80638b034cSRoberto Vargas } 81638b034cSRoberto Vargas 82638b034cSRoberto Vargas zero_normalmem((void *) va, chunk); 83638b034cSRoberto Vargas 84638b034cSRoberto Vargas r = mmap_remove_dynamic_region(va, chunk); 85638b034cSRoberto Vargas if (r != 0) { 86638b034cSRoberto Vargas INFO("PSCI: mmap_remove_dynamic_region failed with %d\n", r); 87638b034cSRoberto Vargas panic(); 88638b034cSRoberto Vargas } 89638b034cSRoberto Vargas 90638b034cSRoberto Vargas begin += chunk; 91638b034cSRoberto Vargas size -= chunk; 92638b034cSRoberto Vargas } 93638b034cSRoberto Vargas } 94638b034cSRoberto Vargas } 95638b034cSRoberto Vargas #endif 96638b034cSRoberto Vargas 9743cbaf06SRoberto Vargas /* 9843cbaf06SRoberto Vargas * This function checks that a region (addr + nbytes-1) of memory is totally 9943cbaf06SRoberto Vargas * covered by one of the regions defined in tbl. 10043cbaf06SRoberto Vargas * tbl must be a valid pointer to a memory mem_region_t array, nregions 10143cbaf06SRoberto Vargas * is the size of the array and the region described by addr and nbytes must 10243cbaf06SRoberto Vargas * not generate an overflow. 10343cbaf06SRoberto Vargas * Returns: 10443cbaf06SRoberto Vargas * -1 means that the region is not covered by any of the regions 10543cbaf06SRoberto Vargas * described in tbl. 10643cbaf06SRoberto Vargas * 0 the region (addr + nbytes-1) is covered by one of the regions described 10743cbaf06SRoberto Vargas * in tbl 10843cbaf06SRoberto Vargas */ 10943cbaf06SRoberto Vargas int mem_region_in_array_chk(mem_region_t *tbl, size_t nregions, 11043cbaf06SRoberto Vargas uintptr_t addr, size_t nbytes) 11143cbaf06SRoberto Vargas { 11243cbaf06SRoberto Vargas uintptr_t region_start, region_end, start, end; 11343cbaf06SRoberto Vargas size_t i; 11443cbaf06SRoberto Vargas 11543cbaf06SRoberto Vargas assert(tbl); 11643cbaf06SRoberto Vargas assert(nbytes > 0); 11743cbaf06SRoberto Vargas assert(!check_uptr_overflow(addr, nbytes-1)); 11843cbaf06SRoberto Vargas 11943cbaf06SRoberto Vargas region_start = addr; 12043cbaf06SRoberto Vargas region_end = addr + (nbytes - 1); 12143cbaf06SRoberto Vargas for (i = 0; i < nregions; i++) { 12243cbaf06SRoberto Vargas assert(tbl->nbytes > 0); 12343cbaf06SRoberto Vargas assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1)); 12443cbaf06SRoberto Vargas start = tbl->base; 12543cbaf06SRoberto Vargas end = start + (tbl->nbytes - 1); 12643cbaf06SRoberto Vargas if (region_start >= start && region_end <= end) 12743cbaf06SRoberto Vargas return 0; 12843cbaf06SRoberto Vargas tbl++; 12943cbaf06SRoberto Vargas } 13043cbaf06SRoberto Vargas 13143cbaf06SRoberto Vargas return -1; 13243cbaf06SRoberto Vargas } 133