1
2
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
21
22
23
24#ifndef MEM_EXTENDED_PARAMETER_TYPE_BITS
25
26#define MEM_EXTENDED_PARAMETER_TYPE_BITS 4
27
28
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
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
55
56
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
68
69
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
84
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
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
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
122int
123eal_mem_win32api_init(void)
124{
125 VirtualAlloc2_ptr = VirtualAlloc2;
126 return 0;
127}
128
129#endif
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
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
242int
243rte_eal_using_phys_addrs(void)
244{
245 return virt2phys_device != INVALID_HANDLE_VALUE;
246}
247
248
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
259 case ERROR_COMMITMENT_LIMIT:
260
261 case ERROR_NO_SYSTEM_RESOURCES:
262
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
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
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
352
353
354
355
356
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(¶m, 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, ¶m, param_count);
375 if (addr == NULL) {
376
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
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
406
407
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
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
426
427
428
429 return 0;
430}
431
432
433
434
435
436
437
438
439
440
441
442
443
444
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
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
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
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
504
505
506
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
561
562
563
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
613
614
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
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
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