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     else
68         return -RT_ERROR;
69     return RT_EOK;
70 }
71 
_verify_file_content(struct rt_lwp * lwp,const char * mmap_buf,int ch)72 static void _verify_file_content(struct rt_lwp *lwp, const char *mmap_buf, int ch)
73 {
74     utest_int_equal(RT_EOK, _lwp_get_user(lwp, (char *)mmap_buf, page_sz_buf));
75     utest_int_equal(RT_EOK, memtest(page_sz_buf, ch, PAGE_SZ));
76 }
77 
test_mmap_fd_fixed(void)78 static void test_mmap_fd_fixed(void)
79 {
80     former_vsz = rt_aspace_count_vsz(lwp->aspace);
81     former_vcount = count_vcount(lwp->aspace);
82 
83     /* create an existed mapping */
84     long temp_fd;
85     temp_fd = open(FILE_PATH, O_RDONLY);
86     LOG_D("New fd=%ld path=%s", temp_fd, FILE_PATH);
87     uassert_true(temp_fd >= 0);
88     utest_int_equal(
89         lwp_mmap2(lwp, ex_start, ex_size, ex_prot, ex_flags, temp_fd, pgoffset),
90         ex_start);
91     utest_int_equal(former_vsz + ex_size, rt_aspace_count_vsz(lwp->aspace));
92     utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace));
93     _verify_file_content(lwp, private0, 'a');
94     _verify_file_content(lwp, private1, 'b');
95     _verify_file_content(lwp, private2, 'c');
96     _verify_file_content(lwp, private3, 'd');
97     _verify_file_content(lwp, private4, 'e');
98     former_vsz += ex_size;
99     former_vcount += 1;
100 
101     /* create an override mapping */
102     utest_int_equal(
103         lwp_mmap2(lwp, private2, or_size, or_prot, or_flags, anon_fd, pgoffset),
104         private2);
105     utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
106     utest_int_equal(former_vcount + 2, count_vcount(lwp->aspace));
107     former_vcount += 2;
108     _verify_file_content(lwp, private0, 'a');
109     _verify_file_content(lwp, private1, 'b');
110     _verify_file_content(lwp, private2, 0);
111     _verify_file_content(lwp, private3, 'd');
112     _verify_file_content(lwp, private4, 'e');
113 
114     /* fix private from left most */
115     utest_int_equal(
116         lwp_mmap2(lwp, private0, or_size, or_prot, or_flags, anon_fd, pgoffset),
117         private0);
118     utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
119     utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace));
120     former_vcount += 1;
121     _verify_file_content(lwp, private0, 0);
122     _verify_file_content(lwp, private1, 'b');
123     _verify_file_content(lwp, private2, 0);
124     _verify_file_content(lwp, private3, 'd');
125     _verify_file_content(lwp, private4, 'e');
126 
127     /* fix private from right most */
128     utest_int_equal(
129         lwp_mmap2(lwp, private4, or_size, or_prot, or_flags, anon_fd, pgoffset),
130         private4);
131     utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
132     utest_int_equal(former_vcount + 1, count_vcount(lwp->aspace));
133     former_vcount += 1;
134     _verify_file_content(lwp, private0, 0);
135     _verify_file_content(lwp, private1, 'b');
136     _verify_file_content(lwp, private2, 0);
137     _verify_file_content(lwp, private3, 'd');
138     _verify_file_content(lwp, private4, 0);
139 
140     /* fix private from left-middle */
141     utest_int_equal(
142         lwp_mmap2(lwp, private1, or_size, or_prot, or_flags, anon_fd, pgoffset),
143         private1);
144     utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
145     utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace));
146     former_vcount -= 1;
147     _verify_file_content(lwp, private0, 0);
148     _verify_file_content(lwp, private1, 0);
149     _verify_file_content(lwp, private2, 0);
150     _verify_file_content(lwp, private3, 'd');
151     _verify_file_content(lwp, private4, 0);
152 
153     /* fix private from right-middle */
154     utest_int_equal(
155         lwp_mmap2(lwp, private3, or_size, or_prot, or_flags, anon_fd, pgoffset),
156         private3);
157     utest_int_equal(former_vsz, rt_aspace_count_vsz(lwp->aspace));
158     utest_int_equal(former_vcount - 1, count_vcount(lwp->aspace));
159     former_vcount -= 1;
160     _verify_file_content(lwp, private0, 0);
161     _verify_file_content(lwp, private1, 0);
162     _verify_file_content(lwp, private2, 0);
163     _verify_file_content(lwp, private3, 0);
164     _verify_file_content(lwp, private4, 0);
165 
166     /* close */
167     close(temp_fd);
168     utest_int_equal(RT_EOK, rt_aspace_unmap_range(lwp->aspace, ex_start, FILE_SZ));
169 }
170 
testcase_main(void)171 static void testcase_main(void)
172 {
173     test_mmap_fd_fixed();
174 }
175 
_setup_file_content(long fd)176 static void _setup_file_content(long fd)
177 {
178     char ch = 'a';
179     for (size_t i = 0; i < PAGE_COUNT; i++, ch++)
180     {
181         memset(page_sz_buf, ch, PAGE_SZ);
182         write(fd, page_sz_buf, PAGE_SZ);
183     }
184 }
185 
utest_tc_init(void)186 static rt_err_t utest_tc_init(void)
187 {
188     /* setup file */
189     long temp_file_des;
190     temp_file_des = open(FILE_PATH, O_RDWR | O_CREAT, 0777);
191     LOG_D("New fd=%ld path=%s", temp_file_des, FILE_PATH);
192     if (temp_file_des < 0)
193         return -RT_ERROR;
194     _setup_file_content(temp_file_des);
195     close(temp_file_des);
196 
197     lwp = lwp_create(0);
198     if (lwp)
199         lwp_user_space_init(lwp, 1);
200     else
201         return -RT_ENOMEM;
202     return RT_EOK;
203 }
204 
utest_tc_cleanup(void)205 static rt_err_t utest_tc_cleanup(void)
206 {
207     lwp_ref_dec(lwp);
208     return RT_EOK;
209 }
210 
testcase(void)211 static void testcase(void)
212 {
213     UTEST_UNIT_RUN(testcase_main);
214 }
215 UTEST_TC_EXPORT(testcase, "testcases.lwp.mman.mmap_fd.map_fixed_split", utest_tc_init, utest_tc_cleanup, 10);
216