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