1 /*
2 * Copyright (c) 2021 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/ztest.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/cache.h>
10
11 #include <zephyr/toolchain.h>
12 #include <zephyr/sys/printk.h>
13 #include <zephyr/sys/util.h>
14
15 #include <zephyr/drivers/mm/system_mm.h>
16
17 #include <soc.h>
18 #include <adsp_memory.h>
19
20 #define N_PAGES 3
21 #define PAGE_SZ CONFIG_MM_DRV_PAGE_SIZE
22
23 struct pagemem {
24 uint32_t mem[1024];
25 };
26
27 /*
28 * Test 3 pages at a time, but another set of 3 pages
29 * is needed for remapping test.
30 */
__aligned(PAGE_SZ)31 uint8_t __aligned(PAGE_SZ) buf[2 * N_PAGES * PAGE_SZ];
32
33 ZTEST(adsp_mem, test_adsp_mem_map_region)
34 {
35 int ret;
36 uintptr_t pa[N_PAGES];
37 struct pagemem *page_buf = (void *)buf;
38
39 /* Find a virtual address beyond physical memory */
40 void *va = (void *)ROUND_UP(L2_SRAM_BASE + L2_SRAM_SIZE, PAGE_SZ);
41
42 for (int i = 0; i < N_PAGES; i++) {
43 /* First N_PAGES pages of page_buf */
44 pa[i] = POINTER_TO_UINT(&page_buf[i]);
45 }
46
47 /* Map our physical pages to the new location */
48 ret = sys_mm_drv_map_region(va, pa[0], N_PAGES * PAGE_SZ, 0U);
49
50 zassert_true(ret == 0, "sys_mm_drv_map_region() failed (%d)", ret);
51
52 /* Mark the new pages */
53 struct pagemem *vps = va;
54 const uint32_t markers[] = { 0x11111111, 0x22222222, 0x33333333 };
55
56 for (int i = 0; i < N_PAGES; i++) {
57 vps[i].mem[0] = markers[i];
58
59 /*
60 * Make sure it is written back to the mapped
61 * physical memory.
62 */
63 sys_cache_data_flush_range(&vps[i].mem[0], PAGE_SZ);
64
65 /*
66 * pa[i] is a cached address which means that the cached
67 * version still has the old value before the assignment
68 * above. So we need to invalidate the cache to reload
69 * the new value.
70 */
71 sys_cache_data_invd_range(UINT_TO_POINTER(pa[i]), PAGE_SZ);
72 }
73
74 /* Verify the originals reflect the change */
75 for (int i = 0; i < N_PAGES; i++) {
76 zassert_equal(vps[i].mem[0], *(uint32_t *)pa[i],
77 "mapping and original don't match (0x%x != 0x%x)",
78 vps[i].mem[0], *(uint32_t *)pa[i]);
79 }
80
81 /* Remap to another region (this will unmap the first virtual pages) */
82 struct pagemem *vps2 = &vps[N_PAGES];
83
84 /*
85 * Need to unmap vps2 as sys_mm_drv_remap_region() checks
86 * if the new virtual memory region is all unmapped.
87 */
88 ret = sys_mm_drv_unmap_region(vps2, N_PAGES * PAGE_SZ);
89 zassert_true(ret == 0, "sys_mm_drv_unmap_region() failed (%d)", ret);
90
91 ret = sys_mm_drv_remap_region(vps, N_PAGES * PAGE_SZ, vps2);
92 zassert_true(ret == 0, "sys_mm_drv_remap_region() failed (%d)", ret);
93
94 for (int i = 0; i < N_PAGES; i++) {
95 zassert_equal(vps2[i].mem[0], *(uint32_t *)pa[i],
96 "remapping and original don't match");
97 }
98
99 /* Now copy the remapped pages to a third virtual region */
100 struct pagemem *vps3 = &vps2[N_PAGES];
101 uintptr_t new_pages[N_PAGES];
102
103 for (int i = 0; i < N_PAGES; i++) {
104 /* N_PAGES after the first N_PAGES pages of page_buf */
105 new_pages[i] = POINTER_TO_UINT(&page_buf[i + N_PAGES]);
106 }
107
108 /*
109 * Need to unmap vps3 as sys_mm_drv_remap_region() checks
110 * if the new virtual memory region is all unmapped.
111 */
112 ret = sys_mm_drv_unmap_region(vps3, N_PAGES * PAGE_SZ);
113 zassert_true(ret == 0, "sys_mm_drv_unmap_region() failed (%d)", ret);
114
115 ret = sys_mm_drv_move_region(vps2, N_PAGES * PAGE_SZ,
116 vps3, new_pages[0]);
117 zassert_true(ret == 0, "sys_mm_drv_move_region() failed (%d)", ret);
118
119 /* Make sure they match the originals */
120 for (int i = 0; i < N_PAGES; i++) {
121 zassert_equal(vps3[i].mem[0], *(uint32_t *)pa[i],
122 "page copy failed to match data (0x%x != 0x%x)",
123 vps3[i].mem[0], *(uint32_t *)pa[i]);
124 }
125
126 /* Modify the copy and make sure the originals are unmodified */
127 const int poison = 0x5a5a5a5a;
128
129 for (int i = 0; i < N_PAGES; i++) {
130 vps3[i].mem[0] = poison;
131
132 /*
133 * Make sure it is written back to the mapped
134 * physical memory.
135 */
136 sys_cache_data_flush_range(&vps3[i].mem[0], PAGE_SZ);
137
138 zassert_equal(*(int *)pa[i], markers[i],
139 "page copy modified original");
140 }
141
142 /* Unmap */
143 ret = sys_mm_drv_unmap_region(vps2, N_PAGES * PAGE_SZ);
144 zassert_true(ret == 0, "sys_mm_drv_unmap_region() failed (%d)", ret);
145
146 /* Verify the copied region was not unmapped */
147 for (int i = 0; i < N_PAGES; i++) {
148 zassert_equal(vps3[i].mem[0], poison,
149 "copied page data changed after unmap");
150 }
151
152 /* Verify the originals are still unmodified */
153 for (int i = 0; i < N_PAGES; i++) {
154 zassert_equal(*(int *)pa[i], markers[i],
155 "original page data changed after unmap");
156 }
157 }
158
ZTEST(adsp_mem,test_adsp_mem_map_array)159 ZTEST(adsp_mem, test_adsp_mem_map_array)
160 {
161 int ret;
162 uintptr_t pa[N_PAGES];
163 struct pagemem *page_buf = (void *)buf;
164
165 /* Find a virtual address beyond physical memory */
166 void *va = (void *)ROUND_UP(L2_SRAM_BASE + L2_SRAM_SIZE, PAGE_SZ);
167
168 for (int i = 0; i < N_PAGES; i++) {
169 /* Uses pages #0, #2, #4 */
170 pa[i] = POINTER_TO_UINT(&page_buf[i * 2]);
171 }
172
173 /* Map our physical pages to the new location */
174 ret = sys_mm_drv_map_array(va, pa, N_PAGES, 0U);
175
176 zassert_true(ret == 0, "sys_mm_drv_map_array() failed (%d)", ret);
177
178 /* Mark the new pages */
179 struct pagemem *vps = va;
180 const uint32_t markers[] = { 0x11111111, 0x22222222, 0x33333333 };
181
182 for (int i = 0; i < N_PAGES; i++) {
183 vps[i].mem[0] = markers[i];
184
185 /*
186 * Make sure it is written back to the mapped
187 * physical memory.
188 */
189 sys_cache_data_flush_range(&vps[i].mem[0], PAGE_SZ);
190
191 /*
192 * pa[i] is a cached address which means that the cached
193 * version still has the old value before the assignment
194 * above. So we need to invalidate the cache to reload
195 * the new value.
196 */
197 sys_cache_data_invd_range(UINT_TO_POINTER(pa[i]), PAGE_SZ);
198 }
199
200 /* Verify the originals reflect the change */
201 for (int i = 0; i < N_PAGES; i++) {
202 zassert_equal(vps[i].mem[0], *(uint32_t *)pa[i],
203 "mapping and original don't match (0x%x != 0x%x)",
204 vps[i].mem[0], *(uint32_t *)pa[i]);
205 }
206
207 /* Remap to another region (this will unmap the first virtual pages) */
208 struct pagemem *vps2 = &vps[N_PAGES];
209
210 /*
211 * Need to unmap vps2 as sys_mm_drv_remap_region() checks
212 * if the new virtual memory region is all unmapped.
213 */
214 ret = sys_mm_drv_unmap_region(vps2, N_PAGES * PAGE_SZ);
215 zassert_true(ret == 0, "sys_mm_drv_unmap_region() failed (%d)", ret);
216
217 ret = sys_mm_drv_remap_region(vps, N_PAGES * PAGE_SZ, vps2);
218 zassert_true(ret == 0, "sys_mm_drv_remap_region() failed (%d)", ret);
219
220 for (int i = 0; i < N_PAGES; i++) {
221 zassert_equal(vps2[i].mem[0], *(uint32_t *)pa[i],
222 "remapping and original don't match");
223 }
224
225 /* Now copy the remapped pages to a third virtual region */
226 struct pagemem *vps3 = &vps2[N_PAGES];
227 uintptr_t new_pages[N_PAGES];
228
229 for (int i = 0; i < N_PAGES; i++) {
230 /* Uses pages #1, #3, #5 */
231 new_pages[i] = POINTER_TO_UINT(&page_buf[i * 2 + 1]);
232 }
233
234 /*
235 * Need to unmap vps3 as sys_mm_drv_remap_region() checks
236 * if the new virtual memory region is all unmapped.
237 */
238 ret = sys_mm_drv_unmap_region(vps3, N_PAGES * PAGE_SZ);
239 zassert_true(ret == 0, "sys_mm_drv_unmap_region() failed (%d)", ret);
240
241 ret = sys_mm_drv_move_array(vps2, N_PAGES * PAGE_SZ,
242 vps3, new_pages, N_PAGES);
243 zassert_true(ret == 0, "sys_mm_drv_move_array() failed (%d)", ret);
244
245 /* Make sure they match the originals */
246 for (int i = 0; i < N_PAGES; i++) {
247 zassert_equal(vps3[i].mem[0], *(uint32_t *)pa[i],
248 "page copy failed to match data (0x%x != 0x%x)",
249 vps3[i].mem[0], *(uint32_t *)pa[i]);
250 }
251
252 /* Modify the copy and make sure the originals are unmodified */
253 const int poison = 0x5a5a5a5a;
254
255 for (int i = 0; i < N_PAGES; i++) {
256 vps3[i].mem[0] = poison;
257
258 /*
259 * Make sure it is written back to the mapped
260 * physical memory.
261 */
262 sys_cache_data_flush_range(&vps3[i].mem[0], PAGE_SZ);
263
264 zassert_equal(*(int *)pa[i], markers[i],
265 "page copy modified original");
266 }
267
268 /* Unmap */
269 ret = sys_mm_drv_unmap_region(vps2, N_PAGES * PAGE_SZ);
270 zassert_true(ret == 0, "sys_mm_drv_unmap_region() failed (%d)", ret);
271
272 /* Verify the copied region was not unmapped */
273 for (int i = 0; i < N_PAGES; i++) {
274 zassert_equal(vps3[i].mem[0], poison,
275 "copied page data changed after unmap");
276 }
277
278 /* Verify the originals are still unmodified */
279 for (int i = 0; i < N_PAGES; i++) {
280 zassert_equal(*(int *)pa[i], markers[i],
281 "original page data changed after unmap");
282 }
283 }
284
285 ZTEST_SUITE(adsp_mem, NULL, NULL, NULL, NULL, NULL);
286