eal/windows: implement basic memory management
[dpdk.git] / lib / librte_eal / windows / eal_memory.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2020 Dmitry Kozlyuk
3  */
4
5 #include <inttypes.h>
6 #include <io.h>
7
8 #include <rte_eal_paging.h>
9 #include <rte_errno.h>
10
11 #include "eal_internal_cfg.h"
12 #include "eal_memalloc.h"
13 #include "eal_memcfg.h"
14 #include "eal_options.h"
15 #include "eal_private.h"
16 #include "eal_windows.h"
17
18 #include <rte_virt2phys.h>
19
20 /* MinGW-w64 headers lack VirtualAlloc2() in some distributions.
21  * Provide a copy of definitions and code to load it dynamically.
22  * Note: definitions are copied verbatim from Microsoft documentation
23  * and don't follow DPDK code style.
24  *
25  * MEM_RESERVE_PLACEHOLDER being defined means VirtualAlloc2() is present too.
26  */
27 #ifndef MEM_PRESERVE_PLACEHOLDER
28
29 /* https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-mem_extended_parameter_type */
30 typedef enum MEM_EXTENDED_PARAMETER_TYPE {
31         MemExtendedParameterInvalidType,
32         MemExtendedParameterAddressRequirements,
33         MemExtendedParameterNumaNode,
34         MemExtendedParameterPartitionHandle,
35         MemExtendedParameterUserPhysicalHandle,
36         MemExtendedParameterAttributeFlags,
37         MemExtendedParameterMax
38 } *PMEM_EXTENDED_PARAMETER_TYPE;
39
40 #define MEM_EXTENDED_PARAMETER_TYPE_BITS 4
41
42 /* https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-mem_extended_parameter */
43 typedef struct MEM_EXTENDED_PARAMETER {
44         struct {
45                 DWORD64 Type : MEM_EXTENDED_PARAMETER_TYPE_BITS;
46                 DWORD64 Reserved : 64 - MEM_EXTENDED_PARAMETER_TYPE_BITS;
47         } DUMMYSTRUCTNAME;
48         union {
49                 DWORD64 ULong64;
50                 PVOID   Pointer;
51                 SIZE_T  Size;
52                 HANDLE  Handle;
53                 DWORD   ULong;
54         } DUMMYUNIONNAME;
55 } MEM_EXTENDED_PARAMETER, *PMEM_EXTENDED_PARAMETER;
56
57 /* https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc2 */
58 typedef PVOID (*VirtualAlloc2_type)(
59         HANDLE                 Process,
60         PVOID                  BaseAddress,
61         SIZE_T                 Size,
62         ULONG                  AllocationType,
63         ULONG                  PageProtection,
64         MEM_EXTENDED_PARAMETER *ExtendedParameters,
65         ULONG                  ParameterCount
66 );
67
68 /* VirtualAlloc2() flags. */
69 #define MEM_COALESCE_PLACEHOLDERS 0x00000001
70 #define MEM_PRESERVE_PLACEHOLDER  0x00000002
71 #define MEM_REPLACE_PLACEHOLDER   0x00004000
72 #define MEM_RESERVE_PLACEHOLDER   0x00040000
73
74 /* Named exactly as the function, so that user code does not depend
75  * on it being found at compile time or dynamically.
76  */
77 static VirtualAlloc2_type VirtualAlloc2;
78
79 int
80 eal_mem_win32api_init(void)
81 {
82         /* Contrary to the docs, VirtualAlloc2() is not in kernel32.dll,
83          * see https://github.com/MicrosoftDocs/feedback/issues/1129.
84          */
85         static const char library_name[] = "kernelbase.dll";
86         static const char function[] = "VirtualAlloc2";
87
88         HMODULE library = NULL;
89         int ret = 0;
90
91         /* Already done. */
92         if (VirtualAlloc2 != NULL)
93                 return 0;
94
95         library = LoadLibraryA(library_name);
96         if (library == NULL) {
97                 RTE_LOG_WIN32_ERR("LoadLibraryA(\"%s\")", library_name);
98                 return -1;
99         }
100
101         VirtualAlloc2 = (VirtualAlloc2_type)(
102                 (void *)GetProcAddress(library, function));
103         if (VirtualAlloc2 == NULL) {
104                 RTE_LOG_WIN32_ERR("GetProcAddress(\"%s\", \"%s\")\n",
105                         library_name, function);
106
107                 /* Contrary to the docs, Server 2016 is not supported. */
108                 RTE_LOG(ERR, EAL, "Windows 10 or Windows Server 2019 "
109                         " is required for memory management\n");
110                 ret = -1;
111         }
112
113         FreeLibrary(library);
114
115         return ret;
116 }
117
118 #else
119
120 /* Stub in case VirtualAlloc2() is provided by the compiler. */
121 int
122 eal_mem_win32api_init(void)
123 {
124         return 0;
125 }
126
127 #endif /* defined(MEM_RESERVE_PLACEHOLDER) */
128
129 static HANDLE virt2phys_device = INVALID_HANDLE_VALUE;
130
131 int
132 eal_mem_virt2iova_init(void)
133 {
134         HDEVINFO list = INVALID_HANDLE_VALUE;
135         SP_DEVICE_INTERFACE_DATA ifdata;
136         SP_DEVICE_INTERFACE_DETAIL_DATA *detail = NULL;
137         DWORD detail_size;
138         int ret = -1;
139
140         list = SetupDiGetClassDevs(
141                 &GUID_DEVINTERFACE_VIRT2PHYS, NULL, NULL,
142                 DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
143         if (list == INVALID_HANDLE_VALUE) {
144                 RTE_LOG_WIN32_ERR("SetupDiGetClassDevs()");
145                 goto exit;
146         }
147
148         ifdata.cbSize = sizeof(ifdata);
149         if (!SetupDiEnumDeviceInterfaces(
150                 list, NULL, &GUID_DEVINTERFACE_VIRT2PHYS, 0, &ifdata)) {
151                 RTE_LOG_WIN32_ERR("SetupDiEnumDeviceInterfaces()");
152                 goto exit;
153         }
154
155         if (!SetupDiGetDeviceInterfaceDetail(
156                 list, &ifdata, NULL, 0, &detail_size, NULL)) {
157                 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
158                         RTE_LOG_WIN32_ERR(
159                                 "SetupDiGetDeviceInterfaceDetail(probe)");
160                         goto exit;
161                 }
162         }
163
164         detail = malloc(detail_size);
165         if (detail == NULL) {
166                 RTE_LOG(ERR, EAL, "Cannot allocate virt2phys "
167                         "device interface detail data\n");
168                 goto exit;
169         }
170
171         detail->cbSize = sizeof(*detail);
172         if (!SetupDiGetDeviceInterfaceDetail(
173                 list, &ifdata, detail, detail_size, NULL, NULL)) {
174                 RTE_LOG_WIN32_ERR("SetupDiGetDeviceInterfaceDetail(read)");
175                 goto exit;
176         }
177
178         RTE_LOG(DEBUG, EAL, "Found virt2phys device: %s\n", detail->DevicePath);
179
180         virt2phys_device = CreateFile(
181                 detail->DevicePath, 0, 0, NULL, OPEN_EXISTING, 0, NULL);
182         if (virt2phys_device == INVALID_HANDLE_VALUE) {
183                 RTE_LOG_WIN32_ERR("CreateFile()");
184                 goto exit;
185         }
186
187         /* Indicate success. */
188         ret = 0;
189
190 exit:
191         if (detail != NULL)
192                 free(detail);
193         if (list != INVALID_HANDLE_VALUE)
194                 SetupDiDestroyDeviceInfoList(list);
195
196         return ret;
197 }
198
199 phys_addr_t
200 rte_mem_virt2phy(const void *virt)
201 {
202         LARGE_INTEGER phys;
203         DWORD bytes_returned;
204
205         if (virt2phys_device == INVALID_HANDLE_VALUE)
206                 return RTE_BAD_PHYS_ADDR;
207
208         if (!DeviceIoControl(
209                         virt2phys_device, IOCTL_VIRT2PHYS_TRANSLATE,
210                         &virt, sizeof(virt), &phys, sizeof(phys),
211                         &bytes_returned, NULL)) {
212                 RTE_LOG_WIN32_ERR("DeviceIoControl(IOCTL_VIRT2PHYS_TRANSLATE)");
213                 return RTE_BAD_PHYS_ADDR;
214         }
215
216         return phys.QuadPart;
217 }
218
219 /* Windows currently only supports IOVA as PA. */
220 rte_iova_t
221 rte_mem_virt2iova(const void *virt)
222 {
223         phys_addr_t phys;
224
225         if (virt2phys_device == INVALID_HANDLE_VALUE)
226                 return RTE_BAD_IOVA;
227
228         phys = rte_mem_virt2phy(virt);
229         if (phys == RTE_BAD_PHYS_ADDR)
230                 return RTE_BAD_IOVA;
231
232         return (rte_iova_t)phys;
233 }
234
235 /* Always using physical addresses under Windows if they can be obtained. */
236 int
237 rte_eal_using_phys_addrs(void)
238 {
239         return virt2phys_device != INVALID_HANDLE_VALUE;
240 }
241
242 /* Approximate error mapping from VirtualAlloc2() to POSIX mmap(3). */
243 static void
244 set_errno_from_win32_alloc_error(DWORD code)
245 {
246         switch (code) {
247         case ERROR_SUCCESS:
248                 rte_errno = 0;
249                 break;
250
251         case ERROR_INVALID_ADDRESS:
252                 /* A valid requested address is not available. */
253         case ERROR_COMMITMENT_LIMIT:
254                 /* May occur when committing regular memory. */
255         case ERROR_NO_SYSTEM_RESOURCES:
256                 /* Occurs when the system runs out of hugepages. */
257                 rte_errno = ENOMEM;
258                 break;
259
260         case ERROR_INVALID_PARAMETER:
261         default:
262                 rte_errno = EINVAL;
263                 break;
264         }
265 }
266
267 void *
268 eal_mem_reserve(void *requested_addr, size_t size, int flags)
269 {
270         HANDLE process;
271         void *virt;
272
273         /* Windows requires hugepages to be committed. */
274         if (flags & EAL_RESERVE_HUGEPAGES) {
275                 rte_errno = ENOTSUP;
276                 return NULL;
277         }
278
279         process = GetCurrentProcess();
280
281         virt = VirtualAlloc2(process, requested_addr, size,
282                 MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS,
283                 NULL, 0);
284         if (virt == NULL) {
285                 DWORD err = GetLastError();
286                 RTE_LOG_WIN32_ERR("VirtualAlloc2()");
287                 set_errno_from_win32_alloc_error(err);
288                 return NULL;
289         }
290
291         if ((flags & EAL_RESERVE_FORCE_ADDRESS) && (virt != requested_addr)) {
292                 if (!VirtualFreeEx(process, virt, 0, MEM_RELEASE))
293                         RTE_LOG_WIN32_ERR("VirtualFreeEx()");
294                 rte_errno = ENOMEM;
295                 return NULL;
296         }
297
298         return virt;
299 }
300
301 void *
302 eal_mem_alloc_socket(size_t size, int socket_id)
303 {
304         DWORD flags = MEM_RESERVE | MEM_COMMIT;
305         void *addr;
306
307         flags = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES;
308         addr = VirtualAllocExNuma(GetCurrentProcess(), NULL, size, flags,
309                 PAGE_READWRITE, eal_socket_numa_node(socket_id));
310         if (addr == NULL)
311                 rte_errno = ENOMEM;
312         return addr;
313 }
314
315 void *
316 eal_mem_commit(void *requested_addr, size_t size, int socket_id)
317 {
318         HANDLE process;
319         MEM_EXTENDED_PARAMETER param;
320         DWORD param_count = 0;
321         DWORD flags;
322         void *addr;
323
324         process = GetCurrentProcess();
325
326         if (requested_addr != NULL) {
327                 MEMORY_BASIC_INFORMATION info;
328
329                 if (VirtualQueryEx(process, requested_addr, &info,
330                                 sizeof(info)) != sizeof(info)) {
331                         RTE_LOG_WIN32_ERR("VirtualQuery(%p)", requested_addr);
332                         return NULL;
333                 }
334
335                 /* Split reserved region if only a part is committed. */
336                 flags = MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER;
337                 if ((info.RegionSize > size) && !VirtualFreeEx(
338                                 process, requested_addr, size, flags)) {
339                         RTE_LOG_WIN32_ERR(
340                                 "VirtualFreeEx(%p, %zu, preserve placeholder)",
341                                 requested_addr, size);
342                         return NULL;
343                 }
344
345                 /* Temporarily release the region to be committed.
346                  *
347                  * There is an inherent race for this memory range
348                  * if another thread allocates memory via OS API.
349                  * However, VirtualAlloc2(MEM_REPLACE_PLACEHOLDER)
350                  * doesn't work with MEM_LARGE_PAGES on Windows Server.
351                  */
352                 if (!VirtualFreeEx(process, requested_addr, 0, MEM_RELEASE)) {
353                         RTE_LOG_WIN32_ERR("VirtualFreeEx(%p, 0, release)",
354                                 requested_addr);
355                         return NULL;
356                 }
357         }
358
359         if (socket_id != SOCKET_ID_ANY) {
360                 param_count = 1;
361                 memset(&param, 0, sizeof(param));
362                 param.Type = MemExtendedParameterNumaNode;
363                 param.ULong = eal_socket_numa_node(socket_id);
364         }
365
366         flags = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES;
367         addr = VirtualAlloc2(process, requested_addr, size,
368                 flags, PAGE_READWRITE, &param, param_count);
369         if (addr == NULL) {
370                 /* Logging may overwrite GetLastError() result. */
371                 DWORD err = GetLastError();
372                 RTE_LOG_WIN32_ERR("VirtualAlloc2(%p, %zu, commit large pages)",
373                         requested_addr, size);
374                 set_errno_from_win32_alloc_error(err);
375                 return NULL;
376         }
377
378         if ((requested_addr != NULL) && (addr != requested_addr)) {
379                 /* We lost the race for the requested_addr. */
380                 if (!VirtualFreeEx(process, addr, 0, MEM_RELEASE))
381                         RTE_LOG_WIN32_ERR("VirtualFreeEx(%p, release)", addr);
382
383                 rte_errno = EADDRNOTAVAIL;
384                 return NULL;
385         }
386
387         return addr;
388 }
389
390 int
391 eal_mem_decommit(void *addr, size_t size)
392 {
393         HANDLE process;
394         void *stub;
395         DWORD flags;
396
397         process = GetCurrentProcess();
398
399         /* Hugepages cannot be decommited on Windows,
400          * so free them and replace the block with a placeholder.
401          * There is a race for VA in this block until VirtualAlloc2 call.
402          */
403         if (!VirtualFreeEx(process, addr, 0, MEM_RELEASE)) {
404                 RTE_LOG_WIN32_ERR("VirtualFreeEx(%p, 0, release)", addr);
405                 return -1;
406         }
407
408         flags = MEM_RESERVE | MEM_RESERVE_PLACEHOLDER;
409         stub = VirtualAlloc2(
410                 process, addr, size, flags, PAGE_NOACCESS, NULL, 0);
411         if (stub == NULL) {
412                 /* We lost the race for the VA. */
413                 if (!VirtualFreeEx(process, stub, 0, MEM_RELEASE))
414                         RTE_LOG_WIN32_ERR("VirtualFreeEx(%p, release)", stub);
415                 rte_errno = EADDRNOTAVAIL;
416                 return -1;
417         }
418
419         /* No need to join reserved regions adjacent to the freed one:
420          * eal_mem_commit() will just pick up the page-size placeholder
421          * created here.
422          */
423         return 0;
424 }
425
426 /**
427  * Free a reserved memory region in full or in part.
428  *
429  * @param addr
430  *  Starting address of the area to free.
431  * @param size
432  *  Number of bytes to free. Must be a multiple of page size.
433  * @param reserved
434  *  Fail if the region is not in reserved state.
435  * @return
436  *  * 0 on successful deallocation;
437  *  * 1 if region must be in reserved state but it is not;
438  *  * (-1) on system API failures.
439  */
440 static int
441 mem_free(void *addr, size_t size, bool reserved)
442 {
443         MEMORY_BASIC_INFORMATION info;
444         HANDLE process;
445
446         process = GetCurrentProcess();
447
448         if (VirtualQueryEx(
449                         process, addr, &info, sizeof(info)) != sizeof(info)) {
450                 RTE_LOG_WIN32_ERR("VirtualQueryEx(%p)", addr);
451                 return -1;
452         }
453
454         if (reserved && (info.State != MEM_RESERVE))
455                 return 1;
456
457         /* Free complete region. */
458         if ((addr == info.AllocationBase) && (size == info.RegionSize)) {
459                 if (!VirtualFreeEx(process, addr, 0, MEM_RELEASE)) {
460                         RTE_LOG_WIN32_ERR("VirtualFreeEx(%p, 0, release)",
461                                 addr);
462                 }
463                 return 0;
464         }
465
466         /* Split the part to be freed and the remaining reservation. */
467         if (!VirtualFreeEx(process, addr, size,
468                         MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER)) {
469                 RTE_LOG_WIN32_ERR(
470                         "VirtualFreeEx(%p, %zu, preserve placeholder)",
471                         addr, size);
472                 return -1;
473         }
474
475         /* Actually free reservation part. */
476         if (!VirtualFreeEx(process, addr, 0, MEM_RELEASE)) {
477                 RTE_LOG_WIN32_ERR("VirtualFreeEx(%p, 0, release)", addr);
478                 return -1;
479         }
480
481         return 0;
482 }
483
484 void
485 eal_mem_free(void *virt, size_t size)
486 {
487         mem_free(virt, size, false);
488 }
489
490 int
491 eal_mem_set_dump(void *virt, size_t size, bool dump)
492 {
493         RTE_SET_USED(virt);
494         RTE_SET_USED(size);
495         RTE_SET_USED(dump);
496
497         /* Windows does not dump reserved memory by default.
498          *
499          * There is <werapi.h> to include or exclude regions from the dump,
500          * but this is not currently required by EAL.
501          */
502
503         rte_errno = ENOTSUP;
504         return -1;
505 }
506
507 void *
508 rte_mem_map(void *requested_addr, size_t size, int prot, int flags,
509         int fd, size_t offset)
510 {
511         HANDLE file_handle = INVALID_HANDLE_VALUE;
512         HANDLE mapping_handle = INVALID_HANDLE_VALUE;
513         DWORD sys_prot = 0;
514         DWORD sys_access = 0;
515         DWORD size_high = (DWORD)(size >> 32);
516         DWORD size_low = (DWORD)size;
517         DWORD offset_high = (DWORD)(offset >> 32);
518         DWORD offset_low = (DWORD)offset;
519         LPVOID virt = NULL;
520
521         if (prot & RTE_PROT_EXECUTE) {
522                 if (prot & RTE_PROT_READ) {
523                         sys_prot = PAGE_EXECUTE_READ;
524                         sys_access = FILE_MAP_READ | FILE_MAP_EXECUTE;
525                 }
526                 if (prot & RTE_PROT_WRITE) {
527                         sys_prot = PAGE_EXECUTE_READWRITE;
528                         sys_access = FILE_MAP_WRITE | FILE_MAP_EXECUTE;
529                 }
530         } else {
531                 if (prot & RTE_PROT_READ) {
532                         sys_prot = PAGE_READONLY;
533                         sys_access = FILE_MAP_READ;
534                 }
535                 if (prot & RTE_PROT_WRITE) {
536                         sys_prot = PAGE_READWRITE;
537                         sys_access = FILE_MAP_WRITE;
538                 }
539         }
540
541         if (flags & RTE_MAP_PRIVATE)
542                 sys_access |= FILE_MAP_COPY;
543
544         if ((flags & RTE_MAP_ANONYMOUS) == 0)
545                 file_handle = (HANDLE)_get_osfhandle(fd);
546
547         mapping_handle = CreateFileMapping(
548                 file_handle, NULL, sys_prot, size_high, size_low, NULL);
549         if (mapping_handle == INVALID_HANDLE_VALUE) {
550                 RTE_LOG_WIN32_ERR("CreateFileMapping()");
551                 return NULL;
552         }
553
554         /* There is a race for the requested_addr between mem_free()
555          * and MapViewOfFileEx(). MapViewOfFile3() that can replace a reserved
556          * region with a mapping in a single operation, but it does not support
557          * private mappings.
558          */
559         if (requested_addr != NULL) {
560                 int ret = mem_free(requested_addr, size, true);
561                 if (ret) {
562                         if (ret > 0) {
563                                 RTE_LOG(ERR, EAL, "Cannot map memory "
564                                         "to a region not reserved\n");
565                                 rte_errno = EADDRNOTAVAIL;
566                         }
567                         return NULL;
568                 }
569         }
570
571         virt = MapViewOfFileEx(mapping_handle, sys_access,
572                 offset_high, offset_low, size, requested_addr);
573         if (!virt) {
574                 RTE_LOG_WIN32_ERR("MapViewOfFileEx()");
575                 return NULL;
576         }
577
578         if ((flags & RTE_MAP_FORCE_ADDRESS) && (virt != requested_addr)) {
579                 if (!UnmapViewOfFile(virt))
580                         RTE_LOG_WIN32_ERR("UnmapViewOfFile()");
581                 virt = NULL;
582         }
583
584         if (!CloseHandle(mapping_handle))
585                 RTE_LOG_WIN32_ERR("CloseHandle()");
586
587         return virt;
588 }
589
590 int
591 rte_mem_unmap(void *virt, size_t size)
592 {
593         RTE_SET_USED(size);
594
595         if (!UnmapViewOfFile(virt)) {
596                 RTE_LOG_WIN32_ERR("UnmapViewOfFile()");
597                 rte_errno = EINVAL;
598                 return -1;
599         }
600         return 0;
601 }
602
603 uint64_t
604 eal_get_baseaddr(void)
605 {
606         /* Windows strategy for memory allocation is undocumented.
607          * Returning 0 here effectively disables address guessing
608          * unless user provides an address hint.
609          */
610         return 0;
611 }
612
613 size_t
614 rte_mem_page_size(void)
615 {
616         static SYSTEM_INFO info;
617
618         if (info.dwPageSize == 0)
619                 GetSystemInfo(&info);
620
621         return info.dwPageSize;
622 }
623
624 int
625 rte_mem_lock(const void *virt, size_t size)
626 {
627         /* VirtualLock() takes `void*`, work around compiler warning. */
628         void *addr = (void *)((uintptr_t)virt);
629
630         if (!VirtualLock(addr, size)) {
631                 RTE_LOG_WIN32_ERR("VirtualLock(%p %#zx)", virt, size);
632                 return -1;
633         }
634
635         return 0;
636 }
637
638 int
639 rte_eal_memseg_init(void)
640 {
641         if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
642                 EAL_LOG_NOT_IMPLEMENTED();
643                 return -1;
644         }
645
646         return eal_dynmem_memseg_lists_init();
647 }
648
649 static int
650 eal_nohuge_init(void)
651 {
652         struct rte_mem_config *mcfg;
653         struct rte_memseg_list *msl;
654         int n_segs;
655         uint64_t mem_sz, page_sz;
656         void *addr;
657
658         mcfg = rte_eal_get_configuration()->mem_config;
659
660         /* nohuge mode is legacy mode */
661         internal_config.legacy_mem = 1;
662
663         msl = &mcfg->memsegs[0];
664
665         mem_sz = internal_config.memory;
666         page_sz = RTE_PGSIZE_4K;
667         n_segs = mem_sz / page_sz;
668
669         if (eal_memseg_list_init_named(
670                         msl, "nohugemem", page_sz, n_segs, 0, true)) {
671                 return -1;
672         }
673
674         addr = VirtualAlloc(
675                 NULL, mem_sz, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
676         if (addr == NULL) {
677                 RTE_LOG_WIN32_ERR("VirtualAlloc(size=%#zx)", mem_sz);
678                 RTE_LOG(ERR, EAL, "Cannot allocate memory\n");
679                 return -1;
680         }
681
682         msl->base_va = addr;
683         msl->len = mem_sz;
684
685         eal_memseg_list_populate(msl, addr, n_segs);
686
687         if (mcfg->dma_maskbits &&
688                 rte_mem_check_dma_mask_thread_unsafe(mcfg->dma_maskbits)) {
689                 RTE_LOG(ERR, EAL,
690                         "%s(): couldn't allocate memory due to IOVA "
691                         "exceeding limits of current DMA mask.\n", __func__);
692                 return -1;
693         }
694
695         return 0;
696 }
697
698 int
699 rte_eal_hugepage_init(void)
700 {
701         return internal_config.no_hugetlbfs ?
702                 eal_nohuge_init() : eal_dynmem_hugepage_init();
703 }
704
705 int
706 rte_eal_hugepage_attach(void)
707 {
708         EAL_LOG_NOT_IMPLEMENTED();
709         return -1;
710 }