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