xref: /spdk/test/env/memory/memory_ut.c (revision 8a0a98d35e21f282088edf28b9e8da66ec390e3a)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "env_dpdk/memory.c"
35 
36 #include "common/lib/test_env.c"
37 #include "spdk_cunit.h"
38 
39 #include "spdk/bit_array.h"
40 
41 static struct rte_mem_config g_mcfg = {};
42 
43 static struct rte_config g_cfg = {
44 	.mem_config = &g_mcfg,
45 };
46 
47 struct rte_config *
48 rte_eal_get_configuration(void)
49 {
50 	return &g_cfg;
51 }
52 
53 #if RTE_VERSION >= RTE_VERSION_NUM(18, 05, 0, 0)
54 typedef void (*rte_mem_event_callback_t)(enum rte_mem_event event_type,
55 		const void *addr, size_t len, void *arg);
56 typedef int (*rte_memseg_contig_walk_t)(const struct rte_memseg_list *msl,
57 					const struct rte_memseg *ms, size_t len, void *arg);
58 DEFINE_STUB(rte_mem_event_callback_register, int, (const char *name, rte_mem_event_callback_t clb,
59 		void *arg), 0);
60 DEFINE_STUB(rte_memseg_contig_walk, int, (rte_memseg_contig_walk_t func, void *arg), 0);
61 #endif
62 
63 #define PAGE_ARRAY_SIZE (100)
64 static struct spdk_bit_array *g_page_array;
65 
66 static int
67 test_mem_map_notify(void *cb_ctx, struct spdk_mem_map *map,
68 		    enum spdk_mem_map_notify_action action,
69 		    void *vaddr, size_t len)
70 {
71 	uint32_t i, end;
72 
73 	SPDK_CU_ASSERT_FATAL(((uintptr_t)vaddr & MASK_2MB) == 0);
74 	SPDK_CU_ASSERT_FATAL((len & MASK_2MB) == 0);
75 
76 	/*
77 	 * This is a test requirement - the bit array we use to verify
78 	 * pages are valid is only so large.
79 	 */
80 	SPDK_CU_ASSERT_FATAL((uintptr_t)vaddr < (VALUE_2MB * PAGE_ARRAY_SIZE));
81 
82 	i = (uintptr_t)vaddr >> SHIFT_2MB;
83 	end = i + (len >> SHIFT_2MB);
84 	for (; i < end; i++) {
85 		switch (action) {
86 		case SPDK_MEM_MAP_NOTIFY_REGISTER:
87 			/* This page should not already be registered */
88 			SPDK_CU_ASSERT_FATAL(spdk_bit_array_get(g_page_array, i) == false);
89 			SPDK_CU_ASSERT_FATAL(spdk_bit_array_set(g_page_array, i) == 0);
90 			break;
91 		case SPDK_MEM_MAP_NOTIFY_UNREGISTER:
92 			SPDK_CU_ASSERT_FATAL(spdk_bit_array_get(g_page_array, i) == true);
93 			spdk_bit_array_clear(g_page_array, i);
94 			break;
95 		default:
96 			SPDK_UNREACHABLE();
97 		}
98 	}
99 
100 	return 0;
101 }
102 
103 static void
104 test_mem_map_alloc_free(void)
105 {
106 	struct spdk_mem_map *map;
107 	uint64_t default_translation = 0xDEADBEEF0BADF00D;
108 
109 	map = spdk_mem_map_alloc(default_translation, test_mem_map_notify, NULL);
110 	SPDK_CU_ASSERT_FATAL(map != NULL);
111 
112 	spdk_mem_map_free(&map);
113 	CU_ASSERT(map == NULL);
114 }
115 
116 static void
117 test_mem_map_translation(void)
118 {
119 	struct spdk_mem_map *map;
120 	uint64_t default_translation = 0xDEADBEEF0BADF00D;
121 	uint64_t addr;
122 	int rc;
123 
124 	map = spdk_mem_map_alloc(default_translation, test_mem_map_notify, NULL);
125 	SPDK_CU_ASSERT_FATAL(map != NULL);
126 
127 	/* Try to get translation for address with no translation */
128 	addr = spdk_mem_map_translate(map, 10, VALUE_2MB);
129 	CU_ASSERT(addr == default_translation);
130 
131 	/* Set translation for region of non-2MB multiple size */
132 	rc = spdk_mem_map_set_translation(map, VALUE_2MB, 1234, VALUE_2MB);
133 	CU_ASSERT(rc == -EINVAL);
134 
135 	/* Set translation for vaddr that isn't 2MB aligned */
136 	rc = spdk_mem_map_set_translation(map, 1234, VALUE_2MB, VALUE_2MB);
137 	CU_ASSERT(rc == -EINVAL);
138 
139 	/* Set translation for one 2MB page */
140 	rc = spdk_mem_map_set_translation(map, VALUE_2MB, VALUE_2MB, VALUE_2MB);
141 	CU_ASSERT(rc == 0);
142 
143 	/* Set translation for region that overlaps the previous translation */
144 	rc = spdk_mem_map_set_translation(map, 0, 3 * VALUE_2MB, 0);
145 	CU_ASSERT(rc == 0);
146 
147 	/* Clear translation for the middle page of the larger region. */
148 	rc = spdk_mem_map_clear_translation(map, VALUE_2MB, VALUE_2MB);
149 	CU_ASSERT(rc == 0);
150 
151 	/* Get translation for first page */
152 	addr = spdk_mem_map_translate(map, 0, VALUE_2MB);
153 	CU_ASSERT(addr == 0);
154 
155 	/* Verify translation for 2nd page is the default */
156 	addr = spdk_mem_map_translate(map, VALUE_2MB, VALUE_2MB);
157 	CU_ASSERT(addr == default_translation);
158 
159 	/* Get translation for third page */
160 	addr = spdk_mem_map_translate(map, 2 * VALUE_2MB, VALUE_2MB);
161 	/*
162 	 * Note that addr should be 0, not 4MB. When we set the
163 	 * translation above, we said the whole 6MB region
164 	 * should translate to 0.
165 	 */
166 	CU_ASSERT(addr == 0);
167 
168 	/* Clear translation for the first page */
169 	rc = spdk_mem_map_clear_translation(map, 0, VALUE_2MB);
170 	CU_ASSERT(rc == 0);
171 
172 	/* Get translation for the first page */
173 	addr = spdk_mem_map_translate(map, 0, VALUE_2MB);
174 	CU_ASSERT(addr == default_translation);
175 
176 	/* Clear translation for the third page */
177 	rc = spdk_mem_map_clear_translation(map, 2 * VALUE_2MB, VALUE_2MB);
178 	CU_ASSERT(rc == 0);
179 
180 	/* Get translation for the third page */
181 	addr = spdk_mem_map_translate(map, 2 * VALUE_2MB, VALUE_2MB);
182 	CU_ASSERT(addr == default_translation);
183 
184 	spdk_mem_map_free(&map);
185 	CU_ASSERT(map == NULL);
186 }
187 
188 static void
189 test_mem_map_registration(void)
190 {
191 	int rc;
192 	struct spdk_mem_map *map;
193 	uint64_t default_translation = 0xDEADBEEF0BADF00D;
194 
195 	map = spdk_mem_map_alloc(default_translation, test_mem_map_notify, NULL);
196 	SPDK_CU_ASSERT_FATAL(map != NULL);
197 
198 	/* Unregister memory region that wasn't previously registered */
199 	rc =  spdk_mem_unregister((void *)VALUE_2MB, VALUE_2MB);
200 	CU_ASSERT(rc == -EINVAL);
201 
202 	/* Register non-2MB multiple size */
203 	rc = spdk_mem_register((void *)VALUE_2MB, 1234);
204 	CU_ASSERT(rc == -EINVAL);
205 
206 	/* Register region that isn't 2MB aligned */
207 	rc = spdk_mem_register((void *)1234, VALUE_2MB);
208 	CU_ASSERT(rc == -EINVAL);
209 
210 	/* Register one 2MB page */
211 	rc = spdk_mem_register((void *)VALUE_2MB, VALUE_2MB);
212 	CU_ASSERT(rc == 0);
213 
214 	/* Register an overlapping address range */
215 	rc = spdk_mem_register((void *)0, 3 * VALUE_2MB);
216 	CU_ASSERT(rc == 0);
217 
218 	/*
219 	 * Unregister the middle page of the larger region.
220 	 * It was set twice, so unregister it twice.
221 	 */
222 	rc = spdk_mem_unregister((void *)VALUE_2MB, VALUE_2MB);
223 	CU_ASSERT(rc == 0);
224 	rc = spdk_mem_unregister((void *)VALUE_2MB, VALUE_2MB);
225 	CU_ASSERT(rc == 0);
226 
227 	/* Unregister the first page */
228 	rc = spdk_mem_unregister((void *)0, VALUE_2MB);
229 	CU_ASSERT(rc == 0);
230 
231 	/* Unregister the third page */
232 	rc = spdk_mem_unregister((void *)(2 * VALUE_2MB), VALUE_2MB);
233 	CU_ASSERT(rc == 0);
234 
235 	spdk_mem_map_free(&map);
236 	CU_ASSERT(map == NULL);
237 }
238 
239 int
240 main(int argc, char **argv)
241 {
242 	CU_pSuite	suite = NULL;
243 	unsigned int	num_failures;
244 
245 	/*
246 	 * These tests can use PAGE_ARRAY_SIZE 2MB pages of memory.
247 	 * Note that the tests just verify addresses - this memory
248 	 * is not actually allocated.
249 	  */
250 	g_page_array = spdk_bit_array_create(PAGE_ARRAY_SIZE);
251 
252 	/* Initialize the memory map */
253 	if (spdk_mem_map_init() < 0) {
254 		return CUE_NOMEMORY;
255 	}
256 
257 	if (CU_initialize_registry() != CUE_SUCCESS) {
258 		return CU_get_error();
259 	}
260 
261 	suite = CU_add_suite("memory", NULL, NULL);
262 	if (suite == NULL) {
263 		CU_cleanup_registry();
264 		return CU_get_error();
265 	}
266 
267 	if (
268 		CU_add_test(suite, "alloc and free memory map", test_mem_map_alloc_free) == NULL ||
269 		CU_add_test(suite, "mem map translation", test_mem_map_translation) == NULL ||
270 		CU_add_test(suite, "mem map registration", test_mem_map_registration) == NULL
271 	) {
272 		CU_cleanup_registry();
273 		return CU_get_error();
274 	}
275 
276 	CU_basic_set_mode(CU_BRM_VERBOSE);
277 	CU_basic_run_tests();
278 	num_failures = CU_get_number_of_failures();
279 	CU_cleanup_registry();
280 
281 	spdk_bit_array_free(&g_page_array);
282 
283 	return num_failures;
284 }
285