From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 9D3CAA0598; Fri, 10 Apr 2020 18:44:00 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 5A4611D5EA; Fri, 10 Apr 2020 18:43:55 +0200 (CEST) Received: from mail-lj1-f169.google.com (mail-lj1-f169.google.com [209.85.208.169]) by dpdk.org (Postfix) with ESMTP id A57A31D5D1 for ; Fri, 10 Apr 2020 18:43:53 +0200 (CEST) Received: by mail-lj1-f169.google.com with SMTP id m8so2536171lji.1 for ; Fri, 10 Apr 2020 09:43:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=gfW3y/5LQggQ0PcxTgCG1BekomfCj+6oX7F0uzrixTk=; b=eJ4gBydpCCrR61Ph5Onhd5y+N0zfKyiloD0mbZkeGE29ogHCw2mbASIGJ5neixdNWV MIAkQhcsXb5mchAhDdHJ1VERp9BWBrKa0d/9GZSBR/zRHjFA+F39E62UPwJ1o0IXcBUz msFqso4OEGptjZOnlCzrAwEnIuwD6bTYmveqsY+MC845Tjfb2ZnW5sjygzrln/6yyTSr 4LPUvuM4RhNX1jN2mBqUIxO9Jy/zz9OibMDcSKRNToMe8xuMfDSyUuaY7JMFkQvArtp3 Hzamq7MEauOUIiD6BxaS3B54FOmhBe/rOUTeU5Sh8mUEz9WjUvUcj3dpQ5jchr4i/fRJ IvFQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=gfW3y/5LQggQ0PcxTgCG1BekomfCj+6oX7F0uzrixTk=; b=ILdGyyuhYmQdNTVnty7C6x2Q83uO8WVg/sFYfcapgTVBk1bmKSaGQOl9rspJl/hfEF b+HkvxohknLSMRUBmClwtY+60hBCC1N2HRF+DouAAfyvOQ1sCbEAzWB5YA3YLshBVNU4 do73jQ5fha5EYosQ9Zz0NjfvCG3Kd3kWtwSLboILaQ14jw2uA/0olU1QgCdzNQ3wuvre F9vzYSpWlOeJ9EriC8GhWTd1xDgsy/YgG4xgGELyy0nOb5J8QXmgs8+uQs+1f0u115KB ZF+MRh+Ejd2AeVZk0YWK7q5DUUl4eb8iMQK1cD7jrh141zrglPU8TU+MAPGhO+D6T/p3 a3pQ== X-Gm-Message-State: AGi0PuYBUNJh5calIslfhONj6p559XppC9/qoe+eEuY/9npuo9uFdBfL gorfhQS9kV/hfgDxGx5p3zk265YmCEfL3Q== X-Google-Smtp-Source: APiQypJNEFPRFIPAmLEMFNVdjoOtlfZnA0KRruyKMWVOuflOAizZCy01iP8VqFIouyAo0yT9M6Bl0w== X-Received: by 2002:a2e:994d:: with SMTP id r13mr1306212ljj.15.1586537032472; Fri, 10 Apr 2020 09:43:52 -0700 (PDT) Received: from localhost.localdomain (broadband-37-110-65-23.ip.moscow.rt.ru. [37.110.65.23]) by smtp.googlemail.com with ESMTPSA id d21sm1343075ljc.49.2020.04.10.09.43.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 10 Apr 2020 09:43:51 -0700 (PDT) From: Dmitry Kozlyuk To: dev@dpdk.org Cc: "Dmitry Malloy (MESHCHANINOV)" , Narcisa Ana Maria Vasile , Fady Bader , Tal Shnaiderman , Dmitry Kozlyuk Date: Fri, 10 Apr 2020 19:43:33 +0300 Message-Id: <20200410164342.1194634-2-dmitry.kozliuk@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200410164342.1194634-1-dmitry.kozliuk@gmail.com> References: <20200330041026.784624-1-dmitry.kozliuk@gmail.com> <20200410164342.1194634-1-dmitry.kozliuk@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Subject: [dpdk-dev] [PATCH v2 1/1] virt2phys: virtual to physical address translator for Windows X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" 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. Signed-off-by: Dmitry Kozlyuk --- Note: this patch is for dpdk-kmods tree. windows/README.rst | 92 ++++++++ windows/virt2phys/virt2phys.c | 129 +++++++++++ windows/virt2phys/virt2phys.h | 34 +++ windows/virt2phys/virt2phys.inf | 64 ++++++ windows/virt2phys/virt2phys.sln | 27 +++ windows/virt2phys/virt2phys.vcxproj | 228 ++++++++++++++++++++ windows/virt2phys/virt2phys.vcxproj.filters | 36 ++++ 7 files changed, 610 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..e30d4dc --- /dev/null +++ b/windows/README.rst @@ -0,0 +1,92 @@ +Developing Windows Drivers +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D + +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: + +.. code-block:: console + + msbuild + +To build a particular combination of configuration and platform: + +.. code-block:: console + + msbuild -p:Configuration=3DDebug;Platform=3Dx64 + + +Install the Drivers +------------------- + +Disable Driver Signature Enforcement +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By default Windows prohibits installing and loading drivers without `digit= al +signature`_ obtained from Microsoft. For development signature enforcement= may +be disabled as follows. + +In Elevated Command Prompt (from this point, sufficient privileges are +assumed): + +.. code-block:: console + + 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 drive= rs. + +.. _digital signature: https://docs.microsoft.com/en-us/windows-hardware/d= rivers/install/driver-signing + + +Install, List, and Remove 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: + +.. code-block:: console + + pnputil /add-driver x64\Debug\virt2phys\virt2phys\virt2phys.inf /insta= ll + +A graphical confirmation to load an unsigned driver will still appear. + +To list installed drivers: + +.. code-block:: console + + pnputil /enum-drivers + +To remove the driver package and to uninstall its devices: + +.. code-block:: console + + pnputil /delete-driver oem2.inf /uninstall diff --git a/windows/virt2phys/virt2phys.c b/windows/virt2phys/virt2phys.c new file mode 100755 index 0000000..e157e9c --- /dev/null +++ b/windows/virt2phys/virt2phys.c @@ -0,0 +1,129 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2020 Dmitry Kozlyuk + */ + +#include +#include +#include +#include + +#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 =3D WdfDriverCreate( + driver_object, registry_path, + &attributes, &config, WDF_NO_HANDLE); + if (!NT_SUCCESS(status)) { + KdPrint(("WdfDriverCreate() failed, status=3D%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 =3D WdfDeviceCreate(&init, &attributes, &device); + if (!NT_SUCCESS(status)) { + KdPrint(("WdfDeviceCreate() failed, status=3D%08x\n", status)); + return status; + } + + status =3D WdfDeviceCreateDeviceInterface( + device, &GUID_DEVINTERFACE_VIRT2PHYS, NULL); + if (!NT_SUCCESS(status)) { + KdPrint(("WdfDeviceCreateDeviceInterface() failed, " + "status=3D%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 !=3D WdfRequestTypeDeviceControl) { + KdPrint(("bogus request type=3D%u\n", params.Type)); + WdfRequestComplete(request, STATUS_NOT_SUPPORTED); + return; + } + + code =3D params.Parameters.DeviceIoControl.IoControlCode; + if (code !=3D IOCTL_VIRT2PHYS_TRANSLATE) { + KdPrint(("bogus IO control code=3D%lu\n", code)); + WdfRequestComplete(request, STATUS_NOT_SUPPORTED); + return; + } + + status =3D WdfRequestRetrieveInputBuffer( + request, sizeof(*virt), (PVOID *)&virt, &size); + if (!NT_SUCCESS(status)) { + KdPrint(("WdfRequestRetrieveInputBuffer() failed, " + "status=3D%08x\n", status)); + WdfRequestComplete(request, status); + return; + } + + status =3D WdfRequestRetrieveOutputBuffer( + request, sizeof(*phys), (PVOID *)&phys, &size); + if (!NT_SUCCESS(status)) { + KdPrint(("WdfRequestRetrieveOutputBuffer() failed, " + "status=3D%08x\n", status)); + WdfRequestComplete(request, status); + return; + } + + *phys =3D 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..e35765e --- /dev/null +++ b/windows/virt2phys/virt2phys.inf @@ -0,0 +1,64 @@ +; SPDX-License-Identifier: BSD-3-Clause +; Copyright (c) 2020 Dmitry Kozlyuk + +[Version] +Signature =3D "$WINDOWS NT$" +Class =3D %ClassName% +ClassGuid =3D {78A1C341-4539-11d3-B88D-00C04FAD5171} +Provider =3D %ManufacturerName% +CatalogFile =3D virt2phys.cat +DriverVer =3D + +[DestinationDirs] +DefaultDestDir =3D 12 + +; =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Class section =3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +[ClassInstall32] +Addreg =3D virt2phys_ClassReg + +[virt2phys_ClassReg] +HKR,,,0,%ClassName% +HKR,,Icon,,-5 + +[SourceDisksNames] +1 =3D %DiskName%,,,"" + +[SourceDisksFiles] +virt2phys.sys =3D 1,, + +;***************************************** +; Install Section +;***************************************** + +[Manufacturer] +%ManufacturerName%=3DStandard,NT$ARCH$ + +[Standard.NT$ARCH$] +%virt2phys.DeviceDesc%=3Dvirt2phys_Device, Root\virt2phys + +[virt2phys_Device.NT] +CopyFiles =3D Drivers_Dir + +[Drivers_Dir] +virt2phys.sys + +;-------------- Service installation +[virt2phys_Device.NT.Services] +AddService =3D virt2phys,%SPSVCINST_ASSOCSERVICE%, virt2phys_Service_Inst + +; -------------- virt2phys driver install sections +[virt2phys_Service_Inst] +DisplayName =3D %virt2phys.SVCDESC% +ServiceType =3D 1 ; SERVICE_KERNEL_DRIVER +StartType =3D 3 ; SERVICE_DEMAND_START +ErrorControl =3D 1 ; SERVICE_ERROR_NORMAL +ServiceBinary =3D %12%\virt2phys.sys + +[Strings] +SPSVCINST_ASSOCSERVICE =3D 0x00000002 +ManufacturerName =3D "Dmitry Kozlyuk" +ClassName =3D "Kernel bypass" +DiskName =3D "virt2phys Installation Disk" +virt2phys.DeviceDesc =3D "Virtual to physical address translator" +virt2phys.SVCDESC =3D "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 @@ +=EF=BB=BF=0D +Microsoft Visual Studio Solution File, Format Version 12.00=0D +# Visual Studio Version 16=0D +VisualStudioVersion =3D 16.0.29613.14=0D +MinimumVisualStudioVersion =3D 10.0.40219.1=0D +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") =3D "virt2phys", "virt2p= hys.vcxproj", "{0EEF826B-9391-43A8-A722-BDD6F6115137}"=0D +EndProject=0D +Global=0D + GlobalSection(SolutionConfigurationPlatforms) =3D preSolution=0D + Debug|x64 =3D Debug|x64=0D + Release|x64 =3D Release|x64=0D + EndGlobalSection=0D + GlobalSection(ProjectConfigurationPlatforms) =3D postSolution=0D + {0EEF826B-9391-43A8-A722-BDD6F6115137}.Debug|x64.ActiveCfg =3D Debug|x64= =0D + {0EEF826B-9391-43A8-A722-BDD6F6115137}.Debug|x64.Build.0 =3D Debug|x64=0D + {0EEF826B-9391-43A8-A722-BDD6F6115137}.Debug|x64.Deploy.0 =3D Debug|x64= =0D + {0EEF826B-9391-43A8-A722-BDD6F6115137}.Release|x64.ActiveCfg =3D Release= |x64=0D + {0EEF826B-9391-43A8-A722-BDD6F6115137}.Release|x64.Build.0 =3D Release|x= 64=0D + {0EEF826B-9391-43A8-A722-BDD6F6115137}.Release|x64.Deploy.0 =3D Release|= x64=0D + EndGlobalSection=0D + GlobalSection(SolutionProperties) =3D preSolution=0D + HideSolutionNode =3D FALSE=0D + EndGlobalSection=0D + GlobalSection(ExtensibilityGlobals) =3D postSolution=0D + SolutionGuid =3D {845012FB-4471-4A12-A1C4-FF7E05C40E8E}=0D + EndGlobalSection=0D +EndGlobal=0D diff --git a/windows/virt2phys/virt2phys.vcxproj b/windows/virt2phys/virt2p= hys.vcxproj new file mode 100755 index 0000000..fa51916 --- /dev/null +++ b/windows/virt2phys/virt2phys.vcxproj @@ -0,0 +1,228 @@ +=EF=BB=BF=0D +=0D + =0D + =0D + Debug=0D + Win32=0D + =0D + =0D + Release=0D + Win32=0D + =0D + =0D + Debug=0D + x64=0D + =0D + =0D + Release=0D + x64=0D + =0D + =0D + Debug=0D + ARM=0D + =0D + =0D + Release=0D + ARM=0D + =0D + =0D + Debug=0D + ARM64=0D + =0D + =0D + Release=0D + ARM64=0D + =0D + =0D + =0D + =0D + =0D + =0D + =0D + =0D + =0D + =0D + =0D + =0D + {0EEF826B-9391-43A8-A722-BDD6F6115137}=0D + {497e31cb-056b-4f31-abb8-447fd55ee5a5}=0D + v4.5=0D + 12.0=0D + Debug=0D + Win32=0D + virt2phys=0D + =0D + =0D + =0D + Windows10=0D + true=0D + WindowsKernelModeDriver10.0=0D + Driver=0D + KMDF=0D + Universal=0D + =0D + =0D + Windows10=0D + false=0D + WindowsKernelModeDriver10.0=0D + Driver=0D + KMDF=0D + Universal=0D + =0D + =0D + Windows10=0D + true=0D + WindowsKernelModeDriver10.0=0D + Driver=0D + KMDF=0D + Universal=0D + =0D + =0D + Windows10=0D + false=0D + WindowsKernelModeDriver10.0=0D + Driver=0D + KMDF=0D + Universal=0D + =0D + =0D + Windows10=0D + true=0D + WindowsKernelModeDriver10.0=0D + Driver=0D + KMDF=0D + Universal=0D + =0D + =0D + Windows10=0D + false=0D + WindowsKernelModeDriver10.0=0D + Driver=0D + KMDF=0D + Universal=0D + =0D + =0D + Windows10=0D + true=0D + WindowsKernelModeDriver10.0=0D + Driver=0D + KMDF=0D + Universal=0D + =0D + =0D + Windows10=0D + false=0D + WindowsKernelModeDriver10.0=0D + Driver=0D + KMDF=0D + Universal=0D + =0D + =0D + =0D + =0D + =0D + =0D + =0D + =0D + =0D + =0D + DbgengKernelDebugger=0D + =0D + =0D + DbgengKernelDebugger=0D + =0D + =0D + DbgengKernelDebugger=0D + =0D + =0D + DbgengKernelDebugger=0D + =0D + =0D + DbgengKernelDebugger=0D + =0D + =0D + DbgengKernelDebugger=0D + =0D + =0D + DbgengKernelDebugger=0D + =0D + =0D + DbgengKernelDebugger=0D + =0D + =0D + =0D + true=0D + true=0D + trace.h=0D + true=0D + =0D + =0D + =0D + =0D + true=0D + true=0D + trace.h=0D + true=0D + =0D + =0D + =0D + =0D + false=0D + true=0D + trace.h=0D + true=0D + =0D + =0D + $(DDK_LIB_PATH)wdmsec.lib;%(AdditionalDepend= encies)=0D + =0D + =0D + 0.1=0D + =0D + =0D + =0D + =0D + true=0D + true=0D + trace.h=0D + true=0D + =0D + =0D + =0D + =0D + true=0D + true=0D + trace.h=0D + true=0D + =0D + =0D + =0D + =0D + true=0D + true=0D + trace.h=0D + true=0D + =0D + =0D + =0D + =0D + true=0D + true=0D + trace.h=0D + true=0D + =0D + =0D + =0D + =0D + true=0D + true=0D + trace.h=0D + true=0D + =0D + =0D + =0D + =0D + =0D + =0D + =0D + =0D + \ No newline at end of file diff --git a/windows/virt2phys/virt2phys.vcxproj.filters b/windows/virt2phy= s/virt2phys.vcxproj.filters new file mode 100755 index 0000000..0fe65fc --- /dev/null +++ b/windows/virt2phys/virt2phys.vcxproj.filters @@ -0,0 +1,36 @@ +=EF=BB=BF=0D +=0D + =0D + =0D + {4FC737F1-C7A5-4376-A066-2A32D752A2FF}=0D + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx=0D + =0D + =0D + {93995380-89BD-4b04-88EB-625FBE52EBFB}=0D + h;hpp;hxx;hm;inl;inc;xsd=0D + =0D + =0D + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}=0D + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx= ;tiff;tif;png;wav;mfcribbon-ms=0D + =0D + =0D + {8E41214B-6785-4CFE-B992-037D68949A14}=0D + inf;inv;inx;mof;mc;=0D + =0D + =0D + =0D + =0D + Driver Files=0D + =0D + =0D + =0D + =0D + Header Files=0D + =0D + =0D + =0D + =0D + Source Files=0D + =0D + =0D +=0D --=20 2.25.1