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