From patchwork Thu Aug 13 23:21:35 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Narcisa Ana Maria Vasile X-Patchwork-Id: 75532 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 5EA22A04B1; Fri, 14 Aug 2020 01:24:47 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id A5DD31C1AC; Fri, 14 Aug 2020 01:23:02 +0200 (CEST) Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by dpdk.org (Postfix) with ESMTP id 14E8E1C0D6 for ; Fri, 14 Aug 2020 01:22:45 +0200 (CEST) Received: by linux.microsoft.com (Postfix, from userid 1059) id 0ADE820B4925; Thu, 13 Aug 2020 16:22:43 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 0ADE820B4925 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1597360964; bh=MAglrWKnKyTwFctSqKDCEUDbabjzxb77NgSYTuH9dBc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=HFvDpbKpjcYZr618gt0DvXyeffL5uKbTGzXAfPYa+hEHqEH5gOIysFvGfuvjptKMq E2KGb7gKTtOZkkWJ/kjEgGKzg4AQNE6lM50bFbNm4Kdwb/KqZwM/Odj4AoQScBWCGu QNnvMkHRxfOi7fGufhsgjvZpI23M3OulOSWS/9QM= From: Narcisa Ana Maria Vasile To: dev@dpdk.org, thomas@monjalon.net, haramakr@linux.microsoft.com, ocardona@microsoft.com, pallavi.kadam@intel.com, dmitry.kozliuk@gmail.com Cc: ranjit.menon@intel.com, dmitrym@microsoft.com, Harini Ramakrishnan Date: Thu, 13 Aug 2020 16:21:35 -0700 Message-Id: <1597360905-74106-13-git-send-email-navasile@linux.microsoft.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1597360905-74106-1-git-send-email-navasile@linux.microsoft.com> References: <1597360905-74106-1-git-send-email-navasile@linux.microsoft.com> Subject: [dpdk-dev] [PATCH 12/22] uio: Fix 64 bit BARs mapping 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" From: Harini Ramakrishnan --- kernel/windows/netuio/netuio.inf | 12 +- kernel/windows/netuio/netuio_dev.c | 181 +++++++++++++++++------ kernel/windows/netuio/netuio_dev.h | 15 +- kernel/windows/netuio/netuio_drv.c | 43 +++--- kernel/windows/netuio/netuio_drv.h | 1 + kernel/windows/netuio/netuio_interface.h | 10 +- kernel/windows/netuio/netuio_queue.c | 176 ++++++++++++++-------- kernel/windows/netuio/netuio_queue.h | 2 + 8 files changed, 297 insertions(+), 143 deletions(-) diff --git a/kernel/windows/netuio/netuio.inf b/kernel/windows/netuio/netuio.inf index b1696cc50..4c4d5e047 100644 --- a/kernel/windows/netuio/netuio.inf +++ b/kernel/windows/netuio/netuio.inf @@ -38,7 +38,7 @@ Signature="$WINDOWS NT$" Class=Net ClassGuid={4d36e972-e325-11ce-bfc1-08002be10318} -Provider=%ManufacturerName% +Provider=%Intel% CatalogFile=netuio.cat DriverVer= @@ -47,7 +47,8 @@ DriverVer= ;***************************************** [Manufacturer] -%ManufacturerName%=Standard,NT$ARCH$ +%Intel%=Standard,NT$ARCH$ +%Broadcom%=Broadcom,NT$ARCH$ [Standard.NT$ARCH$] %F1583.netuio.Description%=netuio_Device, PCI\VEN_8086&DEV_1583 @@ -56,6 +57,9 @@ DriverVer= %F37D0.netuio.Description%=netuio_Device, PCI\VEN_8086&DEV_37D0 %F153B.netuio.Description%=netuio_Device, PCI\VEN_8086&DEV_153B +[Broadcom.NT$ARCH$] +%F16D7.netuio.Description%=netuio_Device, PCI\VEN_14E4&DEV_16D7 + [netuio_Device.NT] CopyFiles=Drivers_Dir @@ -113,7 +117,8 @@ KmdfLibraryVersion = $KMDFVERSION$ [Strings] SPSVCINST_ASSOCSERVICE= 0x00000002 -ManufacturerName="Intel" +Intel = "Intel" +Broadcom = "Broadcom Corporation" ClassName = "Intel(R) DPDK netUIO Driver" DiskName = "DPDK netUIO Installation Disk" F1583.netuio.Description = "DPDK netUIO for Intel(R) Ethernet Converged Network Adapter XL710-Q2" @@ -121,5 +126,6 @@ F158A.netuio.Description = "DPDK netUIO for Intel(R) Ethernet Network Adapter XX F158B.netuio.Description = "DPDK netUIO for Intel(R) Ethernet Network Adapter XXV710-DA1" F37D0.netuio.Description = "DPDK netUIO for Intel(R) Ethernet Connection X722" F153B.netuio.Description = "DPDK netUIO for Intel(R) Ethernet Connection I217-V" +F16D7.netuio.Description = "DPDK netUIO for Broadcom P225p NetXtreme-E Dual-port 10Gb/25Gb Ethernet PCIe Adapter" netuio.DeviceDesc = "netuio Device" netuio.SVCDESC = "netuio Service" diff --git a/kernel/windows/netuio/netuio_dev.c b/kernel/windows/netuio/netuio_dev.c index a1fe447f7..3b5c95e84 100644 --- a/kernel/windows/netuio/netuio_dev.c +++ b/kernel/windows/netuio/netuio_dev.c @@ -27,16 +27,28 @@ Return Value: NTSTATUS netuio_create_device(_Inout_ PWDFDEVICE_INIT DeviceInit) { - WDF_OBJECT_ATTRIBUTES deviceAttributes; - WDFDEVICE device = NULL; NTSTATUS status; + WDFDEVICE device = NULL; + + WDF_OBJECT_ATTRIBUTES deviceAttributes; + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + WDF_FILEOBJECT_CONFIG fileConfig; PAGED_CODE(); - WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, NETUIO_CONTEXT_DATA); + // Register PnP power management callbacks + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + pnpPowerCallbacks.EvtDevicePrepareHardware = netuio_evt_prepare_hw; + pnpPowerCallbacks.EvtDeviceReleaseHardware = netuio_evt_release_hw; + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); + + // Register callbacks for when a HANDLE is opened or closed. + WDF_FILEOBJECT_CONFIG_INIT(&fileConfig, WDF_NO_EVENT_CALLBACK, WDF_NO_EVENT_CALLBACK, netuio_evt_file_cleanup); + WdfDeviceInitSetFileObjectConfig(DeviceInit, &fileConfig, WDF_NO_OBJECT_ATTRIBUTES); // Set the device context cleanup callback. // This function will be called when the WDF Device Object associated to the current device is destroyed + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, NETUIO_CONTEXT_DATA); deviceAttributes.EvtCleanupCallback = netuio_evt_device_context_cleanup; status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device); @@ -88,63 +100,112 @@ netuio_map_hw_resources(_In_ WDFDEVICE Device, _In_ WDFCMRESLIST Resources, _In_ { UNREFERENCED_PARAMETER(Resources); - NTSTATUS status = STATUS_SUCCESS; + NTSTATUS status; PNETUIO_CONTEXT_DATA netuio_contextdata; netuio_contextdata = netuio_get_context_data(Device); - if (!netuio_contextdata) + if (!netuio_contextdata) { return STATUS_UNSUCCESSFUL; + } - PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor; - UINT8 bar_index = 0; + PCI_COMMON_HEADER pci_config = {0}; + ULONG bytes_returned; - // Collect device BAR resources from the ResourcesTranslated object - for (ULONG idx = 0; idx < WdfCmResourceListGetCount(ResourcesTranslated); idx++) { - descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, idx); - if (!descriptor) { - status = STATUS_DEVICE_CONFIGURATION_ERROR; - goto end; + // Read PCI configuration space + bytes_returned = netuio_contextdata->bus_interface.GetBusData( + netuio_contextdata->bus_interface.Context, + PCI_WHICHSPACE_CONFIG, + &pci_config, + 0, + sizeof(pci_config)); + + if (bytes_returned != sizeof(pci_config)) { + status = STATUS_NOT_SUPPORTED; + goto end; + } + + // Device type is implictly enforced by .inf + ASSERT(PCI_CONFIGURATION_TYPE(&pci_config) == PCI_DEVICE_TYPE); + + PCM_PARTIAL_RESOURCE_DESCRIPTOR descriptor; + ULONG next_descriptor = 0; + ULONGLONG bar_addr = 0; + ULONG curr_bar = 0; + ULONG prev_bar = 0; + + for (INT bar_index = 0; bar_index < PCI_MAX_BAR; bar_index++) { + prev_bar = curr_bar; + curr_bar = pci_config.u.type0.BaseAddresses[bar_index]; + if (curr_bar == 0 || (prev_bar & PCI_TYPE_64BIT)) { + // Skip this bar + netuio_contextdata->bar[bar_index].base_addr.QuadPart = 0; + netuio_contextdata->bar[bar_index].size = 0; + netuio_contextdata->bar[bar_index].virt_addr = 0; + + netuio_contextdata->dpdk_hw[bar_index].mdl = NULL; + netuio_contextdata->dpdk_hw[bar_index].mem.size = 0; + + continue; } - switch (descriptor->Type) { - case CmResourceTypeMemory: - // Retrieve and map the BARs - netuio_contextdata->bar[bar_index].base_addr.QuadPart = descriptor->u.Memory.Start.QuadPart; - netuio_contextdata->bar[bar_index].size = descriptor->u.Memory.Length; - netuio_contextdata->bar[bar_index].virt_addr = - MmMapIoSpace(descriptor->u.Memory.Start, descriptor->u.Memory.Length, MmNonCached); + // Find next CmResourceTypeMemory + do { + descriptor = WdfCmResourceListGetDescriptor(ResourcesTranslated, next_descriptor); + next_descriptor++; - if (netuio_contextdata->bar[bar_index].virt_addr == NULL) { - status = STATUS_UNSUCCESSFUL; + if (descriptor == NULL) { + status = STATUS_DEVICE_CONFIGURATION_ERROR; goto end; } + } while (descriptor->Type != CmResourceTypeMemory); - bar_index++; - break; + // Assert that we have the correct descriptor + ASSERT((descriptor->Flags & CM_RESOURCE_MEMORY_BAR) != 0); - // Don't handle any other resource type - // This could be device-private type added by the PCI bus driver. - case CmResourceTypeInterrupt: - default: - break; + if (curr_bar & PCI_TYPE_64BIT) { + ASSERT(bar_index != PCI_TYPE0_ADDRESSES - 1); + bar_addr = ((ULONGLONG)pci_config.u.type0.BaseAddresses[bar_index + 1] << 32) | (curr_bar & PCI_ADDRESS_MEMORY_ADDRESS_MASK); + } + else + { + bar_addr = curr_bar & PCI_ADDRESS_MEMORY_ADDRESS_MASK; } - } - // Allocate an MDL for the device BAR, so that we can map it to the user's process context later... - if (status == STATUS_SUCCESS) { - // Bar 0 is typically the HW BAR - if (netuio_contextdata->bar[0].virt_addr) { - netuio_contextdata->dpdk_hw.mdl = IoAllocateMdl(netuio_contextdata->bar[0].virt_addr, (ULONG)netuio_contextdata->bar[0].size, FALSE, FALSE, NULL); - if (!netuio_contextdata->dpdk_hw.mdl) { - status = STATUS_INSUFFICIENT_RESOURCES; - goto end; - } - netuio_contextdata->dpdk_hw.mem.size = netuio_contextdata->bar[0].size; + ASSERT((ULONGLONG)descriptor->u.Memory.Start.QuadPart == bar_addr); + + // Retrieve and map the BARs + netuio_contextdata->bar[bar_index].base_addr.QuadPart = descriptor->u.Memory.Start.QuadPart; + netuio_contextdata->bar[bar_index].size = descriptor->u.Memory.Length; + netuio_contextdata->bar[bar_index].virt_addr = MmMapIoSpace(descriptor->u.Memory.Start, + descriptor->u.Memory.Length, + MmNonCached); + if (netuio_contextdata->bar[bar_index].virt_addr == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto end; } - } + + // Allocate an MDL for the device BAR, so we can map it to the user's process context later. + netuio_contextdata->dpdk_hw[bar_index].mdl = IoAllocateMdl(netuio_contextdata->bar[bar_index].virt_addr, + (ULONG)netuio_contextdata->bar[bar_index].size, + FALSE, + FALSE, + NULL); + if (!netuio_contextdata->dpdk_hw[bar_index].mdl) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto end; + } + + netuio_contextdata->dpdk_hw[bar_index].mem.size = netuio_contextdata->bar[bar_index].size; + } // for bar_index + + status = STATUS_SUCCESS; end: + if (status != STATUS_SUCCESS) { + netuio_free_hw_resources(Device); + } + return status; } @@ -155,15 +216,21 @@ netuio_free_hw_resources(_In_ WDFDEVICE Device) netuio_contextdata = netuio_get_context_data(Device); if (netuio_contextdata) { - // Free the allocated MDL - if (netuio_contextdata->dpdk_hw.mdl) - IoFreeMdl(netuio_contextdata->dpdk_hw.mdl); - - // Unmap all the BAR regions previously mapped for (UINT8 bar_index = 0; bar_index < PCI_MAX_BAR; bar_index++) { - if (netuio_contextdata->bar[bar_index].virt_addr) + + // Free the allocated MDLs + if (netuio_contextdata->dpdk_hw[bar_index].mdl) { + IoFreeMdl(netuio_contextdata->dpdk_hw[bar_index].mdl); + } + + // Unmap all the BAR regions previously mapped + if (netuio_contextdata->bar[bar_index].virt_addr) { MmUnmapIoSpace(netuio_contextdata->bar[bar_index].virt_addr, netuio_contextdata->bar[bar_index].size); + } } + + RtlZeroMemory(netuio_contextdata->dpdk_hw, sizeof(netuio_contextdata->dpdk_hw)); + RtlZeroMemory(netuio_contextdata->bar, sizeof(netuio_contextdata->bar)); } } @@ -246,13 +313,16 @@ create_device_specific_symbolic_link(_In_ WDFOBJECT device) static NTSTATUS allocate_usermemory_segment(_In_ WDFOBJECT device) { - NTSTATUS status = STATUS_SUCCESS; + NTSTATUS status; PNETUIO_CONTEXT_DATA netuio_contextdata; netuio_contextdata = netuio_get_context_data(device); if (!netuio_contextdata) - return STATUS_UNSUCCESSFUL; + { + status = STATUS_INVALID_DEVICE_STATE; + goto end; + } PHYSICAL_ADDRESS lowest_acceptable_address; PHYSICAL_ADDRESS highest_acceptable_address; @@ -287,7 +357,14 @@ allocate_usermemory_segment(_In_ WDFOBJECT device) // Store the region's physical address netuio_contextdata->dpdk_seg.mem.phys_addr = MmGetPhysicalAddress(netuio_contextdata->dpdk_seg.mem.virt_addr); + status = STATUS_SUCCESS; + end: + if (status != STATUS_SUCCESS) + { + free_usermemory_segment(device); + } + return status; } @@ -299,9 +376,15 @@ free_usermemory_segment(_In_ WDFOBJECT device) if (netuio_contextdata) { if (netuio_contextdata->dpdk_seg.mdl) + { IoFreeMdl(netuio_contextdata->dpdk_seg.mdl); + netuio_contextdata->dpdk_seg.mdl = NULL; + } if (netuio_contextdata->dpdk_seg.mem.virt_addr) + { MmFreeContiguousMemory(netuio_contextdata->dpdk_seg.mem.virt_addr); + netuio_contextdata->dpdk_seg.mem.virt_addr = NULL; + } } } diff --git a/kernel/windows/netuio/netuio_dev.h b/kernel/windows/netuio/netuio_dev.h index a19a4fb42..59956720e 100644 --- a/kernel/windows/netuio/netuio_dev.h +++ b/kernel/windows/netuio/netuio_dev.h @@ -12,7 +12,6 @@ EXTERN_C_START #include "netuio_interface.h" // Constants -#define PCI_MAX_BAR 3 #define USER_MEMORY_SEGMENT_SIZE (256ULL * 1024ULL * 1024ULL) // 256MB struct pci_bar { @@ -29,13 +28,13 @@ struct mem_map_region { // The device context performs the same job as a WDM device extension in the driver frameworks typedef struct _NETUIO_CONTEXT_DATA { - WDFDEVICE wdf_device; // WDF device handle to the FDO - BUS_INTERFACE_STANDARD bus_interface; // Bus interface for config space access - struct pci_bar bar[PCI_MAX_BAR]; // device BARs - struct dev_addr addr; // B:D:F details of device - USHORT dev_numa_node; // The NUMA node of the device - struct mem_map_region dpdk_hw; // mapped region for the device's register space - struct mem_map_region dpdk_seg; // mapped region allocated for DPDK process use + WDFDEVICE wdf_device; // WDF device handle to the FDO + BUS_INTERFACE_STANDARD bus_interface; // Bus interface for config space access + struct pci_bar bar[PCI_MAX_BAR]; // device BARs + struct dev_addr addr; // B:D:F details of device + USHORT dev_numa_node; // The NUMA node of the device + struct mem_map_region dpdk_hw[PCI_MAX_BAR]; // mapped region for the device's register space + struct mem_map_region dpdk_seg; // mapped region allocated for DPDK process use } NETUIO_CONTEXT_DATA, *PNETUIO_CONTEXT_DATA; diff --git a/kernel/windows/netuio/netuio_drv.c b/kernel/windows/netuio/netuio_drv.c index d45a9ec4f..554629c98 100644 --- a/kernel/windows/netuio/netuio_drv.c +++ b/kernel/windows/netuio/netuio_drv.c @@ -62,25 +62,8 @@ Return Value: NTSTATUS netuio_evt_device_add(_In_ WDFDRIVER Driver, _Inout_ PWDFDEVICE_INIT DeviceInit) { - NTSTATUS status; - WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; - UNREFERENCED_PARAMETER(Driver); - - PAGED_CODE(); - - // Zero out the PnpPowerCallbacks structure - WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); - - // Register Plug-aNd-Play and power management callbacks - pnpPowerCallbacks.EvtDevicePrepareHardware = netuio_evt_prepare_hw; - pnpPowerCallbacks.EvtDeviceReleaseHardware = netuio_evt_release_hw; - - WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); - - status = netuio_create_device(DeviceInit); - - return status; + return netuio_create_device(DeviceInit); } /* @@ -140,3 +123,27 @@ netuio_evt_driver_context_cleanup(_In_ WDFOBJECT DriverObject) DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_NETUIO_INFO_LEVEL, "netUIO Driver unloaded.\n"); PAGED_CODE(); } + +/* +Routine Description : + EVT_WDF_FILE_CLEANUP callback, called when user process handle is closed. + + Undoes IOCTL_NETUIO_MAP_HW_INTO_USERMODE. + +Return value : + None +-*/ +VOID +netuio_evt_file_cleanup(_In_ WDFFILEOBJECT FileObject) +{ + WDFDEVICE device; + PNETUIO_CONTEXT_DATA netuio_contextdata; + + device = WdfFileObjectGetDevice(FileObject); + netuio_contextdata = netuio_get_context_data(device); + + if (netuio_contextdata) + { + netuio_unmap_address_from_user_process(netuio_contextdata); + } +} diff --git a/kernel/windows/netuio/netuio_drv.h b/kernel/windows/netuio/netuio_drv.h index 39d7f301e..5dc778625 100644 --- a/kernel/windows/netuio/netuio_drv.h +++ b/kernel/windows/netuio/netuio_drv.h @@ -27,6 +27,7 @@ EVT_WDF_DRIVER_DEVICE_ADD netuio_evt_device_add; EVT_WDF_OBJECT_CONTEXT_CLEANUP netuio_evt_driver_context_cleanup; EVT_WDF_DEVICE_PREPARE_HARDWARE netuio_evt_prepare_hw; EVT_WDF_DEVICE_RELEASE_HARDWARE netuio_evt_release_hw; +EVT_WDF_FILE_CLOSE netuio_evt_file_cleanup; EXTERN_C_END diff --git a/kernel/windows/netuio/netuio_interface.h b/kernel/windows/netuio/netuio_interface.h index f84ee895c..82fb1cb50 100644 --- a/kernel/windows/netuio/netuio_interface.h +++ b/kernel/windows/netuio/netuio_interface.h @@ -22,8 +22,8 @@ DEFINE_GUID (GUID_DEVINTERFACE_netUIO, 0x08336f60,0x0679,0x4c6c,0x85,0xd2,0xae,0 #define NETUIO_DRIVER_NAME _T("netuio") // IOCTL code definitions -#define IOCTL_NETUIO_GET_HW_DATA CTL_CODE(FILE_DEVICE_NETWORK, 51, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) -#define IOCTL_NETUIO_PCI_CONFIG_IO CTL_CODE(FILE_DEVICE_NETWORK, 52, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_NETUIO_MAP_HW_INTO_USERMODE CTL_CODE(FILE_DEVICE_NETWORK, 51, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) +#define IOCTL_NETUIO_PCI_CONFIG_IO CTL_CODE(FILE_DEVICE_NETWORK, 52, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) struct mem_region { UINT64 size; // memory region size @@ -43,13 +43,13 @@ enum pci_io { PCI_IO_WRITE = 1 }; +#define PCI_MAX_BAR 6 + struct dpdk_private_info { - struct mem_region hw; + struct mem_region hw[PCI_MAX_BAR]; struct mem_region ms; struct dev_addr dev_addr; - struct mem_region bar1; -// struct mem_region bar2; UINT16 dev_id; UINT16 sub_dev_id; USHORT dev_numa_node; diff --git a/kernel/windows/netuio/netuio_queue.c b/kernel/windows/netuio/netuio_queue.c index 760b4a7e5..9c7ff7d06 100644 --- a/kernel/windows/netuio/netuio_queue.c +++ b/kernel/windows/netuio/netuio_queue.c @@ -11,54 +11,113 @@ #pragma alloc_text (PAGE, netuio_queue_initialize) #endif -VOID netuio_read_PCI_config(PNETUIO_CONTEXT_DATA netuio_contextdata, ULONG offset, UINT32 access_size, _Out_ UINT64 *output) -{ - *output = 0; - netuio_contextdata->bus_interface.GetBusData(netuio_contextdata->bus_interface.Context, - PCI_WHICHSPACE_CONFIG, - output, - offset, - access_size); -} - -VOID netuio_write_PCI_config(PNETUIO_CONTEXT_DATA netuio_contextdata, ULONG offset, UINT32 access_size, union dpdk_pci_config_io_data const *input) -{ - netuio_contextdata->bus_interface.SetBusData(netuio_contextdata->bus_interface.Context, - PCI_WHICHSPACE_CONFIG, - (PVOID)input, - offset, - access_size); -} - -static NTSTATUS +static void netuio_handle_get_hw_data_request(_In_ WDFREQUEST Request, _In_ PNETUIO_CONTEXT_DATA netuio_contextdata, _In_ PVOID outputBuf, _In_ size_t outputBufSize) { - NTSTATUS status = STATUS_SUCCESS; - WDF_REQUEST_PARAMETERS params; WDF_REQUEST_PARAMETERS_INIT(¶ms); WdfRequestGetParameters(Request, ¶ms); - if (!netuio_contextdata || (outputBufSize != sizeof(struct dpdk_private_info))) { - status = STATUS_INVALID_PARAMETER; - goto end; - } + ASSERT(outputBufSize == sizeof(struct dpdk_private_info)); struct dpdk_private_info *dpdk_pvt_info = (struct dpdk_private_info *)outputBuf; RtlZeroMemory(dpdk_pvt_info, outputBufSize); - dpdk_pvt_info->hw.phys_addr.QuadPart = netuio_contextdata->bar[0].base_addr.QuadPart; - dpdk_pvt_info->hw.user_mapped_virt_addr = netuio_contextdata->dpdk_hw.mem.user_mapped_virt_addr; - dpdk_pvt_info->hw.size = netuio_contextdata->bar[0].size; + for (ULONG idx = 0; idx < PCI_MAX_BAR; idx++) { + dpdk_pvt_info->hw[idx].phys_addr.QuadPart = netuio_contextdata->bar[idx].base_addr.QuadPart; + dpdk_pvt_info->hw[idx].user_mapped_virt_addr = netuio_contextdata->dpdk_hw[idx].mem.user_mapped_virt_addr; + dpdk_pvt_info->hw[idx].size = netuio_contextdata->bar[idx].size; + } dpdk_pvt_info->ms.phys_addr.QuadPart = netuio_contextdata->dpdk_seg.mem.phys_addr.QuadPart; dpdk_pvt_info->ms.user_mapped_virt_addr = netuio_contextdata->dpdk_seg.mem.user_mapped_virt_addr; dpdk_pvt_info->ms.size = netuio_contextdata->dpdk_seg.mem.size; +} + +/* +Routine Description: + Maps address ranges into the usermode process's address space. The following + ranges are mapped: + + * Any PCI BARs that our device was assigned + * The scratch buffer of contiguous pages + +Return Value: + NTSTATUS +*/ +static NTSTATUS +netuio_map_address_into_user_process(_In_ PNETUIO_CONTEXT_DATA netuio_contextdata) +{ + NTSTATUS status = STATUS_SUCCESS; + + // Map the scratch memory regions to the user's process context + MmBuildMdlForNonPagedPool(netuio_contextdata->dpdk_seg.mdl); + netuio_contextdata->dpdk_seg.mem.user_mapped_virt_addr = + MmMapLockedPagesSpecifyCache( + netuio_contextdata->dpdk_seg.mdl, UserMode, MmCached, + NULL, FALSE, (NormalPagePriority | MdlMappingNoExecute)); + + if (netuio_contextdata->dpdk_seg.mem.user_mapped_virt_addr == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto end; + } + + // Map any device BAR(s) to the user's process context + for (INT idx = 0; idx < PCI_MAX_BAR; idx++) { + if (netuio_contextdata->dpdk_hw[idx].mdl == NULL) { + continue; + } + + MmBuildMdlForNonPagedPool(netuio_contextdata->dpdk_hw[idx].mdl); + netuio_contextdata->dpdk_hw[idx].mem.user_mapped_virt_addr = + MmMapLockedPagesSpecifyCache( + netuio_contextdata->dpdk_hw[idx].mdl, UserMode, MmCached, + NULL, FALSE, (NormalPagePriority | MdlMappingNoExecute)); + + if (netuio_contextdata->dpdk_hw[idx].mem.user_mapped_virt_addr == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto end; + } + } + end: + if (status != STATUS_SUCCESS) { + netuio_unmap_address_from_user_process(netuio_contextdata); + } + return status; } +/* +Routine Description: + Unmaps all address ranges from the usermode process address space. + MUST be called in the context of the same process which created + the mapping. + +Return Value: + None + */ +VOID +netuio_unmap_address_from_user_process(_In_ PNETUIO_CONTEXT_DATA netuio_contextdata) +{ + if (netuio_contextdata->dpdk_seg.mem.user_mapped_virt_addr != NULL) { + MmUnmapLockedPages( + netuio_contextdata->dpdk_seg.mem.user_mapped_virt_addr, + netuio_contextdata->dpdk_seg.mdl); + netuio_contextdata->dpdk_seg.mem.user_mapped_virt_addr = NULL; + } + + for (INT idx = 0; idx < PCI_MAX_BAR; idx++) { + if (netuio_contextdata->dpdk_hw[idx].mem.user_mapped_virt_addr != NULL) { + MmUnmapLockedPages( + netuio_contextdata->dpdk_hw[idx].mem.user_mapped_virt_addr, + netuio_contextdata->dpdk_hw[idx].mdl); + netuio_contextdata->dpdk_hw[idx].mem.user_mapped_virt_addr = NULL; + } + } +} + /* Routine Description: The I/O dispatch callbacks for the frameworks device object are configured here. @@ -123,7 +182,7 @@ netuio_evt_IO_device_control(_In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, netuio_contextdata = netuio_get_context_data(device); switch (IoControlCode) { - case IOCTL_NETUIO_GET_HW_DATA: + case IOCTL_NETUIO_MAP_HW_INTO_USERMODE: // First retrieve the input buffer and see if it matches our device status = WdfRequestRetrieveInputBuffer(Request, sizeof(struct dpdk_private_info), &input_buf, &input_buf_size); if (!NT_SUCCESS(status)) { @@ -140,35 +199,29 @@ netuio_evt_IO_device_control(_In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, break; } - // Map the previously allocated/defined memory regions to the user's process context - MmBuildMdlForNonPagedPool(netuio_contextdata->dpdk_hw.mdl); - netuio_contextdata->dpdk_hw.mem.user_mapped_virt_addr = - MmMapLockedPagesSpecifyCache(netuio_contextdata->dpdk_hw.mdl, UserMode, MmCached, - NULL, FALSE, (NormalPagePriority | MdlMappingNoExecute)); - - MmBuildMdlForNonPagedPool(netuio_contextdata->dpdk_seg.mdl); - netuio_contextdata->dpdk_seg.mem.user_mapped_virt_addr = - MmMapLockedPagesSpecifyCache(netuio_contextdata->dpdk_seg.mdl, UserMode, MmCached, - NULL, FALSE, (NormalPagePriority | MdlMappingNoExecute)); - - if (!netuio_contextdata->dpdk_hw.mem.user_mapped_virt_addr && !netuio_contextdata->dpdk_seg.mem.user_mapped_virt_addr) { - status = STATUS_INSUFFICIENT_RESOURCES; + if (netuio_contextdata->dpdk_seg.mem.user_mapped_virt_addr != NULL) { + status = STATUS_ALREADY_COMMITTED; break; } - // Zero out the physically contiguous block - RtlZeroMemory(netuio_contextdata->dpdk_seg.mem.virt_addr, netuio_contextdata->dpdk_seg.mem.size); - // Return relevant data to the caller status = WdfRequestRetrieveOutputBuffer(Request, sizeof(struct dpdk_private_info), &output_buf, &output_buf_size); if (!NT_SUCCESS(status)) { status = STATUS_INVALID_BUFFER_SIZE; break; } + + // Zero out the physically contiguous block + RtlZeroMemory(netuio_contextdata->dpdk_seg.mem.virt_addr, netuio_contextdata->dpdk_seg.mem.size); + + status = netuio_map_address_into_user_process(netuio_contextdata); + if (status != STATUS_SUCCESS) { + break; + } + ASSERT(output_buf_size == OutputBufferLength); - status = netuio_handle_get_hw_data_request(Request, netuio_contextdata, output_buf, output_buf_size); - if (NT_SUCCESS(status)) - bytes_returned = output_buf_size; + netuio_handle_get_hw_data_request(Request, netuio_contextdata, output_buf, output_buf_size); + bytes_returned = output_buf_size; break; @@ -206,19 +259,22 @@ netuio_evt_IO_device_control(_In_ WDFQUEUE Queue, _In_ WDFREQUEST Request, ASSERT(output_buf_size == OutputBufferLength); if (dpdk_pci_io_input->op == PCI_IO_READ) { - netuio_read_PCI_config(netuio_contextdata, - dpdk_pci_io_input->offset, - dpdk_pci_io_input->access_size, - (UINT64*)output_buf); - - bytes_returned = sizeof(UINT64); + *(UINT64 *)output_buf = 0; + bytes_returned = netuio_contextdata->bus_interface.GetBusData( + netuio_contextdata->bus_interface.Context, + PCI_WHICHSPACE_CONFIG, + output_buf, + dpdk_pci_io_input->offset, + dpdk_pci_io_input->access_size); } else if (dpdk_pci_io_input->op == PCI_IO_WRITE) { - netuio_write_PCI_config(netuio_contextdata, - dpdk_pci_io_input->offset, - dpdk_pci_io_input->access_size, - &dpdk_pci_io_input->data); - bytes_returned = 0; + // returns bytes written + bytes_returned = netuio_contextdata->bus_interface.SetBusData( + netuio_contextdata->bus_interface.Context, + PCI_WHICHSPACE_CONFIG, + (PVOID)&dpdk_pci_io_input->data, + dpdk_pci_io_input->offset, + dpdk_pci_io_input->access_size); } else { status = STATUS_INVALID_PARAMETER; diff --git a/kernel/windows/netuio/netuio_queue.h b/kernel/windows/netuio/netuio_queue.h index 6a0306516..90fdb4008 100644 --- a/kernel/windows/netuio/netuio_queue.h +++ b/kernel/windows/netuio/netuio_queue.h @@ -17,6 +17,8 @@ typedef struct _QUEUE_CONTEXT { WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(QUEUE_CONTEXT, QueueGetContext) +VOID +netuio_unmap_address_from_user_process(_In_ PNETUIO_CONTEXT_DATA netuio_contextdata); NTSTATUS netuio_queue_initialize(_In_ WDFDEVICE hDevice);