1*4418919fSjohnjiang /* SPDX-License-Identifier: BSD-3-Clause
2*4418919fSjohnjiang * Copyright(c) 2018 Intel Corporation
3*4418919fSjohnjiang */
4*4418919fSjohnjiang
5*4418919fSjohnjiang #include <errno.h>
6*4418919fSjohnjiang #include <stdio.h>
7*4418919fSjohnjiang #include <stdlib.h>
8*4418919fSjohnjiang #include <string.h>
9*4418919fSjohnjiang #include <fcntl.h>
10*4418919fSjohnjiang #include <sys/mman.h>
11*4418919fSjohnjiang #include <sys/wait.h>
12*4418919fSjohnjiang
13*4418919fSjohnjiang #include <rte_common.h>
14*4418919fSjohnjiang #include <rte_debug.h>
15*4418919fSjohnjiang #include <rte_eal.h>
16*4418919fSjohnjiang #include <rte_errno.h>
17*4418919fSjohnjiang #include <rte_malloc.h>
18*4418919fSjohnjiang #include <rte_ring.h>
19*4418919fSjohnjiang #include <rte_string_fns.h>
20*4418919fSjohnjiang
21*4418919fSjohnjiang #include "test.h"
22*4418919fSjohnjiang
23*4418919fSjohnjiang #define EXTERNAL_MEM_SZ (RTE_PGSIZE_4K << 10) /* 4M of data */
24*4418919fSjohnjiang
25*4418919fSjohnjiang static int
check_mem(void * addr,rte_iova_t * iova,size_t pgsz,int n_pages)26*4418919fSjohnjiang check_mem(void *addr, rte_iova_t *iova, size_t pgsz, int n_pages)
27*4418919fSjohnjiang {
28*4418919fSjohnjiang int i;
29*4418919fSjohnjiang
30*4418919fSjohnjiang /* check that we can get this memory from EAL now */
31*4418919fSjohnjiang for (i = 0; i < n_pages; i++) {
32*4418919fSjohnjiang const struct rte_memseg_list *msl;
33*4418919fSjohnjiang const struct rte_memseg *ms;
34*4418919fSjohnjiang void *cur = RTE_PTR_ADD(addr, pgsz * i);
35*4418919fSjohnjiang rte_iova_t expected_iova;
36*4418919fSjohnjiang
37*4418919fSjohnjiang msl = rte_mem_virt2memseg_list(cur);
38*4418919fSjohnjiang if (!msl->external) {
39*4418919fSjohnjiang printf("%s():%i: Memseg list is not marked as external\n",
40*4418919fSjohnjiang __func__, __LINE__);
41*4418919fSjohnjiang return -1;
42*4418919fSjohnjiang }
43*4418919fSjohnjiang
44*4418919fSjohnjiang ms = rte_mem_virt2memseg(cur, msl);
45*4418919fSjohnjiang if (ms == NULL) {
46*4418919fSjohnjiang printf("%s():%i: Failed to retrieve memseg for external mem\n",
47*4418919fSjohnjiang __func__, __LINE__);
48*4418919fSjohnjiang return -1;
49*4418919fSjohnjiang }
50*4418919fSjohnjiang if (ms->addr != cur) {
51*4418919fSjohnjiang printf("%s():%i: VA mismatch\n", __func__, __LINE__);
52*4418919fSjohnjiang return -1;
53*4418919fSjohnjiang }
54*4418919fSjohnjiang expected_iova = (iova == NULL) ? RTE_BAD_IOVA : iova[i];
55*4418919fSjohnjiang if (ms->iova != expected_iova) {
56*4418919fSjohnjiang printf("%s():%i: IOVA mismatch\n", __func__, __LINE__);
57*4418919fSjohnjiang return -1;
58*4418919fSjohnjiang }
59*4418919fSjohnjiang }
60*4418919fSjohnjiang return 0;
61*4418919fSjohnjiang }
62*4418919fSjohnjiang
63*4418919fSjohnjiang static int
test_malloc_invalid_param(void * addr,size_t len,size_t pgsz,rte_iova_t * iova,int n_pages)64*4418919fSjohnjiang test_malloc_invalid_param(void *addr, size_t len, size_t pgsz, rte_iova_t *iova,
65*4418919fSjohnjiang int n_pages)
66*4418919fSjohnjiang {
67*4418919fSjohnjiang static const char * const names[] = {
68*4418919fSjohnjiang NULL, /* NULL name */
69*4418919fSjohnjiang "", /* empty name */
70*4418919fSjohnjiang "this heap name is definitely way too long to be valid"
71*4418919fSjohnjiang };
72*4418919fSjohnjiang const char *valid_name = "valid heap name";
73*4418919fSjohnjiang unsigned int i;
74*4418919fSjohnjiang
75*4418919fSjohnjiang /* check invalid name handling */
76*4418919fSjohnjiang for (i = 0; i < RTE_DIM(names); i++) {
77*4418919fSjohnjiang const char *name = names[i];
78*4418919fSjohnjiang
79*4418919fSjohnjiang /* these calls may fail for other reasons, so check errno */
80*4418919fSjohnjiang if (rte_malloc_heap_create(name) >= 0 || rte_errno != EINVAL) {
81*4418919fSjohnjiang printf("%s():%i: Created heap with invalid name\n",
82*4418919fSjohnjiang __func__, __LINE__);
83*4418919fSjohnjiang goto fail;
84*4418919fSjohnjiang }
85*4418919fSjohnjiang
86*4418919fSjohnjiang if (rte_malloc_heap_destroy(name) >= 0 || rte_errno != EINVAL) {
87*4418919fSjohnjiang printf("%s():%i: Destroyed heap with invalid name\n",
88*4418919fSjohnjiang __func__, __LINE__);
89*4418919fSjohnjiang goto fail;
90*4418919fSjohnjiang }
91*4418919fSjohnjiang
92*4418919fSjohnjiang if (rte_malloc_heap_get_socket(name) >= 0 ||
93*4418919fSjohnjiang rte_errno != EINVAL) {
94*4418919fSjohnjiang printf("%s():%i: Found socket for heap with invalid name\n",
95*4418919fSjohnjiang __func__, __LINE__);
96*4418919fSjohnjiang goto fail;
97*4418919fSjohnjiang }
98*4418919fSjohnjiang
99*4418919fSjohnjiang if (rte_malloc_heap_memory_add(name, addr, len,
100*4418919fSjohnjiang NULL, 0, pgsz) >= 0 || rte_errno != EINVAL) {
101*4418919fSjohnjiang printf("%s():%i: Added memory to heap with invalid name\n",
102*4418919fSjohnjiang __func__, __LINE__);
103*4418919fSjohnjiang goto fail;
104*4418919fSjohnjiang }
105*4418919fSjohnjiang if (rte_malloc_heap_memory_remove(name, addr, len) >= 0 ||
106*4418919fSjohnjiang rte_errno != EINVAL) {
107*4418919fSjohnjiang printf("%s():%i: Removed memory from heap with invalid name\n",
108*4418919fSjohnjiang __func__, __LINE__);
109*4418919fSjohnjiang goto fail;
110*4418919fSjohnjiang }
111*4418919fSjohnjiang
112*4418919fSjohnjiang if (rte_malloc_heap_memory_attach(name, addr, len) >= 0 ||
113*4418919fSjohnjiang rte_errno != EINVAL) {
114*4418919fSjohnjiang printf("%s():%i: Attached memory to heap with invalid name\n",
115*4418919fSjohnjiang __func__, __LINE__);
116*4418919fSjohnjiang goto fail;
117*4418919fSjohnjiang }
118*4418919fSjohnjiang if (rte_malloc_heap_memory_detach(name, addr, len) >= 0 ||
119*4418919fSjohnjiang rte_errno != EINVAL) {
120*4418919fSjohnjiang printf("%s():%i: Detached memory from heap with invalid name\n",
121*4418919fSjohnjiang __func__, __LINE__);
122*4418919fSjohnjiang goto fail;
123*4418919fSjohnjiang }
124*4418919fSjohnjiang }
125*4418919fSjohnjiang
126*4418919fSjohnjiang /* do same as above, but with a valid heap name */
127*4418919fSjohnjiang
128*4418919fSjohnjiang /* skip create call */
129*4418919fSjohnjiang if (rte_malloc_heap_destroy(valid_name) >= 0 || rte_errno != ENOENT) {
130*4418919fSjohnjiang printf("%s():%i: Destroyed heap with invalid name\n",
131*4418919fSjohnjiang __func__, __LINE__);
132*4418919fSjohnjiang goto fail;
133*4418919fSjohnjiang }
134*4418919fSjohnjiang if (rte_malloc_heap_get_socket(valid_name) >= 0 ||
135*4418919fSjohnjiang rte_errno != ENOENT) {
136*4418919fSjohnjiang printf("%s():%i: Found socket for heap with invalid name\n",
137*4418919fSjohnjiang __func__, __LINE__);
138*4418919fSjohnjiang goto fail;
139*4418919fSjohnjiang }
140*4418919fSjohnjiang
141*4418919fSjohnjiang /* these calls may fail for other reasons, so check errno */
142*4418919fSjohnjiang if (rte_malloc_heap_memory_add(valid_name, addr, len,
143*4418919fSjohnjiang NULL, 0, pgsz) >= 0 || rte_errno != ENOENT) {
144*4418919fSjohnjiang printf("%s():%i: Added memory to non-existent heap\n",
145*4418919fSjohnjiang __func__, __LINE__);
146*4418919fSjohnjiang goto fail;
147*4418919fSjohnjiang }
148*4418919fSjohnjiang if (rte_malloc_heap_memory_remove(valid_name, addr, len) >= 0 ||
149*4418919fSjohnjiang rte_errno != ENOENT) {
150*4418919fSjohnjiang printf("%s():%i: Removed memory from non-existent heap\n",
151*4418919fSjohnjiang __func__, __LINE__);
152*4418919fSjohnjiang goto fail;
153*4418919fSjohnjiang }
154*4418919fSjohnjiang
155*4418919fSjohnjiang if (rte_malloc_heap_memory_attach(valid_name, addr, len) >= 0 ||
156*4418919fSjohnjiang rte_errno != ENOENT) {
157*4418919fSjohnjiang printf("%s():%i: Attached memory to non-existent heap\n",
158*4418919fSjohnjiang __func__, __LINE__);
159*4418919fSjohnjiang goto fail;
160*4418919fSjohnjiang }
161*4418919fSjohnjiang if (rte_malloc_heap_memory_detach(valid_name, addr, len) >= 0 ||
162*4418919fSjohnjiang rte_errno != ENOENT) {
163*4418919fSjohnjiang printf("%s():%i: Detached memory from non-existent heap\n",
164*4418919fSjohnjiang __func__, __LINE__);
165*4418919fSjohnjiang goto fail;
166*4418919fSjohnjiang }
167*4418919fSjohnjiang
168*4418919fSjohnjiang /* create a valid heap but test other invalid parameters */
169*4418919fSjohnjiang if (rte_malloc_heap_create(valid_name) != 0) {
170*4418919fSjohnjiang printf("%s():%i: Failed to create valid heap\n",
171*4418919fSjohnjiang __func__, __LINE__);
172*4418919fSjohnjiang goto fail;
173*4418919fSjohnjiang }
174*4418919fSjohnjiang
175*4418919fSjohnjiang /* zero length */
176*4418919fSjohnjiang if (rte_malloc_heap_memory_add(valid_name, addr, 0,
177*4418919fSjohnjiang NULL, 0, pgsz) >= 0 || rte_errno != EINVAL) {
178*4418919fSjohnjiang printf("%s():%i: Added memory with invalid parameters\n",
179*4418919fSjohnjiang __func__, __LINE__);
180*4418919fSjohnjiang goto fail;
181*4418919fSjohnjiang }
182*4418919fSjohnjiang
183*4418919fSjohnjiang if (rte_malloc_heap_memory_remove(valid_name, addr, 0) >= 0 ||
184*4418919fSjohnjiang rte_errno != EINVAL) {
185*4418919fSjohnjiang printf("%s():%i: Removed memory with invalid parameters\n",
186*4418919fSjohnjiang __func__, __LINE__);
187*4418919fSjohnjiang goto fail;
188*4418919fSjohnjiang }
189*4418919fSjohnjiang
190*4418919fSjohnjiang if (rte_malloc_heap_memory_attach(valid_name, addr, 0) >= 0 ||
191*4418919fSjohnjiang rte_errno != EINVAL) {
192*4418919fSjohnjiang printf("%s():%i: Attached memory with invalid parameters\n",
193*4418919fSjohnjiang __func__, __LINE__);
194*4418919fSjohnjiang goto fail;
195*4418919fSjohnjiang }
196*4418919fSjohnjiang if (rte_malloc_heap_memory_detach(valid_name, addr, 0) >= 0 ||
197*4418919fSjohnjiang rte_errno != EINVAL) {
198*4418919fSjohnjiang printf("%s():%i: Detached memory with invalid parameters\n",
199*4418919fSjohnjiang __func__, __LINE__);
200*4418919fSjohnjiang goto fail;
201*4418919fSjohnjiang }
202*4418919fSjohnjiang
203*4418919fSjohnjiang /* zero address */
204*4418919fSjohnjiang if (rte_malloc_heap_memory_add(valid_name, NULL, len,
205*4418919fSjohnjiang NULL, 0, pgsz) >= 0 || rte_errno != EINVAL) {
206*4418919fSjohnjiang printf("%s():%i: Added memory with invalid parameters\n",
207*4418919fSjohnjiang __func__, __LINE__);
208*4418919fSjohnjiang goto fail;
209*4418919fSjohnjiang }
210*4418919fSjohnjiang
211*4418919fSjohnjiang if (rte_malloc_heap_memory_remove(valid_name, NULL, len) >= 0 ||
212*4418919fSjohnjiang rte_errno != EINVAL) {
213*4418919fSjohnjiang printf("%s():%i: Removed memory with invalid parameters\n",
214*4418919fSjohnjiang __func__, __LINE__);
215*4418919fSjohnjiang goto fail;
216*4418919fSjohnjiang }
217*4418919fSjohnjiang
218*4418919fSjohnjiang if (rte_malloc_heap_memory_attach(valid_name, NULL, len) >= 0 ||
219*4418919fSjohnjiang rte_errno != EINVAL) {
220*4418919fSjohnjiang printf("%s():%i: Attached memory with invalid parameters\n",
221*4418919fSjohnjiang __func__, __LINE__);
222*4418919fSjohnjiang goto fail;
223*4418919fSjohnjiang }
224*4418919fSjohnjiang if (rte_malloc_heap_memory_detach(valid_name, NULL, len) >= 0 ||
225*4418919fSjohnjiang rte_errno != EINVAL) {
226*4418919fSjohnjiang printf("%s():%i: Detached memory with invalid parameters\n",
227*4418919fSjohnjiang __func__, __LINE__);
228*4418919fSjohnjiang goto fail;
229*4418919fSjohnjiang }
230*4418919fSjohnjiang
231*4418919fSjohnjiang /* the following tests are only valid if IOVA table is not NULL */
232*4418919fSjohnjiang if (iova != NULL) {
233*4418919fSjohnjiang /* wrong page count */
234*4418919fSjohnjiang if (rte_malloc_heap_memory_add(valid_name, addr, len,
235*4418919fSjohnjiang iova, 0, pgsz) >= 0 || rte_errno != EINVAL) {
236*4418919fSjohnjiang printf("%s():%i: Added memory with invalid parameters\n",
237*4418919fSjohnjiang __func__, __LINE__);
238*4418919fSjohnjiang goto fail;
239*4418919fSjohnjiang }
240*4418919fSjohnjiang if (rte_malloc_heap_memory_add(valid_name, addr, len,
241*4418919fSjohnjiang iova, n_pages - 1, pgsz) >= 0 ||
242*4418919fSjohnjiang rte_errno != EINVAL) {
243*4418919fSjohnjiang printf("%s():%i: Added memory with invalid parameters\n",
244*4418919fSjohnjiang __func__, __LINE__);
245*4418919fSjohnjiang goto fail;
246*4418919fSjohnjiang }
247*4418919fSjohnjiang if (rte_malloc_heap_memory_add(valid_name, addr, len,
248*4418919fSjohnjiang iova, n_pages + 1, pgsz) >= 0 ||
249*4418919fSjohnjiang rte_errno != EINVAL) {
250*4418919fSjohnjiang printf("%s():%i: Added memory with invalid parameters\n",
251*4418919fSjohnjiang __func__, __LINE__);
252*4418919fSjohnjiang goto fail;
253*4418919fSjohnjiang }
254*4418919fSjohnjiang }
255*4418919fSjohnjiang
256*4418919fSjohnjiang /* tests passed, destroy heap */
257*4418919fSjohnjiang if (rte_malloc_heap_destroy(valid_name) != 0) {
258*4418919fSjohnjiang printf("%s():%i: Failed to destroy valid heap\n",
259*4418919fSjohnjiang __func__, __LINE__);
260*4418919fSjohnjiang goto fail;
261*4418919fSjohnjiang }
262*4418919fSjohnjiang return 0;
263*4418919fSjohnjiang fail:
264*4418919fSjohnjiang rte_malloc_heap_destroy(valid_name);
265*4418919fSjohnjiang return -1;
266*4418919fSjohnjiang }
267*4418919fSjohnjiang
268*4418919fSjohnjiang static int
test_malloc_basic(void * addr,size_t len,size_t pgsz,rte_iova_t * iova,int n_pages)269*4418919fSjohnjiang test_malloc_basic(void *addr, size_t len, size_t pgsz, rte_iova_t *iova,
270*4418919fSjohnjiang int n_pages)
271*4418919fSjohnjiang {
272*4418919fSjohnjiang const char *heap_name = "heap";
273*4418919fSjohnjiang void *ptr = NULL;
274*4418919fSjohnjiang int socket_id;
275*4418919fSjohnjiang const struct rte_memzone *mz = NULL, *contig_mz = NULL;
276*4418919fSjohnjiang
277*4418919fSjohnjiang /* create heap */
278*4418919fSjohnjiang if (rte_malloc_heap_create(heap_name) != 0) {
279*4418919fSjohnjiang printf("%s():%i: Failed to create malloc heap\n",
280*4418919fSjohnjiang __func__, __LINE__);
281*4418919fSjohnjiang goto fail;
282*4418919fSjohnjiang }
283*4418919fSjohnjiang
284*4418919fSjohnjiang /* get socket ID corresponding to this heap */
285*4418919fSjohnjiang socket_id = rte_malloc_heap_get_socket(heap_name);
286*4418919fSjohnjiang if (socket_id < 0) {
287*4418919fSjohnjiang printf("%s():%i: cannot find socket for external heap\n",
288*4418919fSjohnjiang __func__, __LINE__);
289*4418919fSjohnjiang goto fail;
290*4418919fSjohnjiang }
291*4418919fSjohnjiang
292*4418919fSjohnjiang /* heap is empty, so any allocation should fail */
293*4418919fSjohnjiang ptr = rte_malloc_socket("EXTMEM", 64, 0, socket_id);
294*4418919fSjohnjiang if (ptr != NULL) {
295*4418919fSjohnjiang printf("%s():%i: Allocated from empty heap\n", __func__,
296*4418919fSjohnjiang __LINE__);
297*4418919fSjohnjiang goto fail;
298*4418919fSjohnjiang }
299*4418919fSjohnjiang
300*4418919fSjohnjiang /* add memory to heap */
301*4418919fSjohnjiang if (rte_malloc_heap_memory_add(heap_name, addr, len,
302*4418919fSjohnjiang iova, n_pages, pgsz) != 0) {
303*4418919fSjohnjiang printf("%s():%i: Failed to add memory to heap\n",
304*4418919fSjohnjiang __func__, __LINE__);
305*4418919fSjohnjiang goto fail;
306*4418919fSjohnjiang }
307*4418919fSjohnjiang
308*4418919fSjohnjiang /* check if memory is accessible from EAL */
309*4418919fSjohnjiang if (check_mem(addr, iova, pgsz, n_pages) < 0)
310*4418919fSjohnjiang goto fail;
311*4418919fSjohnjiang
312*4418919fSjohnjiang /* allocate - this now should succeed */
313*4418919fSjohnjiang ptr = rte_malloc_socket("EXTMEM", 64, 0, socket_id);
314*4418919fSjohnjiang if (ptr == NULL) {
315*4418919fSjohnjiang printf("%s():%i: Failed to allocate from external heap\n",
316*4418919fSjohnjiang __func__, __LINE__);
317*4418919fSjohnjiang goto fail;
318*4418919fSjohnjiang }
319*4418919fSjohnjiang
320*4418919fSjohnjiang /* check if address is in expected range */
321*4418919fSjohnjiang if (ptr < addr || ptr >= RTE_PTR_ADD(addr, len)) {
322*4418919fSjohnjiang printf("%s():%i: Allocated from unexpected address space\n",
323*4418919fSjohnjiang __func__, __LINE__);
324*4418919fSjohnjiang goto fail;
325*4418919fSjohnjiang }
326*4418919fSjohnjiang
327*4418919fSjohnjiang /* we've allocated something - removing memory should fail */
328*4418919fSjohnjiang if (rte_malloc_heap_memory_remove(heap_name, addr, len) >= 0 ||
329*4418919fSjohnjiang rte_errno != EBUSY) {
330*4418919fSjohnjiang printf("%s():%i: Removing memory succeeded when memory is not free\n",
331*4418919fSjohnjiang __func__, __LINE__);
332*4418919fSjohnjiang goto fail;
333*4418919fSjohnjiang }
334*4418919fSjohnjiang if (rte_malloc_heap_destroy(heap_name) >= 0 || rte_errno != EBUSY) {
335*4418919fSjohnjiang printf("%s():%i: Destroying heap succeeded when memory is not free\n",
336*4418919fSjohnjiang __func__, __LINE__);
337*4418919fSjohnjiang goto fail;
338*4418919fSjohnjiang }
339*4418919fSjohnjiang
340*4418919fSjohnjiang /* try allocating a memzone */
341*4418919fSjohnjiang mz = rte_memzone_reserve("heap_test", pgsz * 2, socket_id, 0);
342*4418919fSjohnjiang if (mz == NULL) {
343*4418919fSjohnjiang printf("%s():%i: Failed to reserve memzone\n",
344*4418919fSjohnjiang __func__, __LINE__);
345*4418919fSjohnjiang goto fail;
346*4418919fSjohnjiang }
347*4418919fSjohnjiang /* try allocating an IOVA-contiguous memzone - this should succeed
348*4418919fSjohnjiang * if we've set up a contiguous IOVA table, and fail if we haven't.
349*4418919fSjohnjiang */
350*4418919fSjohnjiang contig_mz = rte_memzone_reserve("heap_test_contig", pgsz * 2, socket_id,
351*4418919fSjohnjiang RTE_MEMZONE_IOVA_CONTIG);
352*4418919fSjohnjiang if ((iova == NULL) != (contig_mz == NULL)) {
353*4418919fSjohnjiang printf("%s():%i: Failed to reserve memzone\n",
354*4418919fSjohnjiang __func__, __LINE__);
355*4418919fSjohnjiang goto fail;
356*4418919fSjohnjiang }
357*4418919fSjohnjiang
358*4418919fSjohnjiang rte_malloc_dump_stats(stdout, NULL);
359*4418919fSjohnjiang rte_malloc_dump_heaps(stdout);
360*4418919fSjohnjiang
361*4418919fSjohnjiang /* free memory - removing it should now succeed */
362*4418919fSjohnjiang rte_free(ptr);
363*4418919fSjohnjiang ptr = NULL;
364*4418919fSjohnjiang
365*4418919fSjohnjiang rte_memzone_free(mz);
366*4418919fSjohnjiang mz = NULL;
367*4418919fSjohnjiang rte_memzone_free(contig_mz);
368*4418919fSjohnjiang contig_mz = NULL;
369*4418919fSjohnjiang
370*4418919fSjohnjiang if (rte_malloc_heap_memory_remove(heap_name, addr, len) != 0) {
371*4418919fSjohnjiang printf("%s():%i: Removing memory from heap failed\n",
372*4418919fSjohnjiang __func__, __LINE__);
373*4418919fSjohnjiang goto fail;
374*4418919fSjohnjiang }
375*4418919fSjohnjiang if (rte_malloc_heap_destroy(heap_name) != 0) {
376*4418919fSjohnjiang printf("%s():%i: Destroying heap failed\n",
377*4418919fSjohnjiang __func__, __LINE__);
378*4418919fSjohnjiang goto fail;
379*4418919fSjohnjiang }
380*4418919fSjohnjiang
381*4418919fSjohnjiang return 0;
382*4418919fSjohnjiang fail:
383*4418919fSjohnjiang rte_memzone_free(contig_mz);
384*4418919fSjohnjiang rte_memzone_free(mz);
385*4418919fSjohnjiang rte_free(ptr);
386*4418919fSjohnjiang /* even if something failed, attempt to clean up */
387*4418919fSjohnjiang rte_malloc_heap_memory_remove(heap_name, addr, len);
388*4418919fSjohnjiang rte_malloc_heap_destroy(heap_name);
389*4418919fSjohnjiang
390*4418919fSjohnjiang return -1;
391*4418919fSjohnjiang }
392*4418919fSjohnjiang
393*4418919fSjohnjiang static int
test_extmem_invalid_param(void * addr,size_t len,size_t pgsz,rte_iova_t * iova,int n_pages)394*4418919fSjohnjiang test_extmem_invalid_param(void *addr, size_t len, size_t pgsz, rte_iova_t *iova,
395*4418919fSjohnjiang int n_pages)
396*4418919fSjohnjiang {
397*4418919fSjohnjiang /* these calls may fail for other reasons, so check errno */
398*4418919fSjohnjiang if (rte_extmem_unregister(addr, len) >= 0 ||
399*4418919fSjohnjiang rte_errno != ENOENT) {
400*4418919fSjohnjiang printf("%s():%i: Unregistered non-existent memory\n",
401*4418919fSjohnjiang __func__, __LINE__);
402*4418919fSjohnjiang return -1;
403*4418919fSjohnjiang }
404*4418919fSjohnjiang
405*4418919fSjohnjiang if (rte_extmem_attach(addr, len) >= 0 ||
406*4418919fSjohnjiang rte_errno != ENOENT) {
407*4418919fSjohnjiang printf("%s():%i: Attached to non-existent memory\n",
408*4418919fSjohnjiang __func__, __LINE__);
409*4418919fSjohnjiang return -1;
410*4418919fSjohnjiang }
411*4418919fSjohnjiang if (rte_extmem_attach(addr, len) >= 0 ||
412*4418919fSjohnjiang rte_errno != ENOENT) {
413*4418919fSjohnjiang printf("%s():%i: Detached from non-existent memory\n",
414*4418919fSjohnjiang __func__, __LINE__);
415*4418919fSjohnjiang return -1;
416*4418919fSjohnjiang }
417*4418919fSjohnjiang
418*4418919fSjohnjiang /* zero length */
419*4418919fSjohnjiang if (rte_extmem_register(addr, 0, NULL, 0, pgsz) >= 0 ||
420*4418919fSjohnjiang rte_errno != EINVAL) {
421*4418919fSjohnjiang printf("%s():%i: Registered memory with invalid parameters\n",
422*4418919fSjohnjiang __func__, __LINE__);
423*4418919fSjohnjiang return -1;
424*4418919fSjohnjiang }
425*4418919fSjohnjiang
426*4418919fSjohnjiang if (rte_extmem_unregister(addr, 0) >= 0 ||
427*4418919fSjohnjiang rte_errno != EINVAL) {
428*4418919fSjohnjiang printf("%s():%i: Unregistered memory with invalid parameters\n",
429*4418919fSjohnjiang __func__, __LINE__);
430*4418919fSjohnjiang return -1;
431*4418919fSjohnjiang }
432*4418919fSjohnjiang
433*4418919fSjohnjiang if (rte_extmem_attach(addr, 0) >= 0 ||
434*4418919fSjohnjiang rte_errno != EINVAL) {
435*4418919fSjohnjiang printf("%s():%i: Attached memory with invalid parameters\n",
436*4418919fSjohnjiang __func__, __LINE__);
437*4418919fSjohnjiang return -1;
438*4418919fSjohnjiang }
439*4418919fSjohnjiang if (rte_extmem_attach(addr, 0) >= 0 ||
440*4418919fSjohnjiang rte_errno != EINVAL) {
441*4418919fSjohnjiang printf("%s():%i: Detached memory with invalid parameters\n",
442*4418919fSjohnjiang __func__, __LINE__);
443*4418919fSjohnjiang return -1;
444*4418919fSjohnjiang }
445*4418919fSjohnjiang
446*4418919fSjohnjiang /* zero address */
447*4418919fSjohnjiang if (rte_extmem_register(NULL, len, NULL, 0, pgsz) >= 0 ||
448*4418919fSjohnjiang rte_errno != EINVAL) {
449*4418919fSjohnjiang printf("%s():%i: Registered memory with invalid parameters\n",
450*4418919fSjohnjiang __func__, __LINE__);
451*4418919fSjohnjiang return -1;
452*4418919fSjohnjiang }
453*4418919fSjohnjiang
454*4418919fSjohnjiang if (rte_extmem_unregister(NULL, len) >= 0 ||
455*4418919fSjohnjiang rte_errno != EINVAL) {
456*4418919fSjohnjiang printf("%s():%i: Unregistered memory with invalid parameters\n",
457*4418919fSjohnjiang __func__, __LINE__);
458*4418919fSjohnjiang return -1;
459*4418919fSjohnjiang }
460*4418919fSjohnjiang
461*4418919fSjohnjiang if (rte_extmem_attach(NULL, len) >= 0 ||
462*4418919fSjohnjiang rte_errno != EINVAL) {
463*4418919fSjohnjiang printf("%s():%i: Attached memory with invalid parameters\n",
464*4418919fSjohnjiang __func__, __LINE__);
465*4418919fSjohnjiang return -1;
466*4418919fSjohnjiang }
467*4418919fSjohnjiang if (rte_extmem_attach(NULL, len) >= 0 ||
468*4418919fSjohnjiang rte_errno != EINVAL) {
469*4418919fSjohnjiang printf("%s():%i: Detached memory with invalid parameters\n",
470*4418919fSjohnjiang __func__, __LINE__);
471*4418919fSjohnjiang return -1;
472*4418919fSjohnjiang }
473*4418919fSjohnjiang
474*4418919fSjohnjiang /* the following tests are only valid if IOVA table is not NULL */
475*4418919fSjohnjiang if (iova != NULL) {
476*4418919fSjohnjiang /* wrong page count */
477*4418919fSjohnjiang if (rte_extmem_register(addr, len,
478*4418919fSjohnjiang iova, 0, pgsz) >= 0 || rte_errno != EINVAL) {
479*4418919fSjohnjiang printf("%s():%i: Registered memory with invalid parameters\n",
480*4418919fSjohnjiang __func__, __LINE__);
481*4418919fSjohnjiang return -1;
482*4418919fSjohnjiang }
483*4418919fSjohnjiang if (rte_extmem_register(addr, len,
484*4418919fSjohnjiang iova, n_pages - 1, pgsz) >= 0 ||
485*4418919fSjohnjiang rte_errno != EINVAL) {
486*4418919fSjohnjiang printf("%s():%i: Registered memory with invalid parameters\n",
487*4418919fSjohnjiang __func__, __LINE__);
488*4418919fSjohnjiang return -1;
489*4418919fSjohnjiang }
490*4418919fSjohnjiang if (rte_extmem_register(addr, len,
491*4418919fSjohnjiang iova, n_pages + 1, pgsz) >= 0 ||
492*4418919fSjohnjiang rte_errno != EINVAL) {
493*4418919fSjohnjiang printf("%s():%i: Registered memory with invalid parameters\n",
494*4418919fSjohnjiang __func__, __LINE__);
495*4418919fSjohnjiang return -1;
496*4418919fSjohnjiang }
497*4418919fSjohnjiang }
498*4418919fSjohnjiang
499*4418919fSjohnjiang return 0;
500*4418919fSjohnjiang }
501*4418919fSjohnjiang
502*4418919fSjohnjiang static int
test_extmem_basic(void * addr,size_t len,size_t pgsz,rte_iova_t * iova,int n_pages)503*4418919fSjohnjiang test_extmem_basic(void *addr, size_t len, size_t pgsz, rte_iova_t *iova,
504*4418919fSjohnjiang int n_pages)
505*4418919fSjohnjiang {
506*4418919fSjohnjiang /* register memory */
507*4418919fSjohnjiang if (rte_extmem_register(addr, len, iova, n_pages, pgsz) != 0) {
508*4418919fSjohnjiang printf("%s():%i: Failed to register memory\n",
509*4418919fSjohnjiang __func__, __LINE__);
510*4418919fSjohnjiang goto fail;
511*4418919fSjohnjiang }
512*4418919fSjohnjiang
513*4418919fSjohnjiang /* check if memory is accessible from EAL */
514*4418919fSjohnjiang if (check_mem(addr, iova, pgsz, n_pages) < 0)
515*4418919fSjohnjiang goto fail;
516*4418919fSjohnjiang
517*4418919fSjohnjiang if (rte_extmem_unregister(addr, len) != 0) {
518*4418919fSjohnjiang printf("%s():%i: Removing memory from heap failed\n",
519*4418919fSjohnjiang __func__, __LINE__);
520*4418919fSjohnjiang goto fail;
521*4418919fSjohnjiang }
522*4418919fSjohnjiang
523*4418919fSjohnjiang return 0;
524*4418919fSjohnjiang fail:
525*4418919fSjohnjiang /* even if something failed, attempt to clean up */
526*4418919fSjohnjiang rte_extmem_unregister(addr, len);
527*4418919fSjohnjiang
528*4418919fSjohnjiang return -1;
529*4418919fSjohnjiang }
530*4418919fSjohnjiang
531*4418919fSjohnjiang /* we need to test attach/detach in secondary processes. */
532*4418919fSjohnjiang static int
test_external_mem(void)533*4418919fSjohnjiang test_external_mem(void)
534*4418919fSjohnjiang {
535*4418919fSjohnjiang size_t len = EXTERNAL_MEM_SZ;
536*4418919fSjohnjiang size_t pgsz = RTE_PGSIZE_4K;
537*4418919fSjohnjiang rte_iova_t iova[len / pgsz];
538*4418919fSjohnjiang void *addr;
539*4418919fSjohnjiang int ret, n_pages;
540*4418919fSjohnjiang int i;
541*4418919fSjohnjiang
542*4418919fSjohnjiang /* create external memory area */
543*4418919fSjohnjiang n_pages = RTE_DIM(iova);
544*4418919fSjohnjiang addr = mmap(NULL, len, PROT_WRITE | PROT_READ,
545*4418919fSjohnjiang MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
546*4418919fSjohnjiang if (addr == MAP_FAILED) {
547*4418919fSjohnjiang printf("%s():%i: Failed to create dummy memory area\n",
548*4418919fSjohnjiang __func__, __LINE__);
549*4418919fSjohnjiang return -1;
550*4418919fSjohnjiang }
551*4418919fSjohnjiang for (i = 0; i < n_pages; i++) {
552*4418919fSjohnjiang /* arbitrary IOVA */
553*4418919fSjohnjiang rte_iova_t tmp = 0x100000000 + i * pgsz;
554*4418919fSjohnjiang iova[i] = tmp;
555*4418919fSjohnjiang }
556*4418919fSjohnjiang
557*4418919fSjohnjiang /* test external heap memory */
558*4418919fSjohnjiang ret = test_malloc_invalid_param(addr, len, pgsz, iova, n_pages);
559*4418919fSjohnjiang ret |= test_malloc_basic(addr, len, pgsz, iova, n_pages);
560*4418919fSjohnjiang /* when iova table is NULL, everything should still work */
561*4418919fSjohnjiang ret |= test_malloc_invalid_param(addr, len, pgsz, NULL, n_pages);
562*4418919fSjohnjiang ret |= test_malloc_basic(addr, len, pgsz, NULL, n_pages);
563*4418919fSjohnjiang
564*4418919fSjohnjiang /* test non-heap memory */
565*4418919fSjohnjiang ret |= test_extmem_invalid_param(addr, len, pgsz, iova, n_pages);
566*4418919fSjohnjiang ret |= test_extmem_basic(addr, len, pgsz, iova, n_pages);
567*4418919fSjohnjiang /* when iova table is NULL, everything should still work */
568*4418919fSjohnjiang ret |= test_extmem_invalid_param(addr, len, pgsz, NULL, n_pages);
569*4418919fSjohnjiang ret |= test_extmem_basic(addr, len, pgsz, NULL, n_pages);
570*4418919fSjohnjiang
571*4418919fSjohnjiang munmap(addr, len);
572*4418919fSjohnjiang
573*4418919fSjohnjiang return ret;
574*4418919fSjohnjiang }
575*4418919fSjohnjiang
576*4418919fSjohnjiang REGISTER_TEST_COMMAND(external_mem_autotest, test_external_mem);
577