* [dpdk-dev] [RFC PATCH 0/9] Windows basic memory management
@ 2020-03-30 4:10 Dmitry Kozlyuk
2020-03-30 4:10 ` [dpdk-dev] [PATCH 1/1] virt2phys: virtual to physical address translator for Windows Dmitry Kozlyuk
` (9 more replies)
0 siblings, 10 replies; 218+ messages in thread
From: Dmitry Kozlyuk @ 2020-03-30 4:10 UTC (permalink / raw)
To: dev; +Cc: Dmitry Malloy (MESHCHANINOV), Dmitry Kozlyuk
This RFC implements basic MM with the following features:
* Hugepages are dynamically allocated in user-mode.
* IOVA is always PA, obtained through kernel-mode driver.
* No 32-bit support (presumably not demanded).
* No multi-process support. Note that without --in-memory EAL MM
will create files in current working (runtime) directory.
* No-huge mode for testing with no IOVA available. IOVA could be obtained
using Address Windowing Extensions, but it is doubtfully demanded.
Roadmap for Windows [1] proposes that memory management (MM) should be
implemented in basic and advanced stages:
1. Basic MM must be sufficient for core libraries and network PMDs:
2. Advanced MM could address features missing from basic stage.
Advanced memory management discussion is out of scope of this RFC.
Windows community calls suggest is will be focused on security and IOMMU
support. I will post a separate thread with background and suggestions.
Cc'ing Dmitry Malloy (MESHCHANINOV) nevertheless.
Because netUIO is not yet committed to dpdk-kmods, the first commit
introduces a new simple driver, virt2phys. It will almost certainly
become a part of netUIO once it is available for patches. Until then, it
must be installed according to documentation provided with the patch.
User-mode code locates the driver interface by GUID, so transition from
virt2phys to netUIO should not require changes to DPDK.
Hugepages allocation on Windows requires some privilege setup. Please
refer to documentation provided in the "initialize hugepage info" patch.
New EAL public functions for memory mapping are introduced. Their
implementation for Linux and FreeBSD is identical. The upcoming patch series
reorganizing EAL directories will help fixing that [2].
Windows MM duplicates quite a lot of code from Linux EAL:
* eal_memalloc_alloc_seg_bulk
* eal_memalloc_free_seg_bulk
* calc_num_pages_per_socket
* rte_eal_hugepage_init
Need input if it should be left as-is to evolve independently, or some
"common to memory hot-plug" code should be factored out. This
duplication may be reduced naturally when advanced MM is implemented.
Notes on checkpatch warnings:
* No space after comma / no space before closing parent in macros---
definitely a false-positive, unclear how to suppress this.
* Issues from imported BSD code---probably should be ignored?
* Checkpatch is not run against dpdk-kmods (Windows drivers).
[1]: http://core.dpdk.org/roadmap/windows/
[2]: https://patchwork.dpdk.org/project/dpdk/list/?series=9070
Dmitry Kozlyuk (8):
eal/windows: do not expose private EAL facilities
eal/windows: improve CPU and NUMA node detection
eal/windows: initialize hugepage info
eal: introduce internal wrappers for file operations
eal: introduce memory management wrappers
eal/windows: fix rte_page_sizes with Clang on Windows
eal/windows: replace sys/queue.h with a complete one from FreeBSD
eal/windows: implement basic memory management
config/meson.build | 12 +-
doc/guides/windows_gsg/build_dpdk.rst | 20 -
doc/guides/windows_gsg/index.rst | 1 +
doc/guides/windows_gsg/run_apps.rst | 47 +
lib/librte_eal/common/eal_common_fbarray.c | 57 +-
lib/librte_eal/common/eal_common_memory.c | 50 +-
lib/librte_eal/common/eal_private.h | 116 +-
lib/librte_eal/common/include/rte_memory.h | 69 +
lib/librte_eal/common/malloc_heap.c | 1 +
lib/librte_eal/freebsd/eal/eal.c | 40 +
lib/librte_eal/freebsd/eal/eal_memory.c | 118 +-
lib/librte_eal/linux/eal/eal.c | 40 +
lib/librte_eal/linux/eal/eal_memory.c | 117 ++
lib/librte_eal/meson.build | 4 +
lib/librte_eal/rte_eal_exports.def | 119 ++
lib/librte_eal/rte_eal_version.map | 4 +
lib/librte_eal/windows/eal/eal.c | 152 +++
lib/librte_eal/windows/eal/eal_hugepages.c | 108 ++
lib/librte_eal/windows/eal/eal_lcore.c | 187 ++-
lib/librte_eal/windows/eal/eal_memalloc.c | 423 ++++++
lib/librte_eal/windows/eal/eal_memory.c | 1166 +++++++++++++++++
lib/librte_eal/windows/eal/eal_mp.c | 103 ++
lib/librte_eal/windows/eal/eal_thread.c | 1 +
lib/librte_eal/windows/eal/eal_windows.h | 113 ++
lib/librte_eal/windows/eal/include/pthread.h | 2 +
lib/librte_eal/windows/eal/include/rte_os.h | 48 +-
.../windows/eal/include/rte_virt2phys.h | 34 +
.../windows/eal/include/rte_windows.h | 43 +
.../windows/eal/include/sys/queue.h | 663 +++++++++-
lib/librte_eal/windows/eal/include/unistd.h | 3 +
lib/librte_eal/windows/eal/meson.build | 15 +
31 files changed, 3626 insertions(+), 250 deletions(-)
create mode 100644 doc/guides/windows_gsg/run_apps.rst
create mode 100644 lib/librte_eal/windows/eal/eal_hugepages.c
create mode 100644 lib/librte_eal/windows/eal/eal_memalloc.c
create mode 100644 lib/librte_eal/windows/eal/eal_memory.c
create mode 100644 lib/librte_eal/windows/eal/eal_mp.c
create mode 100644 lib/librte_eal/windows/eal/eal_windows.h
create mode 100644 lib/librte_eal/windows/eal/include/rte_virt2phys.h
create mode 100644 lib/librte_eal/windows/eal/include/rte_windows.h
--
2.25.1
^ permalink raw reply [flat|nested] 218+ messages in thread
* [dpdk-dev] [PATCH 1/1] virt2phys: virtual to physical address translator for Windows
2020-03-30 4:10 [dpdk-dev] [RFC PATCH 0/9] Windows basic memory management Dmitry Kozlyuk
@ 2020-03-30 4:10 ` Dmitry Kozlyuk
2020-03-30 6:58 ` Jerin Jacob
2020-04-10 1:45 ` Ranjit Menon
2020-03-30 4:10 ` [dpdk-dev] [RFC PATCH 2/9] eal/windows: do not expose private EAL facilities Dmitry Kozlyuk
` (8 subsequent siblings)
9 siblings, 2 replies; 218+ messages in thread
From: Dmitry Kozlyuk @ 2020-03-30 4:10 UTC (permalink / raw)
To: dev; +Cc: Dmitry Malloy (MESHCHANINOV), Dmitry Kozlyuk
This patch is for dpdk-kmods tree.
This driver supports Windows EAL memory management by translating
current process virtual addresses to physical addresses (IOVA).
Standalone virt2phys allows using DPDK without PMD and provides a
reference implementation. UIO drivers might also implement virt2phys
interface, thus rendering this separate driver unneeded.
Signed-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
---
windows/README.rst | 79 +++++++
windows/virt2phys/virt2phys.c | 129 +++++++++++
windows/virt2phys/virt2phys.h | 34 +++
windows/virt2phys/virt2phys.inf | 85 ++++++++
windows/virt2phys/virt2phys.sln | 27 +++
windows/virt2phys/virt2phys.vcxproj | 228 ++++++++++++++++++++
windows/virt2phys/virt2phys.vcxproj.filters | 36 ++++
7 files changed, 618 insertions(+)
create mode 100644 windows/README.rst
create mode 100755 windows/virt2phys/virt2phys.c
create mode 100755 windows/virt2phys/virt2phys.h
create mode 100755 windows/virt2phys/virt2phys.inf
create mode 100755 windows/virt2phys/virt2phys.sln
create mode 100755 windows/virt2phys/virt2phys.vcxproj
create mode 100755 windows/virt2phys/virt2phys.vcxproj.filters
diff --git a/windows/README.rst b/windows/README.rst
new file mode 100644
index 0000000..84506fa
--- /dev/null
+++ b/windows/README.rst
@@ -0,0 +1,79 @@
+Developing Windows Drivers
+==========================
+
+Prerequisites
+-------------
+
+Building Windows Drivers is only possible on Windows.
+
+1. Visual Studio 2019 Community or Professional Edition
+2. Windows Driver Kit (WDK) for Windows 10, version 1903
+
+Follow the official instructions to obtain all of the above:
+https://docs.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk
+
+
+Build the Drivers
+-----------------
+
+Build from Visual Studio
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Open a solution (``*.sln``) with Visual Studio and build it (Ctrl+Shift+B).
+
+
+Build from Command-Line
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Run "Developer Command Prompt for VS 2019" from the Start menu.
+
+Navigate to the solution directory (with ``*.sln``), then run:
+
+ msbuild
+
+To build a particular combination of configuration and platform:
+
+ msbuild -p:Configuration=Debug;Platform=x64
+
+
+Install the Drivers
+-------------------
+
+Disable Driver Signature Enforcement
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+By default Windows prohibits installing and loading drivers without digital
+signature obtained from Microsoft (read more: `Driver Signing`_).
+For development signature enforcement may be disabled as follows.
+
+In Elevated Command Prompt:
+
+ bcdedit -set loadoptions DISABLE_INTEGRITY_CHECKS
+ bcdedit -set TESTSIGNING ON
+ shutdown -r -t 0
+
+Upon reboot, an overlay message should appear on the desktop informing
+that Windows is in test mode, which means it allows loading unsigned drivers.
+
+.. Driver Signing: https://docs.microsoft.com/en-us/windows-hardware/drivers/install/driver-signing
+
+
+Install, List, and Uninstall Drivers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Driver package is by default located in a subdirectory of its source tree,
+e.g. ``x64\Debug\virt2phys\virt2phys`` (note two levels of ``virt2phys``).
+
+To install the driver and bind associated devices to it:
+
+ pnputil /add-driver x64\Debug\virt2phys\virt2phys\virt2phys.inf /install
+
+A graphical confirmation to load an unsigned driver will still appear.
+
+To list installed drivers:
+
+ pnputil /enum-drivers
+
+To remove the driver package and to uninstall its devices:
+
+ pnputil /delete-drive oem2.inf /install
diff --git a/windows/virt2phys/virt2phys.c b/windows/virt2phys/virt2phys.c
new file mode 100755
index 0000000..6c494d4
--- /dev/null
+++ b/windows/virt2phys/virt2phys.c
@@ -0,0 +1,129 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Dmitry Kozlyuk
+ */
+
+#include <ntddk.h>
+#include <wdf.h>
+#include <wdmsec.h>
+#include <initguid.h>
+
+#include "virt2phys.h"
+
+DRIVER_INITIALIZE DriverEntry;
+EVT_WDF_DRIVER_DEVICE_ADD virt2phys_driver_EvtDeviceAdd;
+EVT_WDF_IO_IN_CALLER_CONTEXT virt2phys_device_EvtIoInCallerContext;
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT driver_object, IN PUNICODE_STRING registry_path)
+{
+ WDF_DRIVER_CONFIG config;
+ WDF_OBJECT_ATTRIBUTES attributes;
+ NTSTATUS status;
+
+ PAGED_CODE();
+
+ WDF_DRIVER_CONFIG_INIT(&config, virt2phys_driver_EvtDeviceAdd);
+ WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
+ status = WdfDriverCreate(
+ driver_object, registry_path,
+ &attributes, &config, WDF_NO_HANDLE);
+ if (!NT_SUCCESS(status)) {
+ KdPrint(("WdfDriverCreate() failed, status=%08x\n", status));
+ }
+
+ return status;
+}
+
+_Use_decl_annotations_
+NTSTATUS
+virt2phys_driver_EvtDeviceAdd(
+ WDFDRIVER driver, PWDFDEVICE_INIT init)
+{
+ WDF_OBJECT_ATTRIBUTES attributes;
+ WDFDEVICE device;
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(driver);
+
+ PAGED_CODE();
+
+ WdfDeviceInitSetIoType(
+ init, WdfDeviceIoNeither);
+ WdfDeviceInitSetIoInCallerContextCallback(
+ init, virt2phys_device_EvtIoInCallerContext);
+
+ WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
+
+ status = WdfDeviceCreate(&init, &attributes, &device);
+ if (!NT_SUCCESS(status)) {
+ KdPrint(("WdfDeviceCreate() failed, status=%08x\n", status));
+ return status;
+ }
+
+ status = WdfDeviceCreateDeviceInterface(
+ device, &GUID_DEVINTERFACE_VIRT2PHYS, NULL);
+ if (!NT_SUCCESS(status)) {
+ KdPrint(("WdfDeviceCreateDeviceInterface() failed, "
+ "status=%08x\n", status));
+ return status;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+_Use_decl_annotations_
+VOID
+virt2phys_device_EvtIoInCallerContext(
+ IN WDFDEVICE device, IN WDFREQUEST request)
+{
+ WDF_REQUEST_PARAMETERS params;
+ ULONG code;
+ PVOID *virt;
+ PHYSICAL_ADDRESS *phys;
+ size_t size;
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(device);
+
+ PAGED_CODE();
+
+ WDF_REQUEST_PARAMETERS_INIT(¶ms);
+ WdfRequestGetParameters(request, ¶ms);
+
+ if (params.Type != WdfRequestTypeDeviceControl) {
+ KdPrint(("bogus request type=%u\n", params.Type));
+ WdfRequestComplete(request, STATUS_NOT_SUPPORTED);
+ return;
+ }
+
+ code = params.Parameters.DeviceIoControl.IoControlCode;
+ if (code != IOCTL_VIRT2PHYS_TRANSLATE) {
+ KdPrint(("bogus IO control code=%lu\n", code));
+ WdfRequestComplete(request, STATUS_NOT_SUPPORTED);
+ return;
+ }
+
+ status = WdfRequestRetrieveInputBuffer(
+ request, sizeof(*virt), (PVOID *)&virt, &size);
+ if (!NT_SUCCESS(status)) {
+ KdPrint(("WdfRequestRetrieveInputBuffer() failed, "
+ "status=%08x\n", status));
+ WdfRequestComplete(request, status);
+ return;
+ }
+
+ status = WdfRequestRetrieveOutputBuffer(
+ request, sizeof(*phys), &phys, &size);
+ if (!NT_SUCCESS(status)) {
+ KdPrint(("WdfRequestRetrieveOutputBuffer() failed, "
+ "status=%08x\n", status));
+ WdfRequestComplete(request, status);
+ return;
+ }
+
+ *phys = MmGetPhysicalAddress(*virt);
+
+ WdfRequestCompleteWithInformation(
+ request, STATUS_SUCCESS, sizeof(*phys));
+}
diff --git a/windows/virt2phys/virt2phys.h b/windows/virt2phys/virt2phys.h
new file mode 100755
index 0000000..4bb2b4a
--- /dev/null
+++ b/windows/virt2phys/virt2phys.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2020 Dmitry Kozlyuk
+ */
+
+/**
+ * @file virt2phys driver interface
+ */
+
+/**
+ * Driver device interface GUID {539c2135-793a-4926-afec-d3a1b61bbc8a}.
+ */
+DEFINE_GUID(GUID_DEVINTERFACE_VIRT2PHYS,
+ 0x539c2135, 0x793a, 0x4926,
+ 0xaf, 0xec, 0xd3, 0xa1, 0xb6, 0x1b, 0xbc, 0x8a);
+
+/**
+ * Driver device type for IO control codes.
+ */
+#define VIRT2PHYS_DEVTYPE 0x8000
+
+/**
+ * Translate a valid non-paged virtual address to a physical address.
+ *
+ * Note: A physical address zero (0) is reported if input address
+ * is paged out or not mapped. However, if input is a valid mapping
+ * of I/O port 0x0000, output is also zero. There is no way
+ * to distinguish between these cases by return value only.
+ *
+ * Input: a non-paged virtual address (PVOID).
+ *
+ * Output: the corresponding physical address (LARGE_INTEGER).
+ */
+#define IOCTL_VIRT2PHYS_TRANSLATE CTL_CODE( \
+ VIRT2PHYS_DEVTYPE, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
diff --git a/windows/virt2phys/virt2phys.inf b/windows/virt2phys/virt2phys.inf
new file mode 100755
index 0000000..e8adaac
--- /dev/null
+++ b/windows/virt2phys/virt2phys.inf
@@ -0,0 +1,85 @@
+; SPDX-License-Identifier: BSD-3-Clause
+; Copyright (c) 2020 Dmitry Kozlyuk
+
+[Version]
+Signature = "$WINDOWS NT$"
+Class = %ClassName%
+ClassGuid = {78A1C341-4539-11d3-B88D-00C04FAD5171}
+Provider = %ManufacturerName%
+CatalogFile = virt2phys.cat
+DriverVer =
+
+[DestinationDirs]
+DefaultDestDir = 12
+virt2phys_Device_CoInstaller_CopyFiles = 11
+
+; ================= Class section =====================
+
+[ClassInstall32]
+Addreg = virt2phys_ClassReg
+
+[virt2phys_ClassReg]
+HKR,,,0,%ClassName%
+HKR,,Icon,,-5
+
+[SourceDisksNames]
+1 = %DiskName%,,,""
+
+[SourceDisksFiles]
+virt2phys.sys = 1,,
+WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll = 1
+
+;*****************************************
+; Install Section
+;*****************************************
+
+[Manufacturer]
+%ManufacturerName%=Standard,NT$ARCH$
+
+[Standard.NT$ARCH$]
+%virt2phys.DeviceDesc%=virt2phys_Device, Root\virt2phys
+
+[virt2phys_Device.NT]
+CopyFiles = Drivers_Dir
+
+[Drivers_Dir]
+virt2phys.sys
+
+;-------------- Service installation
+[virt2phys_Device.NT.Services]
+AddService = virt2phys,%SPSVCINST_ASSOCSERVICE%, virt2phys_Service_Inst
+
+; -------------- virt2phys driver install sections
+[virt2phys_Service_Inst]
+DisplayName = %virt2phys.SVCDESC%
+ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+StartType = 3 ; SERVICE_DEMAND_START
+ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\virt2phys.sys
+
+;
+;--- virt2phys_Device Coinstaller installation ------
+;
+
+[virt2phys_Device.NT.CoInstallers]
+AddReg = virt2phys_Device_CoInstaller_AddReg
+CopyFiles = virt2phys_Device_CoInstaller_CopyFiles
+
+[virt2phys_Device_CoInstaller_AddReg]
+HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller"
+
+[virt2phys_Device_CoInstaller_CopyFiles]
+WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll
+
+[virt2phys_Device.NT.Wdf]
+KmdfService = virt2phys, virt2phys_wdfsect
+[virt2phys_wdfsect]
+KmdfLibraryVersion = $KMDFVERSION$
+
+[Strings]
+SPSVCINST_ASSOCSERVICE = 0x00000002
+ManufacturerName = "Dmitry Kozlyuk"
+ClassName = "Kernel bypass"
+DiskName = "virt2phys Installation Disk"
+virt2phys.DeviceDesc = "Virtual to physical address translator"
+virt2phys.SVCDESC = "virt2phys Service"
diff --git a/windows/virt2phys/virt2phys.sln b/windows/virt2phys/virt2phys.sln
new file mode 100755
index 0000000..0f5ecdc
--- /dev/null
+++ b/windows/virt2phys/virt2phys.sln
@@ -0,0 +1,27 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29613.14
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "virt2phys", "virt2phys.vcxproj", "{0EEF826B-9391-43A8-A722-BDD6F6115137}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0EEF826B-9391-43A8-A722-BDD6F6115137}.Debug|x64.ActiveCfg = Debug|x64
+ {0EEF826B-9391-43A8-A722-BDD6F6115137}.Debug|x64.Build.0 = Debug|x64
+ {0EEF826B-9391-43A8-A722-BDD6F6115137}.Debug|x64.Deploy.0 = Debug|x64
+ {0EEF826B-9391-43A8-A722-BDD6F6115137}.Release|x64.ActiveCfg = Release|x64
+ {0EEF826B-9391-43A8-A722-BDD6F6115137}.Release|x64.Build.0 = Release|x64
+ {0EEF826B-9391-43A8-A722-BDD6F6115137}.Release|x64.Deploy.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {845012FB-4471-4A12-A1C4-FF7E05C40E8E}
+ EndGlobalSection
+EndGlobal
diff --git a/windows/virt2phys/virt2phys.vcxproj b/windows/virt2phys/virt2phys.vcxproj
new file mode 100755
index 0000000..fa51916
--- /dev/null
+++ b/windows/virt2phys/virt2phys.vcxproj
@@ -0,0 +1,228 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|ARM">
+ <Configuration>Debug</Configuration>
+ <Platform>ARM</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|ARM">
+ <Configuration>Release</Configuration>
+ <Platform>ARM</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|ARM64">
+ <Configuration>Debug</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|ARM64">
+ <Configuration>Release</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="virt2phys.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="virt2phys.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Include="virt2phys.inf" />
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{0EEF826B-9391-43A8-A722-BDD6F6115137}</ProjectGuid>
+ <TemplateGuid>{497e31cb-056b-4f31-abb8-447fd55ee5a5}</TemplateGuid>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
+ <Configuration>Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <RootNamespace>virt2phys</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ <DriverType>KMDF</DriverType>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ <DriverType>KMDF</DriverType>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ <DriverType>KMDF</DriverType>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ <DriverType>KMDF</DriverType>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ <DriverType>KMDF</DriverType>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ <DriverType>KMDF</DriverType>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ <DriverType>KMDF</DriverType>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ <DriverType>KMDF</DriverType>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <WppEnabled>true</WppEnabled>
+ <WppRecorderEnabled>true</WppRecorderEnabled>
+ <WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
+ <WppKernelMode>true</WppKernelMode>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WppEnabled>true</WppEnabled>
+ <WppRecorderEnabled>true</WppRecorderEnabled>
+ <WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
+ <WppKernelMode>true</WppKernelMode>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <WppEnabled>false</WppEnabled>
+ <WppRecorderEnabled>true</WppRecorderEnabled>
+ <WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
+ <WppKernelMode>true</WppKernelMode>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>$(DDK_LIB_PATH)wdmsec.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <Inf>
+ <TimeStamp>0.1</TimeStamp>
+ </Inf>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WppEnabled>true</WppEnabled>
+ <WppRecorderEnabled>true</WppRecorderEnabled>
+ <WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
+ <WppKernelMode>true</WppKernelMode>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
+ <ClCompile>
+ <WppEnabled>true</WppEnabled>
+ <WppRecorderEnabled>true</WppRecorderEnabled>
+ <WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
+ <WppKernelMode>true</WppKernelMode>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
+ <ClCompile>
+ <WppEnabled>true</WppEnabled>
+ <WppRecorderEnabled>true</WppRecorderEnabled>
+ <WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
+ <WppKernelMode>true</WppKernelMode>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <ClCompile>
+ <WppEnabled>true</WppEnabled>
+ <WppRecorderEnabled>true</WppRecorderEnabled>
+ <WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
+ <WppKernelMode>true</WppKernelMode>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <ClCompile>
+ <WppEnabled>true</WppEnabled>
+ <WppRecorderEnabled>true</WppRecorderEnabled>
+ <WppScanConfigurationData Condition="'%(ClCompile.ScanConfigurationData)' == ''">trace.h</WppScanConfigurationData>
+ <WppKernelMode>true</WppKernelMode>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <FilesToPackage Include="$(TargetPath)" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/windows/virt2phys/virt2phys.vcxproj.filters b/windows/virt2phys/virt2phys.vcxproj.filters
new file mode 100755
index 0000000..0fe65fc
--- /dev/null
+++ b/windows/virt2phys/virt2phys.vcxproj.filters
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ <Filter Include="Driver Files">
+ <UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier>
+ <Extensions>inf;inv;inx;mof;mc;</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Include="virt2phys.inf">
+ <Filter>Driver Files</Filter>
+ </Inf>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="virt2phys.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="virt2phys.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project>
--
2.25.1
^ permalink raw reply related [flat|nested] 218+ messages in thread
* [dpdk-dev] [RFC PATCH 2/9] eal/windows: do not expose private EAL facilities
2020-03-30 4:10 [dpdk-dev] [RFC PATCH 0/9] Windows basic memory management Dmitry Kozlyuk
2020-03-30 4:10 ` [dpdk-dev] [PATCH 1/1] virt2phys: virtual to physical address translator for Windows Dmitry Kozlyuk
@ 2020-03-30 4:10 ` Dmitry Kozlyuk
2020-03-30 4:10 ` [dpdk-dev] [RFC PATCH 3/9] eal/windows: improve CPU and NUMA node detection Dmitry Kozlyuk
` (7 subsequent siblings)
9 siblings, 0 replies; 218+ messages in thread
From: Dmitry Kozlyuk @ 2020-03-30 4:10 UTC (permalink / raw)
To: dev
Cc: Dmitry Malloy (MESHCHANINOV), Dmitry Kozlyuk, Harini Ramakrishnan,
Omar Cardona, Pallavi Kadam, Ranjit Menon, Thomas Monjalon,
Anand Rawat
The goal of rte_os.h is to mitigate OS differences for EAL users.
In Windows EAL, rte_os.h did excessive things:
1. It included platform SDK headers (windows.h, etc). Those files are
huge, require specific inclusion order, and are generally unused by
the code including rte_os.h. Declarations from platform SDK may
break otherwise platform-independent code, e.g. min, max, ERROR.
2. It included pthread.h, which is clearly not always required.
3. It defined functions private to Windows EAL.
Reorganize Windows EAL includes in the following way:
1. Create rte_windows.h to properly import Windows-specific facilities.
Primary users are bus drivers, tests, and external applications.
2. Remove platform SDK includes from rte_os.h to prevent breaking
otherwise portable code by including rte_os.h on Windows.
Copy necessary definitions to avoid including those headers.
3. Remove pthread.h include from rte_os.h.
4. Move declarations private to Windows EAL into eal_windows.h.
Fixes: 428eb983f5f7 ("eal: add OS specific header file")
Signed-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
---
lib/librte_eal/windows/eal/eal.c | 2 +
lib/librte_eal/windows/eal/eal_lcore.c | 2 +
lib/librte_eal/windows/eal/eal_thread.c | 1 +
lib/librte_eal/windows/eal/eal_windows.h | 29 ++++++++++++
lib/librte_eal/windows/eal/include/pthread.h | 2 +
lib/librte_eal/windows/eal/include/rte_os.h | 44 ++++++-------------
.../windows/eal/include/rte_windows.h | 41 +++++++++++++++++
lib/librte_eal/windows/eal/meson.build | 1 +
8 files changed, 91 insertions(+), 31 deletions(-)
create mode 100644 lib/librte_eal/windows/eal/eal_windows.h
create mode 100644 lib/librte_eal/windows/eal/include/rte_windows.h
diff --git a/lib/librte_eal/windows/eal/eal.c b/lib/librte_eal/windows/eal/eal.c
index e4b50df3b..2cf7a04ef 100644
--- a/lib/librte_eal/windows/eal/eal.c
+++ b/lib/librte_eal/windows/eal/eal.c
@@ -18,6 +18,8 @@
#include <eal_options.h>
#include <eal_private.h>
+#include "eal_windows.h"
+
/* Allow the application to print its usage message too if set */
static rte_usage_hook_t rte_application_usage_hook;
diff --git a/lib/librte_eal/windows/eal/eal_lcore.c b/lib/librte_eal/windows/eal/eal_lcore.c
index b3a6c63af..82ee45413 100644
--- a/lib/librte_eal/windows/eal/eal_lcore.c
+++ b/lib/librte_eal/windows/eal/eal_lcore.c
@@ -2,12 +2,14 @@
* Copyright(c) 2019 Intel Corporation
*/
+#include <pthread.h>
#include <stdint.h>
#include <rte_common.h>
#include "eal_private.h"
#include "eal_thread.h"
+#include "eal_windows.h"
/* global data structure that contains the CPU map */
static struct _wcpu_map {
diff --git a/lib/librte_eal/windows/eal/eal_thread.c b/lib/librte_eal/windows/eal/eal_thread.c
index 9e4bbaa08..e149199a6 100644
--- a/lib/librte_eal/windows/eal/eal_thread.c
+++ b/lib/librte_eal/windows/eal/eal_thread.c
@@ -14,6 +14,7 @@
#include <eal_thread.h>
#include "eal_private.h"
+#include "eal_windows.h"
RTE_DEFINE_PER_LCORE(unsigned int, _lcore_id) = LCORE_ID_ANY;
RTE_DEFINE_PER_LCORE(unsigned int, _socket_id) = (unsigned int)SOCKET_ID_ANY;
diff --git a/lib/librte_eal/windows/eal/eal_windows.h b/lib/librte_eal/windows/eal/eal_windows.h
new file mode 100644
index 000000000..fadd676b2
--- /dev/null
+++ b/lib/librte_eal/windows/eal/eal_windows.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2020 Dmitry Kozlyuk
+ */
+
+#ifndef _EAL_WINDOWS_H_
+#define _EAL_WINDOWS_H_
+
+/**
+ * @file Facilities private to Windows EAL
+ */
+
+#include <rte_windows.h>
+
+/**
+ * Create a map of processors and cores on the system.
+ */
+void eal_create_cpu_map(void);
+
+/**
+ * Create a thread.
+ *
+ * @param thread
+ * The location to store the thread id if successful.
+ * @return
+ * 0 for success, -1 if the thread is not created.
+ */
+int eal_thread_create(pthread_t *thread);
+
+#endif /* _EAL_WINDOWS_H_ */
diff --git a/lib/librte_eal/windows/eal/include/pthread.h b/lib/librte_eal/windows/eal/include/pthread.h
index b9dd18e56..cfd53f0b8 100644
--- a/lib/librte_eal/windows/eal/include/pthread.h
+++ b/lib/librte_eal/windows/eal/include/pthread.h
@@ -5,6 +5,8 @@
#ifndef _PTHREAD_H_
#define _PTHREAD_H_
+#include <stdint.h>
+
/**
* This file is required to support the common code in eal_common_proc.c,
* eal_common_thread.c and common\include\rte_per_lcore.h as Microsoft libc
diff --git a/lib/librte_eal/windows/eal/include/rte_os.h b/lib/librte_eal/windows/eal/include/rte_os.h
index e1e0378e6..510e39e03 100644
--- a/lib/librte_eal/windows/eal/include/rte_os.h
+++ b/lib/librte_eal/windows/eal/include/rte_os.h
@@ -8,20 +8,18 @@
/**
* This is header should contain any function/macro definition
* which are not supported natively or named differently in the
- * Windows OS. Functions will be added in future releases.
+ * Windows OS. It must not include Windows-specific headers.
*/
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+
#ifdef __cplusplus
extern "C" {
#endif
-#include <windows.h>
-#include <basetsd.h>
-#include <pthread.h>
-#include <stdio.h>
-
-/* limits.h replacement */
-#include <stdlib.h>
+/* limits.h replacement, value as in <windows.h> */
#ifndef PATH_MAX
#define PATH_MAX _MAX_PATH
#endif
@@ -31,8 +29,6 @@ extern "C" {
/* strdup is deprecated in Microsoft libc and _strdup is preferred */
#define strdup(str) _strdup(str)
-typedef SSIZE_T ssize_t;
-
#define strtok_r(str, delim, saveptr) strtok_s(str, delim, saveptr)
#define index(a, b) strchr(a, b)
@@ -40,22 +36,14 @@ typedef SSIZE_T ssize_t;
#define strncasecmp(s1, s2, count) _strnicmp(s1, s2, count)
-/**
- * Create a thread.
- * This function is private to EAL.
- *
- * @param thread
- * The location to store the thread id if successful.
- * @return
- * 0 for success, -1 if the thread is not created.
- */
-int eal_thread_create(pthread_t *thread);
+/* cpu_set macros implementation */
+#define RTE_CPU_AND(dst, src1, src2) CPU_AND(dst, src1, src2)
+#define RTE_CPU_OR(dst, src1, src2) CPU_OR(dst, src1, src2)
+#define RTE_CPU_FILL(set) CPU_FILL(set)
+#define RTE_CPU_NOT(dst, src) CPU_NOT(dst, src)
-/**
- * Create a map of processors and cores on the system.
- * This function is private to EAL.
- */
-void eal_create_cpu_map(void);
+/* as in <windows.h> */
+typedef long long ssize_t;
#ifndef RTE_TOOLCHAIN_GCC
static inline int
@@ -86,12 +74,6 @@ asprintf(char **buffer, const char *format, ...)
}
#endif /* RTE_TOOLCHAIN_GCC */
-/* cpu_set macros implementation */
-#define RTE_CPU_AND(dst, src1, src2) CPU_AND(dst, src1, src2)
-#define RTE_CPU_OR(dst, src1, src2) CPU_OR(dst, src1, src2)
-#define RTE_CPU_FILL(set) CPU_FILL(set)
-#define RTE_CPU_NOT(dst, src) CPU_NOT(dst, src)
-
#ifdef __cplusplus
}
#endif
diff --git a/lib/librte_eal/windows/eal/include/rte_windows.h b/lib/librte_eal/windows/eal/include/rte_windows.h
new file mode 100644
index 000000000..ed6e4c148
--- /dev/null
+++ b/lib/librte_eal/windows/eal/include/rte_windows.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2020 Dmitry Kozlyuk
+ */
+
+#ifndef _RTE_WINDOWS_H_
+#define _RTE_WINDOWS_H_
+
+/**
+ * @file Windows-specific facilities
+ *
+ * This file should be included by DPDK libraries and applications
+ * that need access to Windows API. It includes platform SDK headers
+ * in compatible order with proper options and defines error-handling macros.
+ */
+
+/* Disable excessive libraries. */
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+/* Must come first. */
+#include <windows.h>
+
+#include <basetsd.h>
+#include <psapi.h>
+
+/* Have GUIDs defined. */
+#ifndef INITGUID
+#define INITGUID
+#endif
+#include <initguid.h>
+
+/**
+ * Log GetLastError() with context, usually a Win32 API function and arguments.
+ */
+#define RTE_LOG_WIN32_ERR(...) \
+ RTE_LOG(DEBUG, EAL, RTE_FMT("GetLastError()=%lu: " \
+ RTE_FMT_HEAD(__VA_ARGS__,) "\n", GetLastError(), \
+ RTE_FMT_TAIL(__VA_ARGS__,)))
+
+#endif /* _RTE_WINDOWS_H_ */
diff --git a/lib/librte_eal/windows/eal/meson.build b/lib/librte_eal/windows/eal/meson.build
index 2a062c365..21cd84459 100644
--- a/lib/librte_eal/windows/eal/meson.build
+++ b/lib/librte_eal/windows/eal/meson.build
@@ -6,6 +6,7 @@ eal_inc += include_directories('include')
env_objs = []
env_headers = files(
'include/rte_os.h',
+ 'include/rte_windows.h',
)
common_sources = files(
'../../common/eal_common_bus.c',
--
2.25.1
^ permalink raw reply related [flat|nested] 218+ messages in thread
* [dpdk-dev] [RFC PATCH 3/9] eal/windows: improve CPU and NUMA node detection
2020-03-30 4:10 [dpdk-dev] [RFC PATCH 0/9] Windows basic memory management Dmitry Kozlyuk
2020-03-30 4:10 ` [dpdk-dev] [PATCH 1/1] virt2phys: virtual to physical address translator for Windows Dmitry Kozlyuk
2020-03-30 4:10 ` [dpdk-dev] [RFC PATCH 2/9] eal/windows: do not expose private EAL facilities Dmitry Kozlyuk
@ 2020-03-30 4:10 ` Dmitry Kozlyuk
2020-03-30 4:10 ` [dpdk-dev] [RFC PATCH 4/9] eal/windows: initialize hugepage info Dmitry Kozlyuk
` (6 subsequent siblings)
9 siblings, 0 replies; 218+ messages in thread
From: Dmitry Kozlyuk @ 2020-03-30 4:10 UTC (permalink / raw)
To: dev
Cc: Dmitry Malloy (MESHCHANINOV), Dmitry Kozlyuk, Harini Ramakrishnan,
Omar Cardona, Pallavi Kadam, Ranjit Menon, Anand Rawat, Jeff Shaw
1. Map CPU cores to their respective NUMA nodes as reported by system.
2. Support systems with more than 64 cores (multiple processor groups).
3. Fix magic constants, styling issues, and compiler warnings.
4. Add EAL private function to map DPDK socket ID to NUMA node number.
Fixes: 53ffd9f080fc ("eal/windows: add minimum viable code")
Signed-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
---
lib/librte_eal/windows/eal/eal_lcore.c | 185 ++++++++++++++---------
lib/librte_eal/windows/eal/eal_windows.h | 10 ++
2 files changed, 124 insertions(+), 71 deletions(-)
diff --git a/lib/librte_eal/windows/eal/eal_lcore.c b/lib/librte_eal/windows/eal/eal_lcore.c
index 82ee45413..c11f37de3 100644
--- a/lib/librte_eal/windows/eal/eal_lcore.c
+++ b/lib/librte_eal/windows/eal/eal_lcore.c
@@ -3,103 +3,146 @@
*/
#include <pthread.h>
+#include <stdbool.h>
#include <stdint.h>
#include <rte_common.h>
+#include <rte_debug.h>
+#include <rte_lcore.h>
+#include <rte_os.h>
#include "eal_private.h"
#include "eal_thread.h"
#include "eal_windows.h"
-/* global data structure that contains the CPU map */
-static struct _wcpu_map {
- unsigned int total_procs;
- unsigned int proc_sockets;
- unsigned int proc_cores;
- unsigned int reserved;
- struct _win_lcore_map {
- uint8_t socket_id;
- uint8_t core_id;
- } wlcore_map[RTE_MAX_LCORE];
-} wcpu_map = { 0 };
-
-/*
- * Create a map of all processors and associated cores on the system
- */
+/** Number of logical processors (cores) in a processor group (32 or 64). */
+#define EAL_PROCESSOR_GROUP_SIZE (sizeof(KAFFINITY) * CHAR_BIT)
+
+struct lcore_map {
+ uint8_t socket_id;
+ uint8_t core_id;
+};
+
+struct socket_map {
+ uint16_t node_id;
+};
+
+struct cpu_map {
+ unsigned int socket_count;
+ unsigned int lcore_count;
+ struct lcore_map lcores[RTE_MAX_LCORE];
+ struct socket_map sockets[RTE_MAX_NUMA_NODES];
+};
+
+static struct cpu_map cpu_map = { 0 };
+
void
-eal_create_cpu_map()
+eal_create_cpu_map(void)
{
- wcpu_map.total_procs =
- GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
-
- LOGICAL_PROCESSOR_RELATIONSHIP lprocRel;
- DWORD lprocInfoSize = 0;
- BOOL ht_enabled = FALSE;
-
- /* First get the processor package information */
- lprocRel = RelationProcessorPackage;
- /* Determine the size of buffer we need (pass NULL) */
- GetLogicalProcessorInformationEx(lprocRel, NULL, &lprocInfoSize);
- wcpu_map.proc_sockets = lprocInfoSize / 48;
-
- lprocInfoSize = 0;
- /* Next get the processor core information */
- lprocRel = RelationProcessorCore;
- GetLogicalProcessorInformationEx(lprocRel, NULL, &lprocInfoSize);
- wcpu_map.proc_cores = lprocInfoSize / 48;
-
- if (wcpu_map.total_procs > wcpu_map.proc_cores)
- ht_enabled = TRUE;
-
- /* Distribute the socket and core ids appropriately
- * across the logical cores. For now, split the cores
- * equally across the sockets.
- */
- unsigned int lcore = 0;
- for (unsigned int socket = 0; socket <
- wcpu_map.proc_sockets; ++socket) {
- for (unsigned int core = 0;
- core < (wcpu_map.proc_cores / wcpu_map.proc_sockets);
- ++core) {
- wcpu_map.wlcore_map[lcore]
- .socket_id = socket;
- wcpu_map.wlcore_map[lcore]
- .core_id = core;
- lcore++;
- if (ht_enabled) {
- wcpu_map.wlcore_map[lcore]
- .socket_id = socket;
- wcpu_map.wlcore_map[lcore]
- .core_id = core;
- lcore++;
+ SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *infos, *info;
+ DWORD infos_size;
+ bool full = false;
+
+ infos_size = 0;
+ if (!GetLogicalProcessorInformationEx(
+ RelationNumaNode, NULL, &infos_size)) {
+ DWORD error = GetLastError();
+ if (error != ERROR_INSUFFICIENT_BUFFER) {
+ rte_panic("cannot get NUMA node info size, error %lu",
+ GetLastError());
+ }
+ }
+
+ infos = malloc(infos_size);
+ if (infos == NULL) {
+ rte_panic("cannot allocate memory for NUMA node information");
+ return;
+ }
+
+ if (!GetLogicalProcessorInformationEx(
+ RelationNumaNode, infos, &infos_size)) {
+ rte_panic("cannot get NUMA node information, error %lu",
+ GetLastError());
+ }
+
+ info = infos;
+ while ((uint8_t *)info - (uint8_t *)infos < infos_size) {
+ unsigned int node_id = info->NumaNode.NodeNumber;
+ GROUP_AFFINITY *cores = &info->NumaNode.GroupMask;
+ struct lcore_map *lcore;
+ unsigned int i, socket_id;
+
+ /* NUMA node may be reported multiple times if it includes
+ * cores from different processor groups, e. g. 80 cores
+ * of a physical processor comprise one NUMA node, but two
+ * processor groups, because group size is limited by 32/64.
+ */
+ for (socket_id = 0; socket_id < cpu_map.socket_count;
+ socket_id++) {
+ if (cpu_map.sockets[socket_id].node_id == node_id)
+ break;
+ }
+
+ if (socket_id == cpu_map.socket_count) {
+ if (socket_id == RTE_DIM(cpu_map.sockets)) {
+ full = true;
+ goto exit;
}
+
+ cpu_map.sockets[socket_id].node_id = node_id;
+ cpu_map.socket_count++;
+ }
+
+ for (i = 0; i < EAL_PROCESSOR_GROUP_SIZE; i++) {
+ if ((cores->Mask & ((KAFFINITY)1 << i)) == 0)
+ continue;
+
+ if (cpu_map.lcore_count == RTE_DIM(cpu_map.lcores)) {
+ full = true;
+ goto exit;
+ }
+
+ lcore = &cpu_map.lcores[cpu_map.lcore_count];
+ lcore->socket_id = socket_id;
+ lcore->core_id =
+ cores->Group * EAL_PROCESSOR_GROUP_SIZE + i;
+ cpu_map.lcore_count++;
}
+
+ info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(
+ (uint8_t *)info + info->Size);
+ }
+
+exit:
+ if (full) {
+ /* RTE_LOG() is not yet available, but this is important. */
+ fprintf(stderr, "Enumerated maximum of %u NUMA nodes and %u cores\n",
+ cpu_map.socket_count, cpu_map.lcore_count);
}
+
+ free(infos);
}
-/*
- * Check if a cpu is present by the presence of the cpu information for it
- */
int
eal_cpu_detected(unsigned int lcore_id)
{
- return (lcore_id < wcpu_map.total_procs);
+ return lcore_id < cpu_map.lcore_count;
}
-/*
- * Get CPU socket id for a logical core
- */
unsigned
eal_cpu_socket_id(unsigned int lcore_id)
{
- return wcpu_map.wlcore_map[lcore_id].socket_id;
+ return cpu_map.lcores[lcore_id].socket_id;
}
-/*
- * Get CPU socket id (NUMA node) for a logical core
- */
unsigned
eal_cpu_core_id(unsigned int lcore_id)
{
- return wcpu_map.wlcore_map[lcore_id].core_id;
+ return cpu_map.lcores[lcore_id].core_id;
+}
+
+unsigned int
+eal_socket_numa_node(unsigned int socket_id)
+{
+ return cpu_map.sockets[socket_id].node_id;
}
diff --git a/lib/librte_eal/windows/eal/eal_windows.h b/lib/librte_eal/windows/eal/eal_windows.h
index fadd676b2..390d2fd66 100644
--- a/lib/librte_eal/windows/eal/eal_windows.h
+++ b/lib/librte_eal/windows/eal/eal_windows.h
@@ -26,4 +26,14 @@ void eal_create_cpu_map(void);
*/
int eal_thread_create(pthread_t *thread);
+/**
+ * Get system NUMA node number for a socket ID.
+ *
+ * @param socket_id
+ * Valid EAL socket ID.
+ * @return
+ * NUMA node number to use with Win32 API.
+ */
+unsigned int eal_socket_numa_node(unsigned int socket_id);
+
#endif /* _EAL_WINDOWS_H_ */
--
2.25.1
^ permalink raw reply related [flat|nested] 218+ messages in thread
* [dpdk-dev] [RFC PATCH 4/9] eal/windows: initialize hugepage info
2020-03-30 4:10 [dpdk-dev] [RFC PATCH 0/9] Windows basic memory management Dmitry Kozlyuk
` (2 preceding siblings ...)
2020-03-30 4:10 ` [dpdk-dev] [RFC PATCH 3/9] eal/windows: improve CPU and NUMA node detection Dmitry Kozlyuk
@ 2020-03-30 4:10 ` Dmitry Kozlyuk
2020-03-30 4:10 ` [dpdk-dev] [RFC PATCH 5/9] eal: introduce internal wrappers for file operations Dmitry Kozlyuk
` (5 subsequent siblings)
9 siblings, 0 replies; 218+ messages in thread
From: Dmitry Kozlyuk @ 2020-03-30 4:10 UTC (permalink / raw)
To: dev
Cc: Dmitry Malloy (MESHCHANINOV), Dmitry Kozlyuk, Thomas Monjalon,
Harini Ramakrishnan, Omar Cardona, Pallavi Kadam, Ranjit Menon,
John McNamara, Marko Kovacevic
Add hugepages discovery ("large pages" in Windows terminology)
and update documentation for required privilege setup.
Signed-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
---
config/meson.build | 2 +
doc/guides/windows_gsg/build_dpdk.rst | 20 ----
doc/guides/windows_gsg/index.rst | 1 +
doc/guides/windows_gsg/run_apps.rst | 47 +++++++++
lib/librte_eal/windows/eal/eal.c | 14 +++
lib/librte_eal/windows/eal/eal_hugepages.c | 108 +++++++++++++++++++++
lib/librte_eal/windows/eal/meson.build | 1 +
7 files changed, 173 insertions(+), 20 deletions(-)
create mode 100644 doc/guides/windows_gsg/run_apps.rst
create mode 100644 lib/librte_eal/windows/eal/eal_hugepages.c
diff --git a/config/meson.build b/config/meson.build
index abedd76f2..73cf69814 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -263,6 +263,8 @@ if is_windows
if cc.get_id() == 'gcc'
add_project_arguments('-D__USE_MINGW_ANSI_STDIO', language: 'c')
endif
+
+ add_project_link_arguments('-ladvapi32', language: 'c')
endif
if get_option('b_lto')
diff --git a/doc/guides/windows_gsg/build_dpdk.rst b/doc/guides/windows_gsg/build_dpdk.rst
index d46e84e3f..650483e3b 100644
--- a/doc/guides/windows_gsg/build_dpdk.rst
+++ b/doc/guides/windows_gsg/build_dpdk.rst
@@ -111,23 +111,3 @@ Depending on the distribution, paths in this file may need adjustments.
meson --cross-file config/x86/meson_mingw.txt -Dexamples=helloworld build
ninja -C build
-
-
-Run the helloworld example
-==========================
-
-Navigate to the examples in the build directory and run `dpdk-helloworld.exe`.
-
-.. code-block:: console
-
- cd C:\Users\me\dpdk\build\examples
- dpdk-helloworld.exe
- hello from core 1
- hello from core 3
- hello from core 0
- hello from core 2
-
-Note for MinGW-w64: applications are linked to ``libwinpthread-1.dll``
-by default. To run the example, either add toolchain executables directory
-to the PATH or copy the library to the working directory.
-Alternatively, static linking may be used (mind the LGPLv2.1 license).
diff --git a/doc/guides/windows_gsg/index.rst b/doc/guides/windows_gsg/index.rst
index d9b7990a8..e94593572 100644
--- a/doc/guides/windows_gsg/index.rst
+++ b/doc/guides/windows_gsg/index.rst
@@ -12,3 +12,4 @@ Getting Started Guide for Windows
intro
build_dpdk
+ run_apps
diff --git a/doc/guides/windows_gsg/run_apps.rst b/doc/guides/windows_gsg/run_apps.rst
new file mode 100644
index 000000000..21ac7f6c1
--- /dev/null
+++ b/doc/guides/windows_gsg/run_apps.rst
@@ -0,0 +1,47 @@
+.. SPDX-License-Identifier: BSD-3-Clause
+ Copyright(c) 2020 Dmitry Kozlyuk
+
+Running DPDK Applications
+=========================
+
+Grant *Lock pages in memory* Privilege
+--------------------------------------
+
+Use of hugepages ("large pages" in Windows terminolocy) requires
+``SeLockMemoryPrivilege`` for the user running an application.
+
+1. Open *Local Security Policy* snap in, either:
+
+ * Control Panel / Computer Management / Local Security Policy;
+ * or Win+R, type ``secpol``, press Enter.
+
+2. Open *Local Policies / User Rights Assignment / Lock pages in memory.*
+
+3. Add desired users or groups to the list of grantees.
+
+4. Privilege is applied upon next logon. In particular, if privilege has been
+ granted to current user, a logoff is required before it is available.
+
+See `Large-Page Support`_ in MSDN for details.
+
+.. _Large-page Support: https://docs.microsoft.com/en-us/windows/win32/memory/large-page-support
+
+
+Run the ``helloworld`` Example
+------------------------------
+
+Navigate to the examples in the build directory and run `dpdk-helloworld.exe`.
+
+.. code-block:: console
+
+ cd C:\Users\me\dpdk\build\examples
+ dpdk-helloworld.exe
+ hello from core 1
+ hello from core 3
+ hello from core 0
+ hello from core 2
+
+Note for MinGW-w64: applications are linked to ``libwinpthread-1.dll``
+by default. To run the example, either add toolchain executables directory
+to the PATH or copy the library to the working directory.
+Alternatively, static linking may be used (mind the LGPLv2.1 license).
diff --git a/lib/librte_eal/windows/eal/eal.c b/lib/librte_eal/windows/eal/eal.c
index 2cf7a04ef..a84b6147a 100644
--- a/lib/librte_eal/windows/eal/eal.c
+++ b/lib/librte_eal/windows/eal/eal.c
@@ -18,8 +18,11 @@
#include <eal_options.h>
#include <eal_private.h>
+#include "eal_hugepages.h"
#include "eal_windows.h"
+#define MEMSIZE_IF_NO_HUGE_PAGE (64ULL * 1024ULL * 1024ULL)
+
/* Allow the application to print its usage message too if set */
static rte_usage_hook_t rte_application_usage_hook;
@@ -242,6 +245,17 @@ rte_eal_init(int argc, char **argv)
if (fctret < 0)
exit(1);
+ if (!internal_config.no_hugetlbfs && (eal_hugepage_info_init() < 0)) {
+ rte_eal_init_alert("Cannot get hugepage information.");
+ rte_errno = EACCES;
+ return -1;
+ }
+
+ if (internal_config.memory == 0 && !internal_config.force_sockets) {
+ if (internal_config.no_hugetlbfs)
+ internal_config.memory = MEMSIZE_IF_NO_HUGE_PAGE;
+ }
+
eal_thread_init_master(rte_config.master_lcore);
RTE_LCORE_FOREACH_SLAVE(i) {
diff --git a/lib/librte_eal/windows/eal/eal_hugepages.c b/lib/librte_eal/windows/eal/eal_hugepages.c
new file mode 100644
index 000000000..b099d13f9
--- /dev/null
+++ b/lib/librte_eal/windows/eal/eal_hugepages.c
@@ -0,0 +1,108 @@
+#include <rte_errno.h>
+#include <rte_log.h>
+#include <rte_memory.h>
+#include <rte_memzone.h>
+#include <rte_os.h>
+
+#include "eal_filesystem.h"
+#include "eal_hugepages.h"
+#include "eal_internal_cfg.h"
+#include "eal_windows.h"
+
+static int
+hugepage_claim_privilege(void)
+{
+ static const wchar_t privilege[] = L"SeLockMemoryPrivilege";
+
+ HANDLE token;
+ LUID luid;
+ TOKEN_PRIVILEGES tp;
+ int ret = -1;
+
+ if (!OpenProcessToken(GetCurrentProcess(),
+ TOKEN_ADJUST_PRIVILEGES, &token)) {
+ RTE_LOG_WIN32_ERR("OpenProcessToken()");
+ return -1;
+ }
+
+ if (!LookupPrivilegeValueW(NULL, privilege, &luid)) {
+ RTE_LOG_WIN32_ERR("LookupPrivilegeValue(\"%S\")", privilege);
+ goto exit;
+ }
+
+ tp.PrivilegeCount = 1;
+ tp.Privileges[0].Luid = luid;
+ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ if (!AdjustTokenPrivileges(
+ token, FALSE, &tp, sizeof(tp), NULL, NULL)) {
+ RTE_LOG_WIN32_ERR("AdjustTokenPrivileges()");
+ goto exit;
+ }
+
+ ret = 0;
+
+exit:
+ CloseHandle(token);
+
+ return ret;
+}
+
+static int
+hugepage_info_init(void)
+{
+ struct hugepage_info *hpi;
+ unsigned int socket_id;
+ int ret = 0;
+
+ /* Only one hugepage size available in Windows. */
+ internal_config.num_hugepage_sizes = 1;
+ hpi = &internal_config.hugepage_info[0];
+
+ hpi->hugepage_sz = GetLargePageMinimum();
+ if (hpi->hugepage_sz == 0)
+ return -ENOTSUP;
+
+ /* Assume all memory on each NUMA node available for hugepages,
+ * because Windows neither advertises additional limits,
+ * nor provides an API to query them.
+ */
+ for (socket_id = 0; socket_id < rte_socket_count(); socket_id++) {
+ ULONGLONG bytes;
+ unsigned int numa_node;
+
+ numa_node = eal_socket_numa_node(socket_id);
+ if (!GetNumaAvailableMemoryNodeEx(numa_node, &bytes)) {
+ RTE_LOG_WIN32_ERR("GetNumaAvailableMemoryNodeEx(%u)",
+ numa_node);
+ continue;
+ }
+
+ hpi->num_pages[socket_id] = bytes / hpi->hugepage_sz;
+ RTE_LOG(DEBUG, EAL,
+ "Found %u hugepages of %zu bytes on socket %u\n",
+ hpi->num_pages[socket_id], hpi->hugepage_sz, socket_id);
+ }
+
+ /* No hugepage filesystem in Windows. */
+ hpi->lock_descriptor = -1;
+ memset(hpi->hugedir, 0, sizeof(hpi->hugedir));
+
+ return ret;
+}
+
+int
+eal_hugepage_info_init(void)
+{
+ if (hugepage_claim_privilege() < 0) {
+ RTE_LOG(ERR, EAL, "Cannot claim hugepage privilege\n");
+ return -1;
+ }
+
+ if (hugepage_info_init() < 0) {
+ RTE_LOG(ERR, EAL, "Cannot get hugepage information\n");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/lib/librte_eal/windows/eal/meson.build b/lib/librte_eal/windows/eal/meson.build
index 21cd84459..8b407c9ae 100644
--- a/lib/librte_eal/windows/eal/meson.build
+++ b/lib/librte_eal/windows/eal/meson.build
@@ -22,6 +22,7 @@ common_sources = files(
)
env_sources = files('eal.c',
'eal_debug.c',
+ 'eal_hugepages.c',
'eal_lcore.c',
'eal_thread.c',
'getopt.c',
--
2.25.1
^ permalink raw reply related [flat|nested] 218+ messages in thread
* [dpdk-dev] [RFC PATCH 5/9] eal: introduce internal wrappers for file operations
2020-03-30 4:10 [dpdk-dev] [RFC PATCH 0/9] Windows basic memory management Dmitry Kozlyuk
` (3 preceding siblings ...)
2020-03-30 4:10 ` [dpdk-dev] [RFC PATCH 4/9] eal/windows: initialize hugepage info Dmitry Kozlyuk
@ 2020-03-30 4:10 ` Dmitry Kozlyuk
2020-03-30 7:04 ` Jerin Jacob
2020-03-30 4:10 ` [dpdk-dev] [RFC PATCH 6/9] eal: introduce memory management wrappers Dmitry Kozlyuk
` (4 subsequent siblings)
9 siblings, 1 reply; 218+ messages in thread
From: Dmitry Kozlyuk @ 2020-03-30 4:10 UTC (permalink / raw)
To: dev
Cc: Dmitry Malloy (MESHCHANINOV), Dmitry Kozlyuk, Bruce Richardson,
Harini Ramakrishnan, Omar Cardona, Pallavi Kadam, Ranjit Menon
EAL common code uses file locking and truncation. Introduce
OS-independent wrapeprs in order to support both POSIX and Windows:
* eal_file_lock: lock or unlock an open file.
* eal_file_truncate: enforce a given size for an open file.
Wrappers follow POSIX semantics, but interface is not POSIX,
so that it can be made more clean, e.g. by not mixing locking
operation and behaviour on conflict.
Signed-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
WIP2
---
lib/librte_eal/common/eal_private.h | 45 ++++++++++++++++
lib/librte_eal/freebsd/eal/eal.c | 40 ++++++++++++++
lib/librte_eal/linux/eal/eal.c | 40 ++++++++++++++
lib/librte_eal/windows/eal/eal.c | 83 +++++++++++++++++++++++++++++
4 files changed, 208 insertions(+)
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index ddcfbe2e4..0130571e8 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -443,4 +443,49 @@ rte_option_usage(void);
uint64_t
eal_get_baseaddr(void);
+/** File locking operation. */
+enum rte_flock_op {
+ RTE_FLOCK_SHARED, /**< Acquire a shared lock. */
+ RTE_FLOCK_EXCLUSIVE, /**< Acquire an exclusive lock. */
+ RTE_FLOCK_UNLOCK /**< Release a previously taken lock. */
+};
+
+/** Behavior on file locking conflict. */
+enum rte_flock_mode {
+ RTE_FLOCK_WAIT, /**< Wait until the file gets unlocked to lock it. */
+ RTE_FLOCK_RETURN /**< Return immediately if the file is locked. */
+};
+
+/**
+ * Lock or unlock the file.
+ *
+ * On failure @code rte_errno @endcode is set to the error code
+ * specified by POSIX flock(3) description.
+ *
+ * @param fd
+ * Opened file descriptor.
+ * @param op
+ * Operation to perform.
+ * @param mode
+ * Behavior on conflict.
+ * @return
+ * 0 on success, (-1) on failure.
+ */
+int eal_file_lock(int fd, enum rte_flock_op op, enum rte_flock_mode mode);
+
+/**
+ * Truncate or extend the file to the specified size.
+ *
+ * On failure @code rte_errno @endcode is set to the error code
+ * specified by POSIX ftruncate(3) description.
+ *
+ * @param fd
+ * Opened file descriptor.
+ * @param size
+ * Desired file size.
+ * @return
+ * 0 on success, (-1) on failure.
+ */
+int eal_file_truncate(int fd, ssize_t size);
+
#endif /* _EAL_PRIVATE_H_ */
diff --git a/lib/librte_eal/freebsd/eal/eal.c b/lib/librte_eal/freebsd/eal/eal.c
index 6ae37e7e6..4bbcc7ab7 100644
--- a/lib/librte_eal/freebsd/eal/eal.c
+++ b/lib/librte_eal/freebsd/eal/eal.c
@@ -697,6 +697,46 @@ static void rte_eal_init_alert(const char *msg)
RTE_LOG(ERR, EAL, "%s\n", msg);
}
+int
+eal_file_truncate(int fd, ssize_t size)
+{
+ int ret;
+
+ ret = ftruncate(fd, size);
+ if (ret)
+ rte_errno = errno;
+
+ return ret;
+}
+
+int
+eal_file_lock(int fd, enum rte_flock_op op, enum rte_flock_mode mode)
+{
+ int sys_flags = 0;
+ int ret;
+
+ if (mode == RTE_FLOCK_RETURN)
+ sys_flags |= LOCK_NB;
+
+ switch (op) {
+ case RTE_FLOCK_EXCLUSIVE:
+ sys_flags |= LOCK_EX;
+ break;
+ case RTE_FLOCK_SHARED:
+ sys_flags |= LOCK_SH;
+ break;
+ case RTE_FLOCK_UNLOCK:
+ sys_flags |= LOCK_UN;
+ break;
+ }
+
+ ret = flock(fd, sys_flags);
+ if (ret)
+ rte_errno = errno;
+
+ return ret;
+}
+
/* Launch threads, called at application init(). */
int
rte_eal_init(int argc, char **argv)
diff --git a/lib/librte_eal/linux/eal/eal.c b/lib/librte_eal/linux/eal/eal.c
index 9530ee55f..d75c162c1 100644
--- a/lib/librte_eal/linux/eal/eal.c
+++ b/lib/librte_eal/linux/eal/eal.c
@@ -956,6 +956,46 @@ is_iommu_enabled(void)
return n > 2;
}
+int
+eal_file_truncate(int fd, ssize_t size)
+{
+ int ret;
+
+ ret = ftruncate(fd, size);
+ if (ret)
+ rte_errno = errno;
+
+ return ret;
+}
+
+int
+eal_file_lock(int fd, enum rte_flock_op op, enum rte_flock_mode mode)
+{
+ int sys_flags = 0;
+ int ret;
+
+ if (mode == RTE_FLOCK_RETURN)
+ sys_flags |= LOCK_NB;
+
+ switch (op) {
+ case RTE_FLOCK_EXCLUSIVE:
+ sys_flags |= LOCK_EX;
+ break;
+ case RTE_FLOCK_SHARED:
+ sys_flags |= LOCK_SH;
+ break;
+ case RTE_FLOCK_UNLOCK:
+ sys_flags |= LOCK_UN;
+ break;
+ }
+
+ ret = flock(fd, sys_flags);
+ if (ret)
+ rte_errno = errno;
+
+ return ret;
+}
+
/* Launch threads, called at application init(). */
int
rte_eal_init(int argc, char **argv)
diff --git a/lib/librte_eal/windows/eal/eal.c b/lib/librte_eal/windows/eal/eal.c
index a84b6147a..4932185ec 100644
--- a/lib/librte_eal/windows/eal/eal.c
+++ b/lib/librte_eal/windows/eal/eal.c
@@ -224,6 +224,89 @@ rte_eal_init_alert(const char *msg)
RTE_LOG(ERR, EAL, "%s\n", msg);
}
+int
+eal_file_truncate(int fd, ssize_t size)
+{
+ HANDLE handle;
+ DWORD ret;
+ LONG low = (LONG)((size_t)size);
+ LONG high = (LONG)((size_t)size >> 32);
+
+ handle = (HANDLE)_get_osfhandle(fd);
+ if (handle == INVALID_HANDLE_VALUE) {
+ rte_errno = EBADF;
+ return -1;
+ }
+
+ ret = SetFilePointer(handle, low, &high, FILE_BEGIN);
+ if (ret == INVALID_SET_FILE_POINTER) {
+ RTE_LOG_WIN32_ERR("SetFilePointer()");
+ rte_errno = EINVAL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+lock_file(HANDLE handle, enum rte_flock_op op, enum rte_flock_mode mode)
+{
+ DWORD sys_flags = 0;
+ OVERLAPPED overlapped;
+
+ if (op == RTE_FLOCK_EXCLUSIVE)
+ sys_flags |= LOCKFILE_EXCLUSIVE_LOCK;
+ if (mode == RTE_FLOCK_RETURN)
+ sys_flags |= LOCKFILE_FAIL_IMMEDIATELY;
+
+ memset(&overlapped, 0, sizeof(overlapped));
+ if (!LockFileEx(handle, sys_flags, 0, 0, 0, &overlapped)) {
+ if ((sys_flags & LOCKFILE_FAIL_IMMEDIATELY) &&
+ (GetLastError() == ERROR_IO_PENDING)) {
+ rte_errno = EWOULDBLOCK;
+ } else {
+ RTE_LOG_WIN32_ERR("LockFileEx()");
+ rte_errno = EINVAL;
+ }
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+unlock_file(HANDLE handle)
+{
+ if (!UnlockFileEx(handle, 0, 0, 0, NULL)) {
+ RTE_LOG_WIN32_ERR("UnlockFileEx()");
+ rte_errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+int
+eal_file_lock(int fd, enum rte_flock_op op, enum rte_flock_mode mode)
+{
+ HANDLE handle = (HANDLE)_get_osfhandle(fd);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ rte_errno = EBADF;
+ return -1;
+ }
+
+ switch (op) {
+ case RTE_FLOCK_EXCLUSIVE:
+ case RTE_FLOCK_SHARED:
+ return lock_file(handle, op, mode);
+ case RTE_FLOCK_UNLOCK:
+ return unlock_file(handle);
+ default:
+ rte_errno = EINVAL;
+ return -1;
+ }
+}
+
/* Launch threads, called at application init(). */
int
rte_eal_init(int argc, char **argv)
--
2.25.1
^ permalink raw reply related [flat|nested] 218+ messages in thread
* [dpdk-dev] [RFC PATCH 6/9] eal: introduce memory management wrappers
2020-03-30 4:10 [dpdk-dev] [RFC PATCH 0/9] Windows basic memory management Dmitry Kozlyuk
` (4 preceding siblings ...)
2020-03-30 4:10 ` [dpdk-dev] [RFC PATCH 5/9] eal: introduce internal wrappers for file operations Dmitry Kozlyuk
@ 2020-03-30 4:10 ` Dmitry Kozlyuk
2020-03-30 7:31 ` Thomas Monjalon
2020-03-30 4:10 ` [dpdk-dev] [RFC PATCH 7/9] eal/windows: fix rte_page_sizes with Clang on Windows Dmitry Kozlyuk
` (3 subsequent siblings)
9 siblings, 1 reply; 218+ messages in thread
From: Dmitry Kozlyuk @ 2020-03-30 4:10 UTC (permalink / raw)
To: dev
Cc: Dmitry Malloy (MESHCHANINOV), Dmitry Kozlyuk, Thomas Monjalon,
Anatoly Burakov, Bruce Richardson, Harini Ramakrishnan,
Omar Cardona, Pallavi Kadam, Ranjit Menon
System meory management is implemented differently for POSIX and
Windows. Introduce wrapper functions for operations used across DPDK:
* rte_mem_map()
Create memory mapping for a regular file or a page file (swap).
This supports mapping to a reserved memory region even on Windows.
* rte_mem_unmap()
Remove mapping created with rte_mem_map().
* rte_get_page_size()
Obtain default system page size.
* rte_mem_lock()
Make arbitrary-sized memory region non-swappable.
Wrappers follow POSIX semantics limited to DPDK tasks, but their
signatures deliberately differ from POSIX ones to be more safe and
expressive.
Signed-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
---
config/meson.build | 10 +-
lib/librte_eal/common/eal_private.h | 71 +++-
lib/librte_eal/common/include/rte_memory.h | 63 +++
lib/librte_eal/freebsd/eal/eal_memory.c | 117 ++++++
lib/librte_eal/linux/eal/eal_memory.c | 117 ++++++
lib/librte_eal/rte_eal_exports.def | 4 +
lib/librte_eal/rte_eal_version.map | 4 +
lib/librte_eal/windows/eal/eal.c | 6 +
lib/librte_eal/windows/eal/eal_memory.c | 433 +++++++++++++++++++++
lib/librte_eal/windows/eal/eal_windows.h | 51 +++
lib/librte_eal/windows/eal/meson.build | 1 +
11 files changed, 871 insertions(+), 6 deletions(-)
create mode 100644 lib/librte_eal/windows/eal/eal_memory.c
diff --git a/config/meson.build b/config/meson.build
index 73cf69814..295425742 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -256,14 +256,20 @@ if is_freebsd
endif
if is_windows
- # Minimum supported API is Windows 7.
- add_project_arguments('-D_WIN32_WINNT=0x0601', language: 'c')
+ # VirtualAlloc2() is available since Windows 10 / Server 2016.
+ add_project_arguments('-D_WIN32_WINNT=0x0A00', language: 'c')
# Use MinGW-w64 stdio, because DPDK assumes ANSI-compliant formatting.
if cc.get_id() == 'gcc'
add_project_arguments('-D__USE_MINGW_ANSI_STDIO', language: 'c')
endif
+ # Contrary to docs, VirtualAlloc2() is exported by mincore.lib
+ # in Windows SDK, while MinGW exports it by advapi32.a.
+ if is_ms_linker
+ add_project_link_arguments('-lmincore', language: 'c')
+ endif
+
add_project_link_arguments('-ladvapi32', language: 'c')
endif
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index 0130571e8..2e5e4312a 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -11,6 +11,7 @@
#include <rte_dev.h>
#include <rte_lcore.h>
+#include <rte_memory.h>
/**
* Structure storing internal configuration (per-lcore)
@@ -202,6 +203,16 @@ int rte_eal_alarm_init(void);
*/
int rte_eal_check_module(const char *module_name);
+/**
+ * Memory reservation flags.
+ */
+enum rte_mem_reserve_flags {
+ /**< Reserve hugepages. */
+ RTE_RESERVE_HUGEPAGES = 1 << 0,
+ /**< Fail if requested address is not available. */
+ RTE_RESERVE_EXACT_ADDRESS = 1 << 1
+};
+
/**
* Get virtual area of specified size from the OS.
*
@@ -215,8 +226,8 @@ int rte_eal_check_module(const char *module_name);
* Page size on which to align requested virtual area.
* @param flags
* EAL_VIRTUAL_AREA_* flags.
- * @param mmap_flags
- * Extra flags passed directly to mmap().
+ * @param reserve_flags
+ * Extra flags passed directly to eal_mem_reserve().
*
* @return
* Virtual area address if successful.
@@ -232,8 +243,8 @@ int rte_eal_check_module(const char *module_name);
#define EAL_VIRTUAL_AREA_UNMAP (1 << 2)
/**< immediately unmap reserved virtual area. */
void *
-eal_get_virtual_area(void *requested_addr, size_t *size,
- size_t page_sz, int flags, int mmap_flags);
+eal_get_virtual_area(void *requested_addr, size_t *size, size_t page_sz,
+ int flags, enum rte_mem_reserve_flags reserve_flags);
/**
* Get cpu core_id.
@@ -488,4 +499,56 @@ int eal_file_lock(int fd, enum rte_flock_op op, enum rte_flock_mode mode);
*/
int eal_file_truncate(int fd, ssize_t size);
+/**
+ * Reserve a region of virtual memory.
+ *
+ * Use eal_mem_free() to free reserved memory.
+ *
+ * @param requested_addr
+ * A desired reservation address. The system may not respect it.
+ * NULL means the address will be chosen by the system.
+ * @param size
+ * Reservation size. Must be a multiple of system page size.
+ * @param flags
+ * Reservation options.
+ * @returns
+ * Starting address of the reserved area on success, NULL on failure.
+ * Callers must not access this memory until remapping it.
+ */
+void *eal_mem_reserve(void *requested_addr, size_t size,
+ enum rte_mem_reserve_flags flags);
+
+/**
+ * Allocate a contiguous chunk of virtual memory.
+ *
+ * Use eal_mem_free() to free allocated memory.
+ *
+ * @param size
+ * Number of bytes to allocate.
+ * @param page_size
+ * If non-zero, means memory must be allocated in hugepages
+ * of the specified size. The @code size @endcode parameter
+ * must then be a multiple of the largest hugepage size requested.
+ * @return
+ * Address of allocated memory or NULL on failure (rte_errno is set).
+ */
+void *eal_mem_alloc(size_t size, enum rte_page_sizes page_size);
+
+/**
+ * Free memory obtained by eal_mem_reserve() or eal_mem_alloc().
+ *
+ * If @code virt @endcode and @code size @endcode describe a part of the
+ * reserved region, only this part of the region is freed (accurately
+ * up to the system page size). If @code virt @endcode points to allocated
+ * memory, @code size @endcode must match the one specified on allocation.
+ * The behavior is undefined if the memory pointed by @code virt @endcode
+ * is obtained from another source than listed above.
+ *
+ * @param virt
+ * A virtual address in a region previously reserved.
+ * @param size
+ * Number of bytes to unreserve.
+ */
+void eal_mem_free(void *virt, size_t size);
+
#endif /* _EAL_PRIVATE_H_ */
diff --git a/lib/librte_eal/common/include/rte_memory.h b/lib/librte_eal/common/include/rte_memory.h
index 3d8d0bd69..1742fde9a 100644
--- a/lib/librte_eal/common/include/rte_memory.h
+++ b/lib/librte_eal/common/include/rte_memory.h
@@ -85,6 +85,69 @@ struct rte_memseg_list {
struct rte_fbarray memseg_arr;
};
+/**
+ * Memory protection flags.
+ */
+enum rte_mem_prot {
+ RTE_PROT_READ = 1 << 0, /**< Read access. */
+ RTE_PROT_WRITE = 1 << 1, /**< Write access. */
+ RTE_PROT_EXECUTE = 1 << 2 /**< Code execution. */
+};
+
+/**
+ * Memory mapping additional flags.
+ *
+ * In Linux and FreeBSD, each flag is semantically equivalent
+ * to OS-specific mmap(3) flag with the same or similar name.
+ * In Windows, POSIX and MAP_ANONYMOUS semantics are followed.
+ */
+enum rte_map_flags {
+ /** Changes of mapped memory are visible to other processes. */
+ RTE_MAP_SHARED = 1 << 0,
+ /** Mapping is not backed by a regular file. */
+ RTE_MAP_ANONYMOUS = 1 << 1,
+ /** Copy-on-write mapping, changes are invisible to other processes. */
+ RTE_MAP_PRIVATE = 1 << 2,
+ /** Fail if requested address cannot be taken. */
+ RTE_MAP_FIXED = 1 << 3
+};
+
+/**
+ * OS-independent implementation of POSIX mmap(3)
+ * with MAP_ANONYMOUS Linux/FreeBSD extension.
+ */
+__rte_experimental
+void *rte_mem_map(void *requested_addr, size_t size, enum rte_mem_prot prot,
+ enum rte_map_flags flags, int fd, size_t offset);
+
+/**
+ * OS-independent implementation of POSIX munmap(3).
+ */
+__rte_experimental
+int rte_mem_unmap(void *virt, size_t size);
+
+/**
+ * Get system page size. This function never failes.
+ *
+ * @return
+ * Positive page size in bytes.
+ */
+__rte_experimental
+int rte_get_page_size(void);
+
+/**
+ * Lock region in physical memory and prevent it from swapping.
+ *
+ * @param virt
+ * The virtual address.
+ * @param size
+ * Size of the region.
+ * @return
+ * 0 on success, negative on error.
+ */
+__rte_experimental
+int rte_mem_lock(const void *virt, size_t size);
+
/**
* Lock page in physical memory and prevent from swapping.
*
diff --git a/lib/librte_eal/freebsd/eal/eal_memory.c b/lib/librte_eal/freebsd/eal/eal_memory.c
index a97d8f0f0..bcceba636 100644
--- a/lib/librte_eal/freebsd/eal/eal_memory.c
+++ b/lib/librte_eal/freebsd/eal/eal_memory.c
@@ -534,3 +534,120 @@ rte_eal_memseg_init(void)
memseg_primary_init() :
memseg_secondary_init();
}
+
+void *
+eal_mem_reserve(void *requested_addr, size_t size,
+ enum rte_mem_reserve_flags flags)
+{
+ int sys_flags = MAP_PRIVATE | MAP_ANONYMOUS;
+
+ if (flags & RTE_RESERVE_HUGEPAGES)
+ sys_flags |= MAP_HUGETLB;
+ if (flags & RTE_RESERVE_EXACT_ADDRESS)
+ sys_flags |= MAP_FIXED;
+
+ return mem_map(requested_addr, size, PROT_READ, sys_flags, -1, 0);
+}
+
+void *
+eal_mem_alloc(size_t size, enum rte_page_sizes page_size)
+{
+ int flags = MAP_ANONYMOUS | MAP_PRIVATE;
+
+ if (page_size != 0) {
+ /* as per mmap() manpage, all page sizes are log2 of page size
+ * shifted by MAP_HUGE_SHIFT
+ */
+ int page_flag = rte_log2_u64(page_size) << MAP_HUGE_SHIFT;
+ flags |= MAP_HUGETLB | page_flag;
+ }
+
+ return mem_map(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0);
+}
+
+void
+eal_mem_free(void *virt, size_t size)
+{
+ mem_unmap(virt, size);
+}
+
+static int
+mem_rte_to_sys_prot(enum rte_mem_prot prot)
+{
+ int sys_prot = 0;
+
+ if (prot & RTE_PROT_READ)
+ sys_prot |= PROT_READ;
+ if (prot & RTE_PROT_WRITE)
+ sys_prot |= PROT_WRITE;
+ if (prot & RTE_PROT_EXECUTE)
+ sys_prot |= PROT_EXEC;
+
+ return sys_prot;
+}
+
+static void *
+mem_map(void *requested_addr, size_t size, int prot, int flags,
+ int fd, size_t offset)
+{
+ void *virt = mmap(requested_addr, size, prot, flags, fd, offset);
+ if (virt == MAP_FAILED) {
+ RTE_LOG(ERR, EAL,
+ "Cannot mmap(%p, 0x%zx, 0x%x, 0x%x, %d, 0x%zx): %s\n",
+ requested_addr, size, prot, flags, fd, offset,
+ strerror(errno));
+ rte_errno = errno;
+ }
+ return virt;
+}
+
+static int
+mem_unmap(void *virt, size_t size)
+{
+ int ret = munmap(virt, size);
+ if (ret < 0) {
+ RTE_LOG(ERR, EAL, "Cannot munmap(%p, 0x%zx): %s\n",
+ virt, size, strerror(errno));
+ rte_errno = errno;
+ }
+ return ret;
+}
+
+void *
+rte_mem_map(void *requested_addr, size_t size, enum rte_mem_prot prot,
+ enum rte_map_flags flags, int fd, size_t offset)
+{
+ int sys_prot = 0;
+ int sys_flags = 0;
+
+ sys_prot = mem_rte_to_sys_prot(prot);
+
+ if (flags & RTE_MAP_SHARED)
+ sys_flags |= MAP_SHARED;
+ if (flags & RTE_MAP_ANONYMOUS)
+ sys_flags |= MAP_ANONYMOUS;
+ if (flags & RTE_MAP_PRIVATE)
+ sys_flags |= MAP_PRIVATE;
+ if (flags & RTE_MAP_FIXED)
+ sys_flags |= MAP_FIXED;
+
+ return mem_map(requested_addr, size, sys_prot, sys_flags, fd, offset);
+}
+
+int
+rte_mem_unmap(void *virt, size_t size)
+{
+ return mem_unmap(virt, size);
+}
+
+int
+rte_get_page_size(void)
+{
+ return getpagesize();
+}
+
+int
+rte_mem_lock(const void *virt, size_t size)
+{
+ return mlock(virt, size);
+}
diff --git a/lib/librte_eal/linux/eal/eal_memory.c b/lib/librte_eal/linux/eal/eal_memory.c
index 7a9c97ff8..72205580a 100644
--- a/lib/librte_eal/linux/eal/eal_memory.c
+++ b/lib/librte_eal/linux/eal/eal_memory.c
@@ -2479,3 +2479,120 @@ rte_eal_memseg_init(void)
#endif
memseg_secondary_init();
}
+
+static void *
+mem_map(void *requested_addr, size_t size, int prot, int flags,
+ int fd, size_t offset)
+{
+ void *virt = mmap(requested_addr, size, prot, flags, fd, offset);
+ if (virt == MAP_FAILED) {
+ RTE_LOG(ERR, EAL,
+ "Cannot mmap(%p, 0x%zx, 0x%x, 0x%x, %d, 0x%zx): %s\n",
+ requested_addr, size, prot, flags, fd, offset,
+ strerror(errno));
+ rte_errno = errno;
+ }
+ return virt;
+}
+
+static int
+mem_unmap(void *virt, size_t size)
+{
+ int ret = munmap(virt, size);
+ if (ret < 0) {
+ RTE_LOG(ERR, EAL, "Cannot munmap(%p, 0x%zx): %s\n",
+ virt, size, strerror(errno));
+ rte_errno = errno;
+ }
+ return ret;
+}
+
+void *
+eal_mem_reserve(void *requested_addr, size_t size,
+ enum rte_mem_reserve_flags flags)
+{
+ int sys_flags = MAP_PRIVATE | MAP_ANONYMOUS;
+
+ if (flags & RTE_RESERVE_HUGEPAGES)
+ sys_flags |= MAP_HUGETLB;
+ if (flags & RTE_RESERVE_EXACT_ADDRESS)
+ sys_flags |= MAP_FIXED;
+
+ return mem_map(requested_addr, size, PROT_READ, sys_flags, -1, 0);
+}
+
+void *
+eal_mem_alloc(size_t size, enum rte_page_sizes page_size)
+{
+ int flags = MAP_ANONYMOUS | MAP_PRIVATE;
+
+ if (page_size != 0) {
+ /* as per mmap() manpage, all page sizes are log2 of page size
+ * shifted by MAP_HUGE_SHIFT
+ */
+ int page_flag = rte_log2_u64(page_size) << MAP_HUGE_SHIFT;
+ flags |= MAP_HUGETLB | page_flag;
+ }
+
+ return mem_map(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0);
+}
+
+void
+eal_mem_free(void *virt, size_t size)
+{
+ mem_unmap(virt, size);
+}
+
+static int
+mem_rte_to_sys_prot(enum rte_mem_prot prot)
+{
+ int sys_prot = 0;
+
+ if (prot & RTE_PROT_READ)
+ sys_prot |= PROT_READ;
+ if (prot & RTE_PROT_WRITE)
+ sys_prot |= PROT_WRITE;
+ if (prot & RTE_PROT_EXECUTE)
+ sys_prot |= PROT_EXEC;
+
+ return sys_prot;
+}
+
+void *
+rte_mem_map(void *requested_addr, size_t size, enum rte_mem_prot prot,
+ enum rte_map_flags flags, int fd, size_t offset)
+{
+ int sys_prot = 0;
+ int sys_flags = 0;
+
+ sys_prot = mem_rte_to_sys_prot(prot);
+
+ if (flags & RTE_MAP_SHARED)
+ sys_flags |= MAP_SHARED;
+ if (flags & RTE_MAP_ANONYMOUS)
+ sys_flags |= MAP_ANONYMOUS;
+ if (flags & RTE_MAP_PRIVATE)
+ sys_flags |= MAP_PRIVATE;
+ if (flags & RTE_MAP_FIXED)
+ sys_flags |= MAP_FIXED;
+
+ return mem_map(requested_addr, size, sys_prot, sys_flags, fd, offset);
+}
+
+int
+rte_mem_unmap(void *virt, size_t size)
+{
+ return mem_unmap(virt, size);
+}
+
+int
+rte_get_page_size(void)
+{
+ return getpagesize();
+}
+
+int
+rte_mem_lock(const void *virt, size_t size)
+{
+ return mlock(virt, size);
+}
diff --git a/lib/librte_eal/rte_eal_exports.def b/lib/librte_eal/rte_eal_exports.def
index 12a6c79d6..bacf9a107 100644
--- a/lib/librte_eal/rte_eal_exports.def
+++ b/lib/librte_eal/rte_eal_exports.def
@@ -5,5 +5,9 @@ EXPORTS
rte_eal_mp_remote_launch
rte_eal_mp_wait_lcore
rte_eal_remote_launch
+ rte_get_page_size
rte_log
+ rte_mem_lock
+ rte_mem_map
+ rte_mem_unmap
rte_vlog
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index f9ede5b41..07128898f 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -337,5 +337,9 @@ EXPERIMENTAL {
rte_thread_is_intr;
# added in 20.05
+ rte_get_page_size;
rte_log_can_log;
+ rte_mem_lock;
+ rte_mem_map;
+ rte_mem_unmap;
};
diff --git a/lib/librte_eal/windows/eal/eal.c b/lib/librte_eal/windows/eal/eal.c
index 4932185ec..98afd8a68 100644
--- a/lib/librte_eal/windows/eal/eal.c
+++ b/lib/librte_eal/windows/eal/eal.c
@@ -339,6 +339,12 @@ rte_eal_init(int argc, char **argv)
internal_config.memory = MEMSIZE_IF_NO_HUGE_PAGE;
}
+ if (eal_mem_win32api_init() < 0) {
+ rte_eal_init_alert("Cannot access Win32 memory management");
+ rte_errno = ENOTSUP;
+ return -1;
+ }
+
eal_thread_init_master(rte_config.master_lcore);
RTE_LCORE_FOREACH_SLAVE(i) {
diff --git a/lib/librte_eal/windows/eal/eal_memory.c b/lib/librte_eal/windows/eal/eal_memory.c
new file mode 100644
index 000000000..f8b312d7c
--- /dev/null
+++ b/lib/librte_eal/windows/eal/eal_memory.c
@@ -0,0 +1,433 @@
+#include <io.h>
+
+#include <rte_errno.h>
+#include <rte_memory.h>
+
+#include "eal_private.h"
+#include "eal_windows.h"
+
+/* MinGW-w64 headers lack VirtualAlloc2() in some distributions.
+ * Provide a copy of definitions and code to load it dynamically.
+ * Note: definitions are copied verbatim from Microsoft documentation
+ * and don't follow DPDK code style.
+ */
+#ifndef MEM_PRESERVE_PLACEHOLDER
+
+/* https://docs.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-mem_extended_parameter_type */
+typedef enum MEM_EXTENDED_PARAMETER_TYPE {
+ MemExtendedParameterInvalidType,
+ MemExtendedParameterAddressRequirements,
+ MemExtendedParameterNumaNode,
+ MemExtendedParameterPartitionHandle,
+ MemExtendedParameterMax,
+ MemExtendedParameterUserPhysicalHandle,
+ MemExtendedParameterAttributeFlags
+} *PMEM_EXTENDED_PARAMETER_TYPE;
+
+#define MEM_EXTENDED_PARAMETER_TYPE_BITS 4
+
+/* https://docs.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-mem_extended_parameter */
+typedef struct MEM_EXTENDED_PARAMETER {
+ struct {
+ DWORD64 Type : MEM_EXTENDED_PARAMETER_TYPE_BITS;
+ DWORD64 Reserved : 64 - MEM_EXTENDED_PARAMETER_TYPE_BITS;
+ } DUMMYSTRUCTNAME;
+ union {
+ DWORD64 ULong64;
+ PVOID Pointer;
+ SIZE_T Size;
+ HANDLE Handle;
+ DWORD ULong;
+ } DUMMYUNIONNAME;
+} MEM_EXTENDED_PARAMETER, *PMEM_EXTENDED_PARAMETER;
+
+/* https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc2 */
+typedef PVOID (*VirtualAlloc2_type)(
+ HANDLE Process,
+ PVOID BaseAddress,
+ SIZE_T Size,
+ ULONG AllocationType,
+ ULONG PageProtection,
+ MEM_EXTENDED_PARAMETER *ExtendedParameters,
+ ULONG ParameterCount
+);
+
+/* VirtualAlloc2() flags. */
+#define MEM_COALESCE_PLACEHOLDERS 0x00000001
+#define MEM_PRESERVE_PLACEHOLDER 0x00000002
+#define MEM_REPLACE_PLACEHOLDER 0x00004000
+#define MEM_RESERVE_PLACEHOLDER 0x00040000
+
+/* Named exactly as the function, so that user code does not depend
+ * on it being found at compile time or dynamically.
+ */
+static VirtualAlloc2_type VirtualAlloc2;
+
+int
+eal_mem_win32api_init(void)
+{
+ static const char library_name[] = "kernelbase.dll";
+ static const char function[] = "VirtualAlloc2";
+
+ OSVERSIONINFO info;
+ HMODULE library = NULL;
+ int ret = 0;
+
+ /* Already done. */
+ if (VirtualAlloc2 != NULL)
+ return 0;
+
+ /* IsWindows10OrGreater() may also be unavailable. */
+ memset(&info, 0, sizeof(info));
+ info.dwOSVersionInfoSize = sizeof(info);
+ GetVersionEx(&info);
+
+ /* Checking for Windows 10+ will also detect Windows Server 2016+.
+ * Do not abort, because Windows may report false version depending
+ * on executable manifest, compatibility mode, etc.
+ */
+ if (info.dwMajorVersion < 10)
+ RTE_LOG(DEBUG, EAL, "Windows 10+ or Windows Server 2016+ "
+ "is required for advanced memory features\n");
+
+ library = LoadLibraryA(library_name);
+ if (library == NULL) {
+ RTE_LOG_WIN32_ERR("LoadLibraryA(\"%s\")", library_name);
+ return -1;
+ }
+
+ VirtualAlloc2 = (VirtualAlloc2_type)(
+ (void *)GetProcAddress(library, function));
+ if (VirtualAlloc2 == NULL) {
+ RTE_LOG_WIN32_ERR("GetProcAddress(\"%s\", \"%s\")\n",
+ library_name, function);
+ ret = -1;
+ }
+
+ FreeLibrary(library);
+
+ return ret;
+}
+
+#else
+
+/* Stub in case VirtualAlloc2() is provided by the compiler. */
+int
+eal_mem_win32api_init(void)
+{
+ return 0;
+}
+
+#endif /* no VirtualAlloc2() */
+
+/* Approximate error mapping from VirtualAlloc2() to POSIX mmap(3). */
+static int
+win32_alloc_error_to_errno(DWORD code)
+{
+ switch (code) {
+ case ERROR_SUCCESS:
+ return 0;
+
+ case ERROR_INVALID_ADDRESS:
+ /* A valid requested address is not available. */
+ case ERROR_COMMITMENT_LIMIT:
+ /* May occcur when committing regular memory.