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