1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2023-09-28 zmshahaha the first version
9 */
10
11 #include <mm_memblock.h>
12 #include "common.h"
13 #include <rtservice.h>
14
15 #define SZ_128M 0x08000000
16 #define SZ_256M 0x10000000
17 #define SZ_512M 0x20000000
18 #define SZ_1G 0x40000000
19
20 static struct rt_memblock *mmblk_memory;
21 static struct rt_memblock *mmblk_reserved;
22
23 void rt_memblock_next_free_region_init(void);
24 void rt_memblock_next_free_region(mmblk_flag_t flags, rt_size_t *out_start, rt_size_t *out_end);
25 rt_bool_t rt_memblock_is_last_free(void);
26 void rt_memblock_merge(void);
27
_nth_reg(struct rt_memblock * memblock,rt_uint32_t n)28 struct rt_mmblk_reg *_nth_reg(struct rt_memblock *memblock, rt_uint32_t n)
29 {
30 struct rt_mmblk_reg *ret = RT_NULL;
31
32 rt_slist_for_each_entry(ret, &(memblock->reg_list), node)
33 {
34 if (--n == 0)
35 return ret;
36 }
37
38 return ret;
39 }
40
_reg_cnt(struct rt_memblock * memblock)41 rt_uint32_t _reg_cnt(struct rt_memblock *memblock)
42 {
43 rt_uint32_t ret = 0;
44 struct rt_mmblk_reg *reg;
45
46 rt_slist_for_each_entry(reg, &(memblock->reg_list), node)
47 {
48 ret++;
49 }
50
51 return ret;
52 }
53
_reset_memblock(void)54 void _reset_memblock(void)
55 {
56 struct rt_mmblk_reg *reg;
57
58 rt_slist_for_each_entry(reg, &(mmblk_memory->reg_list), node)
59 {
60 reg->alloc = RT_FALSE;
61 }
62 rt_slist_for_each_entry(reg, &(mmblk_reserved->reg_list), node)
63 {
64 reg->alloc = RT_FALSE;
65 }
66
67 mmblk_memory->reg_list.next = RT_NULL;
68 mmblk_reserved->reg_list.next = RT_NULL;
69 }
70
test_memblock_add_simple(void)71 static void test_memblock_add_simple(void)
72 {
73 _reset_memblock();
74
75 rt_size_t base1 = SZ_1G, size1 = SZ_256M;
76 rt_size_t base2 = SZ_128M, size2 = SZ_128M;
77 rt_err_t err;
78
79 err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE);
80 uassert_int_equal(err, RT_EOK);
81
82 uassert_int_equal(_reg_cnt(mmblk_memory), 1);
83
84 uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base1);
85 uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base1 + size1);
86 uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE);
87
88 err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_HOTPLUG);
89 uassert_int_equal(err, RT_EOK);
90
91 uassert_int_equal(_reg_cnt(mmblk_memory), 2);
92
93 uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base2);
94 uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base2 + size2);
95 uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_HOTPLUG);
96
97 uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base1);
98 uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base1 + size1);
99 uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_NONE);
100 }
101
test_memblock_add_adjacent_top(void)102 static void test_memblock_add_adjacent_top(void)
103 {
104 _reset_memblock();
105
106 rt_size_t base1 = SZ_128M, size1 = SZ_128M;
107 rt_size_t base2 = SZ_256M, size2 = SZ_128M;
108 rt_err_t err;
109
110 err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE);
111 uassert_int_equal(err, RT_EOK);
112 err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE);
113 uassert_int_equal(err, RT_EOK);
114
115 uassert_int_equal(_reg_cnt(mmblk_memory), 2);
116
117 uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base1);
118 uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base1 + size1);
119 uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE);
120
121 uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base2);
122 uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base2 + size2);
123 uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_NONE);
124 }
125
test_memblock_add_adjacent_bottom(void)126 static void test_memblock_add_adjacent_bottom(void)
127 {
128 _reset_memblock();
129
130 rt_size_t base1 = SZ_256M, size1 = SZ_128M;
131 rt_size_t base2 = SZ_128M, size2 = SZ_128M;
132 rt_err_t err;
133
134 err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE);
135 uassert_int_equal(err, RT_EOK);
136 err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE);
137 uassert_int_equal(err, RT_EOK);
138
139 uassert_int_equal(_reg_cnt(mmblk_memory), 2);
140
141 uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base2);
142 uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base2 + size2);
143 uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE);
144
145 uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base1);
146 uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base1 + size1);
147 uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_NONE);
148 }
149
test_memblock_add_between(void)150 static void test_memblock_add_between(void)
151 {
152 _reset_memblock();
153
154 rt_size_t base1 = SZ_512M, size1 = SZ_256M;
155 rt_size_t base2 = SZ_1G, size2 = SZ_512M;
156 rt_size_t base3 = SZ_512M + SZ_256M, size3 = SZ_256M;
157 rt_err_t err;
158
159 err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE);
160 uassert_int_equal(err, RT_EOK);
161 err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE);
162 uassert_int_equal(err, RT_EOK);
163 err = rt_memblock_add_memory("memory3", base3, base3 + size3, MEMBLOCK_HOTPLUG);
164 uassert_int_equal(err, RT_EOK);
165
166 uassert_int_equal(_reg_cnt(mmblk_memory), 3);
167
168 uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base1);
169 uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base1 + size1);
170 uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE);
171
172 uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base3);
173 uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base3 + size3);
174 uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_HOTPLUG);
175
176 uassert_int_equal(_nth_reg(mmblk_memory, 3)->memreg.start, base2);
177 uassert_int_equal(_nth_reg(mmblk_memory, 3)->memreg.end, base2 + size2);
178 uassert_int_equal(_nth_reg(mmblk_memory, 3)->flags, MEMBLOCK_NONE);
179 }
180
test_memblock_merge(void)181 static void test_memblock_merge(void)
182 {
183 _reset_memblock();
184
185 rt_size_t base1 = 0, size1 = SZ_256M;
186 rt_size_t base2 = SZ_256M, size2 = SZ_256M;
187 rt_size_t base3 = SZ_512M, size3 = SZ_256M;
188 rt_size_t base4 = SZ_512M + SZ_256M, size4 = SZ_256M;
189 rt_size_t base5 = SZ_1G, size5 = SZ_512M;
190 rt_err_t err;
191
192 err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE);
193 uassert_int_equal(err, RT_EOK);
194 err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE);
195 uassert_int_equal(err, RT_EOK);
196 err = rt_memblock_add_memory("memory3", base3, base3 + size3, MEMBLOCK_HOTPLUG);
197 uassert_int_equal(err, RT_EOK);
198 err = rt_memblock_add_memory("memory4", base4, base4 + size4, MEMBLOCK_NONE);
199 uassert_int_equal(err, RT_EOK);
200 err = rt_memblock_add_memory("memory5", base5, base5 + size5, MEMBLOCK_NONE);
201 uassert_int_equal(err, RT_EOK);
202
203 rt_memblock_merge();
204
205 uassert_int_equal(_reg_cnt(mmblk_memory), 3);
206
207 uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base1);
208 uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base2 + size2);
209 uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE);
210
211 uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base3);
212 uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base3 + size3);
213 uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_HOTPLUG);
214
215 uassert_int_equal(_nth_reg(mmblk_memory, 3)->memreg.start, base4);
216 uassert_int_equal(_nth_reg(mmblk_memory, 3)->memreg.end, base5 + size5);
217 uassert_int_equal(_nth_reg(mmblk_memory, 3)->flags, MEMBLOCK_NONE);
218 }
219
test_memblock_add(void)220 static void test_memblock_add(void)
221 {
222 test_memblock_add_simple();
223 test_memblock_add_adjacent_top();
224 test_memblock_add_adjacent_bottom();
225 test_memblock_add_between();
226 test_memblock_merge();
227 }
228
test_memblock_reserve_in_memory_start(void)229 static void test_memblock_reserve_in_memory_start(void)
230 {
231 _reset_memblock();
232
233 rt_size_t base1 = SZ_128M, size1 = SZ_256M;
234 rt_size_t baser = SZ_128M, sizer = SZ_128M;
235 rt_size_t free_start, free_end;
236 rt_err_t err;
237
238 err = rt_memblock_add_memory("memory", base1, base1 + size1, MEMBLOCK_NONE);
239 uassert_int_equal(err, RT_EOK);
240 err = rt_memblock_reserve_memory("reserve", baser, baser + sizer, MEMBLOCK_NONE);
241 uassert_int_equal(err, RT_EOK);
242
243 rt_memblock_next_free_region_init();
244
245 rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
246 uassert_int_equal(free_start, SZ_256M);
247 uassert_int_equal(free_end, SZ_128M + SZ_256M);
248
249 rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
250 uassert_int_equal(rt_memblock_is_last_free(), RT_TRUE);
251 }
252
test_memblock_reserve_in_memory_end(void)253 static void test_memblock_reserve_in_memory_end(void)
254 {
255 _reset_memblock();
256
257 rt_size_t base1 = SZ_128M, size1 = SZ_256M;
258 rt_size_t baser = SZ_256M, sizer = SZ_128M;
259 rt_size_t free_start, free_end;
260 rt_err_t err;
261
262 err = rt_memblock_add_memory("memory", base1, base1 + size1, MEMBLOCK_NONE);
263 uassert_int_equal(err, RT_EOK);
264 err = rt_memblock_reserve_memory("reserve", baser, baser + sizer, MEMBLOCK_NONE);
265 uassert_int_equal(err, RT_EOK);
266
267 rt_memblock_next_free_region_init();
268
269 rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
270 uassert_int_equal(free_start, SZ_128M);
271 uassert_int_equal(free_end, SZ_256M);
272
273 rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
274 uassert_int_equal(rt_memblock_is_last_free(), RT_TRUE);
275 }
276
test_memblock_reserve_many_in_one_region(void)277 static void test_memblock_reserve_many_in_one_region(void)
278 {
279 _reset_memblock();
280
281 rt_size_t base = 0, size = SZ_1G;
282 rt_size_t baser1 = 0, sizer1 = SZ_128M;
283 rt_size_t baser2 = SZ_256M, sizer2 = SZ_128M;
284 rt_size_t baser3 = SZ_256M + SZ_128M, sizer3 = SZ_128M;
285 rt_size_t baser4 = SZ_512M + SZ_128M, sizer4 = SZ_128M;
286 rt_size_t baser5 = SZ_1G - SZ_128M, sizer5 = SZ_128M;
287 rt_size_t free_start, free_end;
288 rt_err_t err;
289
290 err = rt_memblock_add_memory("memory", base, base + size, MEMBLOCK_NONE);
291 uassert_int_equal(err, RT_EOK);
292 err = rt_memblock_reserve_memory("reserve1", baser1, baser1 + sizer1, MEMBLOCK_NONE);
293 uassert_int_equal(err, RT_EOK);
294 err = rt_memblock_reserve_memory("reserve2", baser2, baser2 + sizer2, MEMBLOCK_NOMAP);
295 uassert_int_equal(err, RT_EOK);
296 err = rt_memblock_reserve_memory("reserve3", baser3, baser3 + sizer3, MEMBLOCK_NONE);
297 uassert_int_equal(err, RT_EOK);
298 err = rt_memblock_reserve_memory("reserve4", baser4, baser4 + sizer4, MEMBLOCK_NOMAP);
299 uassert_int_equal(err, RT_EOK);
300 err = rt_memblock_reserve_memory("reserve5", baser5, baser5 + sizer5, MEMBLOCK_NONE);
301 uassert_int_equal(err, RT_EOK);
302
303 rt_memblock_next_free_region_init();
304
305 rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
306 uassert_int_equal(free_start, SZ_128M);
307 uassert_int_equal(free_end, SZ_256M);
308
309 rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
310 uassert_int_equal(free_start, SZ_512M);
311 uassert_int_equal(free_end, SZ_512M + SZ_128M);
312
313 rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
314 uassert_int_equal(free_start, SZ_512M + SZ_256M);
315 uassert_int_equal(free_end, SZ_1G - SZ_128M);
316
317 rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
318 uassert_int_equal(rt_memblock_is_last_free(), RT_TRUE);
319 }
320
test_memblock_reserve_large_region(void)321 static void test_memblock_reserve_large_region(void)
322 {
323 _reset_memblock();
324
325 rt_size_t base1 = 0, size1 = SZ_256M;
326 rt_size_t base2 = SZ_256M, size2 = SZ_256M;
327 rt_size_t base3 = SZ_512M, size3 = SZ_256M;
328 rt_size_t base4 = SZ_512M + SZ_256M, size4 = SZ_256M;
329 rt_size_t baser = SZ_256M + SZ_128M, sizer = SZ_512M;
330 rt_size_t free_start, free_end;
331 rt_err_t err;
332
333 err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE);
334 uassert_int_equal(err, RT_EOK);
335 err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE);
336 uassert_int_equal(err, RT_EOK);
337 err = rt_memblock_add_memory("memory3", base3, base3 + size3, MEMBLOCK_NONE);
338 uassert_int_equal(err, RT_EOK);
339 err = rt_memblock_add_memory("memory4", base4, base4 + size4, MEMBLOCK_NONE);
340 uassert_int_equal(err, RT_EOK);
341 err = rt_memblock_reserve_memory("reserve", baser, baser + sizer, MEMBLOCK_NOMAP);
342 uassert_int_equal(err, RT_EOK);
343
344 rt_memblock_next_free_region_init();
345
346 rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
347 uassert_int_equal(free_start, 0);
348 uassert_int_equal(free_end, SZ_256M);
349
350 rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
351 uassert_int_equal(free_start, SZ_256M);
352 uassert_int_equal(free_end, SZ_256M + SZ_128M);
353
354 rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
355 uassert_int_equal(free_start, SZ_512M + SZ_256M + SZ_128M);
356 uassert_int_equal(free_end, SZ_1G);
357
358 rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
359 uassert_int_equal(rt_memblock_is_last_free(), RT_TRUE);
360 }
361
test_memblock_reserve(void)362 static void test_memblock_reserve(void)
363 {
364 test_memblock_reserve_in_memory_start();
365 test_memblock_reserve_in_memory_end();
366 test_memblock_reserve_many_in_one_region();
367 test_memblock_reserve_large_region();
368 }
369
utest_tc_init(void)370 static rt_err_t utest_tc_init(void)
371 {
372 mmblk_memory = rt_memblock_get_memory();
373 mmblk_reserved = rt_memblock_get_reserved();
374 return RT_EOK;
375 }
376
utest_tc_cleanup(void)377 static rt_err_t utest_tc_cleanup(void)
378 {
379 return RT_EOK;
380 }
381
testcase(void)382 static void testcase(void)
383 {
384 UTEST_UNIT_RUN(test_memblock_add);
385 UTEST_UNIT_RUN(test_memblock_reserve);
386 }
387 UTEST_TC_EXPORT(testcase, "testcases.mm.memblock_tc", utest_tc_init, utest_tc_cleanup, 20);
388