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