dpdk/lib/eal/windows/eal_memory.c
<<
>>
Prefs
   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 */
  29typedef 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 */
  40typedef 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 */
  57typedef 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 */
  71static 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
  80int
  81eal_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. */
 122int
 123eal_mem_win32api_init(void)
 124{
 125        VirtualAlloc2_ptr = VirtualAlloc2;
 126        return 0;
 127}
 128
 129#endif /* defined(RTE_TOOLCHAIN_GCC) */
 130
 131static HANDLE virt2phys_device = INVALID_HANDLE_VALUE;
 132
 133int
 134eal_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
 192exit:
 193        free(detail);
 194        if (list != INVALID_HANDLE_VALUE)
 195                SetupDiDestroyDeviceInfoList(list);
 196
 197        return ret;
 198}
 199
 200void
 201eal_mem_virt2iova_cleanup(void)
 202{
 203        if (virt2phys_device != INVALID_HANDLE_VALUE)
 204                CloseHandle(virt2phys_device);
 205}
 206
 207phys_addr_t
 208rte_mem_virt2phy(const void *virt)
 209{
 210        LARGE_INTEGER phys;
 211        DWORD bytes_returned;
 212
 213        if (virt2phys_device == INVALID_HANDLE_VALUE)
 214                return RTE_BAD_PHYS_ADDR;
 215
 216        if (!DeviceIoControl(
 217                        virt2phys_device, IOCTL_VIRT2PHYS_TRANSLATE,
 218                        &virt, sizeof(virt), &phys, sizeof(phys),
 219                        &bytes_returned, NULL)) {
 220                RTE_LOG_WIN32_ERR("DeviceIoControl(IOCTL_VIRT2PHYS_TRANSLATE)");
 221                return RTE_BAD_PHYS_ADDR;
 222        }
 223
 224        return phys.QuadPart;
 225}
 226
 227rte_iova_t
 228rte_mem_virt2iova(const void *virt)
 229{
 230        phys_addr_t phys;
 231
 232        if (rte_eal_iova_mode() == RTE_IOVA_VA)
 233                return (rte_iova_t)virt;
 234
 235        phys = rte_mem_virt2phy(virt);
 236        if (phys == RTE_BAD_PHYS_ADDR)
 237                return RTE_BAD_IOVA;
 238        return (rte_iova_t)phys;
 239}
 240
 241/* Always using physical addresses under Windows if they can be obtained. */
 242int
 243rte_eal_using_phys_addrs(void)
 244{
 245        return virt2phys_device != INVALID_HANDLE_VALUE;
 246}
 247
 248/* Approximate error mapping from VirtualAlloc2() to POSIX mmap(3). */
 249static void
 250set_errno_from_win32_alloc_error(DWORD code)
 251{
 252        switch (code) {
 253        case ERROR_SUCCESS:
 254                rte_errno = 0;
 255                break;
 256
 257        case ERROR_INVALID_ADDRESS:
 258                /* A valid requested address is not available. */
 259        case ERROR_COMMITMENT_LIMIT:
 260                /* May occur when committing regular memory. */
 261        case ERROR_NO_SYSTEM_RESOURCES:
 262                /* Occurs when the system runs out of hugepages. */
 263                rte_errno = ENOMEM;
 264                break;
 265
 266        case ERROR_INVALID_PARAMETER:
 267        default:
 268                rte_errno = EINVAL;
 269                break;
 270        }
 271}
 272
 273void *
 274eal_mem_reserve(void *requested_addr, size_t size, int flags)
 275{
 276        HANDLE process;
 277        void *virt;
 278
 279        /* Windows requires hugepages to be committed. */
 280        if (flags & EAL_RESERVE_HUGEPAGES) {
 281                rte_errno = ENOTSUP;
 282                return NULL;
 283        }
 284
 285        process = GetCurrentProcess();
 286
 287        virt = VirtualAlloc2_ptr(process, requested_addr, size,
 288                MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS,
 289                NULL, 0);
 290        if (virt == NULL) {
 291                DWORD err = GetLastError();
 292                RTE_LOG_WIN32_ERR("VirtualAlloc2()");
 293                set_errno_from_win32_alloc_error(err);
 294                return NULL;
 295        }
 296
 297        if ((flags & EAL_RESERVE_FORCE_ADDRESS) && (virt != requested_addr)) {
 298                if (!VirtualFreeEx(process, virt, 0, MEM_RELEASE))
 299                        RTE_LOG_WIN32_ERR("VirtualFreeEx()");
 300                rte_errno = ENOMEM;
 301                return NULL;
 302        }
 303
 304        return virt;
 305}
 306
 307void *
 308eal_mem_alloc_socket(size_t size, int socket_id)
 309{
 310        DWORD flags = MEM_RESERVE | MEM_COMMIT;
 311        void *addr;
 312
 313        flags = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES;
 314        addr = VirtualAllocExNuma(GetCurrentProcess(), NULL, size, flags,
 315                PAGE_READWRITE, eal_socket_numa_node(socket_id));
 316        if (addr == NULL)
 317                rte_errno = ENOMEM;
 318        return addr;
 319}
 320
 321void *
 322eal_mem_commit(void *requested_addr, size_t size, int socket_id)
 323{
 324        HANDLE process;
 325        MEM_EXTENDED_PARAMETER param;
 326        DWORD param_count = 0;
 327        DWORD flags;
 328        void *addr;
 329
 330        process = GetCurrentProcess();
 331
 332        if (requested_addr != NULL) {
 333                MEMORY_BASIC_INFORMATION info;
 334
 335                if (VirtualQueryEx(process, requested_addr, &info,
 336                                sizeof(info)) != sizeof(info)) {
 337                        RTE_LOG_WIN32_ERR("VirtualQuery(%p)", requested_addr);
 338                        return NULL;
 339                }
 340
 341                /* Split reserved region if only a part is committed. */
 342                flags = MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER;
 343                if ((info.RegionSize > size) && !VirtualFreeEx(
 344                                process, requested_addr, size, flags)) {
 345                        RTE_LOG_WIN32_ERR(
 346                                "VirtualFreeEx(%p, %zu, preserve placeholder)",
 347                                requested_addr, size);
 348                        return NULL;
 349                }
 350
 351                /* Temporarily release the region to be committed.
 352                 *
 353                 * There is an inherent race for this memory range
 354                 * if another thread allocates memory via OS API.
 355                 * However, VirtualAlloc2(MEM_REPLACE_PLACEHOLDER)
 356                 * doesn't work with MEM_LARGE_PAGES on Windows Server.
 357                 */
 358                if (!VirtualFreeEx(process, requested_addr, 0, MEM_RELEASE)) {
 359                        RTE_LOG_WIN32_ERR("VirtualFreeEx(%p, 0, release)",
 360                                requested_addr);
 361                        return NULL;
 362                }
 363        }
 364
 365        if (socket_id != SOCKET_ID_ANY) {
 366                param_count = 1;
 367                memset(&param, 0, sizeof(param));
 368                param.Type = MemExtendedParameterNumaNode;
 369                param.ULong = eal_socket_numa_node(socket_id);
 370        }
 371
 372        flags = MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES;
 373        addr = VirtualAlloc2_ptr(process, requested_addr, size,
 374                flags, PAGE_READWRITE, &param, param_count);
 375        if (addr == NULL) {
 376                /* Logging may overwrite GetLastError() result. */
 377                DWORD err = GetLastError();
 378                RTE_LOG_WIN32_ERR("VirtualAlloc2(%p, %zu, commit large pages)",
 379                        requested_addr, size);
 380                set_errno_from_win32_alloc_error(err);
 381                return NULL;
 382        }
 383
 384        if ((requested_addr != NULL) && (addr != requested_addr)) {
 385                /* We lost the race for the requested_addr. */
 386                if (!VirtualFreeEx(process, addr, 0, MEM_RELEASE))
 387                        RTE_LOG_WIN32_ERR("VirtualFreeEx(%p, release)", addr);
 388
 389                rte_errno = EADDRNOTAVAIL;
 390                return NULL;
 391        }
 392
 393        return addr;
 394}
 395
 396int
 397eal_mem_decommit(void *addr, size_t size)
 398{
 399        HANDLE process;
 400        void *stub;
 401        DWORD flags;
 402
 403        process = GetCurrentProcess();
 404
 405        /* Hugepages cannot be decommited on Windows,
 406         * so free them and replace the block with a placeholder.
 407         * There is a race for VA in this block until VirtualAlloc2 call.
 408         */
 409        if (!VirtualFreeEx(process, addr, 0, MEM_RELEASE)) {
 410                RTE_LOG_WIN32_ERR("VirtualFreeEx(%p, 0, release)", addr);
 411                return -1;
 412        }
 413
 414        flags = MEM_RESERVE | MEM_RESERVE_PLACEHOLDER;
 415        stub = VirtualAlloc2_ptr(
 416                process, addr, size, flags, PAGE_NOACCESS, NULL, 0);
 417        if (stub == NULL) {
 418                /* We lost the race for the VA. */
 419                if (!VirtualFreeEx(process, stub, 0, MEM_RELEASE))
 420                        RTE_LOG_WIN32_ERR("VirtualFreeEx(%p, release)", stub);
 421                rte_errno = EADDRNOTAVAIL;
 422                return -1;
 423        }
 424
 425        /* No need to join reserved regions adjacent to the freed one:
 426         * eal_mem_commit() will just pick up the page-size placeholder
 427         * created here.
 428         */
 429        return 0;
 430}
 431
 432/**
 433 * Free a reserved memory region in full or in part.
 434 *
 435 * @param addr
 436 *  Starting address of the area to free.
 437 * @param size
 438 *  Number of bytes to free. Must be a multiple of page size.
 439 * @param reserved
 440 *  Fail if the region is not in reserved state.
 441 * @return
 442 *  * 0 on successful deallocation;
 443 *  * 1 if region must be in reserved state but it is not;
 444 *  * (-1) on system API failures.
 445 */
 446static int
 447mem_free(void *addr, size_t size, bool reserved)
 448{
 449        MEMORY_BASIC_INFORMATION info;
 450        HANDLE process;
 451
 452        process = GetCurrentProcess();
 453
 454        if (VirtualQueryEx(
 455                        process, addr, &info, sizeof(info)) != sizeof(info)) {
 456                RTE_LOG_WIN32_ERR("VirtualQueryEx(%p)", addr);
 457                return -1;
 458        }
 459
 460        if (reserved && (info.State != MEM_RESERVE))
 461                return 1;
 462
 463        /* Free complete region. */
 464        if ((addr == info.AllocationBase) && (size == info.RegionSize)) {
 465                if (!VirtualFreeEx(process, addr, 0, MEM_RELEASE)) {
 466                        RTE_LOG_WIN32_ERR("VirtualFreeEx(%p, 0, release)",
 467                                addr);
 468                }
 469                return 0;
 470        }
 471
 472        /* Split the part to be freed and the remaining reservation. */
 473        if (!VirtualFreeEx(process, addr, size,
 474                        MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER)) {
 475                RTE_LOG_WIN32_ERR(
 476                        "VirtualFreeEx(%p, %zu, preserve placeholder)",
 477                        addr, size);
 478                return -1;
 479        }
 480
 481        /* Actually free reservation part. */
 482        if (!VirtualFreeEx(process, addr, 0, MEM_RELEASE)) {
 483                RTE_LOG_WIN32_ERR("VirtualFreeEx(%p, 0, release)", addr);
 484                return -1;
 485        }
 486
 487        return 0;
 488}
 489
 490void
 491eal_mem_free(void *virt, size_t size)
 492{
 493        mem_free(virt, size, false);
 494}
 495
 496int
 497eal_mem_set_dump(void *virt, size_t size, bool dump)
 498{
 499        RTE_SET_USED(virt);
 500        RTE_SET_USED(size);
 501        RTE_SET_USED(dump);
 502
 503        /* Windows does not dump reserved memory by default.
 504         *
 505         * There is <werapi.h> to include or exclude regions from the dump,
 506         * but this is not currently required by EAL.
 507         */
 508
 509        rte_errno = ENOTSUP;
 510        return -1;
 511}
 512
 513void *
 514rte_mem_map(void *requested_addr, size_t size, int prot, int flags,
 515        int fd, uint64_t offset)
 516{
 517        HANDLE file_handle = INVALID_HANDLE_VALUE;
 518        HANDLE mapping_handle = INVALID_HANDLE_VALUE;
 519        DWORD sys_prot = 0;
 520        DWORD sys_access = 0;
 521        DWORD size_high = (DWORD)(size >> 32);
 522        DWORD size_low = (DWORD)size;
 523        DWORD offset_high = (DWORD)(offset >> 32);
 524        DWORD offset_low = (DWORD)offset;
 525        LPVOID virt = NULL;
 526
 527        if (prot & RTE_PROT_EXECUTE) {
 528                if (prot & RTE_PROT_READ) {
 529                        sys_prot = PAGE_EXECUTE_READ;
 530                        sys_access = FILE_MAP_READ | FILE_MAP_EXECUTE;
 531                }
 532                if (prot & RTE_PROT_WRITE) {
 533                        sys_prot = PAGE_EXECUTE_READWRITE;
 534                        sys_access = FILE_MAP_WRITE | FILE_MAP_EXECUTE;
 535                }
 536        } else {
 537                if (prot & RTE_PROT_READ) {
 538                        sys_prot = PAGE_READONLY;
 539                        sys_access = FILE_MAP_READ;
 540                }
 541                if (prot & RTE_PROT_WRITE) {
 542                        sys_prot = PAGE_READWRITE;
 543                        sys_access = FILE_MAP_WRITE;
 544                }
 545        }
 546
 547        if (flags & RTE_MAP_PRIVATE)
 548                sys_access |= FILE_MAP_COPY;
 549
 550        if ((flags & RTE_MAP_ANONYMOUS) == 0)
 551                file_handle = (HANDLE)_get_osfhandle(fd);
 552
 553        mapping_handle = CreateFileMapping(
 554                file_handle, NULL, sys_prot, size_high, size_low, NULL);
 555        if (mapping_handle == INVALID_HANDLE_VALUE) {
 556                RTE_LOG_WIN32_ERR("CreateFileMapping()");
 557                return NULL;
 558        }
 559
 560        /* There is a race for the requested_addr between mem_free()
 561         * and MapViewOfFileEx(). MapViewOfFile3() that can replace a reserved
 562         * region with a mapping in a single operation, but it does not support
 563         * private mappings.
 564         */
 565        if (requested_addr != NULL) {
 566                int ret = mem_free(requested_addr, size, true);
 567                if (ret) {
 568                        if (ret > 0) {
 569                                RTE_LOG(ERR, EAL, "Cannot map memory "
 570                                        "to a region not reserved\n");
 571                                rte_errno = EADDRNOTAVAIL;
 572                        }
 573                        return NULL;
 574                }
 575        }
 576
 577        virt = MapViewOfFileEx(mapping_handle, sys_access,
 578                offset_high, offset_low, size, requested_addr);
 579        if (!virt) {
 580                RTE_LOG_WIN32_ERR("MapViewOfFileEx()");
 581                return NULL;
 582        }
 583
 584        if ((flags & RTE_MAP_FORCE_ADDRESS) && (virt != requested_addr)) {
 585                if (!UnmapViewOfFile(virt))
 586                        RTE_LOG_WIN32_ERR("UnmapViewOfFile()");
 587                virt = NULL;
 588        }
 589
 590        if (!CloseHandle(mapping_handle))
 591                RTE_LOG_WIN32_ERR("CloseHandle()");
 592
 593        return virt;
 594}
 595
 596int
 597rte_mem_unmap(void *virt, size_t size)
 598{
 599        RTE_SET_USED(size);
 600
 601        if (!UnmapViewOfFile(virt)) {
 602                RTE_LOG_WIN32_ERR("UnmapViewOfFile()");
 603                rte_errno = EINVAL;
 604                return -1;
 605        }
 606        return 0;
 607}
 608
 609uint64_t
 610eal_get_baseaddr(void)
 611{
 612        /* Windows strategy for memory allocation is undocumented.
 613         * Returning 0 here effectively disables address guessing
 614         * unless user provides an address hint.
 615         */
 616        return 0;
 617}
 618
 619size_t
 620rte_mem_page_size(void)
 621{
 622        static SYSTEM_INFO info;
 623
 624        if (info.dwPageSize == 0)
 625                GetSystemInfo(&info);
 626
 627        return info.dwPageSize;
 628}
 629
 630int
 631rte_mem_lock(const void *virt, size_t size)
 632{
 633        /* VirtualLock() takes `void*`, work around compiler warning. */
 634        void *addr = (void *)((uintptr_t)virt);
 635
 636        if (!VirtualLock(addr, size)) {
 637                RTE_LOG_WIN32_ERR("VirtualLock(%p %#zx)", virt, size);
 638                return -1;
 639        }
 640
 641        return 0;
 642}
 643
 644int
 645rte_eal_memseg_init(void)
 646{
 647        if (rte_eal_process_type() != RTE_PROC_PRIMARY) {
 648                EAL_LOG_NOT_IMPLEMENTED();
 649                return -1;
 650        }
 651
 652        return eal_dynmem_memseg_lists_init();
 653}
 654
 655static int
 656eal_nohuge_init(void)
 657{
 658        struct rte_mem_config *mcfg;
 659        struct rte_memseg_list *msl;
 660        int n_segs;
 661        uint64_t mem_sz, page_sz;
 662        void *addr;
 663
 664        mcfg = rte_eal_get_configuration()->mem_config;
 665        struct internal_config *internal_conf =
 666                eal_get_internal_configuration();
 667
 668        /* nohuge mode is legacy mode */
 669        internal_conf->legacy_mem = 1;
 670
 671        msl = &mcfg->memsegs[0];
 672
 673        mem_sz = internal_conf->memory;
 674        page_sz = RTE_PGSIZE_4K;
 675        n_segs = mem_sz / page_sz;
 676
 677        if (eal_memseg_list_init_named(
 678                        msl, "nohugemem", page_sz, n_segs, 0, true)) {
 679                return -1;
 680        }
 681
 682        addr = VirtualAlloc(
 683                NULL, mem_sz, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
 684        if (addr == NULL) {
 685                RTE_LOG_WIN32_ERR("VirtualAlloc(size=%#zx)", mem_sz);
 686                RTE_LOG(ERR, EAL, "Cannot allocate memory\n");
 687                return -1;
 688        }
 689
 690        msl->base_va = addr;
 691        msl->len = mem_sz;
 692
 693        eal_memseg_list_populate(msl, addr, n_segs);
 694
 695        if (mcfg->dma_maskbits &&
 696                rte_mem_check_dma_mask_thread_unsafe(mcfg->dma_maskbits)) {
 697                RTE_LOG(ERR, EAL,
 698                        "%s(): couldn't allocate memory due to IOVA "
 699                        "exceeding limits of current DMA mask.\n", __func__);
 700                return -1;
 701        }
 702
 703        return 0;
 704}
 705
 706int
 707rte_eal_hugepage_init(void)
 708{
 709        const struct internal_config *internal_conf =
 710                eal_get_internal_configuration();
 711
 712        return internal_conf->no_hugetlbfs ?
 713                eal_nohuge_init() : eal_dynmem_hugepage_init();
 714}
 715
 716int
 717rte_eal_hugepage_attach(void)
 718{
 719        EAL_LOG_NOT_IMPLEMENTED();
 720        return -1;
 721}
 722