From f559dceeb55d357684529fbfc3a1241062ee5a17 Mon Sep 17 00:00:00 2001 From: CYFS <2805686936@qq.com> Date: Thu, 11 Jun 2026 14:40:29 +0800 Subject: utest: move mm testcases to components/mm Signed-off-by: CYFS <2805686936@qq.com> --- Kconfig.utestcases | 2 +- components/mm/SConscript | 2 + components/mm/utest/Kconfig | 17 + components/mm/utest/SConscript | 25 ++ components/mm/utest/aspace_map_expand.c | 119 ++++++ .../mm/utest/aspace_unmap_range_invalid_param.c | 84 ++++ components/mm/utest/aspace_unmap_range_shrink.c | 75 ++++ components/mm/utest/aspace_unmap_range_split.c | 65 ++++ components/mm/utest/common.h | 81 ++++ components/mm/utest/lwp_mmap_expand.c | 109 ++++++ components/mm/utest/lwp_mmap_fd.c | 140 +++++++ components/mm/utest/lwp_mmap_fd_map_fixed_merge.c | 214 +++++++++++ components/mm/utest/lwp_mmap_fd_map_fixed_split.c | 215 +++++++++++ components/mm/utest/lwp_mmap_fix_private.c | 138 +++++++ components/mm/utest/lwp_mmap_map_fixed.c | 117 ++++++ components/mm/utest/mm_api_tc.c | 148 +++++++ components/mm/utest/mm_libcpu_tc.c | 16 + components/mm/utest/mm_lwp_tc.c | 177 +++++++++ components/mm/utest/mm_memblock_tc.c | 423 +++++++++++++++++++++ components/mm/utest/rt_ioremap.c | 74 ++++ components/mm/utest/semaphore.h | 37 ++ components/mm/utest/test_aspace_api.h | 348 +++++++++++++++++ components/mm/utest/test_aspace_api_internal.h | 80 ++++ components/mm/utest/test_bst_adpt.h | 106 ++++++ components/mm/utest/test_cache_aarch64.h | 115 ++++++ components/mm/utest/test_cache_rv64.h | 194 ++++++++++ components/mm/utest/test_synchronization.h | 165 ++++++++ examples/utest/testcases/mm/Kconfig | 17 - examples/utest/testcases/mm/SConscript | 25 -- examples/utest/testcases/mm/aspace_map_expand.c | 119 ------ .../mm/aspace_unmap_range_invalid_param.c | 84 ---- .../utest/testcases/mm/aspace_unmap_range_shrink.c | 75 ---- .../utest/testcases/mm/aspace_unmap_range_split.c | 65 ---- examples/utest/testcases/mm/common.h | 81 ---- examples/utest/testcases/mm/lwp_mmap_expand.c | 109 ------ examples/utest/testcases/mm/lwp_mmap_fd.c | 140 ------- .../testcases/mm/lwp_mmap_fd_map_fixed_merge.c | 214 ----------- .../testcases/mm/lwp_mmap_fd_map_fixed_split.c | 215 ----------- examples/utest/testcases/mm/lwp_mmap_fix_private.c | 138 ------- examples/utest/testcases/mm/lwp_mmap_map_fixed.c | 117 ------ examples/utest/testcases/mm/mm_api_tc.c | 148 ------- examples/utest/testcases/mm/mm_libcpu_tc.c | 16 - examples/utest/testcases/mm/mm_lwp_tc.c | 177 --------- examples/utest/testcases/mm/mm_memblock_tc.c | 423 --------------------- examples/utest/testcases/mm/rt_ioremap.c | 74 ---- examples/utest/testcases/mm/semaphore.h | 37 -- examples/utest/testcases/mm/test_aspace_api.h | 348 ----------------- .../utest/testcases/mm/test_aspace_api_internal.h | 80 ---- examples/utest/testcases/mm/test_bst_adpt.h | 106 ------ examples/utest/testcases/mm/test_cache_aarch64.h | 115 ------ examples/utest/testcases/mm/test_cache_rv64.h | 194 ---------- examples/utest/testcases/mm/test_synchronization.h | 165 -------- 52 files changed, 3285 insertions(+), 3283 deletions(-) create mode 100644 components/mm/utest/Kconfig create mode 100644 components/mm/utest/SConscript create mode 100644 components/mm/utest/aspace_map_expand.c create mode 100644 components/mm/utest/aspace_unmap_range_invalid_param.c create mode 100644 components/mm/utest/aspace_unmap_range_shrink.c create mode 100644 components/mm/utest/aspace_unmap_range_split.c create mode 100644 components/mm/utest/common.h create mode 100644 components/mm/utest/lwp_mmap_expand.c create mode 100644 components/mm/utest/lwp_mmap_fd.c create mode 100644 components/mm/utest/lwp_mmap_fd_map_fixed_merge.c create mode 100644 components/mm/utest/lwp_mmap_fd_map_fixed_split.c create mode 100644 components/mm/utest/lwp_mmap_fix_private.c create mode 100644 components/mm/utest/lwp_mmap_map_fixed.c create mode 100644 components/mm/utest/mm_api_tc.c create mode 100644 components/mm/utest/mm_libcpu_tc.c create mode 100644 components/mm/utest/mm_lwp_tc.c create mode 100644 components/mm/utest/mm_memblock_tc.c create mode 100644 components/mm/utest/rt_ioremap.c create mode 100644 components/mm/utest/semaphore.h create mode 100644 components/mm/utest/test_aspace_api.h create mode 100644 components/mm/utest/test_aspace_api_internal.h create mode 100644 components/mm/utest/test_bst_adpt.h create mode 100644 components/mm/utest/test_cache_aarch64.h create mode 100644 components/mm/utest/test_cache_rv64.h create mode 100644 components/mm/utest/test_synchronization.h delete mode 100644 examples/utest/testcases/mm/Kconfig delete mode 100644 examples/utest/testcases/mm/SConscript delete mode 100644 examples/utest/testcases/mm/aspace_map_expand.c delete mode 100644 examples/utest/testcases/mm/aspace_unmap_range_invalid_param.c delete mode 100644 examples/utest/testcases/mm/aspace_unmap_range_shrink.c delete mode 100644 examples/utest/testcases/mm/aspace_unmap_range_split.c delete mode 100644 examples/utest/testcases/mm/common.h delete mode 100644 examples/utest/testcases/mm/lwp_mmap_expand.c delete mode 100644 examples/utest/testcases/mm/lwp_mmap_fd.c delete mode 100644 examples/utest/testcases/mm/lwp_mmap_fd_map_fixed_merge.c delete mode 100644 examples/utest/testcases/mm/lwp_mmap_fd_map_fixed_split.c delete mode 100644 examples/utest/testcases/mm/lwp_mmap_fix_private.c delete mode 100644 examples/utest/testcases/mm/lwp_mmap_map_fixed.c delete mode 100644 examples/utest/testcases/mm/mm_api_tc.c delete mode 100644 examples/utest/testcases/mm/mm_libcpu_tc.c delete mode 100644 examples/utest/testcases/mm/mm_lwp_tc.c delete mode 100644 examples/utest/testcases/mm/mm_memblock_tc.c delete mode 100644 examples/utest/testcases/mm/rt_ioremap.c delete mode 100644 examples/utest/testcases/mm/semaphore.h delete mode 100644 examples/utest/testcases/mm/test_aspace_api.h delete mode 100644 examples/utest/testcases/mm/test_aspace_api_internal.h delete mode 100644 examples/utest/testcases/mm/test_bst_adpt.h delete mode 100644 examples/utest/testcases/mm/test_cache_aarch64.h delete mode 100644 examples/utest/testcases/mm/test_cache_rv64.h delete mode 100644 examples/utest/testcases/mm/test_synchronization.h diff --git a/Kconfig.utestcases b/Kconfig.utestcases index 69a8a43885..64162324b6 100644 --- a/Kconfig.utestcases +++ b/Kconfig.utestcases @@ -22,12 +22,12 @@ menu "RT-Thread Utestcases" rsource "components/dfs/utest/Kconfig" rsource "components/libc/cplusplus/utest/Kconfig" + rsource "components/mm/utest/Kconfig" rsource "components/net/utest/Kconfig" rsource "components/utilities/utest/utest/Kconfig" endmenu - rsource "examples/utest/testcases/mm/Kconfig" rsource "examples/utest/testcases/tmpfs/Kconfig" endif diff --git a/components/mm/SConscript b/components/mm/SConscript index 39e4f6bbcf..5b259fee10 100644 --- a/components/mm/SConscript +++ b/components/mm/SConscript @@ -13,4 +13,6 @@ if GetDepend('ARCH_ARM_CORTEX_A') or GetDepend('ARCH_ARMV8') or GetDepend('ARCH_ group = DefineGroup('Memm', src, depend = ['ARCH_MM_MMU'], CPPPATH = CPPPATH) +group = group + SConscript(os.path.join('utest', 'SConscript')) + Return('group') diff --git a/components/mm/utest/Kconfig b/components/mm/utest/Kconfig new file mode 100644 index 0000000000..434df5b934 --- /dev/null +++ b/components/mm/utest/Kconfig @@ -0,0 +1,17 @@ +menu "Memory Management Subsytem Testcase" + + config RT_UTEST_MM_API + bool "Enable Utest for MM API" + default n + help + The test covers the Memory Management APIs under the + `components/mm` and `libcpu/[mmu.*|tlb.*|cache.*]` + + config RT_UTEST_MM_LWP + bool "Enable Utest for MM API in lwp" + default n + help + The test covers the Memory Management APIs under the + `components/lwp`. + +endmenu diff --git a/components/mm/utest/SConscript b/components/mm/utest/SConscript new file mode 100644 index 0000000000..edef3914f1 --- /dev/null +++ b/components/mm/utest/SConscript @@ -0,0 +1,25 @@ +Import('rtconfig') +from building import * + +cwd = GetCurrentDir() +src = [] +CPPPATH = [cwd] + +if GetDepend(['RT_UTEST_MM_API', 'RT_USING_SMART']): + # deprecated test, will be rewrited in the future + # src += ['mm_api_tc.c', 'mm_libcpu_tc.c'] + src += ['rt_ioremap.c'] + src += ['aspace_unmap_range_invalid_param.c', 'aspace_unmap_range_shrink.c'] + src += ['aspace_unmap_range_split.c', 'aspace_map_expand.c'] + src += ['lwp_mmap_expand.c', 'lwp_mmap_map_fixed.c', 'lwp_mmap_fix_private.c'] + src += ['lwp_mmap_fd.c', 'lwp_mmap_fd_map_fixed_merge.c', 'lwp_mmap_fd_map_fixed_split.c'] + +if GetDepend(['RT_UTEST_MM_API', 'RT_USING_MEMBLOCK']): + src += ['mm_memblock_tc.c'] + +if GetDepend(['RT_UTEST_MM_LWP', 'RT_USING_SMART']): + src += ['mm_lwp_tc.c'] + +group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/mm/utest/aspace_map_expand.c b/components/mm/utest/aspace_map_expand.c new file mode 100644 index 0000000000..2fd70f1da0 --- /dev/null +++ b/components/mm/utest/aspace_map_expand.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-08-22 Shell test case for aspace_map with varea_expand + */ +#include "common.h" +#include "lwp_user_mm.h" +#include + +#include + +static size_t flags = MMF_PREFETCH | MMF_MAP_FIXED; +static size_t attr = MMU_MAP_K_RWCB; +static rt_mem_obj_t mem_obj = &rt_mm_dummy_mapper; + +static char *ex_vaddr = (void *)0x100000000; +static size_t ex_offset = 1024; +static size_t map_size = 0x3000; + +static size_t former_vsz; +static size_t former_vcount; + +static struct rt_lwp *lwp; + +static int _count_vsz(rt_varea_t varea, void *arg) +{ + rt_base_t *pvsz = arg; + *pvsz += 1; + return 0; +} + +static rt_base_t count_vcount(rt_aspace_t aspace) +{ + rt_base_t vcount = 0; + rt_aspace_traversal(aspace, _count_vsz, &vcount); + return vcount; +} + +static void test_map_varea_expand(void) +{ + char *next_va; + size_t next_offset; + + /* create an existed mapping */ + next_va = ex_vaddr; + former_vsz = rt_aspace_count_vsz(lwp->aspace); + former_vcount = count_vcount(lwp->aspace); + utest_int_equal( + RT_EOK, + rt_aspace_map(lwp->aspace, (void *)&ex_vaddr, map_size, attr, flags, mem_obj, ex_offset) + ); + uassert_true(next_va == ex_vaddr); + utest_int_equal(former_vsz + map_size, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); + former_vsz += map_size; + former_vcount += 1; + + /* test the RIGHT side expansion of varea by rt_aspace_map */ + next_va = ex_vaddr + map_size; + next_offset = ex_offset + (map_size >> MM_PAGE_SHIFT); + utest_int_equal( + RT_EOK, + rt_aspace_map(lwp->aspace, (void *)&next_va, map_size, attr, flags, mem_obj, next_offset) + ); + uassert_true(next_va == (char *)ex_vaddr + map_size); + utest_int_equal(former_vsz + map_size, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount, count_vcount(lwp->aspace)); + former_vsz += map_size; + + /* test the LEFT side expansion of varea by rt_aspace_map */ + next_va = ex_vaddr - map_size; + next_offset = ex_offset - (map_size >> MM_PAGE_SHIFT); + utest_int_equal( + RT_EOK, + rt_aspace_map(lwp->aspace, (void *)&next_va, map_size, attr, flags, mem_obj, next_offset) + ); + uassert_true(next_va == ex_vaddr - map_size); + utest_int_equal(former_vsz + map_size, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount, count_vcount(lwp->aspace)); + former_vsz += map_size; + + /* test the expand varea routine from rt_aspace_map_static */ + utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, next_va, 3 * map_size)); + + /* test the expand varea routine from rt_aspace_map_phy */ + /* test the expand varea routine from rt_aspace_map_phy_static */ + /* these 2 from another file */ +} + +static void aspace_map_tc(void) +{ + CONSIST_HEAP(test_map_varea_expand()); +} + +static rt_err_t utest_tc_init(void) +{ + lwp = lwp_create(0); + if (lwp) + lwp_user_space_init(lwp, 1); + else + return -RT_ENOMEM; + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + lwp_ref_dec(lwp); + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(aspace_map_tc); +} +UTEST_TC_EXPORT(testcase, "testcases.mm.aspace_map.varea_expand", utest_tc_init, utest_tc_cleanup, 10); diff --git a/components/mm/utest/aspace_unmap_range_invalid_param.c b/components/mm/utest/aspace_unmap_range_invalid_param.c new file mode 100644 index 0000000000..1beec1aa8a --- /dev/null +++ b/components/mm/utest/aspace_unmap_range_invalid_param.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-08-17 Shell test case for aspace_unmap_range + */ +#include "common.h" +#include "lwp_user_mm.h" +#include + +#include + +static void *vaddr = (void *)0x100000000; +static size_t existed_size = 0x5000; +static char *unmap_start; +static size_t unmap_size = 0x2000; +static size_t former_vsz; +static struct rt_lwp *lwp; +static size_t flags = MMF_PREFETCH | MMF_MAP_FIXED; + +static void test_unmap_range_invalid_param(void) +{ + rt_mem_obj_t notsupp_object; + + /* create an existed mapping */ + former_vsz = rt_aspace_count_vsz(lwp->aspace); + uassert_true(!rt_aspace_map(lwp->aspace, &vaddr, existed_size, MMU_MAP_K_RWCB, flags, &rt_mm_dummy_mapper, 0)); + utest_int_equal(former_vsz + existed_size, rt_aspace_count_vsz(lwp->aspace)); + former_vsz += existed_size; + + /* test unaligned vaddr start */ + unmap_start = (char *)vaddr - 0x1234; + utest_int_equal(-RT_EINVAL, rt_aspace_unmap_range(lwp->aspace, unmap_start, unmap_size)); + utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); + + /* test unaligned size */ + unmap_size = 0x2000; + unmap_start = (char *)vaddr + existed_size - unmap_size; + utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, unmap_start, unmap_size - 0x123)); + utest_int_equal(former_vsz - unmap_size, rt_aspace_count_vsz(lwp->aspace)); + + /* create another mapping binding to mem_obj without proper handler */ + notsupp_object = rt_mem_obj_create(&rt_mm_dummy_mapper); + notsupp_object->on_varea_shrink = RT_NULL; + + utest_int_equal( + RT_EOK, + rt_aspace_map(lwp->aspace, (void *)&unmap_start, unmap_size, MMU_MAP_K_RWCB, flags, notsupp_object, 0) + ); + + utest_int_equal(-RT_EPERM, rt_aspace_unmap_range(lwp->aspace, unmap_start, 0x1000)); + utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, vaddr, existed_size)); + rt_free(notsupp_object); +} + +static void aspace_unmap_tc(void) +{ + CONSIST_HEAP(test_unmap_range_invalid_param()); +} + +static rt_err_t utest_tc_init(void) +{ + lwp = lwp_create(0); + if (lwp) + lwp_user_space_init(lwp, 1); + else + return -RT_ENOMEM; + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + lwp_ref_dec(lwp); + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(aspace_unmap_tc); +} +UTEST_TC_EXPORT(testcase, "testcases.mm.aspace_unmap_range.invalid_param", utest_tc_init, utest_tc_cleanup, 10); diff --git a/components/mm/utest/aspace_unmap_range_shrink.c b/components/mm/utest/aspace_unmap_range_shrink.c new file mode 100644 index 0000000000..de52572d52 --- /dev/null +++ b/components/mm/utest/aspace_unmap_range_shrink.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-08-17 Shell test case for aspace_unmap_range + */ +#include "common.h" +#include "lwp_user_mm.h" +#include + +#include + +static void *vaddr = (void *)0x100000000; +static size_t existed_size = 0x5000; +static char *unmap_start; +static char *unmap_end; +static size_t former_vsz; +static size_t unmap_size = 0x2000; +static struct rt_lwp *lwp; + +static void test_unmap_range_shrink(void) +{ + /* create an existed mapping */ + former_vsz = rt_aspace_count_vsz(lwp->aspace); + uassert_true(!rt_aspace_map(lwp->aspace, &vaddr, existed_size, MMU_MAP_K_RWCB, MMF_PREFETCH, &rt_mm_dummy_mapper, 0)); + utest_int_equal(former_vsz + existed_size, rt_aspace_count_vsz(lwp->aspace)); + former_vsz += existed_size; + + /* test the shrink mode of unmap from LEFT side */ + unmap_start = (char *)vaddr - unmap_size/2; + uassert_true(!rt_aspace_unmap_range(lwp->aspace, unmap_start, unmap_size)); + unmap_end = unmap_start + unmap_size; + uassert_true(rt_hw_mmu_v2p(lwp->aspace, unmap_end) != ARCH_MAP_FAILED); + utest_int_equal(former_vsz - (unmap_end - (char *)vaddr), rt_aspace_count_vsz(lwp->aspace)); + former_vsz -= unmap_end - (char *)vaddr; + + /* test the shrink mode of unmap from RIGHT side */ + unmap_start = (char *)vaddr + existed_size - unmap_size / 2; + uassert_true(!rt_aspace_unmap_range(lwp->aspace, unmap_start, unmap_size)); + uassert_true(rt_hw_mmu_v2p(lwp->aspace, unmap_start - 1) != ARCH_MAP_FAILED); + utest_int_equal(former_vsz - (unmap_end - (char *)vaddr), rt_aspace_count_vsz(lwp->aspace)); + former_vsz -= unmap_end - (char *)vaddr; + + utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, vaddr, existed_size)); +} + +static void aspace_unmap_tc(void) +{ + CONSIST_HEAP(test_unmap_range_shrink()); +} + +static rt_err_t utest_tc_init(void) +{ + lwp = lwp_create(0); + if (lwp) + lwp_user_space_init(lwp, 1); + else + return -RT_ENOMEM; + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + lwp_ref_dec(lwp); + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(aspace_unmap_tc); +} +UTEST_TC_EXPORT(testcase, "testcases.mm.aspace_unmap_range.shrink", utest_tc_init, utest_tc_cleanup, 10); diff --git a/components/mm/utest/aspace_unmap_range_split.c b/components/mm/utest/aspace_unmap_range_split.c new file mode 100644 index 0000000000..07489df693 --- /dev/null +++ b/components/mm/utest/aspace_unmap_range_split.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-08-17 Shell test case for aspace_unmap_range + */ +#include "common.h" +#include "lwp_user_mm.h" +#include + +#include + +static void *vaddr = (void *)0x100000000; +static size_t existed_size = 0x5000; +static char *unmap_start = (char *)0x100000000 + 0x3000; +static size_t former_vsz; +static size_t unmap_size = 0x1000; +static struct rt_lwp *lwp; + +static void test_unmap_range_split(void) +{ + /* create an existed mapping */ + former_vsz = rt_aspace_count_vsz(lwp->aspace); + uassert_true(!rt_aspace_map(lwp->aspace, &vaddr, existed_size, MMU_MAP_K_RWCB, MMF_PREFETCH, &rt_mm_dummy_mapper, 0)); + utest_int_equal(former_vsz + existed_size, rt_aspace_count_vsz(lwp->aspace)); + former_vsz += existed_size; + + /* test the split mode of unmap */ + utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, unmap_start, unmap_size)); + uassert_true(rt_hw_mmu_v2p(lwp->aspace, unmap_start - 1) != ARCH_MAP_FAILED); + uassert_true(rt_hw_mmu_v2p(lwp->aspace, unmap_start + unmap_size) != ARCH_MAP_FAILED); + utest_int_equal(former_vsz - unmap_size, rt_aspace_count_vsz(lwp->aspace)); + + utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, vaddr, existed_size)); +} + +static void aspace_unmap_tc(void) +{ + CONSIST_HEAP(test_unmap_range_split()); +} + +static rt_err_t utest_tc_init(void) +{ + lwp = lwp_create(0); + if (lwp) + lwp_user_space_init(lwp, 1); + else + return -RT_ENOMEM; + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + lwp_ref_dec(lwp); + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(aspace_unmap_tc); +} +UTEST_TC_EXPORT(testcase, "testcases.mm.aspace_unmap_range.split", utest_tc_init, utest_tc_cleanup, 10); diff --git a/components/mm/utest/common.h b/components/mm/utest/common.h new file mode 100644 index 0000000000..3255e166ca --- /dev/null +++ b/components/mm/utest/common.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-03-20 WangXiaoyao Complete testcase for mm_aspace.c + */ +#ifndef __TEST_MM_COMMON_H__ +#define __TEST_MM_COMMON_H__ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#ifdef RT_USING_SMART +#include +#endif + +#include +#include +#include +#include +#include + +extern rt_base_t rt_heap_lock(void); +extern void rt_heap_unlock(rt_base_t level); + +#define __int_compare(a, b, operator) do{long _a = (long)(a); long _b = (long)(b); __utest_assert((_a) operator (_b), "Assertion Failed: (" #a ") "#operator" (" #b ")"); if (!((_a) operator (_b)))LOG_E("\t"#a"=%ld(0x%lx), "#b"=%ld(0x%lx)", _a, _a, _b, _b);} while (0) +#define utest_int_equal(a, b) __int_compare(a, b, ==) +#define utest_int_less(a, b) __int_compare(a, b, <) +#define utest_int_less_equal(a, b) __int_compare(a, b, <=) + +/** + * @brief During the operations, is heap still the same; + */ +#define CONSIST_HEAP(statement) do { \ + rt_size_t total, used, max_used; \ + rt_size_t totala, useda, max_useda; \ + rt_ubase_t level = rt_heap_lock(); \ + rt_memory_info(&total, &used, &max_used); \ + statement; \ + rt_memory_info(&totala, &useda, &max_useda); \ + rt_heap_unlock(level); \ + utest_int_equal(total, totala); \ + utest_int_equal(used, useda); \ + } while (0) + +#ifdef STANDALONE_TC +#define TC_ASSERT(expr) \ + ((expr) \ + ? 0 \ + : rt_kprintf("AssertFault(%d): %s\n", __LINE__, RT_STRINGIFY(expr))) +#else +#define TC_ASSERT(expr) uassert_true(expr) +#endif + +rt_inline int memtest(volatile char *buf, int value, size_t buf_sz) +{ + int ret = 0; + for (size_t i = 0; i < buf_sz; i++) + { + if (buf[i] != value) + { + ret = -1; + break; + } + } + return ret; +} + +#endif /* __TEST_MM_COMMON_H__ */ diff --git a/components/mm/utest/lwp_mmap_expand.c b/components/mm/utest/lwp_mmap_expand.c new file mode 100644 index 0000000000..ee54f150fa --- /dev/null +++ b/components/mm/utest/lwp_mmap_expand.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-08-22 Shell test case for aspace_map with varea_expand + */ +#include "common.h" +#include "lwp_user_mm.h" +#include + +#include + +static long fd = -1; +static long pgoffset = 0; +static size_t flags = MAP_FIXED | MAP_ANONYMOUS; +static size_t prot1 = PROT_READ | PROT_WRITE; + +static char *ex_vaddr = (void *)0x100000000; +static size_t map_size = 0x3000; + +static size_t former_vsz; +static size_t former_vcount; + +static struct rt_lwp *lwp; + +static int _count_vsz(rt_varea_t varea, void *arg) +{ + rt_base_t *pvsz = arg; + *pvsz += 1; + return 0; +} + +static rt_base_t count_vcount(rt_aspace_t aspace) +{ + rt_base_t vcount = 0; + rt_aspace_traversal(aspace, _count_vsz, &vcount); + return vcount; +} + +static void test_mmap_expand(void) +{ + char *next_va; + + /* map new pages at ex_vaddr to anonymous */ + next_va = ex_vaddr; + former_vsz = rt_aspace_count_vsz(lwp->aspace); + former_vcount = count_vcount(lwp->aspace); + next_va = lwp_mmap2(lwp, next_va, map_size, prot1, flags, fd, pgoffset); + uassert_true(next_va == ex_vaddr); + utest_int_equal(former_vsz + map_size, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); + former_vsz += map_size; + former_vcount += 1; + + /* test the RIGHT side expansion of varea by lwp_mmap2 */ + next_va = ex_vaddr + map_size; + uassert_true( + lwp_mmap2(lwp, next_va, map_size, prot1, flags, fd, pgoffset) + == next_va + ); + utest_int_equal(former_vsz + map_size, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount, count_vcount(lwp->aspace)); + former_vsz += map_size; + + /* test the LEFT side expansion of varea by rt_aspace_map */ + next_va = ex_vaddr - map_size; + uassert_true( + lwp_mmap2(lwp, next_va, map_size, prot1, flags, fd, pgoffset) + == next_va + ); + utest_int_equal(former_vsz + map_size, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount, count_vcount(lwp->aspace)); + former_vsz += map_size; + + /* test other prot/offset/flags */ + + /* clear mapping */ + utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, next_va, 3 * map_size)); +} + +static void aspace_map_tc(void) +{ + CONSIST_HEAP(test_mmap_expand()); +} + +static rt_err_t utest_tc_init(void) +{ + lwp = lwp_create(0); + if (lwp) + lwp_user_space_init(lwp, 1); + else + return -RT_ENOMEM; + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + lwp_ref_dec(lwp); + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(aspace_map_tc); +} +UTEST_TC_EXPORT(testcase, "testcases.lwp.mman.mmap_anon.expand", utest_tc_init, utest_tc_cleanup, 10); diff --git a/components/mm/utest/lwp_mmap_fd.c b/components/mm/utest/lwp_mmap_fd.c new file mode 100644 index 0000000000..da2e4f8edf --- /dev/null +++ b/components/mm/utest/lwp_mmap_fd.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-08-17 Shell test case for aspace_map(MAP_FIXED) + */ +#include "common.h" +#include "lwp_user_mm.h" +#include "utest_assert.h" +#include + +#include + +#define PAGE_SZ (1 << MM_PAGE_SHIFT) +#define PAGE_COUNT ('z' - 'a' + 1) +#define FILE_PATH "/test_mmap" +#define FILE_SZ (PAGE_COUNT * PAGE_SZ) + +static struct rt_lwp *lwp; +static size_t former_vsz; +static size_t former_vcount; +static char page_sz_buf[PAGE_SZ]; + +static void *vaddr = (void *)0x100000000; +static long pgoffset = 0; +static size_t ex_prot = PROT_NONE; +static size_t ex_flags = MAP_PRIVATE | MAP_ANONYMOUS; + +static int _count_vsz(rt_varea_t varea, void *arg) +{ + rt_base_t *pvsz = arg; + *pvsz += 1; + return 0; +} + +static rt_base_t count_vcount(rt_aspace_t aspace) +{ + rt_base_t vcount = 0; + rt_aspace_traversal(aspace, _count_vsz, &vcount); + return vcount; +} + +static rt_err_t _lwp_get_user(struct rt_lwp *lwp, char *vaddr, char *buffer) +{ + rt_varea_t varea = _aspace_bst_search(lwp->aspace, vaddr); + if (varea && varea->mem_obj && varea->mem_obj->page_read) + { + struct rt_aspace_io_msg io_msg; + rt_mm_io_msg_init(&io_msg, MM_PA_TO_OFF(vaddr), vaddr, buffer); + varea->mem_obj->page_read(varea, &io_msg); + } + return RT_EOK; +} + +static void _verify_file_content(const char *mmap_buf) +{ + char ch = 'a'; + for (char *read_va = (char *)mmap_buf; read_va < mmap_buf + FILE_SZ; read_va += PAGE_SZ, ch++) + { + _lwp_get_user(lwp, read_va, page_sz_buf); + utest_int_equal(RT_EOK, memtest(page_sz_buf, ch, PAGE_SZ)); + } +} + +static void test_mmap_fd(void) +{ + former_vsz = rt_aspace_count_vsz(lwp->aspace); + former_vcount = count_vcount(lwp->aspace); + + /* create an existed mapping */ + long temp_fd; + temp_fd = open(FILE_PATH, O_RDONLY); + LOG_D("New fd=%ld path=%s", temp_fd, FILE_PATH); + uassert_true(temp_fd >= 0); + utest_int_equal( + lwp_mmap2(lwp, vaddr, FILE_SZ, ex_prot, ex_flags, temp_fd, pgoffset), + vaddr); + close(temp_fd); + + utest_int_equal(former_vsz + FILE_SZ, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); + + _verify_file_content(vaddr); + + /* create an override mapping */ + + /* close */ + + utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, vaddr, FILE_SZ)); +} + +static void testcase_main(void) +{ + test_mmap_fd(); +} + +static void _setup_file_content(long fd) +{ + char ch = 'a'; + + for (size_t i = 0; i < PAGE_COUNT; i++, ch++) + { + memset(page_sz_buf, ch, PAGE_SZ); + write(fd, page_sz_buf, PAGE_SZ); + } +} + +static rt_err_t utest_tc_init(void) +{ + /* setup file */ + long temp_file_des; + temp_file_des = open(FILE_PATH, O_RDWR | O_CREAT, 0777); + LOG_D("New fd=%ld path=%s", temp_file_des, FILE_PATH); + if (temp_file_des < 0) + return -RT_ERROR; + _setup_file_content(temp_file_des); + close(temp_file_des); + + lwp = lwp_create(0); + if (lwp) + lwp_user_space_init(lwp, 1); + else + return -RT_ENOMEM; + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + lwp_ref_dec(lwp); + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(testcase_main); +} +UTEST_TC_EXPORT(testcase, "testcases.lwp.mman.mmap_fd.basic", utest_tc_init, utest_tc_cleanup, 10); diff --git a/components/mm/utest/lwp_mmap_fd_map_fixed_merge.c b/components/mm/utest/lwp_mmap_fd_map_fixed_merge.c new file mode 100644 index 0000000000..b33606618e --- /dev/null +++ b/components/mm/utest/lwp_mmap_fd_map_fixed_merge.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-08-17 Shell test case for aspace_map(MAP_FIXED) + */ +#include "common.h" +#include "lwp_user_mm.h" +#include "utest_assert.h" +#include + +#include + +#define PAGE_SZ (1 << MM_PAGE_SHIFT) +#define PAGE_COUNT ('z' - 'a' + 1) +#define FILE_PATH "/test_mmap" +#define FILE_SZ (PAGE_COUNT * PAGE_SZ) + +static struct rt_lwp *lwp; +static size_t former_vsz; +static size_t former_vcount; +static char page_sz_buf[PAGE_SZ]; + +static void *ex_start = (void *)0x100000000; +static size_t ex_size = 0x5000; +static long pgoffset = 0; +static size_t ex_prot = PROT_NONE; +static size_t ex_flags = MAP_PRIVATE | MAP_ANONYMOUS; + +static char *private0 = (char *)0x100000000; +static char *private1 = (char *)0x100000000 + 0x1000; +static char *private2 = (char *)0x100000000 + 0x2000; +static char *private3 = (char *)0x100000000 + 0x3000; +static char *private4 = (char *)0x100000000 + 0x4000; +static size_t or_size = 0x1000; +static size_t or_prot = PROT_READ | PROT_WRITE; +static size_t or_flags = MAP_ANON | MAP_FIXED; + +static long anon_fd = -1; + +static int _count_vsz(rt_varea_t varea, void *arg) +{ + rt_base_t *pvsz = arg; + *pvsz += 1; + return 0; +} + +static rt_base_t count_vcount(rt_aspace_t aspace) +{ + rt_base_t vcount = 0; + rt_aspace_traversal(aspace, _count_vsz, &vcount); + return vcount; +} + +static rt_err_t _lwp_get_user(struct rt_lwp *lwp, char *vaddr, char *buffer) +{ + rt_varea_t varea = _aspace_bst_search(lwp->aspace, vaddr); + if (varea && varea->mem_obj && varea->mem_obj->page_read) + { + struct rt_aspace_io_msg io_msg; + rt_mm_io_msg_init(&io_msg, MM_PA_TO_OFF(vaddr), vaddr, buffer); + varea->mem_obj->page_read(varea, &io_msg); + } + return RT_EOK; +} + +static void _verify_file_content(struct rt_lwp *lwp, const char *mmap_buf, int ch) +{ + _lwp_get_user(lwp, (char *)mmap_buf, page_sz_buf); + utest_int_equal(RT_EOK, memtest(page_sz_buf, ch, PAGE_SZ)); +} + +static void test_mmap_fd_fixed(void) +{ + former_vsz = rt_aspace_count_vsz(lwp->aspace); + former_vcount = count_vcount(lwp->aspace); + + /* create an existed mapping */ + long temp_fd; + temp_fd = open(FILE_PATH, O_RDONLY); + LOG_D("New fd=%ld path=%s", temp_fd, FILE_PATH); + uassert_true(temp_fd >= 0); + utest_int_equal( + lwp_mmap2(lwp, ex_start, ex_size, ex_prot, ex_flags, anon_fd, pgoffset), + ex_start); + utest_int_equal(former_vsz + ex_size, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); + former_vsz += ex_size; + former_vcount += 1; + _verify_file_content(lwp, private0, 0); + _verify_file_content(lwp, private1, 0); + _verify_file_content(lwp, private2, 0); + _verify_file_content(lwp, private3, 0); + _verify_file_content(lwp, private4, 0); + + /* create an override mapping */ + utest_int_equal( + lwp_mmap2(lwp, private2, or_size, or_prot, or_flags, temp_fd, 2), + private2); + utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount + 2, count_vcount(lwp->aspace)); + former_vcount += 2; + _verify_file_content(lwp, private0, 0); + _verify_file_content(lwp, private1, 0); + _verify_file_content(lwp, private2, 'c'); + _verify_file_content(lwp, private3, 0); + _verify_file_content(lwp, private4, 0); + + /* fix private from left most */ + utest_int_equal( + lwp_mmap2(lwp, private0, or_size, or_prot, or_flags, temp_fd, 0), + private0); + utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); + former_vcount += 1; + _verify_file_content(lwp, private0, 'a'); + _verify_file_content(lwp, private1, 0); + _verify_file_content(lwp, private2, 'c'); + _verify_file_content(lwp, private3, 0); + _verify_file_content(lwp, private4, 0); + + /* fix private from right most */ + utest_int_equal( + lwp_mmap2(lwp, private4, or_size, or_prot, or_flags, temp_fd, 4), + private4); + utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); + former_vcount += 1; + _verify_file_content(lwp, private0, 'a'); + _verify_file_content(lwp, private1, 0); + _verify_file_content(lwp, private2, 'c'); + _verify_file_content(lwp, private3, 0); + _verify_file_content(lwp, private4, 'e'); + + /* fix private from left-middle */ + utest_int_equal( + lwp_mmap2(lwp, private1, or_size, or_prot, or_flags, temp_fd, 1), + private1); + rt_aspace_print_all(lwp->aspace); + utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace)); + former_vcount -= 1; + _verify_file_content(lwp, private0, 'a'); + _verify_file_content(lwp, private1, 'b'); + _verify_file_content(lwp, private2, 'c'); + _verify_file_content(lwp, private3, 0); + _verify_file_content(lwp, private4, 'e'); + + /* fix private from right-middle */ + utest_int_equal( + lwp_mmap2(lwp, private3, or_size, or_prot, or_flags, temp_fd, 3), + private3); + utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace)); + former_vcount -= 1; + _verify_file_content(lwp, private0, 'a'); + _verify_file_content(lwp, private1, 'b'); + _verify_file_content(lwp, private2, 'c'); + _verify_file_content(lwp, private3, 'd'); + _verify_file_content(lwp, private4, 'e'); + + /* close */ + close(temp_fd); + utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, ex_start, FILE_SZ)); +} + +static void testcase_main(void) +{ + test_mmap_fd_fixed(); +} + +static void _setup_file_content(long fd) +{ + char ch = 'a'; + for (size_t i = 0; i < PAGE_COUNT; i++, ch++) + { + memset(page_sz_buf, ch, PAGE_SZ); + write(fd, page_sz_buf, PAGE_SZ); + } +} + +static rt_err_t utest_tc_init(void) +{ + /* setup file */ + long temp_file_des; + temp_file_des = open(FILE_PATH, O_RDWR | O_CREAT, 0777); + LOG_D("New fd=%ld path=%s", temp_file_des, FILE_PATH); + if (temp_file_des < 0) + return -RT_ERROR; + _setup_file_content(temp_file_des); + close(temp_file_des); + + lwp = lwp_create(0); + if (lwp) + lwp_user_space_init(lwp, 1); + else + return -RT_ENOMEM; + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + lwp_ref_dec(lwp); + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(testcase_main); +} +UTEST_TC_EXPORT(testcase, "testcases.lwp.mman.mmap_fd.map_fixed_merge", utest_tc_init, utest_tc_cleanup, 10); diff --git a/components/mm/utest/lwp_mmap_fd_map_fixed_split.c b/components/mm/utest/lwp_mmap_fd_map_fixed_split.c new file mode 100644 index 0000000000..7f7ef23b30 --- /dev/null +++ b/components/mm/utest/lwp_mmap_fd_map_fixed_split.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-08-17 Shell test case for aspace_map(MAP_FIXED) + */ +#include "common.h" +#include "lwp_user_mm.h" +#include "utest_assert.h" +#include + +#include + +#define PAGE_SZ (1 << MM_PAGE_SHIFT) +#define PAGE_COUNT ('z' - 'a' + 1) +#define FILE_PATH "/test_mmap" +#define FILE_SZ (PAGE_COUNT * PAGE_SZ) + +static struct rt_lwp *lwp; +static size_t former_vsz; +static size_t former_vcount; +static char page_sz_buf[PAGE_SZ]; + +static void *ex_start = (void *)0x100000000; +static size_t ex_size = 0x5000; +static long pgoffset = 0; +static size_t ex_prot = PROT_NONE; +static size_t ex_flags = MAP_PRIVATE | MAP_ANONYMOUS; + +static char *private0 = (char *)0x100000000; +static char *private1 = (char *)0x100000000 + 0x1000; +static char *private2 = (char *)0x100000000 + 0x2000; +static char *private3 = (char *)0x100000000 + 0x3000; +static char *private4 = (char *)0x100000000 + 0x4000; +static size_t or_size = 0x1000; +static size_t or_prot = PROT_READ | PROT_WRITE; +static size_t or_flags = MAP_ANON | MAP_FIXED; + +static long anon_fd = -1; + +static int _count_vsz(rt_varea_t varea, void *arg) +{ + rt_base_t *pvsz = arg; + *pvsz += 1; + return 0; +} + +static rt_base_t count_vcount(rt_aspace_t aspace) +{ + rt_base_t vcount = 0; + rt_aspace_traversal(aspace, _count_vsz, &vcount); + return vcount; +} + +static rt_err_t _lwp_get_user(struct rt_lwp *lwp, char *vaddr, char *buffer) +{ + rt_varea_t varea = _aspace_bst_search(lwp->aspace, vaddr); + if (varea && varea->mem_obj && varea->mem_obj->page_read) + { + struct rt_aspace_io_msg io_msg; + rt_mm_io_msg_init(&io_msg, MM_PA_TO_OFF(vaddr), vaddr, buffer); + varea->mem_obj->page_read(varea, &io_msg); + } + else + return -RT_ERROR; + return RT_EOK; +} + +static void _verify_file_content(struct rt_lwp *lwp, const char *mmap_buf, int ch) +{ + utest_int_equal(RT_EOK, _lwp_get_user(lwp, (char *)mmap_buf, page_sz_buf)); + utest_int_equal(RT_EOK, memtest(page_sz_buf, ch, PAGE_SZ)); +} + +static void test_mmap_fd_fixed(void) +{ + former_vsz = rt_aspace_count_vsz(lwp->aspace); + former_vcount = count_vcount(lwp->aspace); + + /* create an existed mapping */ + long temp_fd; + temp_fd = open(FILE_PATH, O_RDONLY); + LOG_D("New fd=%ld path=%s", temp_fd, FILE_PATH); + uassert_true(temp_fd >= 0); + utest_int_equal( + lwp_mmap2(lwp, ex_start, ex_size, ex_prot, ex_flags, temp_fd, pgoffset), + ex_start); + utest_int_equal(former_vsz + ex_size, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); + _verify_file_content(lwp, private0, 'a'); + _verify_file_content(lwp, private1, 'b'); + _verify_file_content(lwp, private2, 'c'); + _verify_file_content(lwp, private3, 'd'); + _verify_file_content(lwp, private4, 'e'); + former_vsz += ex_size; + former_vcount += 1; + + /* create an override mapping */ + utest_int_equal( + lwp_mmap2(lwp, private2, or_size, or_prot, or_flags, anon_fd, pgoffset), + private2); + utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount + 2, count_vcount(lwp->aspace)); + former_vcount += 2; + _verify_file_content(lwp, private0, 'a'); + _verify_file_content(lwp, private1, 'b'); + _verify_file_content(lwp, private2, 0); + _verify_file_content(lwp, private3, 'd'); + _verify_file_content(lwp, private4, 'e'); + + /* fix private from left most */ + utest_int_equal( + lwp_mmap2(lwp, private0, or_size, or_prot, or_flags, anon_fd, pgoffset), + private0); + utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); + former_vcount += 1; + _verify_file_content(lwp, private0, 0); + _verify_file_content(lwp, private1, 'b'); + _verify_file_content(lwp, private2, 0); + _verify_file_content(lwp, private3, 'd'); + _verify_file_content(lwp, private4, 'e'); + + /* fix private from right most */ + utest_int_equal( + lwp_mmap2(lwp, private4, or_size, or_prot, or_flags, anon_fd, pgoffset), + private4); + utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); + former_vcount += 1; + _verify_file_content(lwp, private0, 0); + _verify_file_content(lwp, private1, 'b'); + _verify_file_content(lwp, private2, 0); + _verify_file_content(lwp, private3, 'd'); + _verify_file_content(lwp, private4, 0); + + /* fix private from left-middle */ + utest_int_equal( + lwp_mmap2(lwp, private1, or_size, or_prot, or_flags, anon_fd, pgoffset), + private1); + utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace)); + former_vcount -= 1; + _verify_file_content(lwp, private0, 0); + _verify_file_content(lwp, private1, 0); + _verify_file_content(lwp, private2, 0); + _verify_file_content(lwp, private3, 'd'); + _verify_file_content(lwp, private4, 0); + + /* fix private from right-middle */ + utest_int_equal( + lwp_mmap2(lwp, private3, or_size, or_prot, or_flags, anon_fd, pgoffset), + private3); + utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace)); + former_vcount -= 1; + _verify_file_content(lwp, private0, 0); + _verify_file_content(lwp, private1, 0); + _verify_file_content(lwp, private2, 0); + _verify_file_content(lwp, private3, 0); + _verify_file_content(lwp, private4, 0); + + /* close */ + close(temp_fd); + utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, ex_start, FILE_SZ)); +} + +static void testcase_main(void) +{ + test_mmap_fd_fixed(); +} + +static void _setup_file_content(long fd) +{ + char ch = 'a'; + for (size_t i = 0; i < PAGE_COUNT; i++, ch++) + { + memset(page_sz_buf, ch, PAGE_SZ); + write(fd, page_sz_buf, PAGE_SZ); + } +} + +static rt_err_t utest_tc_init(void) +{ + /* setup file */ + long temp_file_des; + temp_file_des = open(FILE_PATH, O_RDWR | O_CREAT, 0777); + LOG_D("New fd=%ld path=%s", temp_file_des, FILE_PATH); + if (temp_file_des < 0) + return -RT_ERROR; + _setup_file_content(temp_file_des); + close(temp_file_des); + + lwp = lwp_create(0); + if (lwp) + lwp_user_space_init(lwp, 1); + else + return -RT_ENOMEM; + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + lwp_ref_dec(lwp); + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(testcase_main); +} +UTEST_TC_EXPORT(testcase, "testcases.lwp.mman.mmap_fd.map_fixed_split", utest_tc_init, utest_tc_cleanup, 10); diff --git a/components/mm/utest/lwp_mmap_fix_private.c b/components/mm/utest/lwp_mmap_fix_private.c new file mode 100644 index 0000000000..22261e4b4f --- /dev/null +++ b/components/mm/utest/lwp_mmap_fix_private.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-08-22 Shell test case for aspace_map with varea_expand + */ +#include "common.h" +#include "lwp_user_mm.h" +#include "mm_fault.h" +#include + +#include + +static long fd = -1; +static long pgoffset = 0; +static size_t flags = MAP_FIXED | MAP_ANONYMOUS; +static size_t prot = PROT_READ | PROT_WRITE; + +static char *ex_vaddr = (char *)0x100000000; +static size_t ex_size = 0x5000; +static char *private0 = (char *)0x100000000; +static char *private1 = (char *)0x100000000 + 0x1000; +static char *private2 = (char *)0x100000000 + 0x2000; +static char *private3 = (char *)0x100000000 + 0x3000; +static char *private4 = (char *)0x100000000 + 0x4000; + +/** + * todo: suppoprt prefetch pages, so more than 1 page can install to private at a time + * static size_t priv_size = 0x1000; + */ + +static size_t former_vsz; +static size_t former_vcount; + +static struct rt_lwp *lwp; + +static int _count_vsz(rt_varea_t varea, void *arg) +{ + rt_base_t *pvsz = arg; + *pvsz += 1; + return 0; +} + +static rt_base_t count_vcount(rt_aspace_t aspace) +{ + rt_base_t vcount = 0; + rt_aspace_traversal(aspace, _count_vsz, &vcount); + return vcount; +} + +static void test_mmap_fix_private(void) +{ + char *next_va; + struct rt_aspace_fault_msg msg; + msg.fault_op = MM_FAULT_OP_WRITE; + msg.fault_type = MM_FAULT_TYPE_RWX_PERM; + + /* map new pages at ex_vaddr to anonymous */ + next_va = ex_vaddr; + former_vsz = rt_aspace_count_vsz(lwp->aspace); + former_vcount = count_vcount(lwp->aspace); + next_va = lwp_mmap2(lwp, next_va, ex_size, prot, flags, fd, pgoffset); + uassert_true(next_va == ex_vaddr); + utest_int_equal(former_vsz + ex_size, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); + former_vsz += ex_size; + former_vcount += 1; + + /* fix private in the middle */ + msg.fault_vaddr = private2; + utest_int_equal(MM_FAULT_FIXABLE_TRUE, rt_aspace_fault_try_fix(lwp->aspace, &msg)); + utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount + 2, count_vcount(lwp->aspace)); + former_vcount += 2; + + /* fix private from left most */ + msg.fault_vaddr = private0; + utest_int_equal(MM_FAULT_FIXABLE_TRUE, rt_aspace_fault_try_fix(lwp->aspace, &msg)); + utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); + former_vcount += 1; + + /* fix private from right most */ + msg.fault_vaddr = private4; + utest_int_equal(MM_FAULT_FIXABLE_TRUE, rt_aspace_fault_try_fix(lwp->aspace, &msg)); + utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); + former_vcount += 1; + + /* fix private from left-middle */ + msg.fault_vaddr = private1; + utest_int_equal(MM_FAULT_FIXABLE_TRUE, rt_aspace_fault_try_fix(lwp->aspace, &msg)); + utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace)); + former_vcount -= 1; + + /* fix private from right-middle */ + msg.fault_vaddr = private3; + utest_int_equal(MM_FAULT_FIXABLE_TRUE, rt_aspace_fault_try_fix(lwp->aspace, &msg)); + utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace)); + former_vcount -= 1; + + /* clear mapping */ + utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, ex_vaddr, ex_size)); + rt_free(lwp->aspace->private_object); + lwp->aspace->private_object = RT_NULL; +} + +static void testcase_main(void) +{ + CONSIST_HEAP(test_mmap_fix_private()); +} + +static rt_err_t utest_tc_init(void) +{ + lwp = lwp_create(0); + if (lwp) + lwp_user_space_init(lwp, 1); + else + return -RT_ENOMEM; + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + lwp_ref_dec(lwp); + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(testcase_main); +} +UTEST_TC_EXPORT(testcase, "testcases.lwp.mman.mmap_anon.fix_private", utest_tc_init, utest_tc_cleanup, 10); diff --git a/components/mm/utest/lwp_mmap_map_fixed.c b/components/mm/utest/lwp_mmap_map_fixed.c new file mode 100644 index 0000000000..affc514037 --- /dev/null +++ b/components/mm/utest/lwp_mmap_map_fixed.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-08-17 Shell test case for aspace_map(MAP_FIXED) + */ +#include "common.h" +#include "lwp_user_mm.h" +#include "utest_assert.h" +#include + +#include + +static struct rt_lwp *lwp; +static size_t former_vsz; +static size_t former_vcount; + +static void *vaddr = (void *)0x100000000; +static size_t ex_size = 0x5000; +static char *override_start; +static size_t override_size = 0x2000; +static long fd = -1; +static long pgoffset = 0; +static size_t ex_prot = PROT_NONE; +static size_t ex_flags = MAP_PRIVATE | MAP_ANONYMOUS; +static size_t override_prot = PROT_READ | PROT_WRITE; +static size_t override_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED; + +static int _count_vsz(rt_varea_t varea, void *arg) +{ + rt_base_t *pvsz = arg; + *pvsz += 1; + return 0; +} + +static rt_base_t count_vcount(rt_aspace_t aspace) +{ + rt_base_t vcount = 0; + rt_aspace_traversal(aspace, _count_vsz, &vcount); + return vcount; +} + +static char put_data[] = "hello,world"; + +static void test_map_fixed(void) +{ + void *effect_override; + + former_vsz = rt_aspace_count_vsz(lwp->aspace); + former_vcount = count_vcount(lwp->aspace); + + /* create an existed mapping */ + vaddr = lwp_mmap2(lwp, vaddr, ex_size, ex_prot, ex_flags, fd, pgoffset); + uassert_true((long)vaddr > 0); + utest_int_equal(former_vsz + ex_size, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); + former_vsz += ex_size; + former_vcount += 1; + + /* fix private in the middle */ + override_start = (char *)vaddr + 0x1000; + effect_override = lwp_mmap2(lwp, override_start, override_size, override_prot, override_flags, fd, pgoffset); + uassert_true(effect_override == override_start); + utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); + utest_int_equal(former_vcount + 2, count_vcount(lwp->aspace)); + utest_int_equal( + lwp_data_put(lwp, effect_override, put_data, sizeof(put_data)), + sizeof(put_data) + ); + + utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, vaddr, ex_size)); +} + +static void aspace_unmap_tc(void) +{ + test_map_fixed(); +} + +static rt_size_t total, used, max_used; +static rt_size_t totala, useda, max_useda; +static rt_ubase_t level; +static rt_err_t utest_tc_init(void) +{ + lwp = lwp_create(0); + if (lwp) + lwp_user_space_init(lwp, 1); + else + return -RT_ENOMEM; + + /* stats */ + level = rt_heap_lock(); + rt_memory_info(&total, &used, &max_used); + + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + lwp_ref_dec(lwp); + + /* check */ + rt_memory_info(&totala, &useda, &max_useda); + rt_heap_unlock(level); + utest_int_equal(total, totala); + utest_int_less_equal(useda, used); + + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(aspace_unmap_tc); +} +UTEST_TC_EXPORT(testcase, "testcases.lwp.mman.mmap_anon.fix_private", utest_tc_init, utest_tc_cleanup, 10); diff --git a/components/mm/utest/mm_api_tc.c b/components/mm/utest/mm_api_tc.c new file mode 100644 index 0000000000..d7fcdffb00 --- /dev/null +++ b/components/mm/utest/mm_api_tc.c @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-12-14 WangXiaoyao the first version + * 2023-03-20 WangXiaoyao Format & add more testcases for API under mm_aspace.h + * 2025-12-14 ChuanN-sudo Add standardized utest documentation block + */ + +/** + * Test Case Name: MM API Test + * + * Test Objectives: + * - Verify I/O remapping functionality with cached memory access. + * - Test memory mapping flag creation and extraction mechanisms. + * - Validate address space management operations. + * - Test core APIs: rt_pages_alloc(), rt_ioremap_cached(), rt_iounmap(), rt_pages_free(), + * rt_pages_free(), MMF_CREATE(), MMF_GET_CNTL(), MMF_GET_ALIGN(). + * + * Test Scenarios: + * - Address Space Test (aspace_tc): Tests memory address space management APIs. + * - I/O Remap Test (ioremap_tc): Allocates physical pages, maps to virtual address with cache, verifies data consistency, and cleans up resources. + * - Flag Test (flag_tc): Creates memory mapping flags with different parameters and validates control bits and alignment values extraction. + * + * Verification Metrics: + * - I/O remapping should correctly map physical to virtual addresses. + * - Cached memory access should maintain data consistency between physical and virtual addresses. + * - Memory mapping flags should correctly encode and decode control bits and alignment values. + * - Flag creation with alignment should set MMF_REQUEST_ALIGN bit and store alignment value. + * - Flag creation without alignment should not set alignment-related bits. + * + Dependencies: + * - Hardware requirements: QEMU emulator or any hardware platform that supports RT-Thread with MMU. + * - Software configuration: + * - RT_UTEST_MM_API must be enabled (enable via: RT-Thread Utestcases -> RT-Thread Utestcases -> Memory Management Subsystem Testcase -> Enable Utest for MM API). + * - RT_USING_SMART must be enabled (enable via: Enable RT-Thread Kernel -> RT-Thread Smart (microkernel on kernel/userland)). + * - Environmental Assumptions: MMU support must be available on the target platform. + + * Expected Results: + * - Final output: "[ PASSED ] [ result ] testcase (testcases.mm.api_tc)" + * - No assertion failures during test execution. + */ +#include "common.h" + +/** + * @brief Testing all APIs under components/mm + */ + +void ioremap_tc(void); +void flag_tc(void); + +#ifdef STANDALONE_TC +#define TC_ASSERT(expr) \ + ((expr) \ + ? 0 \ + : rt_kprintf("AssertFault(%d): %s\n", __LINE__, RT_STRINGIFY(expr))) +#else +#define TC_ASSERT(expr) uassert_true(expr) +#endif + +static rt_err_t utest_tc_init(void) +{ + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + return RT_EOK; +} + +#include "test_aspace_api.h" + +static void testcase(void) +{ + aspace_tc(); + ioremap_tc(); + flag_tc(); +} +UTEST_TC_EXPORT(testcase, "testcases.mm.api_tc", utest_tc_init, utest_tc_cleanup, 20); + +void ioremap_tc(void) +{ + const size_t bufsz = 0x1000; + void *paddr = (void *)rt_pages_alloc(rt_page_bits(bufsz)) + PV_OFFSET; + int *vaddr; + vaddr = rt_ioremap_cached(paddr, bufsz); + if (vaddr) + { + TC_ASSERT(*vaddr == *(int *)(paddr - PV_OFFSET)); + + rt_iounmap(vaddr); + rt_pages_free(paddr - PV_OFFSET, 0); + } +} + +void flag_tc(void) +{ + size_t flags; + + flags = MMF_CREATE(MMF_MAP_FIXED, 0x4000); + TC_ASSERT(MMF_GET_CNTL(flags) == (MMF_MAP_FIXED | MMF_REQUEST_ALIGN)); + TC_ASSERT((1 << MMF_GET_ALIGN(flags)) == 0x4000); + + flags = MMF_CREATE(MMF_MAP_FIXED, 0); + TC_ASSERT(MMF_GET_CNTL(flags) == MMF_MAP_FIXED); + TC_ASSERT(MMF_GET_ALIGN(flags) == 0); +} + +#if 0 + +#define BUF_SIZE (4ul << 20) +static char ALIGN(BUF_SIZE) buf[BUF_SIZE]; + +void buddy_tc(void) +{ + size_t total, free; + rt_page_get_info(&total, &free); + + rt_region_t region = { + .start = (size_t)buf, + .end = (size_t)buf + BUF_SIZE, + }; + + size_t new_total, new_free; + rt_page_install(region); + rt_page_get_info(&new_total, &new_free); + TC_ASSERT(new_total - total == (BUF_SIZE >> ARCH_PAGE_SHIFT)); + TC_ASSERT(new_free > free); +} + +void mmu_page_tc() +{ + mm_aspace_t aspace = ASPACE_NEW(); + size_t total, free; + rt_page_get_info(&total, &free); + rt_hw_mmu_map(aspace, (void *)0x3fffffffff, 0, ARCH_PAGE_SIZE, + MMU_MAP_K_RWCB); + rt_hw_mmu_unmap(aspace, (void *)0x3fffffffff, ARCH_PAGE_SIZE); + + size_t new_total, new_free; + rt_page_get_info(&new_total, &new_free); + TC_ASSERT(new_free == free); + mm_aspace_delete(aspace); +} +#endif diff --git a/components/mm/utest/mm_libcpu_tc.c b/components/mm/utest/mm_libcpu_tc.c new file mode 100644 index 0000000000..a8e9c5c06b --- /dev/null +++ b/components/mm/utest/mm_libcpu_tc.c @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-03-17 WangXiaoyao cache API unit test + */ +#include + +#ifdef ARCH_RISCV64 +#include "test_cache_rv64.h" +#elif defined(ARCH_ARMV8) +#include "test_cache_aarch64.h" +#endif diff --git a/components/mm/utest/mm_lwp_tc.c b/components/mm/utest/mm_lwp_tc.c new file mode 100644 index 0000000000..d38a27341d --- /dev/null +++ b/components/mm/utest/mm_lwp_tc.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-03-27 WangXiaoyao testcase for lwp + * 2025-12-14 ChuanN-sudo Add standardized utest documentation block + */ + +/** + * Test Case Name: MM API lwp Test + * + * Test Objectives: + * - Verify LWP user space virtual area mapping functionality. + * - Test user memory accessibility checking mechanisms. + * - Test core APIs: lwp_create(), lwp_user_space_init(), lwp_map_user_varea(), + * lwp_map_user_varea_ext(), lwp_user_accessible_ext(), lwp_ref_dec() + * + * Test Scenarios: + * - User Map Varea Test (user_map_varea_tc): + * - test_user_map_varea(): Creates LWP, initializes user space, maps virtual area with default flags, verifies varea properties (cached, private mapping). + * - test_user_map_varea_ext(): Creates LWP, maps virtual area with NOCACHE flag, verifies uncached memory attributes. + * - Accessible Test (accessible_tc): + * - test_user_accessible(): Creates LWP with user stack, tests accessibility checks for unmapped and mapped memory regions. + * + * Verification Metrics: + * - Virtual areas should be correctly inserted with proper ordering. + * - Default mapping should have cached attributes (MMU_MAP_U_RWCB). + * - NOCACHE mapping should have uncached attributes (MMU_MAP_U_RW). + * - Virtual addresses should be within user space range. + * - Accessibility check should return false for unmapped memory, true for mapped memory. + * + * Dependencies: + * - Hardware requirements: QEMU emulator or any hardware platform that supports RT-Thread with MMU. + * - Software configuration: + * - RT_UTEST_MM_LWP must be enabled (enable via: RT-Thread Utestcases -> RT-Thread Utestcases -> Memory Management Subsystem Testcase -> Enable Utest for MM API in lwp). + * - RT_USING_SMART must be enabled (enable via: Enable RT-Thread Kernel -> RT-Thread Smart (microkernel on kernel/userland)). + * - Environmental Assumptions: MMU support must be available on the target platform. + * + * Expected Results: + * - Final output: "[ PASSED ] [ result ] testcase (testcases.lwp.mm_tc)" + * - No assertion failures during test execution. + */ + +#include "common.h" +#include +#include "lwp_arch.h" +#include "lwp_user_mm.h" +#include "mm_aspace.h" +#include "mm_flag.h" +#include "mmu.h" + +/** + * @brief user map API + * rt_varea_t lwp_map_user_varea(struct rt_lwp *lwp, void *map_va, size_t map_size); + * rt_varea_t lwp_map_user_varea_ext(struct rt_lwp *lwp, void *map_va, size_t map_size, size_t flags); + */ +#if 1 /* make it clear to identify the block :) */ + /* for testing on _aspace_traverse */ + static void *_prev_end; + static size_t _count; + static int _test_increase(rt_varea_t varea, void *param) + { + uassert_true(varea->start >= _prev_end); + _prev_end = varea->start + varea->size; + _count += 1; + return 0; + } + #define TEST_VAREA_INSERT(statement, aspace) do {\ + size_t _prev_count; \ + _count = 0; \ + _prev_end = 0; \ + rt_aspace_traversal((aspace), _test_increase, NULL);\ + _prev_count = _count; \ + statement; \ + _count = 0; \ + _prev_end = 0; \ + rt_aspace_traversal((aspace), _test_increase, NULL);\ + uassert_true(_prev_count + 1 == _count); \ + } while (0) +#endif + +static void test_user_map_varea(void) +{ + const size_t buf_sz = ARCH_PAGE_SIZE * 4; + struct rt_lwp *lwp; + rt_varea_t varea; + lwp = lwp_create(LWP_CREATE_FLAG_NONE); + + /* prepare environment */ + uassert_true(!!lwp); + uassert_true(!lwp_user_space_init(lwp, 1)); + TEST_VAREA_INSERT( + varea = lwp_map_user_varea(lwp, 0, buf_sz), + lwp->aspace); + uassert_true(!!varea); + uassert_true(varea->attr == (MMU_MAP_U_RWCB)); + uassert_true(varea->size == buf_sz); + uassert_true(varea->aspace == lwp->aspace); + uassert_true(varea->flag == MMF_MAP_PRIVATE); + uassert_true(varea->start != 0); + uassert_true(varea->start >= (void *)USER_VADDR_START && varea->start < (void *)USER_VADDR_TOP); + + uassert_true(!(lwp_ref_dec(lwp) - 1)); +} + +static void test_user_map_varea_ext(void) +{ + const size_t buf_sz = ARCH_PAGE_SIZE * 4; + struct rt_lwp *lwp; + rt_varea_t varea; + lwp = lwp_create(LWP_CREATE_FLAG_NONE); + + uassert_true(!!lwp); + uassert_true(!lwp_user_space_init(lwp, 1)); + + TEST_VAREA_INSERT( + varea = lwp_map_user_varea_ext(lwp, 0, buf_sz, LWP_MAP_FLAG_NOCACHE), + lwp->aspace); + uassert_true(!!varea); + uassert_true(varea->attr == (MMU_MAP_U_RW)); + uassert_true(varea->size == buf_sz); + uassert_true(varea->aspace == lwp->aspace); + uassert_true(varea->flag == MMF_MAP_PRIVATE); + uassert_true(varea->start != 0); + uassert_true(varea->start >= (void *)USER_VADDR_START && varea->start < (void *)USER_VADDR_TOP); + + uassert_true(!(lwp_ref_dec(lwp) - 1)); +} + +static void user_map_varea_tc(void) +{ + CONSIST_HEAP(test_user_map_varea()); + CONSIST_HEAP(test_user_map_varea_ext()); +} + +static void test_user_accessible(void) +{ + /* Prepare Environment */ + char *test_address = (char *)(USER_STACK_VEND); + struct rt_lwp *lwp; + lwp = lwp_create(LWP_CREATE_FLAG_NONE); + uassert_true(!!lwp); + uassert_true(!lwp_user_space_init(lwp, 0)); + + /* test if user accessible can operate */ + uassert_true(!lwp_user_accessible_ext(lwp, test_address + 0x1, 0x1)); + /* test if mapping exist, accessible can fill the page and return True */ + uassert_true(lwp_user_accessible_ext(lwp, test_address - 0x10, 0x10)); + + /* Cleanup */ + lwp_ref_dec(lwp); +} + +static void accessible_tc(void) +{ + CONSIST_HEAP(test_user_accessible()); +} + +static rt_err_t utest_tc_init(void) +{ + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(user_map_varea_tc); + UTEST_UNIT_RUN(accessible_tc); +} +UTEST_TC_EXPORT(testcase, "testcases.lwp.mm_tc", utest_tc_init, utest_tc_cleanup, 20); diff --git a/components/mm/utest/mm_memblock_tc.c b/components/mm/utest/mm_memblock_tc.c new file mode 100644 index 0000000000..e99c951c76 --- /dev/null +++ b/components/mm/utest/mm_memblock_tc.c @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-09-28 zmshahaha the first version + * 2026-03-19 cl2t Add standardized utest documentation block + */ + +/** + * Test Case Name: Memory Block Management Test + * + * Test Objectives: + * - Validate the memblock subsystem for early boot memory region management. + * - Test core APIs: rt_memblock_add_memory(), rt_memblock_reserve_memory(), + * rt_memblock_merge(), rt_memblock_next_free_region(). + * + * Test Scenarios: + * - Add Test (test_memblock_add): Verifies adding memory regions in various + * configurations including simple addition, adjacent regions (top/bottom), + * insertion between existing regions, and merging of contiguous regions + * with the same flags. + * - Reserve Test (test_memblock_reserve): Verifies reserving memory within + * existing regions at start/end positions, multiple reservations within + * a single region, and large reservations spanning multiple regions. + * Also validates free region iteration with MEMBLOCK_NOMAP filtering. + * + * Verification Metrics: + * - Region count after add/merge operations matches expected value. + * - Region start/end addresses and flags are correctly maintained. + * - Merge correctly combines adjacent regions with identical flags. + * - Free region iterator correctly skips reserved and NOMAP regions. + * + * Dependencies: + * - Software configuration: RT_USING_SMART and RT_UTEST_MM_MEMBLOCK must + * be enabled. + * - Environmental assumptions: MMU support must be available on the target + * platform. + * + * Expected Results: + * - Final output: "[ PASSED ] [ result ] testcase (testcases.mm.memblock_tc)" + * - No assertion failures during test execution. + */ + +#include +#include "common.h" +#include + +#define SZ_128M 0x08000000 +#define SZ_256M 0x10000000 +#define SZ_512M 0x20000000 +#define SZ_1G 0x40000000 + +static struct rt_memblock *mmblk_memory; +static struct rt_memblock *mmblk_reserved; + +void rt_memblock_next_free_region_init(void); +void rt_memblock_next_free_region(mmblk_flag_t flags, rt_size_t *out_start, rt_size_t *out_end); +rt_bool_t rt_memblock_is_last_free(void); +void rt_memblock_merge(void); + +struct rt_mmblk_reg *_nth_reg(struct rt_memblock *memblock, rt_uint32_t n) +{ + struct rt_mmblk_reg *ret = RT_NULL; + + rt_slist_for_each_entry(ret, &(memblock->reg_list), node) + { + if (--n == 0) + return ret; + } + + return ret; +} + +rt_uint32_t _reg_cnt(struct rt_memblock *memblock) +{ + rt_uint32_t ret = 0; + struct rt_mmblk_reg *reg; + + rt_slist_for_each_entry(reg, &(memblock->reg_list), node) + { + ret++; + } + + return ret; +} + +void _reset_memblock(void) +{ + struct rt_mmblk_reg *reg; + + rt_slist_for_each_entry(reg, &(mmblk_memory->reg_list), node) + { + reg->alloc = RT_FALSE; + } + rt_slist_for_each_entry(reg, &(mmblk_reserved->reg_list), node) + { + reg->alloc = RT_FALSE; + } + + mmblk_memory->reg_list.next = RT_NULL; + mmblk_reserved->reg_list.next = RT_NULL; +} + +static void test_memblock_add_simple(void) +{ + _reset_memblock(); + + rt_size_t base1 = SZ_1G, size1 = SZ_256M; + rt_size_t base2 = SZ_128M, size2 = SZ_128M; + rt_err_t err; + + err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + + uassert_int_equal(_reg_cnt(mmblk_memory), 1); + + uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base1); + uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base1 + size1); + uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE); + + err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_HOTPLUG); + uassert_int_equal(err, RT_EOK); + + uassert_int_equal(_reg_cnt(mmblk_memory), 2); + + uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base2); + uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base2 + size2); + uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_HOTPLUG); + + uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base1); + uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base1 + size1); + uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_NONE); +} + +static void test_memblock_add_adjacent_top(void) +{ + _reset_memblock(); + + rt_size_t base1 = SZ_128M, size1 = SZ_128M; + rt_size_t base2 = SZ_256M, size2 = SZ_128M; + rt_err_t err; + + err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + + uassert_int_equal(_reg_cnt(mmblk_memory), 2); + + uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base1); + uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base1 + size1); + uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE); + + uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base2); + uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base2 + size2); + uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_NONE); +} + +static void test_memblock_add_adjacent_bottom(void) +{ + _reset_memblock(); + + rt_size_t base1 = SZ_256M, size1 = SZ_128M; + rt_size_t base2 = SZ_128M, size2 = SZ_128M; + rt_err_t err; + + err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + + uassert_int_equal(_reg_cnt(mmblk_memory), 2); + + uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base2); + uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base2 + size2); + uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE); + + uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base1); + uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base1 + size1); + uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_NONE); +} + +static void test_memblock_add_between(void) +{ + _reset_memblock(); + + rt_size_t base1 = SZ_512M, size1 = SZ_256M; + rt_size_t base2 = SZ_1G, size2 = SZ_512M; + rt_size_t base3 = SZ_512M + SZ_256M, size3 = SZ_256M; + rt_err_t err; + + err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + err = rt_memblock_add_memory("memory3", base3, base3 + size3, MEMBLOCK_HOTPLUG); + uassert_int_equal(err, RT_EOK); + + uassert_int_equal(_reg_cnt(mmblk_memory), 3); + + uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base1); + uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base1 + size1); + uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE); + + uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base3); + uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base3 + size3); + uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_HOTPLUG); + + uassert_int_equal(_nth_reg(mmblk_memory, 3)->memreg.start, base2); + uassert_int_equal(_nth_reg(mmblk_memory, 3)->memreg.end, base2 + size2); + uassert_int_equal(_nth_reg(mmblk_memory, 3)->flags, MEMBLOCK_NONE); +} + +static void test_memblock_merge(void) +{ + _reset_memblock(); + + rt_size_t base1 = 0, size1 = SZ_256M; + rt_size_t base2 = SZ_256M, size2 = SZ_256M; + rt_size_t base3 = SZ_512M, size3 = SZ_256M; + rt_size_t base4 = SZ_512M + SZ_256M, size4 = SZ_256M; + rt_size_t base5 = SZ_1G, size5 = SZ_512M; + rt_err_t err; + + err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + err = rt_memblock_add_memory("memory3", base3, base3 + size3, MEMBLOCK_HOTPLUG); + uassert_int_equal(err, RT_EOK); + err = rt_memblock_add_memory("memory4", base4, base4 + size4, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + err = rt_memblock_add_memory("memory5", base5, base5 + size5, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + + rt_memblock_merge(); + + uassert_int_equal(_reg_cnt(mmblk_memory), 3); + + uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base1); + uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base2 + size2); + uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE); + + uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base3); + uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base3 + size3); + uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_HOTPLUG); + + uassert_int_equal(_nth_reg(mmblk_memory, 3)->memreg.start, base4); + uassert_int_equal(_nth_reg(mmblk_memory, 3)->memreg.end, base5 + size5); + uassert_int_equal(_nth_reg(mmblk_memory, 3)->flags, MEMBLOCK_NONE); +} + +static void test_memblock_add(void) +{ + test_memblock_add_simple(); + test_memblock_add_adjacent_top(); + test_memblock_add_adjacent_bottom(); + test_memblock_add_between(); + test_memblock_merge(); +} + +static void test_memblock_reserve_in_memory_start(void) +{ + _reset_memblock(); + + rt_size_t base1 = SZ_128M, size1 = SZ_256M; + rt_size_t baser = SZ_128M, sizer = SZ_128M; + rt_size_t free_start, free_end; + rt_err_t err; + + err = rt_memblock_add_memory("memory", base1, base1 + size1, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + err = rt_memblock_reserve_memory("reserve", baser, baser + sizer, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + + rt_memblock_next_free_region_init(); + + rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); + uassert_int_equal(free_start, SZ_256M); + uassert_int_equal(free_end, SZ_128M + SZ_256M); + + rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); + uassert_int_equal(rt_memblock_is_last_free(), RT_TRUE); +} + +static void test_memblock_reserve_in_memory_end(void) +{ + _reset_memblock(); + + rt_size_t base1 = SZ_128M, size1 = SZ_256M; + rt_size_t baser = SZ_256M, sizer = SZ_128M; + rt_size_t free_start, free_end; + rt_err_t err; + + err = rt_memblock_add_memory("memory", base1, base1 + size1, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + err = rt_memblock_reserve_memory("reserve", baser, baser + sizer, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + + rt_memblock_next_free_region_init(); + + rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); + uassert_int_equal(free_start, SZ_128M); + uassert_int_equal(free_end, SZ_256M); + + rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); + uassert_int_equal(rt_memblock_is_last_free(), RT_TRUE); +} + +static void test_memblock_reserve_many_in_one_region(void) +{ + _reset_memblock(); + + rt_size_t base = 0, size = SZ_1G; + rt_size_t baser1 = 0, sizer1 = SZ_128M; + rt_size_t baser2 = SZ_256M, sizer2 = SZ_128M; + rt_size_t baser3 = SZ_256M + SZ_128M, sizer3 = SZ_128M; + rt_size_t baser4 = SZ_512M + SZ_128M, sizer4 = SZ_128M; + rt_size_t baser5 = SZ_1G - SZ_128M, sizer5 = SZ_128M; + rt_size_t free_start, free_end; + rt_err_t err; + + err = rt_memblock_add_memory("memory", base, base + size, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + err = rt_memblock_reserve_memory("reserve1", baser1, baser1 + sizer1, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + err = rt_memblock_reserve_memory("reserve2", baser2, baser2 + sizer2, MEMBLOCK_NOMAP); + uassert_int_equal(err, RT_EOK); + err = rt_memblock_reserve_memory("reserve3", baser3, baser3 + sizer3, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + err = rt_memblock_reserve_memory("reserve4", baser4, baser4 + sizer4, MEMBLOCK_NOMAP); + uassert_int_equal(err, RT_EOK); + err = rt_memblock_reserve_memory("reserve5", baser5, baser5 + sizer5, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + + rt_memblock_next_free_region_init(); + + rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); + uassert_int_equal(free_start, SZ_128M); + uassert_int_equal(free_end, SZ_256M); + + rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); + uassert_int_equal(free_start, SZ_512M); + uassert_int_equal(free_end, SZ_512M + SZ_128M); + + rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); + uassert_int_equal(free_start, SZ_512M + SZ_256M); + uassert_int_equal(free_end, SZ_1G - SZ_128M); + + rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); + uassert_int_equal(rt_memblock_is_last_free(), RT_TRUE); +} + +static void test_memblock_reserve_large_region(void) +{ + _reset_memblock(); + + rt_size_t base1 = 0, size1 = SZ_256M; + rt_size_t base2 = SZ_256M, size2 = SZ_256M; + rt_size_t base3 = SZ_512M, size3 = SZ_256M; + rt_size_t base4 = SZ_512M + SZ_256M, size4 = SZ_256M; + rt_size_t baser = SZ_256M + SZ_128M, sizer = SZ_512M; + rt_size_t free_start, free_end; + rt_err_t err; + + err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + err = rt_memblock_add_memory("memory3", base3, base3 + size3, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + err = rt_memblock_add_memory("memory4", base4, base4 + size4, MEMBLOCK_NONE); + uassert_int_equal(err, RT_EOK); + err = rt_memblock_reserve_memory("reserve", baser, baser + sizer, MEMBLOCK_NOMAP); + uassert_int_equal(err, RT_EOK); + + rt_memblock_next_free_region_init(); + + rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); + uassert_int_equal(free_start, 0); + uassert_int_equal(free_end, SZ_256M); + + rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); + uassert_int_equal(free_start, SZ_256M); + uassert_int_equal(free_end, SZ_256M + SZ_128M); + + rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); + uassert_int_equal(free_start, SZ_512M + SZ_256M + SZ_128M); + uassert_int_equal(free_end, SZ_1G); + + rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); + uassert_int_equal(rt_memblock_is_last_free(), RT_TRUE); +} + +static void test_memblock_reserve(void) +{ + test_memblock_reserve_in_memory_start(); + test_memblock_reserve_in_memory_end(); + test_memblock_reserve_many_in_one_region(); + test_memblock_reserve_large_region(); +} + +static rt_err_t utest_tc_init(void) +{ + mmblk_memory = rt_memblock_get_memory(); + mmblk_reserved = rt_memblock_get_reserved(); + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(test_memblock_add); + UTEST_UNIT_RUN(test_memblock_reserve); +} +UTEST_TC_EXPORT(testcase, "testcases.mm.memblock_tc", utest_tc_init, utest_tc_cleanup, 20); diff --git a/components/mm/utest/rt_ioremap.c b/components/mm/utest/rt_ioremap.c new file mode 100644 index 0000000000..d61dceec42 --- /dev/null +++ b/components/mm/utest/rt_ioremap.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-12-14 WangXiaoyao the first version + * 2023-03-20 WangXiaoyao Format & add more testcases for API under mm_aspace.h + * 2026-03-19 cl2t Add standardized utest documentation block + */ + +/** + * Test Case Name: I/O Remap Test + * + * Test Objectives: + * - Verify the rt_ioremap_cached() API for mapping physical addresses to + * virtual addresses with cached memory access. + * - Test core APIs: rt_pages_alloc(), rt_ioremap_cached(), rt_iounmap(), + * rt_pages_free(). + * + * Test Scenarios: + * - Allocates a physical page (4KB), maps it to a virtual address using + * rt_ioremap_cached(), verifies data consistency between the physical + * and virtual addresses, then unmaps and frees the resources. + * + * Verification Metrics: + * - The value read through the virtual address must equal the value at the + * corresponding physical address. + * - No memory leaks after unmap and free operations (validated via + * CONSIST_HEAP wrapper). + * + * Dependencies: + * - Software configuration: RT_USING_SMART must be enabled. + * - Environmental assumptions: MMU support must be available on the target + * platform. + * + * Expected Results: + * - Final output: "[ PASSED ] [ result ] testcase (testcases.mm.ioremap)" + * - No assertion failures during test execution. + */ + +#include "common.h" + +void ioremap_tc(void) +{ + const size_t bufsz = 0x1000; + void *paddr = (void *)rt_pages_alloc(rt_page_bits(bufsz)) + PV_OFFSET; + int *vaddr; + vaddr = rt_ioremap_cached(paddr, bufsz); + if (vaddr) + { + TC_ASSERT(*vaddr == *(int *)(paddr - PV_OFFSET)); + + rt_iounmap(vaddr); + rt_pages_free(paddr - PV_OFFSET, 0); + } +} + +static rt_err_t utest_tc_init(void) +{ + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + return RT_EOK; +} + +static void test_main(void) +{ + CONSIST_HEAP(ioremap_tc()); +} +UTEST_TC_EXPORT(test_main, "testcases.mm.ioremap", utest_tc_init, utest_tc_cleanup, 20); diff --git a/components/mm/utest/semaphore.h b/components/mm/utest/semaphore.h new file mode 100644 index 0000000000..076f820cf2 --- /dev/null +++ b/components/mm/utest/semaphore.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-03-24 WangXiaoyao Complete testcase for synchronization + */ +#ifndef __SEMAPHORE_H__ +#define __SEMAPHORE_H__ + +#include + +typedef struct { + atomic_int count; +} semaphore_t; + +void semaphore_init(semaphore_t *sem, int count) +{ + atomic_init(&sem->count, count); +} + +void semaphore_wait(semaphore_t *sem) +{ + int count; + do { + count = atomic_load(&sem->count); + } while (count == 0 || !atomic_compare_exchange_weak(&sem->count, &count, count - 1)); +} + +void semaphore_signal(semaphore_t *sem) +{ + atomic_fetch_add(&sem->count, 1); +} + +#endif /* __SEMAPHORE_H__ */ diff --git a/components/mm/utest/test_aspace_api.h b/components/mm/utest/test_aspace_api.h new file mode 100644 index 0000000000..2213888c28 --- /dev/null +++ b/components/mm/utest/test_aspace_api.h @@ -0,0 +1,348 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-03-20 WangXiaoyao Complete testcase for mm_aspace.c + */ +#ifndef __TEST_ASPACE_API_H__ +#define __TEST_ASPACE_API_H__ + +#include "common.h" +#include "mm_aspace.h" +#include "mm_flag.h" +#include "test_aspace_api_internal.h" +#include "test_synchronization.h" + +/** + * @brief API for aspace create/destroy + * + * rt_aspace_t rt_aspace_create(void *start, rt_size_t length, void *pgtbl); + * rt_aspace_t rt_aspace_init(rt_aspace_t aspace, void *start, rt_size_t length, void *pgtbl); + * void rt_aspace_delete(rt_aspace_t aspace); + * void rt_aspace_detach(rt_aspace_t aspace); + * + * the init & detach is covered by create & detach + */ + +static void aspace_create_tc(void) +{ + /* test robustness, detect failure and recover status of overall system */ + rt_aspace_t aspace; + + CONSIST_HEAP(aspace = rt_aspace_create((void *)(0 - 0x1000), 0x1000, NULL)); + uassert_true(!aspace); +} + +#if 1 /* make it clear to identify the block :) */ + /* for testing on _aspace_traverse */ + static void *_prev_end; + static size_t _count; + static int _test_increase(rt_varea_t varea, void *param) + { + uassert_true(varea->start >= _prev_end); + _prev_end = varea->start + varea->size; + _count += 1; + return 0; + } +#endif + +static void aspace_delete_tc(void) +{ + /** + * @brief Requirements: delete should recycle all types of vareas properly inside + * and release the resource allocated for it + */ + rt_aspace_t aspace; + struct rt_mm_va_hint hint = {.flags = 0, + .map_size = 0x1000, + .prefer = 0}; + struct rt_varea varea_phy; + struct rt_varea varea_mobj; + void *pgtbl; + void *vaddr; + + /* compatible to armv7a */ + pgtbl = rt_pages_alloc(2); + uassert_true(!!pgtbl); /* page must be usable */ + rt_memset(pgtbl, 0, ARCH_PAGE_SIZE); + + CONSIST_HEAP({ + aspace = rt_aspace_create((void *)USER_VADDR_START, USER_VADDR_TOP - USER_VADDR_START, pgtbl); + uassert_true(!!aspace); + + /* insert 4 types of vareas into this aspace */ + hint.limit_start = aspace->start; + hint.limit_range_size = aspace->size; + uassert_true(!rt_aspace_map_phy(aspace, &hint, MMU_MAP_K_RWCB, 0, &vaddr)); + uassert_true(!rt_aspace_map_phy_static(aspace, &varea_phy, &hint, MMU_MAP_K_RWCB, 0, &vaddr)); + uassert_true(!rt_aspace_map(aspace, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0)); + uassert_true(!rt_aspace_map_static(aspace, &varea_mobj, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0)); + + /* for testing on _aspace_traverse */ + _count = 0; + _prev_end = 0; + uassert_true(!rt_aspace_traversal(aspace, _test_increase, 0)); + /* ensure the mapping is done */ + uassert_true(_count == 4); + + rt_aspace_delete(aspace); + + uassert_true(rt_pages_free(pgtbl, 2) == 1); /* page free must success */ + }); +} + +/** + * @brief Memory Map on Virtual Address Space to Mappable Object + * int rt_aspace_map(rt_aspace_t aspace, void **addr, rt_size_t length, rt_size_t attr, + * mm_flag_t flags, rt_mem_obj_t mem_obj, rt_size_t offset); + * int rt_aspace_map_static(rt_aspace_t aspace, rt_varea_t varea, void **addr, + * rt_size_t length, rt_size_t attr, mm_flag_t flags, + * rt_mem_obj_t mem_obj, rt_size_t offset); + */ +static void aspace_map_tc(void) +{ + /** + * @brief Requirement: + * Robustness, filter out invalid input + */ + void *vaddr = RT_NULL; + uassert_true(rt_aspace_map(0, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0)); + uassert_true(vaddr == RT_NULL); + + vaddr = (void *)USER_VADDR_START; + uassert_true(rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0)); + uassert_true(vaddr == RT_NULL); + + uassert_true(rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, -1, &rt_mm_dummy_mapper, 0)); + uassert_true(vaddr == RT_NULL); + + /** + * @brief Requirement: + * in _rt_aspace_map:_varea_install + * not covering an existed varea if a named mapping is mandatory + */ + // vaddr = (void *)((rt_ubase_t)aspace_map_tc & ~ARCH_PAGE_MASK); + // CONSIST_HEAP( + // uassert_true( + // rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0))); + // uassert_true(vaddr == RT_NULL); + + /** + * @brief Requirement: + * in _rt_aspace_map:_varea_install:_find_free + * verify that this routine can choose a free region with specified size + * and specified alignment requirement + */ + #define ALIGN_REQ (0x04000000) + CONSIST_HEAP({ + uassert_true(!rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, MMF_CREATE(0, ALIGN_REQ), &rt_mm_dummy_mapper, 0)); + uassert_true(!((rt_ubase_t)vaddr & (ALIGN_REQ - 1))); + rt_aspace_unmap(&rt_kernel_space, vaddr); + }); + + /* test internal APIs */ + test_find_free(); +} + +/** + * @brief Page frames mapping to varea + * complete the page table on specified varea, and handle tlb maintenance + * There are 2 variants of this API + * + * int rt_varea_map_page(rt_varea_t varea, void *vaddr, void *page); + * int rt_varea_map_range(rt_varea_t varea, void *vaddr, void *paddr, rt_size_t length); + */ + +static rt_varea_t _create_varea(const size_t size) +{ + rt_varea_t varea; + void *vaddr = rt_ioremap_start; + + varea = rt_malloc(sizeof(*varea)); + uassert_true(!!varea); + uassert_true(!rt_aspace_map_static(&rt_kernel_space, varea, &vaddr, size, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0)); + varea->flag &= ~MMF_STATIC_ALLOC; + uassert_true(!!vaddr); + return varea; +} + +static void test_varea_map_page(void) +{ + /** + * @brief rt_varea_map_page + * Requirements: complete the page table entry + */ + const size_t buf_sz = 4 * ARCH_PAGE_SIZE; + rt_varea_t varea = _create_varea(buf_sz); + for (size_t i = 0; i < buf_sz; i += ARCH_PAGE_SIZE) + { + void *page = rt_pages_alloc(0); + uassert_true(!!page); + uassert_true(!rt_varea_map_page(varea, varea->start + i, page)); + uassert_true(rt_kmem_v2p(varea->start + i) == (page + PV_OFFSET)); + + /* let page manager handle the free of page */ + rt_varea_pgmgr_insert(varea, page); + uassert_true(rt_kmem_v2p(varea->start + i) == (page + PV_OFFSET)); + } + + uassert_true(!rt_aspace_unmap(&rt_kernel_space, varea->start)); +} + +static void test_varea_map_range(void) +{ + /** + * @brief rt_varea_map_range + * Requirements: complete the page table entry + */ + const size_t buf_sz = 4 * ARCH_PAGE_SIZE; + rt_varea_t varea = _create_varea(buf_sz); + void *page = rt_pages_alloc(rt_page_bits(buf_sz)); + uassert_true(!!page); + uassert_true(!rt_varea_map_range(varea, varea->start, page + PV_OFFSET, buf_sz)); + for (size_t i = 0; i < buf_sz; i += ARCH_PAGE_SIZE) + { + uassert_true(rt_kmem_v2p(varea->start + i) == (page + i + PV_OFFSET)); + } + + uassert_true(rt_pages_free(page, rt_page_bits(buf_sz))); + uassert_true(!rt_aspace_unmap(&rt_kernel_space, varea->start)); +} + +/** + * @brief rt_varea_unmap_page + * Requirements: cancel the page table entry + */ +static void test_varea_unmap_page(void) +{ + /* Prepare environment */ + const size_t buf_sz = 4 * ARCH_PAGE_SIZE; + rt_varea_t varea = _create_varea(buf_sz); + for (size_t i = 0; i < buf_sz; i += ARCH_PAGE_SIZE) + { + void *page = rt_pages_alloc(0); + uassert_true(!!page); + uassert_true(!rt_varea_map_page(varea, varea->start + i, page)); + + /* let page manager handle the free of page */ + rt_varea_pgmgr_insert(varea, page); + uassert_true(rt_kmem_v2p(varea->start + i) == (page + PV_OFFSET)); + } + + /* test if unmap is success */ + for (size_t i = 0; i < buf_sz; i += ARCH_PAGE_SIZE) + { + uassert_true(rt_varea_unmap_page(varea, varea->start + i) == RT_EOK); + uassert_true(rt_kmem_v2p(varea->start + i) == ARCH_MAP_FAILED); + } + + uassert_true(!rt_aspace_unmap(&rt_kernel_space, varea->start)); +} + +/** + * @brief rt_varea_map_range + * Requirements: complete the page table entry + */ +static void test_varea_unmap_range(void) +{ + const size_t buf_sz = 4 * ARCH_PAGE_SIZE; + rt_varea_t varea = _create_varea(buf_sz); + void *page = rt_pages_alloc(rt_page_bits(buf_sz)); + uassert_true(!!page); + uassert_true(!rt_varea_map_range(varea, varea->start, page + PV_OFFSET, buf_sz)); + for (size_t i = 0; i < buf_sz; i += ARCH_PAGE_SIZE) + { + uassert_true(rt_kmem_v2p(varea->start + i) == (page + i + PV_OFFSET)); + } + + /* test if unmap is success */ + uassert_true(rt_varea_unmap_range(varea, varea->start, buf_sz) == RT_EOK); + for (size_t i = 0; i < buf_sz; i += ARCH_PAGE_SIZE) + { + uassert_true(rt_kmem_v2p(varea->start + i) == ARCH_MAP_FAILED); + } + + uassert_true(rt_pages_free(page, rt_page_bits(buf_sz))); + uassert_true(!rt_aspace_unmap(&rt_kernel_space, varea->start)); +} + +static void varea_map_tc(void) +{ + CONSIST_HEAP(test_varea_map_page()); + CONSIST_HEAP(test_varea_map_range()); + CONSIST_HEAP(test_varea_unmap_page()); + CONSIST_HEAP(test_varea_unmap_range()); +} + +static void aspace_traversal_tc(void) +{ + /** + * @brief Requirement + * Iterate over each varea in the kernel space + */ + CONSIST_HEAP(aspace_delete_tc()); + uassert_true(4 == _count); +} + +#ifdef ARCH_ARMV8 +static void aspace_control_tc(void) +{ + /* this case is designed only for one page size */ + const size_t buf_sz = ARCH_PAGE_SIZE; + void *vaddr = RT_NULL; + volatile char *remap_nocache; + int platform_cache_probe; + uassert_true(!rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, MMF_PREFETCH, &rt_mm_dummy_mapper, 0)); + uassert_true(!!vaddr); + + /* map non-cacheable region to verify cache */ + remap_nocache = rt_ioremap(rt_kmem_v2p(vaddr), buf_sz); + uassert_true(!!remap_nocache); + + /* pre probing */ + rt_memset(vaddr, 0xba, buf_sz); + /* no need to sync transaction on same core */ + platform_cache_probe = memtest(remap_nocache, 0xab, buf_sz); + + if (!platform_cache_probe) + { + LOG_I("Cannot distinguish cache attribution on current platform"); + } + else + { + LOG_I("Ready to verify attribution of cached & non-cacheable"); + } + + /* verify cache */ + uassert_true(!rt_aspace_control(&rt_kernel_space, vaddr, MMU_CNTL_NONCACHE)); + rt_memset(vaddr, 0, buf_sz); + uassert_true(!memtest(remap_nocache, 0, buf_sz)); + + /* another option as MMU_CNTL_CACHE */ + uassert_true(!rt_aspace_control(&rt_kernel_space, vaddr, MMU_CNTL_CACHE)); + + rt_iounmap(remap_nocache); + uassert_true(!rt_aspace_unmap(&rt_kernel_space, vaddr)); +} +#endif + +static void aspace_tc(void) +{ + UTEST_UNIT_RUN(aspace_create_tc); + UTEST_UNIT_RUN(aspace_delete_tc); + UTEST_UNIT_RUN(aspace_map_tc); + UTEST_UNIT_RUN(aspace_traversal_tc); +#ifdef ARCH_ARMV8 + UTEST_UNIT_RUN(aspace_control_tc); +#endif + UTEST_UNIT_RUN(varea_map_tc); + + /* functionality */ + UTEST_UNIT_RUN(synchronization_tc); + return ; +} + +#endif /* __TEST_ASPACE_API_H__ */ diff --git a/components/mm/utest/test_aspace_api_internal.h b/components/mm/utest/test_aspace_api_internal.h new file mode 100644 index 0000000000..953424f07c --- /dev/null +++ b/components/mm/utest/test_aspace_api_internal.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-03-23 WangXiaoyao Complete testcase for internal APIs + */ +#ifndef __TEST_ASPACE_API_INTERNAL_H__ +#define __TEST_ASPACE_API_INTERNAL_H__ + +#include "common.h" +#include "mmu.h" +#include "test_bst_adpt.h" +#include + +/** + * @brief 3 cases for find free: + * with prefer & MAP_FIXED + * with prefer + * without prefer + * + * the requirement of find free: + * it will return a subset in address space that is free + * the subset contains `length` contiguous elements + * the alignment is satisfied + */ +static void test_find_free(void) +{ + void *top_page = rt_kernel_space.start + rt_kernel_space.size - 0x1000; + void *vaddr = top_page; + + CONSIST_HEAP({ + /* type 1, on success */ + uassert_true(!rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, MMF_MAP_FIXED, &rt_mm_dummy_mapper, 0)); + uassert_true(vaddr == top_page); + /* type 1, on failure */ + // uassert_true(rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, MMF_MAP_FIXED, &rt_mm_dummy_mapper, 0)); + // uassert_true(!vaddr); + + /* type 2, on success */ + vaddr = top_page; + uassert_true(!rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0)); + uassert_true(vaddr < top_page); + uassert_true(!!vaddr); + rt_aspace_unmap(&rt_kernel_space, vaddr); + /* type 2, on failure */ + vaddr = rt_kernel_space.start; + uassert_true(-RT_ENOSPC == rt_aspace_map(&rt_kernel_space, &vaddr, rt_kernel_space.size - 0x08000000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0)); + uassert_true(!vaddr); + + /* type 3, on success is covered by ioremap */ + /* type 3, on failure */ + size_t map_size = ARCH_PAGE_SIZE; + while (1) + { + void *va = rt_ioremap(0, map_size); + if (va) + { + uassert_true(1); + rt_iounmap(va); + map_size <<= 1; + } + else + { + uassert_true(1); + break; + } + } + + /* free top page */ + rt_aspace_unmap(&rt_kernel_space, top_page); + }); + + /* test mm_private.h */ + CONSIST_HEAP(test_bst_adpt()); +} + +#endif /* __TEST_ASPACE_API_INTERNAL_H__ */ diff --git a/components/mm/utest/test_bst_adpt.h b/components/mm/utest/test_bst_adpt.h new file mode 100644 index 0000000000..e081a754bb --- /dev/null +++ b/components/mm/utest/test_bst_adpt.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-03-23 WangXiaoyao Complete testcase for internal APIs + */ +#ifndef __TEST_BST_ADPT_H__ +#define __TEST_BST_ADPT_H__ + +#include "common.h" + +#ifdef RT_USING_SMART +#include "lwp_user_mm.h" +#include "mm_aspace.h" +#include "mm_flag.h" +#include +#include + +void test_bst_adpt(void) +{ + size_t flags = MMF_MAP_FIXED; + void *target_va = (void *)USER_VADDR_START + 0x3000; + size_t map_size = 0x1000; + void *prev_va = target_va - map_size; + void *next_va = target_va + map_size + 1; + struct rt_lwp *lwp; + rt_aspace_t aspace; + rt_mem_obj_t mem_obj; + + /* create aspace by lwp */ + lwp = lwp_create(LWP_CREATE_FLAG_NONE); + uassert_true(!!lwp); + uassert_true(!lwp_user_space_init(lwp, 0)); + aspace = lwp->aspace; + mem_obj = &rt_mm_dummy_mapper; + uassert_true(!!aspace); + uassert_true(!!mem_obj); + + /* _aspace_bst_search not cover */ + uassert_true(!_aspace_bst_search(aspace, target_va)); // ret == NULL + + uassert_true( + !rt_aspace_map(aspace, &target_va, map_size, MMU_MAP_K_RWCB, flags, mem_obj, 0)); + /* 2 wrappers */ + uassert_true( + !rt_aspace_map(aspace, &prev_va, map_size, MMU_MAP_K_RWCB, flags, mem_obj, 0)); + uassert_true( + !rt_aspace_map(aspace, &next_va, map_size, MMU_MAP_K_RWCB, flags, mem_obj, 0)); + + /* _aspace_bst_search */ + uassert_true(!!_aspace_bst_search(aspace, target_va)); + uassert_true(!_aspace_bst_search(aspace, target_va + map_size)); + uassert_true(!_aspace_bst_search(aspace, target_va - 1)); + + /** + * @brief _aspace_bst_search_exceed + * for given map [start, end] + */ + rt_varea_t find; + find = _aspace_bst_search_exceed(aspace, target_va); + uassert_true(!!find); + uassert_true(find->start == target_va); + + rt_varea_t last = ASPACE_VAREA_LAST(aspace); + find = _aspace_bst_search_exceed(aspace, last->start + 1); + uassert_true(!find); + + /** + * @brief _aspace_bst_search_overlap + * for given map [start, end], five types of overlapping + */ + /* 1. all below */ + struct _mm_range range = {.start = prev_va - 2, .end = prev_va - 1}; + find = _aspace_bst_search_overlap(aspace, range); + uassert_true(!find); + /* 2. start below */ + range.end = prev_va; + find = _aspace_bst_search_overlap(aspace, range); + uassert_true(!!find); + uassert_true(find->start == prev_va); + /* 3. all wrapped */ + range.start = prev_va; + range.end = prev_va + 1; + find = _aspace_bst_search_overlap(aspace, range); + uassert_true(!!find); + uassert_true(find->start == prev_va); + /* 4. end exceed */ + range.start = next_va; + range.end = next_va + map_size + 1; + find = _aspace_bst_search_overlap(aspace, range); + uassert_true(!!find); + uassert_true(find->start == next_va); + /* 5. all exceed */ + range.start = next_va + map_size; + find = _aspace_bst_search_overlap(aspace, range); + uassert_true(!find); + + lwp_ref_dec(lwp); +} + +#endif /* RT_USING_SMART */ + +#endif /* __TEST_BST_ADPT_H__ */ diff --git a/components/mm/utest/test_cache_aarch64.h b/components/mm/utest/test_cache_aarch64.h new file mode 100644 index 0000000000..b103eda213 --- /dev/null +++ b/components/mm/utest/test_cache_aarch64.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-03-17 WangXiaoyao cache API unit test + */ +#ifndef __TEST_CACHE_AARCH64_H__ +#define __TEST_CACHE_AARCH64_H__ + +#include "common.h" +#include + +const char *platform_cache_not_guarantee = "Cannot guarantee cache operation works"; + +/** + * ============================================================== + * TEST FEATURE + * API under cache.h + * + * void rt_hw_icache_invalidate_range(unsigned long start_addr, int size); + * void rt_hw_cpu_icache_invalidate(void *addr, rt_size_t size); + * void rt_hw_cpu_dcache_clean_and_invalidate(void *addr, rt_size_t size); + * ============================================================== + */ + +static int _get1_const(void) +{ + return 1; +} + +static int _get1(void) +{ + return 1; +} + +static int _get2(void) +{ + return 2; +} + +/* hot patching codes and test if the value can be seen by icache */ +static void _test_icache_invalidate_range(void) +{ + /* reset _get1 */ + rt_memcpy(_get1, _get1_const, _get2 - _get1); + rt_hw_cpu_dcache_clean(_get1, _get2 - _get1); + rt_hw_cpu_icache_invalidate(_get1, _get2 - _get1); + uassert_true(1 == _get1()); + + /* now copy _get2 to _get1 */ + rt_memcpy(_get1, _get2, _get2 - _get1); + if (1 != _get1()) + LOG_W(platform_cache_not_guarantee); + + rt_hw_cpu_dcache_clean(_get1, _get2 - _get1); + rt_hw_cpu_icache_invalidate(_get1, _get2 - _get1); + __asm__ volatile("isb"); + uassert_true(2 == _get1()); + LOG_I("%s ok", __func__); +} + +/* due to hardware feature of cortex-a, we should done this on 2 separated cpu */ +static void _test_dcache_clean_and_invalidate(void) +{ + const size_t padding = 1024 * 2; + const size_t buf_sz = ARCH_PAGE_SIZE * 2; + volatile char *remap_nocache; + char *page = rt_pages_alloc(rt_page_bits(buf_sz)); + uassert_true(!!page); + + rt_memset(page, 0xab, buf_sz); + rt_hw_cpu_dcache_invalidate(page, buf_sz); + + int _outdate_flag = 0; + if (memtest(page, 0xab, buf_sz)) + _outdate_flag = 1; + + /* after ioremap, we can access system memory to verify outcome */ + remap_nocache = rt_ioremap(page + PV_OFFSET, buf_sz); + + rt_hw_cpu_dcache_clean(page + padding, ARCH_PAGE_SIZE); + memtest(remap_nocache + padding, 0xab, ARCH_PAGE_SIZE); + + if (!_outdate_flag) + LOG_W(platform_cache_not_guarantee); + else + LOG_I("%s ok", __func__); + + rt_pages_free(page, 0); + rt_iounmap(remap_nocache); +} + +static rt_err_t utest_tc_init(void) +{ + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + return RT_EOK; +} + +static void testcase(void) +{ + /* todo: format API under cache.h first */ + UTEST_UNIT_RUN(_test_icache_invalidate_range); + UTEST_UNIT_RUN(_test_dcache_clean_and_invalidate); +} + +UTEST_TC_EXPORT(testcase, "testcases.libcpu.cache", utest_tc_init, utest_tc_cleanup, 10); + +#endif /* __TEST_CACHE_AARCH64_H__ */ diff --git a/components/mm/utest/test_cache_rv64.h b/components/mm/utest/test_cache_rv64.h new file mode 100644 index 0000000000..3bd7fc26eb --- /dev/null +++ b/components/mm/utest/test_cache_rv64.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-03-17 WangXiaoyao cache API unit test + */ + +#ifndef __TEST_CACHE_RV64_H +#define __TEST_CACHE_RV64_H + +#ifdef ARCH_RISCV64 +#include "riscv_mmu.h" +#include +#include +#include +#include +#include + +/** + * ============================================================== + * TEST FEATURE + * API under cache.h + * rt_hw_sync_cache_local + * + * rt_hw_cpu_dcache_clean + * rt_hw_cpu_dcache_invalidate + * rt_hw_cpu_dcache_clean_invalidate + * rt_hw_cpu_dcache_clean_all + * rt_hw_cpu_dcache_invalidate_all // meaningless + * rt_hw_cpu_dcache_clean_invalidate_all + * rt_hw_cpu_icache_invalidate + * rt_hw_cpu_icache_invalidate_all + * ============================================================== + */ + +/* Ensure the ISA is valid for target ARCHITECTURE */ +static void _illegal_instr(void) +{ + rt_hw_sync_cache_local(_illegal_instr, 64); + rt_hw_cpu_dcache_clean(_illegal_instr, 64); + rt_hw_cpu_dcache_invalidate(_illegal_instr, 64); + // rt_hw_cpu_dcache_clean_invalidate(_illegal_instr, 64); // C908 ONLY + rt_hw_cpu_dcache_clean_all(); + rt_hw_cpu_dcache_invalidate_all(); // !CAREFUL must be inline + // rt_hw_cpu_dcache_clean_invalidate_all(); // C908 ONLY + rt_hw_cpu_icache_invalidate(_illegal_instr, 64); + rt_hw_cpu_icache_invalidate_all(); + uassert_true(1); + LOG_I("All ok!"); +} + +static int _get1(void) +{ + return 1; +} + +static int _get2(void) +{ + return 2; +} + +/* hot patching codes and test if the value can be seen by icache */ +static void _test_cache_sync(void) +{ + uassert_true(1 == _get1()); + rt_memcpy(_get1, _get2, _get2 - _get1); + uassert_true(1 == _get1()); + rt_hw_sync_cache_local(_get1, _get2 - _get1); + uassert_true(2 == _get1()); + LOG_I("%s ok", __func__); +} + +/* test clean operation should do and only effect the range specified by writing to a page */ +static void _test_dcache_clean(void) +{ + const size_t padding = 1024 * 3; + const size_t buf_sz = ARCH_PAGE_SIZE * 2; + + char *page = rt_pages_alloc(rt_page_bits(buf_sz)); + uassert_true(!!page); + + /* after ioremap, we can access system memory to verify outcome */ + volatile char *remap_nocache = rt_ioremap(page + PV_OFFSET, buf_sz); + rt_memset(page, 0xab, buf_sz); + rt_hw_cpu_sync(); + + int _outdate_flag = 0; + for (size_t i = padding; i < ARCH_PAGE_SIZE; i++) + { + if (remap_nocache[i] != 0xab) + { + _outdate_flag = 1; + break; + } + } + + page[padding - 1] = 0xac; + page[padding + ARCH_PAGE_SIZE] = 0xac; + rt_hw_cpu_dcache_clean(page + padding, ARCH_PAGE_SIZE); + + /* free some space in dcache to avoid padding data being written back */ + rt_hw_cpu_dcache_invalidate(page + padding, ARCH_PAGE_SIZE); + uassert_true(remap_nocache[padding - 1] != 0xac); + uassert_true(remap_nocache[padding + ARCH_PAGE_SIZE] != 0xac); + + int _test_ok = 1; + for (size_t i = padding; i < ARCH_PAGE_SIZE; i++) + { + if (remap_nocache[i] != 0xab) + { + _test_ok = 0; + break; + } + } + uassert_true(_test_ok); + + if (!_outdate_flag) + LOG_W("Cannot guarantee clean works"); + else + LOG_I("%s ok", __func__); + + rt_pages_free(page, 0); + rt_iounmap(remap_nocache); +} + +/* test clean op should do and only effect the range */ +static void _test_dcache_invalidate(void) +{ + const size_t padding = 1024 * 3; + const size_t buf_sz = ARCH_PAGE_SIZE * 2; + + /* prepare */ + char *page = rt_pages_alloc(rt_page_bits(buf_sz)); + uassert_true(!!page); + + volatile char *remap_nocache = rt_ioremap(page + PV_OFFSET, buf_sz); + rt_memset(page, 0x0, buf_sz); + rt_hw_cpu_sync(); + + int _outdate_flag = 0; + for (size_t i = padding; i < ARCH_PAGE_SIZE; i++) + { + remap_nocache[i] = 0xab; + rt_hw_cpu_dcache_invalidate((void *)&remap_nocache[i], 1); + } + + rt_hw_cpu_dcache_clean_all(); + + int _test_ok = 1; + for (size_t i = padding; i < ARCH_PAGE_SIZE; i++) + { + if (remap_nocache[i] == 0xab) + { + _test_ok = 0; + break; + } + } + uassert_true(_test_ok); + + LOG_I("%s ok", __func__); + + rt_pages_free(page, 0); + rt_iounmap(remap_nocache); +} + +static rt_err_t utest_tc_init(void) +{ + return RT_EOK; +} + +static rt_err_t utest_tc_cleanup(void) +{ + return RT_EOK; +} + +static void testcase(void) +{ + UTEST_UNIT_RUN(_illegal_instr); +#ifdef BOARD_allwinnerd1s + /* thead ISA extension */ + UTEST_UNIT_RUN(_test_cache_sync); + /* part of it is hard to test on simulation machine */ + UTEST_UNIT_RUN(_test_dcache_clean); + UTEST_UNIT_RUN(_test_dcache_invalidate); +#endif +} + +UTEST_TC_EXPORT(testcase, "testcases.libcpu.cache", utest_tc_init, utest_tc_cleanup, 10); + +#endif /* ARCH_RISCV64 */ +#endif /* __TEST_CACHE_RV64_H */ diff --git a/components/mm/utest/test_synchronization.h b/components/mm/utest/test_synchronization.h new file mode 100644 index 0000000000..7f813ec1f8 --- /dev/null +++ b/components/mm/utest/test_synchronization.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2006-2023, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2023-03-24 WangXiaoyao Complete testcase for synchronization + */ +#ifndef __TEST_SYNCHRONIZATION_H__ +#define __TEST_SYNCHRONIZATION_H__ + +#include "common.h" +#include "semaphore.h" + +#ifdef RT_USING_SMP + +#define THREAD_CNT RT_CPUS_NR +#define TEST_TIMES 2000 +#define PRIO (UTEST_THR_PRIORITY + 1) +/* size of mapping buffer */ +#define BUF_SIZE (64ul << 10) + +/* engage with sibling */ +struct rt_semaphore done; +static semaphore_t sem1[THREAD_CNT / 2]; +static semaphore_t sem2[THREAD_CNT / 2]; + +static void *map(void) +{ + int err; + int flags = MMF_PREFETCH; + size_t attr = MMU_MAP_K_RWCB; + void *vaddr = 0; + err = + rt_aspace_map(&rt_kernel_space, &vaddr, BUF_SIZE, attr, flags, &rt_mm_dummy_mapper, 0); + if (err) + uassert_true(0); + return vaddr; +} + +static void unmap(void *buf) +{ + int err; + err = + rt_aspace_unmap(&rt_kernel_space, buf); + if (err) + uassert_true(0); + return ; +} + +static void group1_entry(void *param) +{ + const size_t id = (size_t)param; + size_t test_times = TEST_TIMES; + size_t alive = test_times / 10; + void *buf; + + while (test_times--) + { + if (test_times % alive == 0) + uassert_true(1); + + buf = map(); + + memset(buf, 'A' + id, BUF_SIZE); + /* if other core write to our cache, force the changes to be visible to us */ + rt_hw_dmb(); + + if (memtest(buf, 'A' + id, BUF_SIZE)) + uassert_true(0); + + semaphore_signal(&sem1[id]); + semaphore_wait(&sem2[id]); + unmap(buf); + } + + rt_sem_release(&done); + return; +} + +static void group2_entry(void *param) +{ + const size_t id = (size_t)param; + size_t test_times = TEST_TIMES; + size_t alive = test_times / 10; + void *buf; + + while (test_times--) + { + if (test_times % alive == 0) + uassert_true(1); + + semaphore_signal(&sem2[id]); + semaphore_wait(&sem1[id]); + buf = map(); + + memset(buf, 'a' + id, BUF_SIZE); + /* if other core write to our cache, force the changes to be visible to us */ + rt_hw_dmb(); + + if (memtest(buf, 'a' + id, BUF_SIZE)) + uassert_true(0); + + unmap(buf); + } + + rt_sem_release(&done); + return; +} + +/** + * @brief On a smp system, we create at least 4 threads + * 2 doing map, 2 doing unmapping at the same moment + */ + +static void synchronization_tc(void) +{ + rt_thread_t group1[THREAD_CNT / 2]; + rt_thread_t group2[THREAD_CNT / 2]; + + rt_sem_init(&done, __func__, 0, RT_IPC_FLAG_FIFO); + + for (size_t i = 0; i < THREAD_CNT / 2; i++) + { + char name[RT_NAME_MAX]; + rt_sprintf(name, "grp1_%d", i); + group1[i] = + rt_thread_create(name, group1_entry, (void *)i, ARCH_PAGE_SIZE, PRIO, 10); + uassert_true(!!group1[i]); + semaphore_init(&sem1[i], 0); + + uassert_true(!rt_thread_startup(group1[i])); + } + + for (size_t i = 0; i < THREAD_CNT / 2; i++) + { + char name[RT_NAME_MAX]; + rt_sprintf(name, "grp2_%d", i); + group2[i] = + rt_thread_create(name, group2_entry, (void *)i, ARCH_PAGE_SIZE, PRIO, 10); + uassert_true(!!group2[i]); + semaphore_init(&sem2[i], 0); + + uassert_true(!rt_thread_startup(group2[i])); + } + + /* wait all thread exit */ + for (size_t i = 0; i < (THREAD_CNT / 2 * 2); i++) + { + rt_sem_take(&done, RT_WAITING_FOREVER); + } + LOG_I("all threads exit"); + rt_sem_detach(&done); +} + +#else /* RT_USING_SMP */ + +static void synchronization_tc(void) +{ + uassert_true(1); +} +#endif /* RT_USING_SMP */ + +#endif /* __TEST_SYNCHRONIZATION_H__ */ diff --git a/examples/utest/testcases/mm/Kconfig b/examples/utest/testcases/mm/Kconfig deleted file mode 100644 index 434df5b934..0000000000 --- a/examples/utest/testcases/mm/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -menu "Memory Management Subsytem Testcase" - - config RT_UTEST_MM_API - bool "Enable Utest for MM API" - default n - help - The test covers the Memory Management APIs under the - `components/mm` and `libcpu/[mmu.*|tlb.*|cache.*]` - - config RT_UTEST_MM_LWP - bool "Enable Utest for MM API in lwp" - default n - help - The test covers the Memory Management APIs under the - `components/lwp`. - -endmenu diff --git a/examples/utest/testcases/mm/SConscript b/examples/utest/testcases/mm/SConscript deleted file mode 100644 index edef3914f1..0000000000 --- a/examples/utest/testcases/mm/SConscript +++ /dev/null @@ -1,25 +0,0 @@ -Import('rtconfig') -from building import * - -cwd = GetCurrentDir() -src = [] -CPPPATH = [cwd] - -if GetDepend(['RT_UTEST_MM_API', 'RT_USING_SMART']): - # deprecated test, will be rewrited in the future - # src += ['mm_api_tc.c', 'mm_libcpu_tc.c'] - src += ['rt_ioremap.c'] - src += ['aspace_unmap_range_invalid_param.c', 'aspace_unmap_range_shrink.c'] - src += ['aspace_unmap_range_split.c', 'aspace_map_expand.c'] - src += ['lwp_mmap_expand.c', 'lwp_mmap_map_fixed.c', 'lwp_mmap_fix_private.c'] - src += ['lwp_mmap_fd.c', 'lwp_mmap_fd_map_fixed_merge.c', 'lwp_mmap_fd_map_fixed_split.c'] - -if GetDepend(['RT_UTEST_MM_API', 'RT_USING_MEMBLOCK']): - src += ['mm_memblock_tc.c'] - -if GetDepend(['RT_UTEST_MM_LWP', 'RT_USING_SMART']): - src += ['mm_lwp_tc.c'] - -group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES'], CPPPATH = CPPPATH) - -Return('group') diff --git a/examples/utest/testcases/mm/aspace_map_expand.c b/examples/utest/testcases/mm/aspace_map_expand.c deleted file mode 100644 index 2fd70f1da0..0000000000 --- a/examples/utest/testcases/mm/aspace_map_expand.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-08-22 Shell test case for aspace_map with varea_expand - */ -#include "common.h" -#include "lwp_user_mm.h" -#include - -#include - -static size_t flags = MMF_PREFETCH | MMF_MAP_FIXED; -static size_t attr = MMU_MAP_K_RWCB; -static rt_mem_obj_t mem_obj = &rt_mm_dummy_mapper; - -static char *ex_vaddr = (void *)0x100000000; -static size_t ex_offset = 1024; -static size_t map_size = 0x3000; - -static size_t former_vsz; -static size_t former_vcount; - -static struct rt_lwp *lwp; - -static int _count_vsz(rt_varea_t varea, void *arg) -{ - rt_base_t *pvsz = arg; - *pvsz += 1; - return 0; -} - -static rt_base_t count_vcount(rt_aspace_t aspace) -{ - rt_base_t vcount = 0; - rt_aspace_traversal(aspace, _count_vsz, &vcount); - return vcount; -} - -static void test_map_varea_expand(void) -{ - char *next_va; - size_t next_offset; - - /* create an existed mapping */ - next_va = ex_vaddr; - former_vsz = rt_aspace_count_vsz(lwp->aspace); - former_vcount = count_vcount(lwp->aspace); - utest_int_equal( - RT_EOK, - rt_aspace_map(lwp->aspace, (void *)&ex_vaddr, map_size, attr, flags, mem_obj, ex_offset) - ); - uassert_true(next_va == ex_vaddr); - utest_int_equal(former_vsz + map_size, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); - former_vsz += map_size; - former_vcount += 1; - - /* test the RIGHT side expansion of varea by rt_aspace_map */ - next_va = ex_vaddr + map_size; - next_offset = ex_offset + (map_size >> MM_PAGE_SHIFT); - utest_int_equal( - RT_EOK, - rt_aspace_map(lwp->aspace, (void *)&next_va, map_size, attr, flags, mem_obj, next_offset) - ); - uassert_true(next_va == (char *)ex_vaddr + map_size); - utest_int_equal(former_vsz + map_size, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount, count_vcount(lwp->aspace)); - former_vsz += map_size; - - /* test the LEFT side expansion of varea by rt_aspace_map */ - next_va = ex_vaddr - map_size; - next_offset = ex_offset - (map_size >> MM_PAGE_SHIFT); - utest_int_equal( - RT_EOK, - rt_aspace_map(lwp->aspace, (void *)&next_va, map_size, attr, flags, mem_obj, next_offset) - ); - uassert_true(next_va == ex_vaddr - map_size); - utest_int_equal(former_vsz + map_size, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount, count_vcount(lwp->aspace)); - former_vsz += map_size; - - /* test the expand varea routine from rt_aspace_map_static */ - utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, next_va, 3 * map_size)); - - /* test the expand varea routine from rt_aspace_map_phy */ - /* test the expand varea routine from rt_aspace_map_phy_static */ - /* these 2 from another file */ -} - -static void aspace_map_tc(void) -{ - CONSIST_HEAP(test_map_varea_expand()); -} - -static rt_err_t utest_tc_init(void) -{ - lwp = lwp_create(0); - if (lwp) - lwp_user_space_init(lwp, 1); - else - return -RT_ENOMEM; - return RT_EOK; -} - -static rt_err_t utest_tc_cleanup(void) -{ - lwp_ref_dec(lwp); - return RT_EOK; -} - -static void testcase(void) -{ - UTEST_UNIT_RUN(aspace_map_tc); -} -UTEST_TC_EXPORT(testcase, "testcases.mm.aspace_map.varea_expand", utest_tc_init, utest_tc_cleanup, 10); diff --git a/examples/utest/testcases/mm/aspace_unmap_range_invalid_param.c b/examples/utest/testcases/mm/aspace_unmap_range_invalid_param.c deleted file mode 100644 index 1beec1aa8a..0000000000 --- a/examples/utest/testcases/mm/aspace_unmap_range_invalid_param.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-08-17 Shell test case for aspace_unmap_range - */ -#include "common.h" -#include "lwp_user_mm.h" -#include - -#include - -static void *vaddr = (void *)0x100000000; -static size_t existed_size = 0x5000; -static char *unmap_start; -static size_t unmap_size = 0x2000; -static size_t former_vsz; -static struct rt_lwp *lwp; -static size_t flags = MMF_PREFETCH | MMF_MAP_FIXED; - -static void test_unmap_range_invalid_param(void) -{ - rt_mem_obj_t notsupp_object; - - /* create an existed mapping */ - former_vsz = rt_aspace_count_vsz(lwp->aspace); - uassert_true(!rt_aspace_map(lwp->aspace, &vaddr, existed_size, MMU_MAP_K_RWCB, flags, &rt_mm_dummy_mapper, 0)); - utest_int_equal(former_vsz + existed_size, rt_aspace_count_vsz(lwp->aspace)); - former_vsz += existed_size; - - /* test unaligned vaddr start */ - unmap_start = (char *)vaddr - 0x1234; - utest_int_equal(-RT_EINVAL, rt_aspace_unmap_range(lwp->aspace, unmap_start, unmap_size)); - utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); - - /* test unaligned size */ - unmap_size = 0x2000; - unmap_start = (char *)vaddr + existed_size - unmap_size; - utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, unmap_start, unmap_size - 0x123)); - utest_int_equal(former_vsz - unmap_size, rt_aspace_count_vsz(lwp->aspace)); - - /* create another mapping binding to mem_obj without proper handler */ - notsupp_object = rt_mem_obj_create(&rt_mm_dummy_mapper); - notsupp_object->on_varea_shrink = RT_NULL; - - utest_int_equal( - RT_EOK, - rt_aspace_map(lwp->aspace, (void *)&unmap_start, unmap_size, MMU_MAP_K_RWCB, flags, notsupp_object, 0) - ); - - utest_int_equal(-RT_EPERM, rt_aspace_unmap_range(lwp->aspace, unmap_start, 0x1000)); - utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, vaddr, existed_size)); - rt_free(notsupp_object); -} - -static void aspace_unmap_tc(void) -{ - CONSIST_HEAP(test_unmap_range_invalid_param()); -} - -static rt_err_t utest_tc_init(void) -{ - lwp = lwp_create(0); - if (lwp) - lwp_user_space_init(lwp, 1); - else - return -RT_ENOMEM; - return RT_EOK; -} - -static rt_err_t utest_tc_cleanup(void) -{ - lwp_ref_dec(lwp); - return RT_EOK; -} - -static void testcase(void) -{ - UTEST_UNIT_RUN(aspace_unmap_tc); -} -UTEST_TC_EXPORT(testcase, "testcases.mm.aspace_unmap_range.invalid_param", utest_tc_init, utest_tc_cleanup, 10); diff --git a/examples/utest/testcases/mm/aspace_unmap_range_shrink.c b/examples/utest/testcases/mm/aspace_unmap_range_shrink.c deleted file mode 100644 index de52572d52..0000000000 --- a/examples/utest/testcases/mm/aspace_unmap_range_shrink.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-08-17 Shell test case for aspace_unmap_range - */ -#include "common.h" -#include "lwp_user_mm.h" -#include - -#include - -static void *vaddr = (void *)0x100000000; -static size_t existed_size = 0x5000; -static char *unmap_start; -static char *unmap_end; -static size_t former_vsz; -static size_t unmap_size = 0x2000; -static struct rt_lwp *lwp; - -static void test_unmap_range_shrink(void) -{ - /* create an existed mapping */ - former_vsz = rt_aspace_count_vsz(lwp->aspace); - uassert_true(!rt_aspace_map(lwp->aspace, &vaddr, existed_size, MMU_MAP_K_RWCB, MMF_PREFETCH, &rt_mm_dummy_mapper, 0)); - utest_int_equal(former_vsz + existed_size, rt_aspace_count_vsz(lwp->aspace)); - former_vsz += existed_size; - - /* test the shrink mode of unmap from LEFT side */ - unmap_start = (char *)vaddr - unmap_size/2; - uassert_true(!rt_aspace_unmap_range(lwp->aspace, unmap_start, unmap_size)); - unmap_end = unmap_start + unmap_size; - uassert_true(rt_hw_mmu_v2p(lwp->aspace, unmap_end) != ARCH_MAP_FAILED); - utest_int_equal(former_vsz - (unmap_end - (char *)vaddr), rt_aspace_count_vsz(lwp->aspace)); - former_vsz -= unmap_end - (char *)vaddr; - - /* test the shrink mode of unmap from RIGHT side */ - unmap_start = (char *)vaddr + existed_size - unmap_size / 2; - uassert_true(!rt_aspace_unmap_range(lwp->aspace, unmap_start, unmap_size)); - uassert_true(rt_hw_mmu_v2p(lwp->aspace, unmap_start - 1) != ARCH_MAP_FAILED); - utest_int_equal(former_vsz - (unmap_end - (char *)vaddr), rt_aspace_count_vsz(lwp->aspace)); - former_vsz -= unmap_end - (char *)vaddr; - - utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, vaddr, existed_size)); -} - -static void aspace_unmap_tc(void) -{ - CONSIST_HEAP(test_unmap_range_shrink()); -} - -static rt_err_t utest_tc_init(void) -{ - lwp = lwp_create(0); - if (lwp) - lwp_user_space_init(lwp, 1); - else - return -RT_ENOMEM; - return RT_EOK; -} - -static rt_err_t utest_tc_cleanup(void) -{ - lwp_ref_dec(lwp); - return RT_EOK; -} - -static void testcase(void) -{ - UTEST_UNIT_RUN(aspace_unmap_tc); -} -UTEST_TC_EXPORT(testcase, "testcases.mm.aspace_unmap_range.shrink", utest_tc_init, utest_tc_cleanup, 10); diff --git a/examples/utest/testcases/mm/aspace_unmap_range_split.c b/examples/utest/testcases/mm/aspace_unmap_range_split.c deleted file mode 100644 index 07489df693..0000000000 --- a/examples/utest/testcases/mm/aspace_unmap_range_split.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-08-17 Shell test case for aspace_unmap_range - */ -#include "common.h" -#include "lwp_user_mm.h" -#include - -#include - -static void *vaddr = (void *)0x100000000; -static size_t existed_size = 0x5000; -static char *unmap_start = (char *)0x100000000 + 0x3000; -static size_t former_vsz; -static size_t unmap_size = 0x1000; -static struct rt_lwp *lwp; - -static void test_unmap_range_split(void) -{ - /* create an existed mapping */ - former_vsz = rt_aspace_count_vsz(lwp->aspace); - uassert_true(!rt_aspace_map(lwp->aspace, &vaddr, existed_size, MMU_MAP_K_RWCB, MMF_PREFETCH, &rt_mm_dummy_mapper, 0)); - utest_int_equal(former_vsz + existed_size, rt_aspace_count_vsz(lwp->aspace)); - former_vsz += existed_size; - - /* test the split mode of unmap */ - utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, unmap_start, unmap_size)); - uassert_true(rt_hw_mmu_v2p(lwp->aspace, unmap_start - 1) != ARCH_MAP_FAILED); - uassert_true(rt_hw_mmu_v2p(lwp->aspace, unmap_start + unmap_size) != ARCH_MAP_FAILED); - utest_int_equal(former_vsz - unmap_size, rt_aspace_count_vsz(lwp->aspace)); - - utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, vaddr, existed_size)); -} - -static void aspace_unmap_tc(void) -{ - CONSIST_HEAP(test_unmap_range_split()); -} - -static rt_err_t utest_tc_init(void) -{ - lwp = lwp_create(0); - if (lwp) - lwp_user_space_init(lwp, 1); - else - return -RT_ENOMEM; - return RT_EOK; -} - -static rt_err_t utest_tc_cleanup(void) -{ - lwp_ref_dec(lwp); - return RT_EOK; -} - -static void testcase(void) -{ - UTEST_UNIT_RUN(aspace_unmap_tc); -} -UTEST_TC_EXPORT(testcase, "testcases.mm.aspace_unmap_range.split", utest_tc_init, utest_tc_cleanup, 10); diff --git a/examples/utest/testcases/mm/common.h b/examples/utest/testcases/mm/common.h deleted file mode 100644 index 3255e166ca..0000000000 --- a/examples/utest/testcases/mm/common.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-03-20 WangXiaoyao Complete testcase for mm_aspace.c - */ -#ifndef __TEST_MM_COMMON_H__ -#define __TEST_MM_COMMON_H__ - -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - -#ifdef RT_USING_SMART -#include -#endif - -#include -#include -#include -#include -#include - -extern rt_base_t rt_heap_lock(void); -extern void rt_heap_unlock(rt_base_t level); - -#define __int_compare(a, b, operator) do{long _a = (long)(a); long _b = (long)(b); __utest_assert((_a) operator (_b), "Assertion Failed: (" #a ") "#operator" (" #b ")"); if (!((_a) operator (_b)))LOG_E("\t"#a"=%ld(0x%lx), "#b"=%ld(0x%lx)", _a, _a, _b, _b);} while (0) -#define utest_int_equal(a, b) __int_compare(a, b, ==) -#define utest_int_less(a, b) __int_compare(a, b, <) -#define utest_int_less_equal(a, b) __int_compare(a, b, <=) - -/** - * @brief During the operations, is heap still the same; - */ -#define CONSIST_HEAP(statement) do { \ - rt_size_t total, used, max_used; \ - rt_size_t totala, useda, max_useda; \ - rt_ubase_t level = rt_heap_lock(); \ - rt_memory_info(&total, &used, &max_used); \ - statement; \ - rt_memory_info(&totala, &useda, &max_useda); \ - rt_heap_unlock(level); \ - utest_int_equal(total, totala); \ - utest_int_equal(used, useda); \ - } while (0) - -#ifdef STANDALONE_TC -#define TC_ASSERT(expr) \ - ((expr) \ - ? 0 \ - : rt_kprintf("AssertFault(%d): %s\n", __LINE__, RT_STRINGIFY(expr))) -#else -#define TC_ASSERT(expr) uassert_true(expr) -#endif - -rt_inline int memtest(volatile char *buf, int value, size_t buf_sz) -{ - int ret = 0; - for (size_t i = 0; i < buf_sz; i++) - { - if (buf[i] != value) - { - ret = -1; - break; - } - } - return ret; -} - -#endif /* __TEST_MM_COMMON_H__ */ diff --git a/examples/utest/testcases/mm/lwp_mmap_expand.c b/examples/utest/testcases/mm/lwp_mmap_expand.c deleted file mode 100644 index ee54f150fa..0000000000 --- a/examples/utest/testcases/mm/lwp_mmap_expand.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-08-22 Shell test case for aspace_map with varea_expand - */ -#include "common.h" -#include "lwp_user_mm.h" -#include - -#include - -static long fd = -1; -static long pgoffset = 0; -static size_t flags = MAP_FIXED | MAP_ANONYMOUS; -static size_t prot1 = PROT_READ | PROT_WRITE; - -static char *ex_vaddr = (void *)0x100000000; -static size_t map_size = 0x3000; - -static size_t former_vsz; -static size_t former_vcount; - -static struct rt_lwp *lwp; - -static int _count_vsz(rt_varea_t varea, void *arg) -{ - rt_base_t *pvsz = arg; - *pvsz += 1; - return 0; -} - -static rt_base_t count_vcount(rt_aspace_t aspace) -{ - rt_base_t vcount = 0; - rt_aspace_traversal(aspace, _count_vsz, &vcount); - return vcount; -} - -static void test_mmap_expand(void) -{ - char *next_va; - - /* map new pages at ex_vaddr to anonymous */ - next_va = ex_vaddr; - former_vsz = rt_aspace_count_vsz(lwp->aspace); - former_vcount = count_vcount(lwp->aspace); - next_va = lwp_mmap2(lwp, next_va, map_size, prot1, flags, fd, pgoffset); - uassert_true(next_va == ex_vaddr); - utest_int_equal(former_vsz + map_size, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); - former_vsz += map_size; - former_vcount += 1; - - /* test the RIGHT side expansion of varea by lwp_mmap2 */ - next_va = ex_vaddr + map_size; - uassert_true( - lwp_mmap2(lwp, next_va, map_size, prot1, flags, fd, pgoffset) - == next_va - ); - utest_int_equal(former_vsz + map_size, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount, count_vcount(lwp->aspace)); - former_vsz += map_size; - - /* test the LEFT side expansion of varea by rt_aspace_map */ - next_va = ex_vaddr - map_size; - uassert_true( - lwp_mmap2(lwp, next_va, map_size, prot1, flags, fd, pgoffset) - == next_va - ); - utest_int_equal(former_vsz + map_size, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount, count_vcount(lwp->aspace)); - former_vsz += map_size; - - /* test other prot/offset/flags */ - - /* clear mapping */ - utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, next_va, 3 * map_size)); -} - -static void aspace_map_tc(void) -{ - CONSIST_HEAP(test_mmap_expand()); -} - -static rt_err_t utest_tc_init(void) -{ - lwp = lwp_create(0); - if (lwp) - lwp_user_space_init(lwp, 1); - else - return -RT_ENOMEM; - return RT_EOK; -} - -static rt_err_t utest_tc_cleanup(void) -{ - lwp_ref_dec(lwp); - return RT_EOK; -} - -static void testcase(void) -{ - UTEST_UNIT_RUN(aspace_map_tc); -} -UTEST_TC_EXPORT(testcase, "testcases.lwp.mman.mmap_anon.expand", utest_tc_init, utest_tc_cleanup, 10); diff --git a/examples/utest/testcases/mm/lwp_mmap_fd.c b/examples/utest/testcases/mm/lwp_mmap_fd.c deleted file mode 100644 index da2e4f8edf..0000000000 --- a/examples/utest/testcases/mm/lwp_mmap_fd.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-08-17 Shell test case for aspace_map(MAP_FIXED) - */ -#include "common.h" -#include "lwp_user_mm.h" -#include "utest_assert.h" -#include - -#include - -#define PAGE_SZ (1 << MM_PAGE_SHIFT) -#define PAGE_COUNT ('z' - 'a' + 1) -#define FILE_PATH "/test_mmap" -#define FILE_SZ (PAGE_COUNT * PAGE_SZ) - -static struct rt_lwp *lwp; -static size_t former_vsz; -static size_t former_vcount; -static char page_sz_buf[PAGE_SZ]; - -static void *vaddr = (void *)0x100000000; -static long pgoffset = 0; -static size_t ex_prot = PROT_NONE; -static size_t ex_flags = MAP_PRIVATE | MAP_ANONYMOUS; - -static int _count_vsz(rt_varea_t varea, void *arg) -{ - rt_base_t *pvsz = arg; - *pvsz += 1; - return 0; -} - -static rt_base_t count_vcount(rt_aspace_t aspace) -{ - rt_base_t vcount = 0; - rt_aspace_traversal(aspace, _count_vsz, &vcount); - return vcount; -} - -static rt_err_t _lwp_get_user(struct rt_lwp *lwp, char *vaddr, char *buffer) -{ - rt_varea_t varea = _aspace_bst_search(lwp->aspace, vaddr); - if (varea && varea->mem_obj && varea->mem_obj->page_read) - { - struct rt_aspace_io_msg io_msg; - rt_mm_io_msg_init(&io_msg, MM_PA_TO_OFF(vaddr), vaddr, buffer); - varea->mem_obj->page_read(varea, &io_msg); - } - return RT_EOK; -} - -static void _verify_file_content(const char *mmap_buf) -{ - char ch = 'a'; - for (char *read_va = (char *)mmap_buf; read_va < mmap_buf + FILE_SZ; read_va += PAGE_SZ, ch++) - { - _lwp_get_user(lwp, read_va, page_sz_buf); - utest_int_equal(RT_EOK, memtest(page_sz_buf, ch, PAGE_SZ)); - } -} - -static void test_mmap_fd(void) -{ - former_vsz = rt_aspace_count_vsz(lwp->aspace); - former_vcount = count_vcount(lwp->aspace); - - /* create an existed mapping */ - long temp_fd; - temp_fd = open(FILE_PATH, O_RDONLY); - LOG_D("New fd=%ld path=%s", temp_fd, FILE_PATH); - uassert_true(temp_fd >= 0); - utest_int_equal( - lwp_mmap2(lwp, vaddr, FILE_SZ, ex_prot, ex_flags, temp_fd, pgoffset), - vaddr); - close(temp_fd); - - utest_int_equal(former_vsz + FILE_SZ, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); - - _verify_file_content(vaddr); - - /* create an override mapping */ - - /* close */ - - utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, vaddr, FILE_SZ)); -} - -static void testcase_main(void) -{ - test_mmap_fd(); -} - -static void _setup_file_content(long fd) -{ - char ch = 'a'; - - for (size_t i = 0; i < PAGE_COUNT; i++, ch++) - { - memset(page_sz_buf, ch, PAGE_SZ); - write(fd, page_sz_buf, PAGE_SZ); - } -} - -static rt_err_t utest_tc_init(void) -{ - /* setup file */ - long temp_file_des; - temp_file_des = open(FILE_PATH, O_RDWR | O_CREAT, 0777); - LOG_D("New fd=%ld path=%s", temp_file_des, FILE_PATH); - if (temp_file_des < 0) - return -RT_ERROR; - _setup_file_content(temp_file_des); - close(temp_file_des); - - lwp = lwp_create(0); - if (lwp) - lwp_user_space_init(lwp, 1); - else - return -RT_ENOMEM; - return RT_EOK; -} - -static rt_err_t utest_tc_cleanup(void) -{ - lwp_ref_dec(lwp); - return RT_EOK; -} - -static void testcase(void) -{ - UTEST_UNIT_RUN(testcase_main); -} -UTEST_TC_EXPORT(testcase, "testcases.lwp.mman.mmap_fd.basic", utest_tc_init, utest_tc_cleanup, 10); diff --git a/examples/utest/testcases/mm/lwp_mmap_fd_map_fixed_merge.c b/examples/utest/testcases/mm/lwp_mmap_fd_map_fixed_merge.c deleted file mode 100644 index b33606618e..0000000000 --- a/examples/utest/testcases/mm/lwp_mmap_fd_map_fixed_merge.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-08-17 Shell test case for aspace_map(MAP_FIXED) - */ -#include "common.h" -#include "lwp_user_mm.h" -#include "utest_assert.h" -#include - -#include - -#define PAGE_SZ (1 << MM_PAGE_SHIFT) -#define PAGE_COUNT ('z' - 'a' + 1) -#define FILE_PATH "/test_mmap" -#define FILE_SZ (PAGE_COUNT * PAGE_SZ) - -static struct rt_lwp *lwp; -static size_t former_vsz; -static size_t former_vcount; -static char page_sz_buf[PAGE_SZ]; - -static void *ex_start = (void *)0x100000000; -static size_t ex_size = 0x5000; -static long pgoffset = 0; -static size_t ex_prot = PROT_NONE; -static size_t ex_flags = MAP_PRIVATE | MAP_ANONYMOUS; - -static char *private0 = (char *)0x100000000; -static char *private1 = (char *)0x100000000 + 0x1000; -static char *private2 = (char *)0x100000000 + 0x2000; -static char *private3 = (char *)0x100000000 + 0x3000; -static char *private4 = (char *)0x100000000 + 0x4000; -static size_t or_size = 0x1000; -static size_t or_prot = PROT_READ | PROT_WRITE; -static size_t or_flags = MAP_ANON | MAP_FIXED; - -static long anon_fd = -1; - -static int _count_vsz(rt_varea_t varea, void *arg) -{ - rt_base_t *pvsz = arg; - *pvsz += 1; - return 0; -} - -static rt_base_t count_vcount(rt_aspace_t aspace) -{ - rt_base_t vcount = 0; - rt_aspace_traversal(aspace, _count_vsz, &vcount); - return vcount; -} - -static rt_err_t _lwp_get_user(struct rt_lwp *lwp, char *vaddr, char *buffer) -{ - rt_varea_t varea = _aspace_bst_search(lwp->aspace, vaddr); - if (varea && varea->mem_obj && varea->mem_obj->page_read) - { - struct rt_aspace_io_msg io_msg; - rt_mm_io_msg_init(&io_msg, MM_PA_TO_OFF(vaddr), vaddr, buffer); - varea->mem_obj->page_read(varea, &io_msg); - } - return RT_EOK; -} - -static void _verify_file_content(struct rt_lwp *lwp, const char *mmap_buf, int ch) -{ - _lwp_get_user(lwp, (char *)mmap_buf, page_sz_buf); - utest_int_equal(RT_EOK, memtest(page_sz_buf, ch, PAGE_SZ)); -} - -static void test_mmap_fd_fixed(void) -{ - former_vsz = rt_aspace_count_vsz(lwp->aspace); - former_vcount = count_vcount(lwp->aspace); - - /* create an existed mapping */ - long temp_fd; - temp_fd = open(FILE_PATH, O_RDONLY); - LOG_D("New fd=%ld path=%s", temp_fd, FILE_PATH); - uassert_true(temp_fd >= 0); - utest_int_equal( - lwp_mmap2(lwp, ex_start, ex_size, ex_prot, ex_flags, anon_fd, pgoffset), - ex_start); - utest_int_equal(former_vsz + ex_size, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); - former_vsz += ex_size; - former_vcount += 1; - _verify_file_content(lwp, private0, 0); - _verify_file_content(lwp, private1, 0); - _verify_file_content(lwp, private2, 0); - _verify_file_content(lwp, private3, 0); - _verify_file_content(lwp, private4, 0); - - /* create an override mapping */ - utest_int_equal( - lwp_mmap2(lwp, private2, or_size, or_prot, or_flags, temp_fd, 2), - private2); - utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount + 2, count_vcount(lwp->aspace)); - former_vcount += 2; - _verify_file_content(lwp, private0, 0); - _verify_file_content(lwp, private1, 0); - _verify_file_content(lwp, private2, 'c'); - _verify_file_content(lwp, private3, 0); - _verify_file_content(lwp, private4, 0); - - /* fix private from left most */ - utest_int_equal( - lwp_mmap2(lwp, private0, or_size, or_prot, or_flags, temp_fd, 0), - private0); - utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); - former_vcount += 1; - _verify_file_content(lwp, private0, 'a'); - _verify_file_content(lwp, private1, 0); - _verify_file_content(lwp, private2, 'c'); - _verify_file_content(lwp, private3, 0); - _verify_file_content(lwp, private4, 0); - - /* fix private from right most */ - utest_int_equal( - lwp_mmap2(lwp, private4, or_size, or_prot, or_flags, temp_fd, 4), - private4); - utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); - former_vcount += 1; - _verify_file_content(lwp, private0, 'a'); - _verify_file_content(lwp, private1, 0); - _verify_file_content(lwp, private2, 'c'); - _verify_file_content(lwp, private3, 0); - _verify_file_content(lwp, private4, 'e'); - - /* fix private from left-middle */ - utest_int_equal( - lwp_mmap2(lwp, private1, or_size, or_prot, or_flags, temp_fd, 1), - private1); - rt_aspace_print_all(lwp->aspace); - utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace)); - former_vcount -= 1; - _verify_file_content(lwp, private0, 'a'); - _verify_file_content(lwp, private1, 'b'); - _verify_file_content(lwp, private2, 'c'); - _verify_file_content(lwp, private3, 0); - _verify_file_content(lwp, private4, 'e'); - - /* fix private from right-middle */ - utest_int_equal( - lwp_mmap2(lwp, private3, or_size, or_prot, or_flags, temp_fd, 3), - private3); - utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace)); - former_vcount -= 1; - _verify_file_content(lwp, private0, 'a'); - _verify_file_content(lwp, private1, 'b'); - _verify_file_content(lwp, private2, 'c'); - _verify_file_content(lwp, private3, 'd'); - _verify_file_content(lwp, private4, 'e'); - - /* close */ - close(temp_fd); - utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, ex_start, FILE_SZ)); -} - -static void testcase_main(void) -{ - test_mmap_fd_fixed(); -} - -static void _setup_file_content(long fd) -{ - char ch = 'a'; - for (size_t i = 0; i < PAGE_COUNT; i++, ch++) - { - memset(page_sz_buf, ch, PAGE_SZ); - write(fd, page_sz_buf, PAGE_SZ); - } -} - -static rt_err_t utest_tc_init(void) -{ - /* setup file */ - long temp_file_des; - temp_file_des = open(FILE_PATH, O_RDWR | O_CREAT, 0777); - LOG_D("New fd=%ld path=%s", temp_file_des, FILE_PATH); - if (temp_file_des < 0) - return -RT_ERROR; - _setup_file_content(temp_file_des); - close(temp_file_des); - - lwp = lwp_create(0); - if (lwp) - lwp_user_space_init(lwp, 1); - else - return -RT_ENOMEM; - return RT_EOK; -} - -static rt_err_t utest_tc_cleanup(void) -{ - lwp_ref_dec(lwp); - return RT_EOK; -} - -static void testcase(void) -{ - UTEST_UNIT_RUN(testcase_main); -} -UTEST_TC_EXPORT(testcase, "testcases.lwp.mman.mmap_fd.map_fixed_merge", utest_tc_init, utest_tc_cleanup, 10); diff --git a/examples/utest/testcases/mm/lwp_mmap_fd_map_fixed_split.c b/examples/utest/testcases/mm/lwp_mmap_fd_map_fixed_split.c deleted file mode 100644 index 7f7ef23b30..0000000000 --- a/examples/utest/testcases/mm/lwp_mmap_fd_map_fixed_split.c +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-08-17 Shell test case for aspace_map(MAP_FIXED) - */ -#include "common.h" -#include "lwp_user_mm.h" -#include "utest_assert.h" -#include - -#include - -#define PAGE_SZ (1 << MM_PAGE_SHIFT) -#define PAGE_COUNT ('z' - 'a' + 1) -#define FILE_PATH "/test_mmap" -#define FILE_SZ (PAGE_COUNT * PAGE_SZ) - -static struct rt_lwp *lwp; -static size_t former_vsz; -static size_t former_vcount; -static char page_sz_buf[PAGE_SZ]; - -static void *ex_start = (void *)0x100000000; -static size_t ex_size = 0x5000; -static long pgoffset = 0; -static size_t ex_prot = PROT_NONE; -static size_t ex_flags = MAP_PRIVATE | MAP_ANONYMOUS; - -static char *private0 = (char *)0x100000000; -static char *private1 = (char *)0x100000000 + 0x1000; -static char *private2 = (char *)0x100000000 + 0x2000; -static char *private3 = (char *)0x100000000 + 0x3000; -static char *private4 = (char *)0x100000000 + 0x4000; -static size_t or_size = 0x1000; -static size_t or_prot = PROT_READ | PROT_WRITE; -static size_t or_flags = MAP_ANON | MAP_FIXED; - -static long anon_fd = -1; - -static int _count_vsz(rt_varea_t varea, void *arg) -{ - rt_base_t *pvsz = arg; - *pvsz += 1; - return 0; -} - -static rt_base_t count_vcount(rt_aspace_t aspace) -{ - rt_base_t vcount = 0; - rt_aspace_traversal(aspace, _count_vsz, &vcount); - return vcount; -} - -static rt_err_t _lwp_get_user(struct rt_lwp *lwp, char *vaddr, char *buffer) -{ - rt_varea_t varea = _aspace_bst_search(lwp->aspace, vaddr); - if (varea && varea->mem_obj && varea->mem_obj->page_read) - { - struct rt_aspace_io_msg io_msg; - rt_mm_io_msg_init(&io_msg, MM_PA_TO_OFF(vaddr), vaddr, buffer); - varea->mem_obj->page_read(varea, &io_msg); - } - else - return -RT_ERROR; - return RT_EOK; -} - -static void _verify_file_content(struct rt_lwp *lwp, const char *mmap_buf, int ch) -{ - utest_int_equal(RT_EOK, _lwp_get_user(lwp, (char *)mmap_buf, page_sz_buf)); - utest_int_equal(RT_EOK, memtest(page_sz_buf, ch, PAGE_SZ)); -} - -static void test_mmap_fd_fixed(void) -{ - former_vsz = rt_aspace_count_vsz(lwp->aspace); - former_vcount = count_vcount(lwp->aspace); - - /* create an existed mapping */ - long temp_fd; - temp_fd = open(FILE_PATH, O_RDONLY); - LOG_D("New fd=%ld path=%s", temp_fd, FILE_PATH); - uassert_true(temp_fd >= 0); - utest_int_equal( - lwp_mmap2(lwp, ex_start, ex_size, ex_prot, ex_flags, temp_fd, pgoffset), - ex_start); - utest_int_equal(former_vsz + ex_size, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); - _verify_file_content(lwp, private0, 'a'); - _verify_file_content(lwp, private1, 'b'); - _verify_file_content(lwp, private2, 'c'); - _verify_file_content(lwp, private3, 'd'); - _verify_file_content(lwp, private4, 'e'); - former_vsz += ex_size; - former_vcount += 1; - - /* create an override mapping */ - utest_int_equal( - lwp_mmap2(lwp, private2, or_size, or_prot, or_flags, anon_fd, pgoffset), - private2); - utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount + 2, count_vcount(lwp->aspace)); - former_vcount += 2; - _verify_file_content(lwp, private0, 'a'); - _verify_file_content(lwp, private1, 'b'); - _verify_file_content(lwp, private2, 0); - _verify_file_content(lwp, private3, 'd'); - _verify_file_content(lwp, private4, 'e'); - - /* fix private from left most */ - utest_int_equal( - lwp_mmap2(lwp, private0, or_size, or_prot, or_flags, anon_fd, pgoffset), - private0); - utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); - former_vcount += 1; - _verify_file_content(lwp, private0, 0); - _verify_file_content(lwp, private1, 'b'); - _verify_file_content(lwp, private2, 0); - _verify_file_content(lwp, private3, 'd'); - _verify_file_content(lwp, private4, 'e'); - - /* fix private from right most */ - utest_int_equal( - lwp_mmap2(lwp, private4, or_size, or_prot, or_flags, anon_fd, pgoffset), - private4); - utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); - former_vcount += 1; - _verify_file_content(lwp, private0, 0); - _verify_file_content(lwp, private1, 'b'); - _verify_file_content(lwp, private2, 0); - _verify_file_content(lwp, private3, 'd'); - _verify_file_content(lwp, private4, 0); - - /* fix private from left-middle */ - utest_int_equal( - lwp_mmap2(lwp, private1, or_size, or_prot, or_flags, anon_fd, pgoffset), - private1); - utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace)); - former_vcount -= 1; - _verify_file_content(lwp, private0, 0); - _verify_file_content(lwp, private1, 0); - _verify_file_content(lwp, private2, 0); - _verify_file_content(lwp, private3, 'd'); - _verify_file_content(lwp, private4, 0); - - /* fix private from right-middle */ - utest_int_equal( - lwp_mmap2(lwp, private3, or_size, or_prot, or_flags, anon_fd, pgoffset), - private3); - utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace)); - former_vcount -= 1; - _verify_file_content(lwp, private0, 0); - _verify_file_content(lwp, private1, 0); - _verify_file_content(lwp, private2, 0); - _verify_file_content(lwp, private3, 0); - _verify_file_content(lwp, private4, 0); - - /* close */ - close(temp_fd); - utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, ex_start, FILE_SZ)); -} - -static void testcase_main(void) -{ - test_mmap_fd_fixed(); -} - -static void _setup_file_content(long fd) -{ - char ch = 'a'; - for (size_t i = 0; i < PAGE_COUNT; i++, ch++) - { - memset(page_sz_buf, ch, PAGE_SZ); - write(fd, page_sz_buf, PAGE_SZ); - } -} - -static rt_err_t utest_tc_init(void) -{ - /* setup file */ - long temp_file_des; - temp_file_des = open(FILE_PATH, O_RDWR | O_CREAT, 0777); - LOG_D("New fd=%ld path=%s", temp_file_des, FILE_PATH); - if (temp_file_des < 0) - return -RT_ERROR; - _setup_file_content(temp_file_des); - close(temp_file_des); - - lwp = lwp_create(0); - if (lwp) - lwp_user_space_init(lwp, 1); - else - return -RT_ENOMEM; - return RT_EOK; -} - -static rt_err_t utest_tc_cleanup(void) -{ - lwp_ref_dec(lwp); - return RT_EOK; -} - -static void testcase(void) -{ - UTEST_UNIT_RUN(testcase_main); -} -UTEST_TC_EXPORT(testcase, "testcases.lwp.mman.mmap_fd.map_fixed_split", utest_tc_init, utest_tc_cleanup, 10); diff --git a/examples/utest/testcases/mm/lwp_mmap_fix_private.c b/examples/utest/testcases/mm/lwp_mmap_fix_private.c deleted file mode 100644 index 22261e4b4f..0000000000 --- a/examples/utest/testcases/mm/lwp_mmap_fix_private.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-08-22 Shell test case for aspace_map with varea_expand - */ -#include "common.h" -#include "lwp_user_mm.h" -#include "mm_fault.h" -#include - -#include - -static long fd = -1; -static long pgoffset = 0; -static size_t flags = MAP_FIXED | MAP_ANONYMOUS; -static size_t prot = PROT_READ | PROT_WRITE; - -static char *ex_vaddr = (char *)0x100000000; -static size_t ex_size = 0x5000; -static char *private0 = (char *)0x100000000; -static char *private1 = (char *)0x100000000 + 0x1000; -static char *private2 = (char *)0x100000000 + 0x2000; -static char *private3 = (char *)0x100000000 + 0x3000; -static char *private4 = (char *)0x100000000 + 0x4000; - -/** - * todo: suppoprt prefetch pages, so more than 1 page can install to private at a time - * static size_t priv_size = 0x1000; - */ - -static size_t former_vsz; -static size_t former_vcount; - -static struct rt_lwp *lwp; - -static int _count_vsz(rt_varea_t varea, void *arg) -{ - rt_base_t *pvsz = arg; - *pvsz += 1; - return 0; -} - -static rt_base_t count_vcount(rt_aspace_t aspace) -{ - rt_base_t vcount = 0; - rt_aspace_traversal(aspace, _count_vsz, &vcount); - return vcount; -} - -static void test_mmap_fix_private(void) -{ - char *next_va; - struct rt_aspace_fault_msg msg; - msg.fault_op = MM_FAULT_OP_WRITE; - msg.fault_type = MM_FAULT_TYPE_RWX_PERM; - - /* map new pages at ex_vaddr to anonymous */ - next_va = ex_vaddr; - former_vsz = rt_aspace_count_vsz(lwp->aspace); - former_vcount = count_vcount(lwp->aspace); - next_va = lwp_mmap2(lwp, next_va, ex_size, prot, flags, fd, pgoffset); - uassert_true(next_va == ex_vaddr); - utest_int_equal(former_vsz + ex_size, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); - former_vsz += ex_size; - former_vcount += 1; - - /* fix private in the middle */ - msg.fault_vaddr = private2; - utest_int_equal(MM_FAULT_FIXABLE_TRUE, rt_aspace_fault_try_fix(lwp->aspace, &msg)); - utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount + 2, count_vcount(lwp->aspace)); - former_vcount += 2; - - /* fix private from left most */ - msg.fault_vaddr = private0; - utest_int_equal(MM_FAULT_FIXABLE_TRUE, rt_aspace_fault_try_fix(lwp->aspace, &msg)); - utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); - former_vcount += 1; - - /* fix private from right most */ - msg.fault_vaddr = private4; - utest_int_equal(MM_FAULT_FIXABLE_TRUE, rt_aspace_fault_try_fix(lwp->aspace, &msg)); - utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); - former_vcount += 1; - - /* fix private from left-middle */ - msg.fault_vaddr = private1; - utest_int_equal(MM_FAULT_FIXABLE_TRUE, rt_aspace_fault_try_fix(lwp->aspace, &msg)); - utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace)); - former_vcount -= 1; - - /* fix private from right-middle */ - msg.fault_vaddr = private3; - utest_int_equal(MM_FAULT_FIXABLE_TRUE, rt_aspace_fault_try_fix(lwp->aspace, &msg)); - utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace)); - former_vcount -= 1; - - /* clear mapping */ - utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, ex_vaddr, ex_size)); - rt_free(lwp->aspace->private_object); - lwp->aspace->private_object = RT_NULL; -} - -static void testcase_main(void) -{ - CONSIST_HEAP(test_mmap_fix_private()); -} - -static rt_err_t utest_tc_init(void) -{ - lwp = lwp_create(0); - if (lwp) - lwp_user_space_init(lwp, 1); - else - return -RT_ENOMEM; - return RT_EOK; -} - -static rt_err_t utest_tc_cleanup(void) -{ - lwp_ref_dec(lwp); - return RT_EOK; -} - -static void testcase(void) -{ - UTEST_UNIT_RUN(testcase_main); -} -UTEST_TC_EXPORT(testcase, "testcases.lwp.mman.mmap_anon.fix_private", utest_tc_init, utest_tc_cleanup, 10); diff --git a/examples/utest/testcases/mm/lwp_mmap_map_fixed.c b/examples/utest/testcases/mm/lwp_mmap_map_fixed.c deleted file mode 100644 index affc514037..0000000000 --- a/examples/utest/testcases/mm/lwp_mmap_map_fixed.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-08-17 Shell test case for aspace_map(MAP_FIXED) - */ -#include "common.h" -#include "lwp_user_mm.h" -#include "utest_assert.h" -#include - -#include - -static struct rt_lwp *lwp; -static size_t former_vsz; -static size_t former_vcount; - -static void *vaddr = (void *)0x100000000; -static size_t ex_size = 0x5000; -static char *override_start; -static size_t override_size = 0x2000; -static long fd = -1; -static long pgoffset = 0; -static size_t ex_prot = PROT_NONE; -static size_t ex_flags = MAP_PRIVATE | MAP_ANONYMOUS; -static size_t override_prot = PROT_READ | PROT_WRITE; -static size_t override_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED; - -static int _count_vsz(rt_varea_t varea, void *arg) -{ - rt_base_t *pvsz = arg; - *pvsz += 1; - return 0; -} - -static rt_base_t count_vcount(rt_aspace_t aspace) -{ - rt_base_t vcount = 0; - rt_aspace_traversal(aspace, _count_vsz, &vcount); - return vcount; -} - -static char put_data[] = "hello,world"; - -static void test_map_fixed(void) -{ - void *effect_override; - - former_vsz = rt_aspace_count_vsz(lwp->aspace); - former_vcount = count_vcount(lwp->aspace); - - /* create an existed mapping */ - vaddr = lwp_mmap2(lwp, vaddr, ex_size, ex_prot, ex_flags, fd, pgoffset); - uassert_true((long)vaddr > 0); - utest_int_equal(former_vsz + ex_size, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace)); - former_vsz += ex_size; - former_vcount += 1; - - /* fix private in the middle */ - override_start = (char *)vaddr + 0x1000; - effect_override = lwp_mmap2(lwp, override_start, override_size, override_prot, override_flags, fd, pgoffset); - uassert_true(effect_override == override_start); - utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace)); - utest_int_equal(former_vcount + 2, count_vcount(lwp->aspace)); - utest_int_equal( - lwp_data_put(lwp, effect_override, put_data, sizeof(put_data)), - sizeof(put_data) - ); - - utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, vaddr, ex_size)); -} - -static void aspace_unmap_tc(void) -{ - test_map_fixed(); -} - -static rt_size_t total, used, max_used; -static rt_size_t totala, useda, max_useda; -static rt_ubase_t level; -static rt_err_t utest_tc_init(void) -{ - lwp = lwp_create(0); - if (lwp) - lwp_user_space_init(lwp, 1); - else - return -RT_ENOMEM; - - /* stats */ - level = rt_heap_lock(); - rt_memory_info(&total, &used, &max_used); - - return RT_EOK; -} - -static rt_err_t utest_tc_cleanup(void) -{ - lwp_ref_dec(lwp); - - /* check */ - rt_memory_info(&totala, &useda, &max_useda); - rt_heap_unlock(level); - utest_int_equal(total, totala); - utest_int_less_equal(useda, used); - - return RT_EOK; -} - -static void testcase(void) -{ - UTEST_UNIT_RUN(aspace_unmap_tc); -} -UTEST_TC_EXPORT(testcase, "testcases.lwp.mman.mmap_anon.fix_private", utest_tc_init, utest_tc_cleanup, 10); diff --git a/examples/utest/testcases/mm/mm_api_tc.c b/examples/utest/testcases/mm/mm_api_tc.c deleted file mode 100644 index d7fcdffb00..0000000000 --- a/examples/utest/testcases/mm/mm_api_tc.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2022-12-14 WangXiaoyao the first version - * 2023-03-20 WangXiaoyao Format & add more testcases for API under mm_aspace.h - * 2025-12-14 ChuanN-sudo Add standardized utest documentation block - */ - -/** - * Test Case Name: MM API Test - * - * Test Objectives: - * - Verify I/O remapping functionality with cached memory access. - * - Test memory mapping flag creation and extraction mechanisms. - * - Validate address space management operations. - * - Test core APIs: rt_pages_alloc(), rt_ioremap_cached(), rt_iounmap(), rt_pages_free(), - * rt_pages_free(), MMF_CREATE(), MMF_GET_CNTL(), MMF_GET_ALIGN(). - * - * Test Scenarios: - * - Address Space Test (aspace_tc): Tests memory address space management APIs. - * - I/O Remap Test (ioremap_tc): Allocates physical pages, maps to virtual address with cache, verifies data consistency, and cleans up resources. - * - Flag Test (flag_tc): Creates memory mapping flags with different parameters and validates control bits and alignment values extraction. - * - * Verification Metrics: - * - I/O remapping should correctly map physical to virtual addresses. - * - Cached memory access should maintain data consistency between physical and virtual addresses. - * - Memory mapping flags should correctly encode and decode control bits and alignment values. - * - Flag creation with alignment should set MMF_REQUEST_ALIGN bit and store alignment value. - * - Flag creation without alignment should not set alignment-related bits. - * - Dependencies: - * - Hardware requirements: QEMU emulator or any hardware platform that supports RT-Thread with MMU. - * - Software configuration: - * - RT_UTEST_MM_API must be enabled (enable via: RT-Thread Utestcases -> RT-Thread Utestcases -> Memory Management Subsystem Testcase -> Enable Utest for MM API). - * - RT_USING_SMART must be enabled (enable via: Enable RT-Thread Kernel -> RT-Thread Smart (microkernel on kernel/userland)). - * - Environmental Assumptions: MMU support must be available on the target platform. - - * Expected Results: - * - Final output: "[ PASSED ] [ result ] testcase (testcases.mm.api_tc)" - * - No assertion failures during test execution. - */ -#include "common.h" - -/** - * @brief Testing all APIs under components/mm - */ - -void ioremap_tc(void); -void flag_tc(void); - -#ifdef STANDALONE_TC -#define TC_ASSERT(expr) \ - ((expr) \ - ? 0 \ - : rt_kprintf("AssertFault(%d): %s\n", __LINE__, RT_STRINGIFY(expr))) -#else -#define TC_ASSERT(expr) uassert_true(expr) -#endif - -static rt_err_t utest_tc_init(void) -{ - return RT_EOK; -} - -static rt_err_t utest_tc_cleanup(void) -{ - return RT_EOK; -} - -#include "test_aspace_api.h" - -static void testcase(void) -{ - aspace_tc(); - ioremap_tc(); - flag_tc(); -} -UTEST_TC_EXPORT(testcase, "testcases.mm.api_tc", utest_tc_init, utest_tc_cleanup, 20); - -void ioremap_tc(void) -{ - const size_t bufsz = 0x1000; - void *paddr = (void *)rt_pages_alloc(rt_page_bits(bufsz)) + PV_OFFSET; - int *vaddr; - vaddr = rt_ioremap_cached(paddr, bufsz); - if (vaddr) - { - TC_ASSERT(*vaddr == *(int *)(paddr - PV_OFFSET)); - - rt_iounmap(vaddr); - rt_pages_free(paddr - PV_OFFSET, 0); - } -} - -void flag_tc(void) -{ - size_t flags; - - flags = MMF_CREATE(MMF_MAP_FIXED, 0x4000); - TC_ASSERT(MMF_GET_CNTL(flags) == (MMF_MAP_FIXED | MMF_REQUEST_ALIGN)); - TC_ASSERT((1 << MMF_GET_ALIGN(flags)) == 0x4000); - - flags = MMF_CREATE(MMF_MAP_FIXED, 0); - TC_ASSERT(MMF_GET_CNTL(flags) == MMF_MAP_FIXED); - TC_ASSERT(MMF_GET_ALIGN(flags) == 0); -} - -#if 0 - -#define BUF_SIZE (4ul << 20) -static char ALIGN(BUF_SIZE) buf[BUF_SIZE]; - -void buddy_tc(void) -{ - size_t total, free; - rt_page_get_info(&total, &free); - - rt_region_t region = { - .start = (size_t)buf, - .end = (size_t)buf + BUF_SIZE, - }; - - size_t new_total, new_free; - rt_page_install(region); - rt_page_get_info(&new_total, &new_free); - TC_ASSERT(new_total - total == (BUF_SIZE >> ARCH_PAGE_SHIFT)); - TC_ASSERT(new_free > free); -} - -void mmu_page_tc() -{ - mm_aspace_t aspace = ASPACE_NEW(); - size_t total, free; - rt_page_get_info(&total, &free); - rt_hw_mmu_map(aspace, (void *)0x3fffffffff, 0, ARCH_PAGE_SIZE, - MMU_MAP_K_RWCB); - rt_hw_mmu_unmap(aspace, (void *)0x3fffffffff, ARCH_PAGE_SIZE); - - size_t new_total, new_free; - rt_page_get_info(&new_total, &new_free); - TC_ASSERT(new_free == free); - mm_aspace_delete(aspace); -} -#endif diff --git a/examples/utest/testcases/mm/mm_libcpu_tc.c b/examples/utest/testcases/mm/mm_libcpu_tc.c deleted file mode 100644 index a8e9c5c06b..0000000000 --- a/examples/utest/testcases/mm/mm_libcpu_tc.c +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-03-17 WangXiaoyao cache API unit test - */ -#include - -#ifdef ARCH_RISCV64 -#include "test_cache_rv64.h" -#elif defined(ARCH_ARMV8) -#include "test_cache_aarch64.h" -#endif diff --git a/examples/utest/testcases/mm/mm_lwp_tc.c b/examples/utest/testcases/mm/mm_lwp_tc.c deleted file mode 100644 index d38a27341d..0000000000 --- a/examples/utest/testcases/mm/mm_lwp_tc.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-03-27 WangXiaoyao testcase for lwp - * 2025-12-14 ChuanN-sudo Add standardized utest documentation block - */ - -/** - * Test Case Name: MM API lwp Test - * - * Test Objectives: - * - Verify LWP user space virtual area mapping functionality. - * - Test user memory accessibility checking mechanisms. - * - Test core APIs: lwp_create(), lwp_user_space_init(), lwp_map_user_varea(), - * lwp_map_user_varea_ext(), lwp_user_accessible_ext(), lwp_ref_dec() - * - * Test Scenarios: - * - User Map Varea Test (user_map_varea_tc): - * - test_user_map_varea(): Creates LWP, initializes user space, maps virtual area with default flags, verifies varea properties (cached, private mapping). - * - test_user_map_varea_ext(): Creates LWP, maps virtual area with NOCACHE flag, verifies uncached memory attributes. - * - Accessible Test (accessible_tc): - * - test_user_accessible(): Creates LWP with user stack, tests accessibility checks for unmapped and mapped memory regions. - * - * Verification Metrics: - * - Virtual areas should be correctly inserted with proper ordering. - * - Default mapping should have cached attributes (MMU_MAP_U_RWCB). - * - NOCACHE mapping should have uncached attributes (MMU_MAP_U_RW). - * - Virtual addresses should be within user space range. - * - Accessibility check should return false for unmapped memory, true for mapped memory. - * - * Dependencies: - * - Hardware requirements: QEMU emulator or any hardware platform that supports RT-Thread with MMU. - * - Software configuration: - * - RT_UTEST_MM_LWP must be enabled (enable via: RT-Thread Utestcases -> RT-Thread Utestcases -> Memory Management Subsystem Testcase -> Enable Utest for MM API in lwp). - * - RT_USING_SMART must be enabled (enable via: Enable RT-Thread Kernel -> RT-Thread Smart (microkernel on kernel/userland)). - * - Environmental Assumptions: MMU support must be available on the target platform. - * - * Expected Results: - * - Final output: "[ PASSED ] [ result ] testcase (testcases.lwp.mm_tc)" - * - No assertion failures during test execution. - */ - -#include "common.h" -#include -#include "lwp_arch.h" -#include "lwp_user_mm.h" -#include "mm_aspace.h" -#include "mm_flag.h" -#include "mmu.h" - -/** - * @brief user map API - * rt_varea_t lwp_map_user_varea(struct rt_lwp *lwp, void *map_va, size_t map_size); - * rt_varea_t lwp_map_user_varea_ext(struct rt_lwp *lwp, void *map_va, size_t map_size, size_t flags); - */ -#if 1 /* make it clear to identify the block :) */ - /* for testing on _aspace_traverse */ - static void *_prev_end; - static size_t _count; - static int _test_increase(rt_varea_t varea, void *param) - { - uassert_true(varea->start >= _prev_end); - _prev_end = varea->start + varea->size; - _count += 1; - return 0; - } - #define TEST_VAREA_INSERT(statement, aspace) do {\ - size_t _prev_count; \ - _count = 0; \ - _prev_end = 0; \ - rt_aspace_traversal((aspace), _test_increase, NULL);\ - _prev_count = _count; \ - statement; \ - _count = 0; \ - _prev_end = 0; \ - rt_aspace_traversal((aspace), _test_increase, NULL);\ - uassert_true(_prev_count + 1 == _count); \ - } while (0) -#endif - -static void test_user_map_varea(void) -{ - const size_t buf_sz = ARCH_PAGE_SIZE * 4; - struct rt_lwp *lwp; - rt_varea_t varea; - lwp = lwp_create(LWP_CREATE_FLAG_NONE); - - /* prepare environment */ - uassert_true(!!lwp); - uassert_true(!lwp_user_space_init(lwp, 1)); - TEST_VAREA_INSERT( - varea = lwp_map_user_varea(lwp, 0, buf_sz), - lwp->aspace); - uassert_true(!!varea); - uassert_true(varea->attr == (MMU_MAP_U_RWCB)); - uassert_true(varea->size == buf_sz); - uassert_true(varea->aspace == lwp->aspace); - uassert_true(varea->flag == MMF_MAP_PRIVATE); - uassert_true(varea->start != 0); - uassert_true(varea->start >= (void *)USER_VADDR_START && varea->start < (void *)USER_VADDR_TOP); - - uassert_true(!(lwp_ref_dec(lwp) - 1)); -} - -static void test_user_map_varea_ext(void) -{ - const size_t buf_sz = ARCH_PAGE_SIZE * 4; - struct rt_lwp *lwp; - rt_varea_t varea; - lwp = lwp_create(LWP_CREATE_FLAG_NONE); - - uassert_true(!!lwp); - uassert_true(!lwp_user_space_init(lwp, 1)); - - TEST_VAREA_INSERT( - varea = lwp_map_user_varea_ext(lwp, 0, buf_sz, LWP_MAP_FLAG_NOCACHE), - lwp->aspace); - uassert_true(!!varea); - uassert_true(varea->attr == (MMU_MAP_U_RW)); - uassert_true(varea->size == buf_sz); - uassert_true(varea->aspace == lwp->aspace); - uassert_true(varea->flag == MMF_MAP_PRIVATE); - uassert_true(varea->start != 0); - uassert_true(varea->start >= (void *)USER_VADDR_START && varea->start < (void *)USER_VADDR_TOP); - - uassert_true(!(lwp_ref_dec(lwp) - 1)); -} - -static void user_map_varea_tc(void) -{ - CONSIST_HEAP(test_user_map_varea()); - CONSIST_HEAP(test_user_map_varea_ext()); -} - -static void test_user_accessible(void) -{ - /* Prepare Environment */ - char *test_address = (char *)(USER_STACK_VEND); - struct rt_lwp *lwp; - lwp = lwp_create(LWP_CREATE_FLAG_NONE); - uassert_true(!!lwp); - uassert_true(!lwp_user_space_init(lwp, 0)); - - /* test if user accessible can operate */ - uassert_true(!lwp_user_accessible_ext(lwp, test_address + 0x1, 0x1)); - /* test if mapping exist, accessible can fill the page and return True */ - uassert_true(lwp_user_accessible_ext(lwp, test_address - 0x10, 0x10)); - - /* Cleanup */ - lwp_ref_dec(lwp); -} - -static void accessible_tc(void) -{ - CONSIST_HEAP(test_user_accessible()); -} - -static rt_err_t utest_tc_init(void) -{ - return RT_EOK; -} - -static rt_err_t utest_tc_cleanup(void) -{ - return RT_EOK; -} - -static void testcase(void) -{ - UTEST_UNIT_RUN(user_map_varea_tc); - UTEST_UNIT_RUN(accessible_tc); -} -UTEST_TC_EXPORT(testcase, "testcases.lwp.mm_tc", utest_tc_init, utest_tc_cleanup, 20); diff --git a/examples/utest/testcases/mm/mm_memblock_tc.c b/examples/utest/testcases/mm/mm_memblock_tc.c deleted file mode 100644 index e99c951c76..0000000000 --- a/examples/utest/testcases/mm/mm_memblock_tc.c +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-09-28 zmshahaha the first version - * 2026-03-19 cl2t Add standardized utest documentation block - */ - -/** - * Test Case Name: Memory Block Management Test - * - * Test Objectives: - * - Validate the memblock subsystem for early boot memory region management. - * - Test core APIs: rt_memblock_add_memory(), rt_memblock_reserve_memory(), - * rt_memblock_merge(), rt_memblock_next_free_region(). - * - * Test Scenarios: - * - Add Test (test_memblock_add): Verifies adding memory regions in various - * configurations including simple addition, adjacent regions (top/bottom), - * insertion between existing regions, and merging of contiguous regions - * with the same flags. - * - Reserve Test (test_memblock_reserve): Verifies reserving memory within - * existing regions at start/end positions, multiple reservations within - * a single region, and large reservations spanning multiple regions. - * Also validates free region iteration with MEMBLOCK_NOMAP filtering. - * - * Verification Metrics: - * - Region count after add/merge operations matches expected value. - * - Region start/end addresses and flags are correctly maintained. - * - Merge correctly combines adjacent regions with identical flags. - * - Free region iterator correctly skips reserved and NOMAP regions. - * - * Dependencies: - * - Software configuration: RT_USING_SMART and RT_UTEST_MM_MEMBLOCK must - * be enabled. - * - Environmental assumptions: MMU support must be available on the target - * platform. - * - * Expected Results: - * - Final output: "[ PASSED ] [ result ] testcase (testcases.mm.memblock_tc)" - * - No assertion failures during test execution. - */ - -#include -#include "common.h" -#include - -#define SZ_128M 0x08000000 -#define SZ_256M 0x10000000 -#define SZ_512M 0x20000000 -#define SZ_1G 0x40000000 - -static struct rt_memblock *mmblk_memory; -static struct rt_memblock *mmblk_reserved; - -void rt_memblock_next_free_region_init(void); -void rt_memblock_next_free_region(mmblk_flag_t flags, rt_size_t *out_start, rt_size_t *out_end); -rt_bool_t rt_memblock_is_last_free(void); -void rt_memblock_merge(void); - -struct rt_mmblk_reg *_nth_reg(struct rt_memblock *memblock, rt_uint32_t n) -{ - struct rt_mmblk_reg *ret = RT_NULL; - - rt_slist_for_each_entry(ret, &(memblock->reg_list), node) - { - if (--n == 0) - return ret; - } - - return ret; -} - -rt_uint32_t _reg_cnt(struct rt_memblock *memblock) -{ - rt_uint32_t ret = 0; - struct rt_mmblk_reg *reg; - - rt_slist_for_each_entry(reg, &(memblock->reg_list), node) - { - ret++; - } - - return ret; -} - -void _reset_memblock(void) -{ - struct rt_mmblk_reg *reg; - - rt_slist_for_each_entry(reg, &(mmblk_memory->reg_list), node) - { - reg->alloc = RT_FALSE; - } - rt_slist_for_each_entry(reg, &(mmblk_reserved->reg_list), node) - { - reg->alloc = RT_FALSE; - } - - mmblk_memory->reg_list.next = RT_NULL; - mmblk_reserved->reg_list.next = RT_NULL; -} - -static void test_memblock_add_simple(void) -{ - _reset_memblock(); - - rt_size_t base1 = SZ_1G, size1 = SZ_256M; - rt_size_t base2 = SZ_128M, size2 = SZ_128M; - rt_err_t err; - - err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - - uassert_int_equal(_reg_cnt(mmblk_memory), 1); - - uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base1); - uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base1 + size1); - uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE); - - err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_HOTPLUG); - uassert_int_equal(err, RT_EOK); - - uassert_int_equal(_reg_cnt(mmblk_memory), 2); - - uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base2); - uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base2 + size2); - uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_HOTPLUG); - - uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base1); - uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base1 + size1); - uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_NONE); -} - -static void test_memblock_add_adjacent_top(void) -{ - _reset_memblock(); - - rt_size_t base1 = SZ_128M, size1 = SZ_128M; - rt_size_t base2 = SZ_256M, size2 = SZ_128M; - rt_err_t err; - - err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - - uassert_int_equal(_reg_cnt(mmblk_memory), 2); - - uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base1); - uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base1 + size1); - uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE); - - uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base2); - uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base2 + size2); - uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_NONE); -} - -static void test_memblock_add_adjacent_bottom(void) -{ - _reset_memblock(); - - rt_size_t base1 = SZ_256M, size1 = SZ_128M; - rt_size_t base2 = SZ_128M, size2 = SZ_128M; - rt_err_t err; - - err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - - uassert_int_equal(_reg_cnt(mmblk_memory), 2); - - uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base2); - uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base2 + size2); - uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE); - - uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base1); - uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base1 + size1); - uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_NONE); -} - -static void test_memblock_add_between(void) -{ - _reset_memblock(); - - rt_size_t base1 = SZ_512M, size1 = SZ_256M; - rt_size_t base2 = SZ_1G, size2 = SZ_512M; - rt_size_t base3 = SZ_512M + SZ_256M, size3 = SZ_256M; - rt_err_t err; - - err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - err = rt_memblock_add_memory("memory3", base3, base3 + size3, MEMBLOCK_HOTPLUG); - uassert_int_equal(err, RT_EOK); - - uassert_int_equal(_reg_cnt(mmblk_memory), 3); - - uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base1); - uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base1 + size1); - uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE); - - uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base3); - uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base3 + size3); - uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_HOTPLUG); - - uassert_int_equal(_nth_reg(mmblk_memory, 3)->memreg.start, base2); - uassert_int_equal(_nth_reg(mmblk_memory, 3)->memreg.end, base2 + size2); - uassert_int_equal(_nth_reg(mmblk_memory, 3)->flags, MEMBLOCK_NONE); -} - -static void test_memblock_merge(void) -{ - _reset_memblock(); - - rt_size_t base1 = 0, size1 = SZ_256M; - rt_size_t base2 = SZ_256M, size2 = SZ_256M; - rt_size_t base3 = SZ_512M, size3 = SZ_256M; - rt_size_t base4 = SZ_512M + SZ_256M, size4 = SZ_256M; - rt_size_t base5 = SZ_1G, size5 = SZ_512M; - rt_err_t err; - - err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - err = rt_memblock_add_memory("memory3", base3, base3 + size3, MEMBLOCK_HOTPLUG); - uassert_int_equal(err, RT_EOK); - err = rt_memblock_add_memory("memory4", base4, base4 + size4, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - err = rt_memblock_add_memory("memory5", base5, base5 + size5, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - - rt_memblock_merge(); - - uassert_int_equal(_reg_cnt(mmblk_memory), 3); - - uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.start, base1); - uassert_int_equal(_nth_reg(mmblk_memory, 1)->memreg.end, base2 + size2); - uassert_int_equal(_nth_reg(mmblk_memory, 1)->flags, MEMBLOCK_NONE); - - uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.start, base3); - uassert_int_equal(_nth_reg(mmblk_memory, 2)->memreg.end, base3 + size3); - uassert_int_equal(_nth_reg(mmblk_memory, 2)->flags, MEMBLOCK_HOTPLUG); - - uassert_int_equal(_nth_reg(mmblk_memory, 3)->memreg.start, base4); - uassert_int_equal(_nth_reg(mmblk_memory, 3)->memreg.end, base5 + size5); - uassert_int_equal(_nth_reg(mmblk_memory, 3)->flags, MEMBLOCK_NONE); -} - -static void test_memblock_add(void) -{ - test_memblock_add_simple(); - test_memblock_add_adjacent_top(); - test_memblock_add_adjacent_bottom(); - test_memblock_add_between(); - test_memblock_merge(); -} - -static void test_memblock_reserve_in_memory_start(void) -{ - _reset_memblock(); - - rt_size_t base1 = SZ_128M, size1 = SZ_256M; - rt_size_t baser = SZ_128M, sizer = SZ_128M; - rt_size_t free_start, free_end; - rt_err_t err; - - err = rt_memblock_add_memory("memory", base1, base1 + size1, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - err = rt_memblock_reserve_memory("reserve", baser, baser + sizer, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - - rt_memblock_next_free_region_init(); - - rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); - uassert_int_equal(free_start, SZ_256M); - uassert_int_equal(free_end, SZ_128M + SZ_256M); - - rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); - uassert_int_equal(rt_memblock_is_last_free(), RT_TRUE); -} - -static void test_memblock_reserve_in_memory_end(void) -{ - _reset_memblock(); - - rt_size_t base1 = SZ_128M, size1 = SZ_256M; - rt_size_t baser = SZ_256M, sizer = SZ_128M; - rt_size_t free_start, free_end; - rt_err_t err; - - err = rt_memblock_add_memory("memory", base1, base1 + size1, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - err = rt_memblock_reserve_memory("reserve", baser, baser + sizer, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - - rt_memblock_next_free_region_init(); - - rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); - uassert_int_equal(free_start, SZ_128M); - uassert_int_equal(free_end, SZ_256M); - - rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); - uassert_int_equal(rt_memblock_is_last_free(), RT_TRUE); -} - -static void test_memblock_reserve_many_in_one_region(void) -{ - _reset_memblock(); - - rt_size_t base = 0, size = SZ_1G; - rt_size_t baser1 = 0, sizer1 = SZ_128M; - rt_size_t baser2 = SZ_256M, sizer2 = SZ_128M; - rt_size_t baser3 = SZ_256M + SZ_128M, sizer3 = SZ_128M; - rt_size_t baser4 = SZ_512M + SZ_128M, sizer4 = SZ_128M; - rt_size_t baser5 = SZ_1G - SZ_128M, sizer5 = SZ_128M; - rt_size_t free_start, free_end; - rt_err_t err; - - err = rt_memblock_add_memory("memory", base, base + size, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - err = rt_memblock_reserve_memory("reserve1", baser1, baser1 + sizer1, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - err = rt_memblock_reserve_memory("reserve2", baser2, baser2 + sizer2, MEMBLOCK_NOMAP); - uassert_int_equal(err, RT_EOK); - err = rt_memblock_reserve_memory("reserve3", baser3, baser3 + sizer3, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - err = rt_memblock_reserve_memory("reserve4", baser4, baser4 + sizer4, MEMBLOCK_NOMAP); - uassert_int_equal(err, RT_EOK); - err = rt_memblock_reserve_memory("reserve5", baser5, baser5 + sizer5, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - - rt_memblock_next_free_region_init(); - - rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); - uassert_int_equal(free_start, SZ_128M); - uassert_int_equal(free_end, SZ_256M); - - rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); - uassert_int_equal(free_start, SZ_512M); - uassert_int_equal(free_end, SZ_512M + SZ_128M); - - rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); - uassert_int_equal(free_start, SZ_512M + SZ_256M); - uassert_int_equal(free_end, SZ_1G - SZ_128M); - - rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); - uassert_int_equal(rt_memblock_is_last_free(), RT_TRUE); -} - -static void test_memblock_reserve_large_region(void) -{ - _reset_memblock(); - - rt_size_t base1 = 0, size1 = SZ_256M; - rt_size_t base2 = SZ_256M, size2 = SZ_256M; - rt_size_t base3 = SZ_512M, size3 = SZ_256M; - rt_size_t base4 = SZ_512M + SZ_256M, size4 = SZ_256M; - rt_size_t baser = SZ_256M + SZ_128M, sizer = SZ_512M; - rt_size_t free_start, free_end; - rt_err_t err; - - err = rt_memblock_add_memory("memory1", base1, base1 + size1, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - err = rt_memblock_add_memory("memory2", base2, base2 + size2, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - err = rt_memblock_add_memory("memory3", base3, base3 + size3, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - err = rt_memblock_add_memory("memory4", base4, base4 + size4, MEMBLOCK_NONE); - uassert_int_equal(err, RT_EOK); - err = rt_memblock_reserve_memory("reserve", baser, baser + sizer, MEMBLOCK_NOMAP); - uassert_int_equal(err, RT_EOK); - - rt_memblock_next_free_region_init(); - - rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); - uassert_int_equal(free_start, 0); - uassert_int_equal(free_end, SZ_256M); - - rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); - uassert_int_equal(free_start, SZ_256M); - uassert_int_equal(free_end, SZ_256M + SZ_128M); - - rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); - uassert_int_equal(free_start, SZ_512M + SZ_256M + SZ_128M); - uassert_int_equal(free_end, SZ_1G); - - rt_memblock_next_free_region(MEMBLOCK_NONE, &free_start, &free_end); - uassert_int_equal(rt_memblock_is_last_free(), RT_TRUE); -} - -static void test_memblock_reserve(void) -{ - test_memblock_reserve_in_memory_start(); - test_memblock_reserve_in_memory_end(); - test_memblock_reserve_many_in_one_region(); - test_memblock_reserve_large_region(); -} - -static rt_err_t utest_tc_init(void) -{ - mmblk_memory = rt_memblock_get_memory(); - mmblk_reserved = rt_memblock_get_reserved(); - return RT_EOK; -} - -static rt_err_t utest_tc_cleanup(void) -{ - return RT_EOK; -} - -static void testcase(void) -{ - UTEST_UNIT_RUN(test_memblock_add); - UTEST_UNIT_RUN(test_memblock_reserve); -} -UTEST_TC_EXPORT(testcase, "testcases.mm.memblock_tc", utest_tc_init, utest_tc_cleanup, 20); diff --git a/examples/utest/testcases/mm/rt_ioremap.c b/examples/utest/testcases/mm/rt_ioremap.c deleted file mode 100644 index d61dceec42..0000000000 --- a/examples/utest/testcases/mm/rt_ioremap.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2022-12-14 WangXiaoyao the first version - * 2023-03-20 WangXiaoyao Format & add more testcases for API under mm_aspace.h - * 2026-03-19 cl2t Add standardized utest documentation block - */ - -/** - * Test Case Name: I/O Remap Test - * - * Test Objectives: - * - Verify the rt_ioremap_cached() API for mapping physical addresses to - * virtual addresses with cached memory access. - * - Test core APIs: rt_pages_alloc(), rt_ioremap_cached(), rt_iounmap(), - * rt_pages_free(). - * - * Test Scenarios: - * - Allocates a physical page (4KB), maps it to a virtual address using - * rt_ioremap_cached(), verifies data consistency between the physical - * and virtual addresses, then unmaps and frees the resources. - * - * Verification Metrics: - * - The value read through the virtual address must equal the value at the - * corresponding physical address. - * - No memory leaks after unmap and free operations (validated via - * CONSIST_HEAP wrapper). - * - * Dependencies: - * - Software configuration: RT_USING_SMART must be enabled. - * - Environmental assumptions: MMU support must be available on the target - * platform. - * - * Expected Results: - * - Final output: "[ PASSED ] [ result ] testcase (testcases.mm.ioremap)" - * - No assertion failures during test execution. - */ - -#include "common.h" - -void ioremap_tc(void) -{ - const size_t bufsz = 0x1000; - void *paddr = (void *)rt_pages_alloc(rt_page_bits(bufsz)) + PV_OFFSET; - int *vaddr; - vaddr = rt_ioremap_cached(paddr, bufsz); - if (vaddr) - { - TC_ASSERT(*vaddr == *(int *)(paddr - PV_OFFSET)); - - rt_iounmap(vaddr); - rt_pages_free(paddr - PV_OFFSET, 0); - } -} - -static rt_err_t utest_tc_init(void) -{ - return RT_EOK; -} - -static rt_err_t utest_tc_cleanup(void) -{ - return RT_EOK; -} - -static void test_main(void) -{ - CONSIST_HEAP(ioremap_tc()); -} -UTEST_TC_EXPORT(test_main, "testcases.mm.ioremap", utest_tc_init, utest_tc_cleanup, 20); diff --git a/examples/utest/testcases/mm/semaphore.h b/examples/utest/testcases/mm/semaphore.h deleted file mode 100644 index 076f820cf2..0000000000 --- a/examples/utest/testcases/mm/semaphore.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-03-24 WangXiaoyao Complete testcase for synchronization - */ -#ifndef __SEMAPHORE_H__ -#define __SEMAPHORE_H__ - -#include - -typedef struct { - atomic_int count; -} semaphore_t; - -void semaphore_init(semaphore_t *sem, int count) -{ - atomic_init(&sem->count, count); -} - -void semaphore_wait(semaphore_t *sem) -{ - int count; - do { - count = atomic_load(&sem->count); - } while (count == 0 || !atomic_compare_exchange_weak(&sem->count, &count, count - 1)); -} - -void semaphore_signal(semaphore_t *sem) -{ - atomic_fetch_add(&sem->count, 1); -} - -#endif /* __SEMAPHORE_H__ */ diff --git a/examples/utest/testcases/mm/test_aspace_api.h b/examples/utest/testcases/mm/test_aspace_api.h deleted file mode 100644 index 2213888c28..0000000000 --- a/examples/utest/testcases/mm/test_aspace_api.h +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-03-20 WangXiaoyao Complete testcase for mm_aspace.c - */ -#ifndef __TEST_ASPACE_API_H__ -#define __TEST_ASPACE_API_H__ - -#include "common.h" -#include "mm_aspace.h" -#include "mm_flag.h" -#include "test_aspace_api_internal.h" -#include "test_synchronization.h" - -/** - * @brief API for aspace create/destroy - * - * rt_aspace_t rt_aspace_create(void *start, rt_size_t length, void *pgtbl); - * rt_aspace_t rt_aspace_init(rt_aspace_t aspace, void *start, rt_size_t length, void *pgtbl); - * void rt_aspace_delete(rt_aspace_t aspace); - * void rt_aspace_detach(rt_aspace_t aspace); - * - * the init & detach is covered by create & detach - */ - -static void aspace_create_tc(void) -{ - /* test robustness, detect failure and recover status of overall system */ - rt_aspace_t aspace; - - CONSIST_HEAP(aspace = rt_aspace_create((void *)(0 - 0x1000), 0x1000, NULL)); - uassert_true(!aspace); -} - -#if 1 /* make it clear to identify the block :) */ - /* for testing on _aspace_traverse */ - static void *_prev_end; - static size_t _count; - static int _test_increase(rt_varea_t varea, void *param) - { - uassert_true(varea->start >= _prev_end); - _prev_end = varea->start + varea->size; - _count += 1; - return 0; - } -#endif - -static void aspace_delete_tc(void) -{ - /** - * @brief Requirements: delete should recycle all types of vareas properly inside - * and release the resource allocated for it - */ - rt_aspace_t aspace; - struct rt_mm_va_hint hint = {.flags = 0, - .map_size = 0x1000, - .prefer = 0}; - struct rt_varea varea_phy; - struct rt_varea varea_mobj; - void *pgtbl; - void *vaddr; - - /* compatible to armv7a */ - pgtbl = rt_pages_alloc(2); - uassert_true(!!pgtbl); /* page must be usable */ - rt_memset(pgtbl, 0, ARCH_PAGE_SIZE); - - CONSIST_HEAP({ - aspace = rt_aspace_create((void *)USER_VADDR_START, USER_VADDR_TOP - USER_VADDR_START, pgtbl); - uassert_true(!!aspace); - - /* insert 4 types of vareas into this aspace */ - hint.limit_start = aspace->start; - hint.limit_range_size = aspace->size; - uassert_true(!rt_aspace_map_phy(aspace, &hint, MMU_MAP_K_RWCB, 0, &vaddr)); - uassert_true(!rt_aspace_map_phy_static(aspace, &varea_phy, &hint, MMU_MAP_K_RWCB, 0, &vaddr)); - uassert_true(!rt_aspace_map(aspace, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0)); - uassert_true(!rt_aspace_map_static(aspace, &varea_mobj, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0)); - - /* for testing on _aspace_traverse */ - _count = 0; - _prev_end = 0; - uassert_true(!rt_aspace_traversal(aspace, _test_increase, 0)); - /* ensure the mapping is done */ - uassert_true(_count == 4); - - rt_aspace_delete(aspace); - - uassert_true(rt_pages_free(pgtbl, 2) == 1); /* page free must success */ - }); -} - -/** - * @brief Memory Map on Virtual Address Space to Mappable Object - * int rt_aspace_map(rt_aspace_t aspace, void **addr, rt_size_t length, rt_size_t attr, - * mm_flag_t flags, rt_mem_obj_t mem_obj, rt_size_t offset); - * int rt_aspace_map_static(rt_aspace_t aspace, rt_varea_t varea, void **addr, - * rt_size_t length, rt_size_t attr, mm_flag_t flags, - * rt_mem_obj_t mem_obj, rt_size_t offset); - */ -static void aspace_map_tc(void) -{ - /** - * @brief Requirement: - * Robustness, filter out invalid input - */ - void *vaddr = RT_NULL; - uassert_true(rt_aspace_map(0, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0)); - uassert_true(vaddr == RT_NULL); - - vaddr = (void *)USER_VADDR_START; - uassert_true(rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0)); - uassert_true(vaddr == RT_NULL); - - uassert_true(rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, -1, &rt_mm_dummy_mapper, 0)); - uassert_true(vaddr == RT_NULL); - - /** - * @brief Requirement: - * in _rt_aspace_map:_varea_install - * not covering an existed varea if a named mapping is mandatory - */ - // vaddr = (void *)((rt_ubase_t)aspace_map_tc & ~ARCH_PAGE_MASK); - // CONSIST_HEAP( - // uassert_true( - // rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0))); - // uassert_true(vaddr == RT_NULL); - - /** - * @brief Requirement: - * in _rt_aspace_map:_varea_install:_find_free - * verify that this routine can choose a free region with specified size - * and specified alignment requirement - */ - #define ALIGN_REQ (0x04000000) - CONSIST_HEAP({ - uassert_true(!rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, MMF_CREATE(0, ALIGN_REQ), &rt_mm_dummy_mapper, 0)); - uassert_true(!((rt_ubase_t)vaddr & (ALIGN_REQ - 1))); - rt_aspace_unmap(&rt_kernel_space, vaddr); - }); - - /* test internal APIs */ - test_find_free(); -} - -/** - * @brief Page frames mapping to varea - * complete the page table on specified varea, and handle tlb maintenance - * There are 2 variants of this API - * - * int rt_varea_map_page(rt_varea_t varea, void *vaddr, void *page); - * int rt_varea_map_range(rt_varea_t varea, void *vaddr, void *paddr, rt_size_t length); - */ - -static rt_varea_t _create_varea(const size_t size) -{ - rt_varea_t varea; - void *vaddr = rt_ioremap_start; - - varea = rt_malloc(sizeof(*varea)); - uassert_true(!!varea); - uassert_true(!rt_aspace_map_static(&rt_kernel_space, varea, &vaddr, size, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0)); - varea->flag &= ~MMF_STATIC_ALLOC; - uassert_true(!!vaddr); - return varea; -} - -static void test_varea_map_page(void) -{ - /** - * @brief rt_varea_map_page - * Requirements: complete the page table entry - */ - const size_t buf_sz = 4 * ARCH_PAGE_SIZE; - rt_varea_t varea = _create_varea(buf_sz); - for (size_t i = 0; i < buf_sz; i += ARCH_PAGE_SIZE) - { - void *page = rt_pages_alloc(0); - uassert_true(!!page); - uassert_true(!rt_varea_map_page(varea, varea->start + i, page)); - uassert_true(rt_kmem_v2p(varea->start + i) == (page + PV_OFFSET)); - - /* let page manager handle the free of page */ - rt_varea_pgmgr_insert(varea, page); - uassert_true(rt_kmem_v2p(varea->start + i) == (page + PV_OFFSET)); - } - - uassert_true(!rt_aspace_unmap(&rt_kernel_space, varea->start)); -} - -static void test_varea_map_range(void) -{ - /** - * @brief rt_varea_map_range - * Requirements: complete the page table entry - */ - const size_t buf_sz = 4 * ARCH_PAGE_SIZE; - rt_varea_t varea = _create_varea(buf_sz); - void *page = rt_pages_alloc(rt_page_bits(buf_sz)); - uassert_true(!!page); - uassert_true(!rt_varea_map_range(varea, varea->start, page + PV_OFFSET, buf_sz)); - for (size_t i = 0; i < buf_sz; i += ARCH_PAGE_SIZE) - { - uassert_true(rt_kmem_v2p(varea->start + i) == (page + i + PV_OFFSET)); - } - - uassert_true(rt_pages_free(page, rt_page_bits(buf_sz))); - uassert_true(!rt_aspace_unmap(&rt_kernel_space, varea->start)); -} - -/** - * @brief rt_varea_unmap_page - * Requirements: cancel the page table entry - */ -static void test_varea_unmap_page(void) -{ - /* Prepare environment */ - const size_t buf_sz = 4 * ARCH_PAGE_SIZE; - rt_varea_t varea = _create_varea(buf_sz); - for (size_t i = 0; i < buf_sz; i += ARCH_PAGE_SIZE) - { - void *page = rt_pages_alloc(0); - uassert_true(!!page); - uassert_true(!rt_varea_map_page(varea, varea->start + i, page)); - - /* let page manager handle the free of page */ - rt_varea_pgmgr_insert(varea, page); - uassert_true(rt_kmem_v2p(varea->start + i) == (page + PV_OFFSET)); - } - - /* test if unmap is success */ - for (size_t i = 0; i < buf_sz; i += ARCH_PAGE_SIZE) - { - uassert_true(rt_varea_unmap_page(varea, varea->start + i) == RT_EOK); - uassert_true(rt_kmem_v2p(varea->start + i) == ARCH_MAP_FAILED); - } - - uassert_true(!rt_aspace_unmap(&rt_kernel_space, varea->start)); -} - -/** - * @brief rt_varea_map_range - * Requirements: complete the page table entry - */ -static void test_varea_unmap_range(void) -{ - const size_t buf_sz = 4 * ARCH_PAGE_SIZE; - rt_varea_t varea = _create_varea(buf_sz); - void *page = rt_pages_alloc(rt_page_bits(buf_sz)); - uassert_true(!!page); - uassert_true(!rt_varea_map_range(varea, varea->start, page + PV_OFFSET, buf_sz)); - for (size_t i = 0; i < buf_sz; i += ARCH_PAGE_SIZE) - { - uassert_true(rt_kmem_v2p(varea->start + i) == (page + i + PV_OFFSET)); - } - - /* test if unmap is success */ - uassert_true(rt_varea_unmap_range(varea, varea->start, buf_sz) == RT_EOK); - for (size_t i = 0; i < buf_sz; i += ARCH_PAGE_SIZE) - { - uassert_true(rt_kmem_v2p(varea->start + i) == ARCH_MAP_FAILED); - } - - uassert_true(rt_pages_free(page, rt_page_bits(buf_sz))); - uassert_true(!rt_aspace_unmap(&rt_kernel_space, varea->start)); -} - -static void varea_map_tc(void) -{ - CONSIST_HEAP(test_varea_map_page()); - CONSIST_HEAP(test_varea_map_range()); - CONSIST_HEAP(test_varea_unmap_page()); - CONSIST_HEAP(test_varea_unmap_range()); -} - -static void aspace_traversal_tc(void) -{ - /** - * @brief Requirement - * Iterate over each varea in the kernel space - */ - CONSIST_HEAP(aspace_delete_tc()); - uassert_true(4 == _count); -} - -#ifdef ARCH_ARMV8 -static void aspace_control_tc(void) -{ - /* this case is designed only for one page size */ - const size_t buf_sz = ARCH_PAGE_SIZE; - void *vaddr = RT_NULL; - volatile char *remap_nocache; - int platform_cache_probe; - uassert_true(!rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, MMF_PREFETCH, &rt_mm_dummy_mapper, 0)); - uassert_true(!!vaddr); - - /* map non-cacheable region to verify cache */ - remap_nocache = rt_ioremap(rt_kmem_v2p(vaddr), buf_sz); - uassert_true(!!remap_nocache); - - /* pre probing */ - rt_memset(vaddr, 0xba, buf_sz); - /* no need to sync transaction on same core */ - platform_cache_probe = memtest(remap_nocache, 0xab, buf_sz); - - if (!platform_cache_probe) - { - LOG_I("Cannot distinguish cache attribution on current platform"); - } - else - { - LOG_I("Ready to verify attribution of cached & non-cacheable"); - } - - /* verify cache */ - uassert_true(!rt_aspace_control(&rt_kernel_space, vaddr, MMU_CNTL_NONCACHE)); - rt_memset(vaddr, 0, buf_sz); - uassert_true(!memtest(remap_nocache, 0, buf_sz)); - - /* another option as MMU_CNTL_CACHE */ - uassert_true(!rt_aspace_control(&rt_kernel_space, vaddr, MMU_CNTL_CACHE)); - - rt_iounmap(remap_nocache); - uassert_true(!rt_aspace_unmap(&rt_kernel_space, vaddr)); -} -#endif - -static void aspace_tc(void) -{ - UTEST_UNIT_RUN(aspace_create_tc); - UTEST_UNIT_RUN(aspace_delete_tc); - UTEST_UNIT_RUN(aspace_map_tc); - UTEST_UNIT_RUN(aspace_traversal_tc); -#ifdef ARCH_ARMV8 - UTEST_UNIT_RUN(aspace_control_tc); -#endif - UTEST_UNIT_RUN(varea_map_tc); - - /* functionality */ - UTEST_UNIT_RUN(synchronization_tc); - return ; -} - -#endif /* __TEST_ASPACE_API_H__ */ diff --git a/examples/utest/testcases/mm/test_aspace_api_internal.h b/examples/utest/testcases/mm/test_aspace_api_internal.h deleted file mode 100644 index 953424f07c..0000000000 --- a/examples/utest/testcases/mm/test_aspace_api_internal.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-03-23 WangXiaoyao Complete testcase for internal APIs - */ -#ifndef __TEST_ASPACE_API_INTERNAL_H__ -#define __TEST_ASPACE_API_INTERNAL_H__ - -#include "common.h" -#include "mmu.h" -#include "test_bst_adpt.h" -#include - -/** - * @brief 3 cases for find free: - * with prefer & MAP_FIXED - * with prefer - * without prefer - * - * the requirement of find free: - * it will return a subset in address space that is free - * the subset contains `length` contiguous elements - * the alignment is satisfied - */ -static void test_find_free(void) -{ - void *top_page = rt_kernel_space.start + rt_kernel_space.size - 0x1000; - void *vaddr = top_page; - - CONSIST_HEAP({ - /* type 1, on success */ - uassert_true(!rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, MMF_MAP_FIXED, &rt_mm_dummy_mapper, 0)); - uassert_true(vaddr == top_page); - /* type 1, on failure */ - // uassert_true(rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, MMF_MAP_FIXED, &rt_mm_dummy_mapper, 0)); - // uassert_true(!vaddr); - - /* type 2, on success */ - vaddr = top_page; - uassert_true(!rt_aspace_map(&rt_kernel_space, &vaddr, 0x1000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0)); - uassert_true(vaddr < top_page); - uassert_true(!!vaddr); - rt_aspace_unmap(&rt_kernel_space, vaddr); - /* type 2, on failure */ - vaddr = rt_kernel_space.start; - uassert_true(-RT_ENOSPC == rt_aspace_map(&rt_kernel_space, &vaddr, rt_kernel_space.size - 0x08000000, MMU_MAP_K_RWCB, 0, &rt_mm_dummy_mapper, 0)); - uassert_true(!vaddr); - - /* type 3, on success is covered by ioremap */ - /* type 3, on failure */ - size_t map_size = ARCH_PAGE_SIZE; - while (1) - { - void *va = rt_ioremap(0, map_size); - if (va) - { - uassert_true(1); - rt_iounmap(va); - map_size <<= 1; - } - else - { - uassert_true(1); - break; - } - } - - /* free top page */ - rt_aspace_unmap(&rt_kernel_space, top_page); - }); - - /* test mm_private.h */ - CONSIST_HEAP(test_bst_adpt()); -} - -#endif /* __TEST_ASPACE_API_INTERNAL_H__ */ diff --git a/examples/utest/testcases/mm/test_bst_adpt.h b/examples/utest/testcases/mm/test_bst_adpt.h deleted file mode 100644 index e081a754bb..0000000000 --- a/examples/utest/testcases/mm/test_bst_adpt.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-03-23 WangXiaoyao Complete testcase for internal APIs - */ -#ifndef __TEST_BST_ADPT_H__ -#define __TEST_BST_ADPT_H__ - -#include "common.h" - -#ifdef RT_USING_SMART -#include "lwp_user_mm.h" -#include "mm_aspace.h" -#include "mm_flag.h" -#include -#include - -void test_bst_adpt(void) -{ - size_t flags = MMF_MAP_FIXED; - void *target_va = (void *)USER_VADDR_START + 0x3000; - size_t map_size = 0x1000; - void *prev_va = target_va - map_size; - void *next_va = target_va + map_size + 1; - struct rt_lwp *lwp; - rt_aspace_t aspace; - rt_mem_obj_t mem_obj; - - /* create aspace by lwp */ - lwp = lwp_create(LWP_CREATE_FLAG_NONE); - uassert_true(!!lwp); - uassert_true(!lwp_user_space_init(lwp, 0)); - aspace = lwp->aspace; - mem_obj = &rt_mm_dummy_mapper; - uassert_true(!!aspace); - uassert_true(!!mem_obj); - - /* _aspace_bst_search not cover */ - uassert_true(!_aspace_bst_search(aspace, target_va)); // ret == NULL - - uassert_true( - !rt_aspace_map(aspace, &target_va, map_size, MMU_MAP_K_RWCB, flags, mem_obj, 0)); - /* 2 wrappers */ - uassert_true( - !rt_aspace_map(aspace, &prev_va, map_size, MMU_MAP_K_RWCB, flags, mem_obj, 0)); - uassert_true( - !rt_aspace_map(aspace, &next_va, map_size, MMU_MAP_K_RWCB, flags, mem_obj, 0)); - - /* _aspace_bst_search */ - uassert_true(!!_aspace_bst_search(aspace, target_va)); - uassert_true(!_aspace_bst_search(aspace, target_va + map_size)); - uassert_true(!_aspace_bst_search(aspace, target_va - 1)); - - /** - * @brief _aspace_bst_search_exceed - * for given map [start, end] - */ - rt_varea_t find; - find = _aspace_bst_search_exceed(aspace, target_va); - uassert_true(!!find); - uassert_true(find->start == target_va); - - rt_varea_t last = ASPACE_VAREA_LAST(aspace); - find = _aspace_bst_search_exceed(aspace, last->start + 1); - uassert_true(!find); - - /** - * @brief _aspace_bst_search_overlap - * for given map [start, end], five types of overlapping - */ - /* 1. all below */ - struct _mm_range range = {.start = prev_va - 2, .end = prev_va - 1}; - find = _aspace_bst_search_overlap(aspace, range); - uassert_true(!find); - /* 2. start below */ - range.end = prev_va; - find = _aspace_bst_search_overlap(aspace, range); - uassert_true(!!find); - uassert_true(find->start == prev_va); - /* 3. all wrapped */ - range.start = prev_va; - range.end = prev_va + 1; - find = _aspace_bst_search_overlap(aspace, range); - uassert_true(!!find); - uassert_true(find->start == prev_va); - /* 4. end exceed */ - range.start = next_va; - range.end = next_va + map_size + 1; - find = _aspace_bst_search_overlap(aspace, range); - uassert_true(!!find); - uassert_true(find->start == next_va); - /* 5. all exceed */ - range.start = next_va + map_size; - find = _aspace_bst_search_overlap(aspace, range); - uassert_true(!find); - - lwp_ref_dec(lwp); -} - -#endif /* RT_USING_SMART */ - -#endif /* __TEST_BST_ADPT_H__ */ diff --git a/examples/utest/testcases/mm/test_cache_aarch64.h b/examples/utest/testcases/mm/test_cache_aarch64.h deleted file mode 100644 index b103eda213..0000000000 --- a/examples/utest/testcases/mm/test_cache_aarch64.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-03-17 WangXiaoyao cache API unit test - */ -#ifndef __TEST_CACHE_AARCH64_H__ -#define __TEST_CACHE_AARCH64_H__ - -#include "common.h" -#include - -const char *platform_cache_not_guarantee = "Cannot guarantee cache operation works"; - -/** - * ============================================================== - * TEST FEATURE - * API under cache.h - * - * void rt_hw_icache_invalidate_range(unsigned long start_addr, int size); - * void rt_hw_cpu_icache_invalidate(void *addr, rt_size_t size); - * void rt_hw_cpu_dcache_clean_and_invalidate(void *addr, rt_size_t size); - * ============================================================== - */ - -static int _get1_const(void) -{ - return 1; -} - -static int _get1(void) -{ - return 1; -} - -static int _get2(void) -{ - return 2; -} - -/* hot patching codes and test if the value can be seen by icache */ -static void _test_icache_invalidate_range(void) -{ - /* reset _get1 */ - rt_memcpy(_get1, _get1_const, _get2 - _get1); - rt_hw_cpu_dcache_clean(_get1, _get2 - _get1); - rt_hw_cpu_icache_invalidate(_get1, _get2 - _get1); - uassert_true(1 == _get1()); - - /* now copy _get2 to _get1 */ - rt_memcpy(_get1, _get2, _get2 - _get1); - if (1 != _get1()) - LOG_W(platform_cache_not_guarantee); - - rt_hw_cpu_dcache_clean(_get1, _get2 - _get1); - rt_hw_cpu_icache_invalidate(_get1, _get2 - _get1); - __asm__ volatile("isb"); - uassert_true(2 == _get1()); - LOG_I("%s ok", __func__); -} - -/* due to hardware feature of cortex-a, we should done this on 2 separated cpu */ -static void _test_dcache_clean_and_invalidate(void) -{ - const size_t padding = 1024 * 2; - const size_t buf_sz = ARCH_PAGE_SIZE * 2; - volatile char *remap_nocache; - char *page = rt_pages_alloc(rt_page_bits(buf_sz)); - uassert_true(!!page); - - rt_memset(page, 0xab, buf_sz); - rt_hw_cpu_dcache_invalidate(page, buf_sz); - - int _outdate_flag = 0; - if (memtest(page, 0xab, buf_sz)) - _outdate_flag = 1; - - /* after ioremap, we can access system memory to verify outcome */ - remap_nocache = rt_ioremap(page + PV_OFFSET, buf_sz); - - rt_hw_cpu_dcache_clean(page + padding, ARCH_PAGE_SIZE); - memtest(remap_nocache + padding, 0xab, ARCH_PAGE_SIZE); - - if (!_outdate_flag) - LOG_W(platform_cache_not_guarantee); - else - LOG_I("%s ok", __func__); - - rt_pages_free(page, 0); - rt_iounmap(remap_nocache); -} - -static rt_err_t utest_tc_init(void) -{ - return RT_EOK; -} - -static rt_err_t utest_tc_cleanup(void) -{ - return RT_EOK; -} - -static void testcase(void) -{ - /* todo: format API under cache.h first */ - UTEST_UNIT_RUN(_test_icache_invalidate_range); - UTEST_UNIT_RUN(_test_dcache_clean_and_invalidate); -} - -UTEST_TC_EXPORT(testcase, "testcases.libcpu.cache", utest_tc_init, utest_tc_cleanup, 10); - -#endif /* __TEST_CACHE_AARCH64_H__ */ diff --git a/examples/utest/testcases/mm/test_cache_rv64.h b/examples/utest/testcases/mm/test_cache_rv64.h deleted file mode 100644 index 3bd7fc26eb..0000000000 --- a/examples/utest/testcases/mm/test_cache_rv64.h +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-03-17 WangXiaoyao cache API unit test - */ - -#ifndef __TEST_CACHE_RV64_H -#define __TEST_CACHE_RV64_H - -#ifdef ARCH_RISCV64 -#include "riscv_mmu.h" -#include -#include -#include -#include -#include - -/** - * ============================================================== - * TEST FEATURE - * API under cache.h - * rt_hw_sync_cache_local - * - * rt_hw_cpu_dcache_clean - * rt_hw_cpu_dcache_invalidate - * rt_hw_cpu_dcache_clean_invalidate - * rt_hw_cpu_dcache_clean_all - * rt_hw_cpu_dcache_invalidate_all // meaningless - * rt_hw_cpu_dcache_clean_invalidate_all - * rt_hw_cpu_icache_invalidate - * rt_hw_cpu_icache_invalidate_all - * ============================================================== - */ - -/* Ensure the ISA is valid for target ARCHITECTURE */ -static void _illegal_instr(void) -{ - rt_hw_sync_cache_local(_illegal_instr, 64); - rt_hw_cpu_dcache_clean(_illegal_instr, 64); - rt_hw_cpu_dcache_invalidate(_illegal_instr, 64); - // rt_hw_cpu_dcache_clean_invalidate(_illegal_instr, 64); // C908 ONLY - rt_hw_cpu_dcache_clean_all(); - rt_hw_cpu_dcache_invalidate_all(); // !CAREFUL must be inline - // rt_hw_cpu_dcache_clean_invalidate_all(); // C908 ONLY - rt_hw_cpu_icache_invalidate(_illegal_instr, 64); - rt_hw_cpu_icache_invalidate_all(); - uassert_true(1); - LOG_I("All ok!"); -} - -static int _get1(void) -{ - return 1; -} - -static int _get2(void) -{ - return 2; -} - -/* hot patching codes and test if the value can be seen by icache */ -static void _test_cache_sync(void) -{ - uassert_true(1 == _get1()); - rt_memcpy(_get1, _get2, _get2 - _get1); - uassert_true(1 == _get1()); - rt_hw_sync_cache_local(_get1, _get2 - _get1); - uassert_true(2 == _get1()); - LOG_I("%s ok", __func__); -} - -/* test clean operation should do and only effect the range specified by writing to a page */ -static void _test_dcache_clean(void) -{ - const size_t padding = 1024 * 3; - const size_t buf_sz = ARCH_PAGE_SIZE * 2; - - char *page = rt_pages_alloc(rt_page_bits(buf_sz)); - uassert_true(!!page); - - /* after ioremap, we can access system memory to verify outcome */ - volatile char *remap_nocache = rt_ioremap(page + PV_OFFSET, buf_sz); - rt_memset(page, 0xab, buf_sz); - rt_hw_cpu_sync(); - - int _outdate_flag = 0; - for (size_t i = padding; i < ARCH_PAGE_SIZE; i++) - { - if (remap_nocache[i] != 0xab) - { - _outdate_flag = 1; - break; - } - } - - page[padding - 1] = 0xac; - page[padding + ARCH_PAGE_SIZE] = 0xac; - rt_hw_cpu_dcache_clean(page + padding, ARCH_PAGE_SIZE); - - /* free some space in dcache to avoid padding data being written back */ - rt_hw_cpu_dcache_invalidate(page + padding, ARCH_PAGE_SIZE); - uassert_true(remap_nocache[padding - 1] != 0xac); - uassert_true(remap_nocache[padding + ARCH_PAGE_SIZE] != 0xac); - - int _test_ok = 1; - for (size_t i = padding; i < ARCH_PAGE_SIZE; i++) - { - if (remap_nocache[i] != 0xab) - { - _test_ok = 0; - break; - } - } - uassert_true(_test_ok); - - if (!_outdate_flag) - LOG_W("Cannot guarantee clean works"); - else - LOG_I("%s ok", __func__); - - rt_pages_free(page, 0); - rt_iounmap(remap_nocache); -} - -/* test clean op should do and only effect the range */ -static void _test_dcache_invalidate(void) -{ - const size_t padding = 1024 * 3; - const size_t buf_sz = ARCH_PAGE_SIZE * 2; - - /* prepare */ - char *page = rt_pages_alloc(rt_page_bits(buf_sz)); - uassert_true(!!page); - - volatile char *remap_nocache = rt_ioremap(page + PV_OFFSET, buf_sz); - rt_memset(page, 0x0, buf_sz); - rt_hw_cpu_sync(); - - int _outdate_flag = 0; - for (size_t i = padding; i < ARCH_PAGE_SIZE; i++) - { - remap_nocache[i] = 0xab; - rt_hw_cpu_dcache_invalidate((void *)&remap_nocache[i], 1); - } - - rt_hw_cpu_dcache_clean_all(); - - int _test_ok = 1; - for (size_t i = padding; i < ARCH_PAGE_SIZE; i++) - { - if (remap_nocache[i] == 0xab) - { - _test_ok = 0; - break; - } - } - uassert_true(_test_ok); - - LOG_I("%s ok", __func__); - - rt_pages_free(page, 0); - rt_iounmap(remap_nocache); -} - -static rt_err_t utest_tc_init(void) -{ - return RT_EOK; -} - -static rt_err_t utest_tc_cleanup(void) -{ - return RT_EOK; -} - -static void testcase(void) -{ - UTEST_UNIT_RUN(_illegal_instr); -#ifdef BOARD_allwinnerd1s - /* thead ISA extension */ - UTEST_UNIT_RUN(_test_cache_sync); - /* part of it is hard to test on simulation machine */ - UTEST_UNIT_RUN(_test_dcache_clean); - UTEST_UNIT_RUN(_test_dcache_invalidate); -#endif -} - -UTEST_TC_EXPORT(testcase, "testcases.libcpu.cache", utest_tc_init, utest_tc_cleanup, 10); - -#endif /* ARCH_RISCV64 */ -#endif /* __TEST_CACHE_RV64_H */ diff --git a/examples/utest/testcases/mm/test_synchronization.h b/examples/utest/testcases/mm/test_synchronization.h deleted file mode 100644 index 7f813ec1f8..0000000000 --- a/examples/utest/testcases/mm/test_synchronization.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2006-2023, RT-Thread Development Team - * - * SPDX-License-Identifier: Apache-2.0 - * - * Change Logs: - * Date Author Notes - * 2023-03-24 WangXiaoyao Complete testcase for synchronization - */ -#ifndef __TEST_SYNCHRONIZATION_H__ -#define __TEST_SYNCHRONIZATION_H__ - -#include "common.h" -#include "semaphore.h" - -#ifdef RT_USING_SMP - -#define THREAD_CNT RT_CPUS_NR -#define TEST_TIMES 2000 -#define PRIO (UTEST_THR_PRIORITY + 1) -/* size of mapping buffer */ -#define BUF_SIZE (64ul << 10) - -/* engage with sibling */ -struct rt_semaphore done; -static semaphore_t sem1[THREAD_CNT / 2]; -static semaphore_t sem2[THREAD_CNT / 2]; - -static void *map(void) -{ - int err; - int flags = MMF_PREFETCH; - size_t attr = MMU_MAP_K_RWCB; - void *vaddr = 0; - err = - rt_aspace_map(&rt_kernel_space, &vaddr, BUF_SIZE, attr, flags, &rt_mm_dummy_mapper, 0); - if (err) - uassert_true(0); - return vaddr; -} - -static void unmap(void *buf) -{ - int err; - err = - rt_aspace_unmap(&rt_kernel_space, buf); - if (err) - uassert_true(0); - return ; -} - -static void group1_entry(void *param) -{ - const size_t id = (size_t)param; - size_t test_times = TEST_TIMES; - size_t alive = test_times / 10; - void *buf; - - while (test_times--) - { - if (test_times % alive == 0) - uassert_true(1); - - buf = map(); - - memset(buf, 'A' + id, BUF_SIZE); - /* if other core write to our cache, force the changes to be visible to us */ - rt_hw_dmb(); - - if (memtest(buf, 'A' + id, BUF_SIZE)) - uassert_true(0); - - semaphore_signal(&sem1[id]); - semaphore_wait(&sem2[id]); - unmap(buf); - } - - rt_sem_release(&done); - return; -} - -static void group2_entry(void *param) -{ - const size_t id = (size_t)param; - size_t test_times = TEST_TIMES; - size_t alive = test_times / 10; - void *buf; - - while (test_times--) - { - if (test_times % alive == 0) - uassert_true(1); - - semaphore_signal(&sem2[id]); - semaphore_wait(&sem1[id]); - buf = map(); - - memset(buf, 'a' + id, BUF_SIZE); - /* if other core write to our cache, force the changes to be visible to us */ - rt_hw_dmb(); - - if (memtest(buf, 'a' + id, BUF_SIZE)) - uassert_true(0); - - unmap(buf); - } - - rt_sem_release(&done); - return; -} - -/** - * @brief On a smp system, we create at least 4 threads - * 2 doing map, 2 doing unmapping at the same moment - */ - -static void synchronization_tc(void) -{ - rt_thread_t group1[THREAD_CNT / 2]; - rt_thread_t group2[THREAD_CNT / 2]; - - rt_sem_init(&done, __func__, 0, RT_IPC_FLAG_FIFO); - - for (size_t i = 0; i < THREAD_CNT / 2; i++) - { - char name[RT_NAME_MAX]; - rt_sprintf(name, "grp1_%d", i); - group1[i] = - rt_thread_create(name, group1_entry, (void *)i, ARCH_PAGE_SIZE, PRIO, 10); - uassert_true(!!group1[i]); - semaphore_init(&sem1[i], 0); - - uassert_true(!rt_thread_startup(group1[i])); - } - - for (size_t i = 0; i < THREAD_CNT / 2; i++) - { - char name[RT_NAME_MAX]; - rt_sprintf(name, "grp2_%d", i); - group2[i] = - rt_thread_create(name, group2_entry, (void *)i, ARCH_PAGE_SIZE, PRIO, 10); - uassert_true(!!group2[i]); - semaphore_init(&sem2[i], 0); - - uassert_true(!rt_thread_startup(group2[i])); - } - - /* wait all thread exit */ - for (size_t i = 0; i < (THREAD_CNT / 2 * 2); i++) - { - rt_sem_take(&done, RT_WAITING_FOREVER); - } - LOG_I("all threads exit"); - rt_sem_detach(&done); -} - -#else /* RT_USING_SMP */ - -static void synchronization_tc(void) -{ - uassert_true(1); -} -#endif /* RT_USING_SMP */ - -#endif /* __TEST_SYNCHRONIZATION_H__ */ -- cgit v1.3.1