1 // SPDX-License-Identifier: GPL-2.0-or-later
2 #include "alloc_helpers_api.h"
3
4 /*
5 * A simple test that tries to allocate a memory region above a specified,
6 * aligned address:
7 *
8 * +
9 * | +-----------+ |
10 * | | rgn | |
11 * +----------+-----------+---------+
12 * ^
13 * |
14 * Aligned min_addr
15 *
16 * Expect to allocate a cleared region at the minimal memory address.
17 */
alloc_from_simple_generic_check(void)18 static int alloc_from_simple_generic_check(void)
19 {
20 struct memblock_region *rgn = &memblock.reserved.regions[0];
21 void *allocated_ptr = NULL;
22 phys_addr_t size = SZ_16;
23 phys_addr_t min_addr;
24
25 PREFIX_PUSH();
26 setup_memblock();
27
28 min_addr = memblock_end_of_DRAM() - SMP_CACHE_BYTES;
29
30 allocated_ptr = memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr);
31
32 ASSERT_NE(allocated_ptr, NULL);
33 ASSERT_MEM_EQ(allocated_ptr, 0, size);
34
35 ASSERT_EQ(rgn->size, size);
36 ASSERT_EQ(rgn->base, min_addr);
37
38 ASSERT_EQ(memblock.reserved.cnt, 1);
39 ASSERT_EQ(memblock.reserved.total_size, size);
40
41 test_pass_pop();
42
43 return 0;
44 }
45
46 /*
47 * A test that tries to allocate a memory region above a certain address.
48 * The minimal address here is not aligned:
49 *
50 * + +
51 * | + +---------+ |
52 * | | | rgn | |
53 * +------+------+---------+------------+
54 * ^ ^------.
55 * | |
56 * min_addr Aligned address
57 * boundary
58 *
59 * Expect to allocate a cleared region at the closest aligned memory address.
60 */
alloc_from_misaligned_generic_check(void)61 static int alloc_from_misaligned_generic_check(void)
62 {
63 struct memblock_region *rgn = &memblock.reserved.regions[0];
64 void *allocated_ptr = NULL;
65 phys_addr_t size = SZ_32;
66 phys_addr_t min_addr;
67
68 PREFIX_PUSH();
69 setup_memblock();
70
71 /* A misaligned address */
72 min_addr = memblock_end_of_DRAM() - (SMP_CACHE_BYTES * 2 - 1);
73
74 allocated_ptr = memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr);
75
76 ASSERT_NE(allocated_ptr, NULL);
77 ASSERT_MEM_EQ(allocated_ptr, 0, size);
78
79 ASSERT_EQ(rgn->size, size);
80 ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - SMP_CACHE_BYTES);
81
82 ASSERT_EQ(memblock.reserved.cnt, 1);
83 ASSERT_EQ(memblock.reserved.total_size, size);
84
85 test_pass_pop();
86
87 return 0;
88 }
89
90 /*
91 * A test that tries to allocate a memory region above an address that is too
92 * close to the end of the memory:
93 *
94 * + +
95 * | +--------+---+ |
96 * | | rgn + | |
97 * +-----------+--------+---+------+
98 * ^ ^
99 * | |
100 * | min_addr
101 * |
102 * Aligned address
103 * boundary
104 *
105 * Expect to prioritize granting memory over satisfying the minimal address
106 * requirement.
107 */
alloc_from_top_down_high_addr_check(void)108 static int alloc_from_top_down_high_addr_check(void)
109 {
110 struct memblock_region *rgn = &memblock.reserved.regions[0];
111 void *allocated_ptr = NULL;
112 phys_addr_t size = SZ_32;
113 phys_addr_t min_addr;
114
115 PREFIX_PUSH();
116 setup_memblock();
117
118 /* The address is too close to the end of the memory */
119 min_addr = memblock_end_of_DRAM() - SZ_16;
120
121 allocated_ptr = memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr);
122
123 ASSERT_NE(allocated_ptr, NULL);
124 ASSERT_EQ(rgn->size, size);
125 ASSERT_EQ(rgn->base, memblock_end_of_DRAM() - SMP_CACHE_BYTES);
126
127 ASSERT_EQ(memblock.reserved.cnt, 1);
128 ASSERT_EQ(memblock.reserved.total_size, size);
129
130 test_pass_pop();
131
132 return 0;
133 }
134
135 /*
136 * A test that tries to allocate a memory region when there is no space
137 * available above the minimal address above a certain address:
138 *
139 * +
140 * | +---------+-------------|
141 * | | rgn | |
142 * +--------+---------+-------------+
143 * ^
144 * |
145 * min_addr
146 *
147 * Expect to prioritize granting memory over satisfying the minimal address
148 * requirement and to allocate next to the previously reserved region. The
149 * regions get merged into one.
150 */
alloc_from_top_down_no_space_above_check(void)151 static int alloc_from_top_down_no_space_above_check(void)
152 {
153 struct memblock_region *rgn = &memblock.reserved.regions[0];
154 void *allocated_ptr = NULL;
155 phys_addr_t r1_size = SZ_64;
156 phys_addr_t r2_size = SZ_2;
157 phys_addr_t total_size = r1_size + r2_size;
158 phys_addr_t min_addr;
159
160 PREFIX_PUSH();
161 setup_memblock();
162
163 min_addr = memblock_end_of_DRAM() - SMP_CACHE_BYTES * 2;
164
165 /* No space above this address */
166 memblock_reserve(min_addr, r2_size);
167
168 allocated_ptr = memblock_alloc_from(r1_size, SMP_CACHE_BYTES, min_addr);
169
170 ASSERT_NE(allocated_ptr, NULL);
171 ASSERT_EQ(rgn->base, min_addr - r1_size);
172 ASSERT_EQ(rgn->size, total_size);
173
174 ASSERT_EQ(memblock.reserved.cnt, 1);
175 ASSERT_EQ(memblock.reserved.total_size, total_size);
176
177 test_pass_pop();
178
179 return 0;
180 }
181
182 /*
183 * A test that tries to allocate a memory region with a minimal address below
184 * the start address of the available memory. As the allocation is top-down,
185 * first reserve a region that will force allocation near the start.
186 * Expect successful allocation and merge of both regions.
187 */
alloc_from_top_down_min_addr_cap_check(void)188 static int alloc_from_top_down_min_addr_cap_check(void)
189 {
190 struct memblock_region *rgn = &memblock.reserved.regions[0];
191 void *allocated_ptr = NULL;
192 phys_addr_t r1_size = SZ_64;
193 phys_addr_t min_addr;
194 phys_addr_t start_addr;
195
196 PREFIX_PUSH();
197 setup_memblock();
198
199 start_addr = (phys_addr_t)memblock_start_of_DRAM();
200 min_addr = start_addr - SMP_CACHE_BYTES * 3;
201
202 memblock_reserve(start_addr + r1_size, MEM_SIZE - r1_size);
203
204 allocated_ptr = memblock_alloc_from(r1_size, SMP_CACHE_BYTES, min_addr);
205
206 ASSERT_NE(allocated_ptr, NULL);
207 ASSERT_EQ(rgn->base, start_addr);
208 ASSERT_EQ(rgn->size, MEM_SIZE);
209
210 ASSERT_EQ(memblock.reserved.cnt, 1);
211 ASSERT_EQ(memblock.reserved.total_size, MEM_SIZE);
212
213 test_pass_pop();
214
215 return 0;
216 }
217
218 /*
219 * A test that tries to allocate a memory region above an address that is too
220 * close to the end of the memory:
221 *
222 * +
223 * |-----------+ + |
224 * | rgn | | |
225 * +-----------+--------------+-----+
226 * ^ ^
227 * | |
228 * Aligned address min_addr
229 * boundary
230 *
231 * Expect to prioritize granting memory over satisfying the minimal address
232 * requirement. Allocation happens at beginning of the available memory.
233 */
alloc_from_bottom_up_high_addr_check(void)234 static int alloc_from_bottom_up_high_addr_check(void)
235 {
236 struct memblock_region *rgn = &memblock.reserved.regions[0];
237 void *allocated_ptr = NULL;
238 phys_addr_t size = SZ_32;
239 phys_addr_t min_addr;
240
241 PREFIX_PUSH();
242 setup_memblock();
243
244 /* The address is too close to the end of the memory */
245 min_addr = memblock_end_of_DRAM() - SZ_8;
246
247 allocated_ptr = memblock_alloc_from(size, SMP_CACHE_BYTES, min_addr);
248
249 ASSERT_NE(allocated_ptr, NULL);
250 ASSERT_EQ(rgn->size, size);
251 ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
252
253 ASSERT_EQ(memblock.reserved.cnt, 1);
254 ASSERT_EQ(memblock.reserved.total_size, size);
255
256 test_pass_pop();
257
258 return 0;
259 }
260
261 /*
262 * A test that tries to allocate a memory region when there is no space
263 * available above the minimal address above a certain address:
264 *
265 * +
266 * |-----------+ +-------------------|
267 * | rgn | | |
268 * +-----------+----+-------------------+
269 * ^
270 * |
271 * min_addr
272 *
273 * Expect to prioritize granting memory over satisfying the minimal address
274 * requirement and to allocate at the beginning of the available memory.
275 */
alloc_from_bottom_up_no_space_above_check(void)276 static int alloc_from_bottom_up_no_space_above_check(void)
277 {
278 struct memblock_region *rgn = &memblock.reserved.regions[0];
279 void *allocated_ptr = NULL;
280 phys_addr_t r1_size = SZ_64;
281 phys_addr_t min_addr;
282 phys_addr_t r2_size;
283
284 PREFIX_PUSH();
285 setup_memblock();
286
287 min_addr = memblock_start_of_DRAM() + SZ_128;
288 r2_size = memblock_end_of_DRAM() - min_addr;
289
290 /* No space above this address */
291 memblock_reserve(min_addr - SMP_CACHE_BYTES, r2_size);
292
293 allocated_ptr = memblock_alloc_from(r1_size, SMP_CACHE_BYTES, min_addr);
294
295 ASSERT_NE(allocated_ptr, NULL);
296 ASSERT_EQ(rgn->base, memblock_start_of_DRAM());
297 ASSERT_EQ(rgn->size, r1_size);
298
299 ASSERT_EQ(memblock.reserved.cnt, 2);
300 ASSERT_EQ(memblock.reserved.total_size, r1_size + r2_size);
301
302 test_pass_pop();
303
304 return 0;
305 }
306
307 /*
308 * A test that tries to allocate a memory region with a minimal address below
309 * the start address of the available memory. Expect to allocate a region
310 * at the beginning of the available memory.
311 */
alloc_from_bottom_up_min_addr_cap_check(void)312 static int alloc_from_bottom_up_min_addr_cap_check(void)
313 {
314 struct memblock_region *rgn = &memblock.reserved.regions[0];
315 void *allocated_ptr = NULL;
316 phys_addr_t r1_size = SZ_64;
317 phys_addr_t min_addr;
318 phys_addr_t start_addr;
319
320 PREFIX_PUSH();
321 setup_memblock();
322
323 start_addr = (phys_addr_t)memblock_start_of_DRAM();
324 min_addr = start_addr - SMP_CACHE_BYTES * 3;
325
326 allocated_ptr = memblock_alloc_from(r1_size, SMP_CACHE_BYTES, min_addr);
327
328 ASSERT_NE(allocated_ptr, NULL);
329 ASSERT_EQ(rgn->base, start_addr);
330 ASSERT_EQ(rgn->size, r1_size);
331
332 ASSERT_EQ(memblock.reserved.cnt, 1);
333 ASSERT_EQ(memblock.reserved.total_size, r1_size);
334
335 test_pass_pop();
336
337 return 0;
338 }
339
340 /* Test case wrappers */
alloc_from_simple_check(void)341 static int alloc_from_simple_check(void)
342 {
343 test_print("\tRunning %s...\n", __func__);
344 run_top_down(alloc_from_simple_generic_check);
345 run_bottom_up(alloc_from_simple_generic_check);
346
347 return 0;
348 }
349
alloc_from_misaligned_check(void)350 static int alloc_from_misaligned_check(void)
351 {
352 test_print("\tRunning %s...\n", __func__);
353 run_top_down(alloc_from_misaligned_generic_check);
354 run_bottom_up(alloc_from_misaligned_generic_check);
355
356 return 0;
357 }
358
alloc_from_high_addr_check(void)359 static int alloc_from_high_addr_check(void)
360 {
361 test_print("\tRunning %s...\n", __func__);
362 memblock_set_bottom_up(false);
363 alloc_from_top_down_high_addr_check();
364 memblock_set_bottom_up(true);
365 alloc_from_bottom_up_high_addr_check();
366
367 return 0;
368 }
369
alloc_from_no_space_above_check(void)370 static int alloc_from_no_space_above_check(void)
371 {
372 test_print("\tRunning %s...\n", __func__);
373 memblock_set_bottom_up(false);
374 alloc_from_top_down_no_space_above_check();
375 memblock_set_bottom_up(true);
376 alloc_from_bottom_up_no_space_above_check();
377
378 return 0;
379 }
380
alloc_from_min_addr_cap_check(void)381 static int alloc_from_min_addr_cap_check(void)
382 {
383 test_print("\tRunning %s...\n", __func__);
384 memblock_set_bottom_up(false);
385 alloc_from_top_down_min_addr_cap_check();
386 memblock_set_bottom_up(true);
387 alloc_from_bottom_up_min_addr_cap_check();
388
389 return 0;
390 }
391
memblock_alloc_helpers_checks(void)392 int memblock_alloc_helpers_checks(void)
393 {
394 const char *func_testing = "memblock_alloc_from";
395
396 prefix_reset();
397 prefix_push(func_testing);
398 test_print("Running %s tests...\n", func_testing);
399
400 reset_memblock_attributes();
401 dummy_physical_memory_init();
402
403 alloc_from_simple_check();
404 alloc_from_misaligned_check();
405 alloc_from_high_addr_check();
406 alloc_from_no_space_above_check();
407 alloc_from_min_addr_cap_check();
408
409 dummy_physical_memory_cleanup();
410
411 prefix_pop();
412
413 return 0;
414 }
415