mm_memblock_tc.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  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. * 2026-03-19 cl2t Add standardized utest documentation block
  10. */
  11. /**
  12. * Test Case Name: Memory Block Management Test
  13. *
  14. * Test Objectives:
  15. * - Validate the memblock subsystem for early boot memory region management.
  16. * - Test core APIs: rt_memblock_add_memory(), rt_memblock_reserve_memory(),
  17. * rt_memblock_merge(), rt_memblock_next_free_region().
  18. *
  19. * Test Scenarios:
  20. * - Add Test (test_memblock_add): Verifies adding memory regions in various
  21. * configurations including simple addition, adjacent regions (top/bottom),
  22. * insertion between existing regions, and merging of contiguous regions
  23. * with the same flags.
  24. * - Reserve Test (test_memblock_reserve): Verifies reserving memory within
  25. * existing regions at start/end positions, multiple reservations within
  26. * a single region, and large reservations spanning multiple regions.
  27. * Also validates free region iteration with MEMBLOCK_NOMAP filtering.
  28. *
  29. * Verification Metrics:
  30. * - Region count after add/merge operations matches expected value.
  31. * - Region start/end addresses and flags are correctly maintained.
  32. * - Merge correctly combines adjacent regions with identical flags.
  33. * - Free region iterator correctly skips reserved and NOMAP regions.
  34. *
  35. * Dependencies:
  36. * - Software configuration: RT_USING_SMART and RT_UTEST_MM_MEMBLOCK must
  37. * be enabled.
  38. * - Environmental assumptions: MMU support must be available on the target
  39. * platform.
  40. *
  41. * Expected Results:
  42. * - Final output: "[ PASSED ] [ result ] testcase (testcases.mm.memblock_tc)"
  43. * - No assertion failures during test execution.
  44. */
  45. #include <mm_memblock.h>
  46. #include "common.h"
  47. #include <rtservice.h>
  48. #define SZ_128M 0x08000000
  49. #define SZ_256M 0x10000000
  50. #define SZ_512M 0x20000000
  51. #define SZ_1G 0x40000000
  52. static struct rt_memblock *mmblk_memory;
  53. static struct rt_memblock *mmblk_reserved;
  54. void rt_memblock_next_free_region_init(void);
  55. void rt_memblock_next_free_region(mmblk_flag_t flags, rt_size_t *out_start, rt_size_t *out_end);
  56. rt_bool_t rt_memblock_is_last_free(void);
  57. void rt_memblock_merge(void);
  58. struct rt_mmblk_reg *_nth_reg(struct rt_memblock *memblock, rt_uint32_t n)
  59. {
  60. struct rt_mmblk_reg *ret = RT_NULL;
  61. rt_slist_for_each_entry(ret, &(memblock->reg_list), node)
  62. {
  63. if (--n == 0)
  64. return ret;
  65. }
  66. return ret;
  67. }
  68. rt_uint32_t _reg_cnt(struct rt_memblock *memblock)
  69. {
  70. rt_uint32_t ret = 0;
  71. struct rt_mmblk_reg *reg;
  72. rt_slist_for_each_entry(reg, &(memblock->reg_list), node)
  73. {
  74. ret++;
  75. }
  76. return ret;
  77. }
  78. void _reset_memblock(void)
  79. {
  80. struct rt_mmblk_reg *reg;
  81. rt_slist_for_each_entry(reg, &(mmblk_memory->reg_list), node)
  82. {
  83. reg->alloc = RT_FALSE;
  84. }
  85. rt_slist_for_each_entry(reg, &(mmblk_reserved->reg_list), node)
  86. {
  87. reg->alloc = RT_FALSE;
  88. }
  89. mmblk_memory->reg_list.next = RT_NULL;
  90. mmblk_reserved->reg_list.next = RT_NULL;
  91. }
  92. static void test_memblock_add_simple(void)
  93. {
  94. _reset_memblock();
  95. rt_size_t base1 = SZ_1G, size1 = SZ_256M;
  96. rt_size_t base2 = SZ_128M, size2 = SZ_128M;
  97. rt_err_t err;
  98. err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE);
  99. uassert_int_equal(err, RT_EOK);
  100. uassert_int_equal(_reg_cnt(mmblk_memory), 1);
  101. uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base1);
  102. uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base1 + size1);
  103. uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE);
  104. err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_HOTPLUG);
  105. uassert_int_equal(err, RT_EOK);
  106. uassert_int_equal(_reg_cnt(mmblk_memory), 2);
  107. uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base2);
  108. uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base2 + size2);
  109. uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_HOTPLUG);
  110. uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base1);
  111. uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base1 + size1);
  112. uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_NONE);
  113. }
  114. static void test_memblock_add_adjacent_top(void)
  115. {
  116. _reset_memblock();
  117. rt_size_t base1 = SZ_128M, size1 = SZ_128M;
  118. rt_size_t base2 = SZ_256M, size2 = SZ_128M;
  119. rt_err_t err;
  120. err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE);
  121. uassert_int_equal(err, RT_EOK);
  122. err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE);
  123. uassert_int_equal(err, RT_EOK);
  124. uassert_int_equal(_reg_cnt(mmblk_memory), 2);
  125. uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base1);
  126. uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base1 + size1);
  127. uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE);
  128. uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base2);
  129. uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base2 + size2);
  130. uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_NONE);
  131. }
  132. static void test_memblock_add_adjacent_bottom(void)
  133. {
  134. _reset_memblock();
  135. rt_size_t base1 = SZ_256M, size1 = SZ_128M;
  136. rt_size_t base2 = SZ_128M, size2 = SZ_128M;
  137. rt_err_t err;
  138. err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE);
  139. uassert_int_equal(err, RT_EOK);
  140. err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE);
  141. uassert_int_equal(err, RT_EOK);
  142. uassert_int_equal(_reg_cnt(mmblk_memory), 2);
  143. uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base2);
  144. uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base2 + size2);
  145. uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE);
  146. uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base1);
  147. uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base1 + size1);
  148. uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_NONE);
  149. }
  150. static void test_memblock_add_between(void)
  151. {
  152. _reset_memblock();
  153. rt_size_t base1 = SZ_512M, size1 = SZ_256M;
  154. rt_size_t base2 = SZ_1G, size2 = SZ_512M;
  155. rt_size_t base3 = SZ_512M + SZ_256M, size3 = SZ_256M;
  156. rt_err_t err;
  157. err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE);
  158. uassert_int_equal(err, RT_EOK);
  159. err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE);
  160. uassert_int_equal(err, RT_EOK);
  161. err = rt_memblock_add_memory("memory3", base3, base3 + size3, MEMBLOCK_HOTPLUG);
  162. uassert_int_equal(err, RT_EOK);
  163. uassert_int_equal(_reg_cnt(mmblk_memory), 3);
  164. uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base1);
  165. uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base1 + size1);
  166. uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE);
  167. uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base3);
  168. uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base3 + size3);
  169. uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_HOTPLUG);
  170. uassert_int_equal(_nth_reg(mmblk_memory, 3)->memreg.start, base2);
  171. uassert_int_equal(_nth_reg(mmblk_memory, 3)->memreg.end, base2 + size2);
  172. uassert_int_equal(_nth_reg(mmblk_memory, 3)->flags, MEMBLOCK_NONE);
  173. }
  174. static void test_memblock_merge(void)
  175. {
  176. _reset_memblock();
  177. rt_size_t base1 = 0, size1 = SZ_256M;
  178. rt_size_t base2 = SZ_256M, size2 = SZ_256M;
  179. rt_size_t base3 = SZ_512M, size3 = SZ_256M;
  180. rt_size_t base4 = SZ_512M + SZ_256M, size4 = SZ_256M;
  181. rt_size_t base5 = SZ_1G, size5 = SZ_512M;
  182. rt_err_t err;
  183. err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE);
  184. uassert_int_equal(err, RT_EOK);
  185. err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE);
  186. uassert_int_equal(err, RT_EOK);
  187. err = rt_memblock_add_memory("memory3", base3, base3 + size3, MEMBLOCK_HOTPLUG);
  188. uassert_int_equal(err, RT_EOK);
  189. err = rt_memblock_add_memory("memory4", base4, base4 + size4, MEMBLOCK_NONE);
  190. uassert_int_equal(err, RT_EOK);
  191. err = rt_memblock_add_memory("memory5", base5, base5 + size5, MEMBLOCK_NONE);
  192. uassert_int_equal(err, RT_EOK);
  193. rt_memblock_merge();
  194. uassert_int_equal(_reg_cnt(mmblk_memory), 3);
  195. uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base1);
  196. uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base2 + size2);
  197. uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE);
  198. uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base3);
  199. uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base3 + size3);
  200. uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_HOTPLUG);
  201. uassert_int_equal(_nth_reg(mmblk_memory, 3)->memreg.start, base4);
  202. uassert_int_equal(_nth_reg(mmblk_memory, 3)->memreg.end, base5 + size5);
  203. uassert_int_equal(_nth_reg(mmblk_memory, 3)->flags, MEMBLOCK_NONE);
  204. }
  205. static void test_memblock_add(void)
  206. {
  207. test_memblock_add_simple();
  208. test_memblock_add_adjacent_top();
  209. test_memblock_add_adjacent_bottom();
  210. test_memblock_add_between();
  211. test_memblock_merge();
  212. }
  213. static void test_memblock_reserve_in_memory_start(void)
  214. {
  215. _reset_memblock();
  216. rt_size_t base1 = SZ_128M, size1 = SZ_256M;
  217. rt_size_t baser = SZ_128M, sizer = SZ_128M;
  218. rt_size_t free_start, free_end;
  219. rt_err_t err;
  220. err = rt_memblock_add_memory("memory", base1, base1 + size1, MEMBLOCK_NONE);
  221. uassert_int_equal(err, RT_EOK);
  222. err = rt_memblock_reserve_memory("reserve", baser, baser + sizer, MEMBLOCK_NONE);
  223. uassert_int_equal(err, RT_EOK);
  224. rt_memblock_next_free_region_init();
  225. rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
  226. uassert_int_equal(free_start, SZ_256M);
  227. uassert_int_equal(free_end, SZ_128M + SZ_256M);
  228. rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
  229. uassert_int_equal(rt_memblock_is_last_free(), RT_TRUE);
  230. }
  231. static void test_memblock_reserve_in_memory_end(void)
  232. {
  233. _reset_memblock();
  234. rt_size_t base1 = SZ_128M, size1 = SZ_256M;
  235. rt_size_t baser = SZ_256M, sizer = SZ_128M;
  236. rt_size_t free_start, free_end;
  237. rt_err_t err;
  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. rt_memblock_next_free_region_init();
  243. rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
  244. uassert_int_equal(free_start, SZ_128M);
  245. uassert_int_equal(free_end, SZ_256M);
  246. rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
  247. uassert_int_equal(rt_memblock_is_last_free(), RT_TRUE);
  248. }
  249. static void test_memblock_reserve_many_in_one_region(void)
  250. {
  251. _reset_memblock();
  252. rt_size_t base = 0, size = SZ_1G;
  253. rt_size_t baser1 = 0, sizer1 = SZ_128M;
  254. rt_size_t baser2 = SZ_256M, sizer2 = SZ_128M;
  255. rt_size_t baser3 = SZ_256M + SZ_128M, sizer3 = SZ_128M;
  256. rt_size_t baser4 = SZ_512M + SZ_128M, sizer4 = SZ_128M;
  257. rt_size_t baser5 = SZ_1G - SZ_128M, sizer5 = SZ_128M;
  258. rt_size_t free_start, free_end;
  259. rt_err_t err;
  260. err = rt_memblock_add_memory("memory", base, base + size, MEMBLOCK_NONE);
  261. uassert_int_equal(err, RT_EOK);
  262. err = rt_memblock_reserve_memory("reserve1", baser1, baser1 + sizer1, MEMBLOCK_NONE);
  263. uassert_int_equal(err, RT_EOK);
  264. err = rt_memblock_reserve_memory("reserve2", baser2, baser2 + sizer2, MEMBLOCK_NOMAP);
  265. uassert_int_equal(err, RT_EOK);
  266. err = rt_memblock_reserve_memory("reserve3", baser3, baser3 + sizer3, MEMBLOCK_NONE);
  267. uassert_int_equal(err, RT_EOK);
  268. err = rt_memblock_reserve_memory("reserve4", baser4, baser4 + sizer4, MEMBLOCK_NOMAP);
  269. uassert_int_equal(err, RT_EOK);
  270. err = rt_memblock_reserve_memory("reserve5", baser5, baser5 + sizer5, MEMBLOCK_NONE);
  271. uassert_int_equal(err, RT_EOK);
  272. rt_memblock_next_free_region_init();
  273. rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
  274. uassert_int_equal(free_start, SZ_128M);
  275. uassert_int_equal(free_end, SZ_256M);
  276. rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
  277. uassert_int_equal(free_start, SZ_512M);
  278. uassert_int_equal(free_end, SZ_512M + SZ_128M);
  279. rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
  280. uassert_int_equal(free_start, SZ_512M + SZ_256M);
  281. uassert_int_equal(free_end, SZ_1G - SZ_128M);
  282. rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
  283. uassert_int_equal(rt_memblock_is_last_free(), RT_TRUE);
  284. }
  285. static void test_memblock_reserve_large_region(void)
  286. {
  287. _reset_memblock();
  288. rt_size_t base1 = 0, size1 = SZ_256M;
  289. rt_size_t base2 = SZ_256M, size2 = SZ_256M;
  290. rt_size_t base3 = SZ_512M, size3 = SZ_256M;
  291. rt_size_t base4 = SZ_512M + SZ_256M, size4 = SZ_256M;
  292. rt_size_t baser = SZ_256M + SZ_128M, sizer = SZ_512M;
  293. rt_size_t free_start, free_end;
  294. rt_err_t err;
  295. err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE);
  296. uassert_int_equal(err, RT_EOK);
  297. err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE);
  298. uassert_int_equal(err, RT_EOK);
  299. err = rt_memblock_add_memory("memory3", base3, base3 + size3, MEMBLOCK_NONE);
  300. uassert_int_equal(err, RT_EOK);
  301. err = rt_memblock_add_memory("memory4", base4, base4 + size4, MEMBLOCK_NONE);
  302. uassert_int_equal(err, RT_EOK);
  303. err = rt_memblock_reserve_memory("reserve", baser, baser + sizer, MEMBLOCK_NOMAP);
  304. uassert_int_equal(err, RT_EOK);
  305. rt_memblock_next_free_region_init();
  306. rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
  307. uassert_int_equal(free_start, 0);
  308. uassert_int_equal(free_end, SZ_256M);
  309. rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
  310. uassert_int_equal(free_start, SZ_256M);
  311. uassert_int_equal(free_end, SZ_256M + SZ_128M);
  312. rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
  313. uassert_int_equal(free_start, SZ_512M + SZ_256M + SZ_128M);
  314. uassert_int_equal(free_end, SZ_1G);
  315. rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end);
  316. uassert_int_equal(rt_memblock_is_last_free(), RT_TRUE);
  317. }
  318. static void test_memblock_reserve(void)
  319. {
  320. test_memblock_reserve_in_memory_start();
  321. test_memblock_reserve_in_memory_end();
  322. test_memblock_reserve_many_in_one_region();
  323. test_memblock_reserve_large_region();
  324. }
  325. static rt_err_t utest_tc_init(void)
  326. {
  327. mmblk_memory = rt_memblock_get_memory();
  328. mmblk_reserved = rt_memblock_get_reserved();
  329. return RT_EOK;
  330. }
  331. static rt_err_t utest_tc_cleanup(void)
  332. {
  333. return RT_EOK;
  334. }
  335. static void testcase(void)
  336. {
  337. UTEST_UNIT_RUN(test_memblock_add);
  338. UTEST_UNIT_RUN(test_memblock_reserve);
  339. }
  340. UTEST_TC_EXPORT(testcase, "testcases.mm.memblock_tc", utest_tc_init, utest_tc_cleanup, 20);