mem_region.c 3.66 KB
Newer Older
1
/*
2
 * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
3
4
5
6
7
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <assert.h>
8

9
#include <common/debug.h>
10
#include <lib/utils.h>
11
#include <lib/xlat_tables/xlat_tables_compat.h>
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

/*
 * All the regions defined in mem_region_t must have the following properties
 *
 * - Any contiguous regions must be merged into a single entry.
 * - The number of bytes of each region must be greater than zero.
 * - The calculation of the highest address within the region (base + nbytes-1)
 *   doesn't produce an overflow.
 *
 * These conditions must be fulfilled by the caller and they aren't checked
 * at runtime.
 */

/*
 * zero_normalmem all the regions defined in tbl.
 * It assumes that MMU is enabled and the memory is Normal memory.
 * tbl must be a valid pointer to a memory mem_region_t array,
 * nregions is the size of the array.
 */
void clear_mem_regions(mem_region_t *tbl, size_t nregions)
{
	size_t i;

35
	assert(tbl != NULL);
36
	assert(nregions > 0U);
37
38
39
40
41
42
43
44
45

	for (i = 0; i < nregions; i++) {
		assert(tbl->nbytes > 0);
		assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
		zero_normalmem((void *) (tbl->base), tbl->nbytes);
		tbl++;
	}
}

46
47
48
49
50
51
52
53
54
55
#if defined(PLAT_XLAT_TABLES_DYNAMIC)
/*
 * zero_normalmem all the regions defined in regions.
 * It assumes that MMU is enabled and the memory is Normal memory.
 * regions must be a valid pointer to a memory mem_region_t array,
 * nregions is the size of the array. va is the virtual address
 * where we want to map the physical pages that are going to
 * be cleared, and chunk is the amount of memory mapped and
 * cleared in every iteration.
 */
Roberto Vargas's avatar
Roberto Vargas committed
56
void clear_map_dyn_mem_regions(struct mem_region *regions,
57
58
59
60
61
62
63
			       size_t nregions,
			       uintptr_t va,
			       size_t chunk)
{
	uintptr_t begin;
	int r;
	size_t size;
64
	const unsigned int attr = MT_MEMORY | MT_RW | MT_NS;
65
66

	assert(regions != NULL);
67
68
69
70
71
72
73
74
	assert(nregions != 0U);
	assert(chunk != 0U);

	for (unsigned int i = 0U; i < nregions; i++) {
		begin = regions[i].base;
		size = regions[i].nbytes;
		if (((begin & (chunk-1U)) != 0U) ||
				((size & (chunk-1U)) != 0U)) {
75
76
77
78
			INFO("PSCI: Not correctly aligned region\n");
			panic();
		}

79
		while (size > 0U) {
80
81
			r = mmap_add_dynamic_region(begin, va, chunk, attr);
			if (r != 0) {
82
83
				INFO("PSCI: %s failed with %d\n",
					"mmap_add_dynamic_region", r);
84
85
86
				panic();
			}

87
			zero_normalmem((void *)va, chunk);
88
89
90

			r = mmap_remove_dynamic_region(va, chunk);
			if (r != 0) {
91
92
				INFO("PSCI: %s failed with %d\n",
					"mmap_remove_dynamic_region", r);
93
94
95
96
97
98
99
100
101
102
				panic();
			}

			begin += chunk;
			size -= chunk;
		}
	}
}
#endif

103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/*
 * This function checks that a region (addr + nbytes-1) of memory is totally
 * covered by one of the regions defined in tbl.
 * tbl must be a valid pointer to a memory mem_region_t array, nregions
 * is the size of the array and the region described by addr and nbytes must
 * not generate an overflow.
 * Returns:
 *  -1 means that the region is not covered by any of the regions
 *     described in tbl.
 *   0 the region (addr + nbytes-1) is covered by one of the regions described
 *     in tbl
 */
int mem_region_in_array_chk(mem_region_t *tbl, size_t nregions,
			    uintptr_t addr, size_t nbytes)
{
	uintptr_t region_start, region_end, start, end;
	size_t i;

121
	assert(tbl != NULL);
122
	assert(nbytes != 0U);
123
124
125
	assert(!check_uptr_overflow(addr, nbytes-1));

	region_start = addr;
126
127
	region_end = addr + (nbytes - 1U);
	for (i = 0U; i < nregions; i++) {
128
129
130
131
		assert(tbl->nbytes > 0);
		assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1));
		start = tbl->base;
		end = start + (tbl->nbytes - 1);
132
		if ((region_start >= start) && (region_end <= end)) {
133
			return 0;
134
		}
135
136
137
138
139
		tbl++;
	}

	return -1;
}