1 // SPDX-License-Identifier: GPL-2.0-or-later
2 #include <string.h>
3 #include <linux/memblock.h>
4 #include <linux/sizes.h>
5 #include "basic_api.h"
6 
7 #define EXPECTED_MEMBLOCK_REGIONS			128
8 
9 static int memblock_initialization_check(void)
10 {
11 	reset_memblock();
12 
13 	assert(memblock.memory.regions);
14 	assert(memblock.memory.cnt == 1);
15 	assert(memblock.memory.max == EXPECTED_MEMBLOCK_REGIONS);
16 	assert(strcmp(memblock.memory.name, "memory") == 0);
17 
18 	assert(memblock.reserved.regions);
19 	assert(memblock.reserved.cnt == 1);
20 	assert(memblock.memory.max == EXPECTED_MEMBLOCK_REGIONS);
21 	assert(strcmp(memblock.reserved.name, "reserved") == 0);
22 
23 	assert(!memblock.bottom_up);
24 	assert(memblock.current_limit == MEMBLOCK_ALLOC_ANYWHERE);
25 
26 	return 0;
27 }
28 
29 /*
30  * A simple test that adds a memory block of a specified base address
31  * and size to the collection of available memory regions (memblock.memory).
32  * It checks if a new entry was created and if region counter and total memory
33  * were correctly updated.
34  */
35 static int memblock_add_simple_check(void)
36 {
37 	struct memblock_region *rgn;
38 
39 	rgn = &memblock.memory.regions[0];
40 
41 	struct region r = {
42 		.base = SZ_1G,
43 		.size = SZ_4M
44 	};
45 
46 	reset_memblock();
47 	memblock_add(r.base, r.size);
48 
49 	assert(rgn->base == r.base);
50 	assert(rgn->size == r.size);
51 
52 	assert(memblock.memory.cnt == 1);
53 	assert(memblock.memory.total_size == r.size);
54 
55 	return 0;
56 }
57 
58 /*
59  * A test that tries to add two memory blocks that don't overlap with one
60  * another. It checks if two correctly initialized entries were added to the
61  * collection of available memory regions (memblock.memory) and if this
62  * change was reflected in memblock.memory's total size and region counter.
63  */
64 static int memblock_add_disjoint_check(void)
65 {
66 	struct memblock_region *rgn1, *rgn2;
67 
68 	rgn1 = &memblock.memory.regions[0];
69 	rgn2 = &memblock.memory.regions[1];
70 
71 	struct region r1 = {
72 		.base = SZ_1G,
73 		.size = SZ_8K
74 	};
75 	struct region r2 = {
76 		.base = SZ_1G + SZ_16K,
77 		.size = SZ_8K
78 	};
79 
80 	reset_memblock();
81 	memblock_add(r1.base, r1.size);
82 	memblock_add(r2.base, r2.size);
83 
84 	assert(rgn1->base == r1.base);
85 	assert(rgn1->size == r1.size);
86 
87 	assert(rgn2->base == r2.base);
88 	assert(rgn2->size == r2.size);
89 
90 	assert(memblock.memory.cnt == 2);
91 	assert(memblock.memory.total_size == r1.size + r2.size);
92 
93 	return 0;
94 }
95 
96 /*
97  * A test that tries to add two memory blocks, where the second one overlaps
98  * with the beginning of the first entry (that is r1.base < r2.base + r2.size).
99  * After this, it checks if two entries are merged into one region that starts
100  * at r2.base and has size of two regions minus their intersection. It also
101  * verifies the reported total size of the available memory and region counter.
102  */
103 static int memblock_add_overlap_top_check(void)
104 {
105 	struct memblock_region *rgn;
106 	phys_addr_t total_size;
107 
108 	rgn = &memblock.memory.regions[0];
109 
110 	struct region r1 = {
111 		.base = SZ_512M,
112 		.size = SZ_1G
113 	};
114 	struct region r2 = {
115 		.base = SZ_256M,
116 		.size = SZ_512M
117 	};
118 
119 	total_size = (r1.base - r2.base) + r1.size;
120 
121 	reset_memblock();
122 	memblock_add(r1.base, r1.size);
123 	memblock_add(r2.base, r2.size);
124 
125 	assert(rgn->base == r2.base);
126 	assert(rgn->size == total_size);
127 
128 	assert(memblock.memory.cnt == 1);
129 	assert(memblock.memory.total_size == total_size);
130 
131 	return 0;
132 }
133 
134 /*
135  * A test that tries to add two memory blocks, where the second one overlaps
136  * with the end of the first entry (that is r2.base < r1.base + r1.size).
137  * After this, it checks if two entries are merged into one region that starts
138  * at r1.base and has size of two regions minus their intersection. It verifies
139  * that memblock can still see only one entry and has a correct total size of
140  * the available memory.
141  */
142 static int memblock_add_overlap_bottom_check(void)
143 {
144 	struct memblock_region *rgn;
145 	phys_addr_t total_size;
146 
147 	rgn = &memblock.memory.regions[0];
148 
149 	struct region r1 = {
150 		.base = SZ_128M,
151 		.size = SZ_512M
152 	};
153 	struct region r2 = {
154 		.base = SZ_256M,
155 		.size = SZ_1G
156 	};
157 
158 	total_size = (r2.base - r1.base) + r2.size;
159 
160 	reset_memblock();
161 	memblock_add(r1.base, r1.size);
162 	memblock_add(r2.base, r2.size);
163 
164 	assert(rgn->base == r1.base);
165 	assert(rgn->size == total_size);
166 
167 	assert(memblock.memory.cnt == 1);
168 	assert(memblock.memory.total_size == total_size);
169 
170 	return 0;
171 }
172 
173 /*
174  * A test that tries to add two memory blocks, where the second one is
175  * within the range of the first entry (that is r1.base < r2.base &&
176  * r2.base + r2.size < r1.base + r1.size). It checks if two entries are merged
177  * into one region that stays the same. The counter and total size of available
178  * memory are expected to not be updated.
179  */
180 static int memblock_add_within_check(void)
181 {
182 	struct memblock_region *rgn;
183 
184 	rgn = &memblock.memory.regions[0];
185 
186 	struct region r1 = {
187 		.base = SZ_8M,
188 		.size = SZ_32M
189 	};
190 	struct region r2 = {
191 		.base = SZ_16M,
192 		.size = SZ_1M
193 	};
194 
195 	reset_memblock();
196 	memblock_add(r1.base, r1.size);
197 	memblock_add(r2.base, r2.size);
198 
199 	assert(rgn->base == r1.base);
200 	assert(rgn->size == r1.size);
201 
202 	assert(memblock.memory.cnt == 1);
203 	assert(memblock.memory.total_size == r1.size);
204 
205 	return 0;
206 }
207 
208 /*
209  * A simple test that tries to add the same memory block twice. The counter
210  * and total size of available memory are expected to not be updated.
211  */
212 static int memblock_add_twice_check(void)
213 {
214 	struct region r = {
215 		.base = SZ_16K,
216 		.size = SZ_2M
217 	};
218 
219 	reset_memblock();
220 
221 	memblock_add(r.base, r.size);
222 	memblock_add(r.base, r.size);
223 
224 	assert(memblock.memory.cnt == 1);
225 	assert(memblock.memory.total_size == r.size);
226 
227 	return 0;
228 }
229 
230 static int memblock_add_checks(void)
231 {
232 	memblock_add_simple_check();
233 	memblock_add_disjoint_check();
234 	memblock_add_overlap_top_check();
235 	memblock_add_overlap_bottom_check();
236 	memblock_add_within_check();
237 	memblock_add_twice_check();
238 
239 	return 0;
240 }
241 
242 int memblock_basic_checks(void)
243 {
244 	memblock_initialization_check();
245 	memblock_add_checks();
246 	return 0;
247 }
248