1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2023-08-17 Shell test case for aspace_map(MAP_FIXED)
9 */
10 #include "common.h"
11 #include "lwp_user_mm.h"
12 #include "utest_assert.h"
13 #include <mm_private.h>
14
15 #include <rtthread.h>
16
17 #define PAGE_SZ (1 << MM_PAGE_SHIFT)
18 #define PAGE_COUNT ('z' - 'a' + 1)
19 #define FILE_PATH "/test_mmap"
20 #define FILE_SZ (PAGE_COUNT * PAGE_SZ)
21
22 static struct rt_lwp *lwp;
23 static size_t former_vsz;
24 static size_t former_vcount;
25 static char page_sz_buf[PAGE_SZ];
26
27 static void *ex_start = (void *)0x100000000;
28 static size_t ex_size = 0x5000;
29 static long pgoffset = 0;
30 static size_t ex_prot = PROT_NONE;
31 static size_t ex_flags = MAP_PRIVATE | MAP_ANONYMOUS;
32
33 static char *private0 = (char *)0x100000000;
34 static char *private1 = (char *)0x100000000 + 0x1000;
35 static char *private2 = (char *)0x100000000 + 0x2000;
36 static char *private3 = (char *)0x100000000 + 0x3000;
37 static char *private4 = (char *)0x100000000 + 0x4000;
38 static size_t or_size = 0x1000;
39 static size_t or_prot = PROT_READ | PROT_WRITE;
40 static size_t or_flags = MAP_ANON | MAP_FIXED;
41
42 static long anon_fd = -1;
43
_count_vsz(rt_varea_t varea,void * arg)44 static int _count_vsz(rt_varea_t varea, void *arg)
45 {
46 rt_base_t *pvsz = arg;
47 *pvsz += 1;
48 return 0;
49 }
50
count_vcount(rt_aspace_t aspace)51 static rt_base_t count_vcount(rt_aspace_t aspace)
52 {
53 rt_base_t vcount = 0;
54 rt_aspace_traversal(aspace, _count_vsz, &vcount);
55 return vcount;
56 }
57
_lwp_get_user(struct rt_lwp * lwp,char * vaddr,char * buffer)58 static rt_err_t _lwp_get_user(struct rt_lwp *lwp, char *vaddr, char *buffer)
59 {
60 rt_varea_t varea = _aspace_bst_search(lwp->aspace, vaddr);
61 if (varea && varea->mem_obj && varea->mem_obj->page_read)
62 {
63 struct rt_aspace_io_msg io_msg;
64 rt_mm_io_msg_init(&io_msg, MM_PA_TO_OFF(vaddr), vaddr, buffer);
65 varea->mem_obj->page_read(varea, &io_msg);
66 }
67 return RT_EOK;
68 }
69
_verify_file_content(struct rt_lwp * lwp,const char * mmap_buf,int ch)70 static void _verify_file_content(struct rt_lwp *lwp, const char *mmap_buf, int ch)
71 {
72 _lwp_get_user(lwp, (char *)mmap_buf, page_sz_buf);
73 utest_int_equal(RT_EOK, memtest(page_sz_buf, ch, PAGE_SZ));
74 }
75
test_mmap_fd_fixed(void)76 static void test_mmap_fd_fixed(void)
77 {
78 former_vsz = rt_aspace_count_vsz(lwp->aspace);
79 former_vcount = count_vcount(lwp->aspace);
80
81 /* create an existed mapping */
82 long temp_fd;
83 temp_fd = open(FILE_PATH, O_RDONLY);
84 LOG_D("New fd=%ld path=%s", temp_fd, FILE_PATH);
85 uassert_true(temp_fd >= 0);
86 utest_int_equal(
87 lwp_mmap2(lwp, ex_start, ex_size, ex_prot, ex_flags, anon_fd, pgoffset),
88 ex_start);
89 utest_int_equal(former_vsz + ex_size, rt_aspace_count_vsz(lwp->aspace));
90 utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace));
91 former_vsz += ex_size;
92 former_vcount += 1;
93 _verify_file_content(lwp, private0, 0);
94 _verify_file_content(lwp, private1, 0);
95 _verify_file_content(lwp, private2, 0);
96 _verify_file_content(lwp, private3, 0);
97 _verify_file_content(lwp, private4, 0);
98
99 /* create an override mapping */
100 utest_int_equal(
101 lwp_mmap2(lwp, private2, or_size, or_prot, or_flags, temp_fd, 2),
102 private2);
103 utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
104 utest_int_equal(former_vcount + 2, count_vcount(lwp->aspace));
105 former_vcount += 2;
106 _verify_file_content(lwp, private0, 0);
107 _verify_file_content(lwp, private1, 0);
108 _verify_file_content(lwp, private2, 'c');
109 _verify_file_content(lwp, private3, 0);
110 _verify_file_content(lwp, private4, 0);
111
112 /* fix private from left most */
113 utest_int_equal(
114 lwp_mmap2(lwp, private0, or_size, or_prot, or_flags, temp_fd, 0),
115 private0);
116 utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
117 utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace));
118 former_vcount += 1;
119 _verify_file_content(lwp, private0, 'a');
120 _verify_file_content(lwp, private1, 0);
121 _verify_file_content(lwp, private2, 'c');
122 _verify_file_content(lwp, private3, 0);
123 _verify_file_content(lwp, private4, 0);
124
125 /* fix private from right most */
126 utest_int_equal(
127 lwp_mmap2(lwp, private4, or_size, or_prot, or_flags, temp_fd, 4),
128 private4);
129 utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
130 utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace));
131 former_vcount += 1;
132 _verify_file_content(lwp, private0, 'a');
133 _verify_file_content(lwp, private1, 0);
134 _verify_file_content(lwp, private2, 'c');
135 _verify_file_content(lwp, private3, 0);
136 _verify_file_content(lwp, private4, 'e');
137
138 /* fix private from left-middle */
139 utest_int_equal(
140 lwp_mmap2(lwp, private1, or_size, or_prot, or_flags, temp_fd, 1),
141 private1);
142 rt_aspace_print_all(lwp->aspace);
143 utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
144 utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace));
145 former_vcount -= 1;
146 _verify_file_content(lwp, private0, 'a');
147 _verify_file_content(lwp, private1, 'b');
148 _verify_file_content(lwp, private2, 'c');
149 _verify_file_content(lwp, private3, 0);
150 _verify_file_content(lwp, private4, 'e');
151
152 /* fix private from right-middle */
153 utest_int_equal(
154 lwp_mmap2(lwp, private3, or_size, or_prot, or_flags, temp_fd, 3),
155 private3);
156 utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
157 utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace));
158 former_vcount -= 1;
159 _verify_file_content(lwp, private0, 'a');
160 _verify_file_content(lwp, private1, 'b');
161 _verify_file_content(lwp, private2, 'c');
162 _verify_file_content(lwp, private3, 'd');
163 _verify_file_content(lwp, private4, 'e');
164
165 /* close */
166 close(temp_fd);
167 utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, ex_start, FILE_SZ));
168 }
169
testcase_main(void)170 static void testcase_main(void)
171 {
172 test_mmap_fd_fixed();
173 }
174
_setup_file_content(long fd)175 static void _setup_file_content(long fd)
176 {
177 char ch = 'a';
178 for (size_t i = 0; i < PAGE_COUNT; i++, ch++)
179 {
180 memset(page_sz_buf, ch, PAGE_SZ);
181 write(fd, page_sz_buf, PAGE_SZ);
182 }
183 }
184
utest_tc_init(void)185 static rt_err_t utest_tc_init(void)
186 {
187 /* setup file */
188 long temp_file_des;
189 temp_file_des = open(FILE_PATH, O_RDWR | O_CREAT, 0777);
190 LOG_D("New fd=%ld path=%s", temp_file_des, FILE_PATH);
191 if (temp_file_des < 0)
192 return -RT_ERROR;
193 _setup_file_content(temp_file_des);
194 close(temp_file_des);
195
196 lwp = lwp_create(0);
197 if (lwp)
198 lwp_user_space_init(lwp, 1);
199 else
200 return -RT_ENOMEM;
201 return RT_EOK;
202 }
203
utest_tc_cleanup(void)204 static rt_err_t utest_tc_cleanup(void)
205 {
206 lwp_ref_dec(lwp);
207 return RT_EOK;
208 }
209
testcase(void)210 static void testcase(void)
211 {
212 UTEST_UNIT_RUN(testcase_main);
213 }
214 UTEST_TC_EXPORT(testcase, "testcases.lwp.mman.mmap_fd.map_fixed_merge", utest_tc_init, utest_tc_cleanup, 10);
215