赛灵思PCIE驱动DMA MSI实现01

  • 内容
  • 评论
  • 相关

最近做项目完成了一个赛灵思PCIE MSI驱动,周末整理一下,分几篇来写吧。首先我们简单说明一下相关概念。

1.1 WDM与WDF

Windows平台下的设备驱动程序从Windows 2000开始都是以WDM ( Windows Driver Model) 框架为平台进行开发。以此模型开发,开发者需要一方面实现驱动程序与硬件的交互,另一方面要对操作系统内核进行操作,难度大。驱动程序容易出现问题,这也是Windows2000以来操作系统容易蓝屏的原因。
为了改善这种局面,降低驱动程序开发者的开发难度,提高系统稳定性,微软推出了新的驱动程序开发模型WDF。WDF对WDM进行了封装,将驱动程序中与操作系统交互的细节由框架实现。这样驱动程序就从内核中分离出来,开发者只需要专注处理与硬件的交互,简化了驱动程序的设计,提高了整个系统的可靠性和稳定性。WDM与WDF样例驱动程序对比如下表所示。通过该表可以看到基于WDF框架的驱动程序,代码量显著减少,开发起来更加容易。
我们知道Windows是一个分层的操作系统,它的运行依赖于上层组件向下层组件的调用。一个简化的I/O流模型如下图:

1.2 开发环境搭建

Windows 驱动程序开发工具包 (WDK) 与 Microsoft Visual Studio 和用于 Windows 驱动程序的调试工具相集成。该集成环境给开发者提供了开发、构建、打包、部署、测试和调试驱动程序时所需的工具。

本课题确定时,微软的最新驱动程序工具包为WDK8.1。WDK8.1 更新与 Microsoft Visual Studio2015 集成。开发者需要首先在微软的官方网站上下载并安装 Visual Studio 2015,然后安装WDK 8.1 更新。微软声明不再对WDK8.0提供支持,也不再对WDK 8.0做任何更新,WDK8.0也不支持Windows8.1的驱动程序开发。所以本课题选用WDK8.1作为开发工具包。然而新技术发展速度飞快,在本课题完成之际,微软打算极力推广的Windows 10操作系统还未正式公布,针对Windows 10的驱动程序开发工具包WDK 10已经推出。未来一定会推广使用WDK10来开发。

下载链接:https://msdn.microsoft.com/zh-cn/windows/hardware/hh852365,下载两个安装包,依次安装,非常简单。

1.3 代码入口

所有驱动都有一个入口函数,类似main入口。
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
注册系统函数,通常被称为Dispatcher:

// setup our dispatch function table in the driver object
DriverObject->MajorFunction[IRP_MJ_PNP] = HYPCIPnpDispatch;
DriverObject->MajorFunction[IRP_MJ_POWER] = HYPCIPowerDispatch;
DriverObject->MajorFunction[IRP_MJ_CREATE] = HYPCICreateDispatch;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = HYPCICloseDispatch;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HYPCIDeviceIoControlDispatch;
DriverObject->MajorFunction[IRP_MJ_READ] = HYPCIReadDispatch;
DriverObject->MajorFunction[IRP_MJ_WRITE] = HYPCIWriteDispatch;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = HYPCICleanupDispatch;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = HYPCISystemControlDispatch;

DriverObject->DriverExtension->AddDevice = HYPCIAddDevice;
DriverObject->DriverUnload = HYPCIUnload;

1.4 完整入口

完整的入口函数注册如下,包括判断windows版本:

#ifdef __cplusplus
extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING  RegistryPath);
#endif
 

// global data
HYPCI_DATA g_Data;

///////////////////////////////////////////////////////////////////////////////////////////////////
//  DriverEntry 
//      Installable driver initialization entry point.
//      This entry point is called directly by the I/O system.
//
//  Arguments:
//      IN  DriverObject
//              pointer to the driver object
//
//      IN  RegistryPath
//              pointer to a unicode string representing the path,
//              to driver-specific key in the registry. 
//
//  Return Value:
//      Status
//
NTSTATUS DriverEntry(IN  PDRIVER_OBJECT  DriverObject, IN  PUNICODE_STRING RegistryPath)
{
    NTSTATUS    status;

	DbgPrint("Compiled at %s on %s", __TIME__, __DATE__);

	 

#ifdef HYPCI_WMI_TRACE 
    WPP_INIT_TRACING(DriverObject, RegistryPath);
#endif

    status = STATUS_SUCCESS;

    RtlZeroMemory(&g_Data, sizeof(HYPCI_DATA));
    // save registry path for wmi
    g_Data.RegistryPath.Length = RegistryPath->Length;
    g_Data.RegistryPath.MaximumLength = RegistryPath->Length + sizeof(UNICODE_NULL);
    g_Data.RegistryPath.Buffer = (PWCHAR)ExAllocatePoolWithTag(
                                            PagedPool,
                                            g_Data.RegistryPath.MaximumLength,
                                            HYPCI_POOL_TAG
                                            );

    if (g_Data.RegistryPath.Buffer == NULL)
    {
        status = STATUS_INSUFFICIENT_RESOURCES;

       JJPCIDbPrint(("Failed to allocate memory for RegistryPath"));

        return status;
    }
    RtlCopyUnicodeString(&g_Data.RegistryPath, RegistryPath);

    // detect current operating system
    if (IoIsWdmVersionAvailable(1, 0x30))
    {
        g_Data.WdmVersion = 0x0130;
    }
    else if (IoIsWdmVersionAvailable(1, 0x20))
    {
        g_Data.WdmVersion = 0x0120;
    }
    else if (IoIsWdmVersionAvailable(1, 0x10))
    {
        g_Data.WdmVersion = 0x0110;
    }
    else if (IoIsWdmVersionAvailable(1, 0x05))
    {
        g_Data.WdmVersion = 0x0105;
    }
    else
    {
        g_Data.WdmVersion = 0x0100;
    }
    // setup our dispatch function table in the driver object
    DriverObject->MajorFunction[IRP_MJ_PNP] = HYPCIPnpDispatch;
    DriverObject->MajorFunction[IRP_MJ_POWER] = HYPCIPowerDispatch;
    DriverObject->MajorFunction[IRP_MJ_CREATE] = HYPCICreateDispatch;
    DriverObject->MajorFunction[IRP_MJ_CLOSE] = HYPCICloseDispatch;
    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = HYPCIDeviceIoControlDispatch;
    DriverObject->MajorFunction[IRP_MJ_READ] = HYPCIReadDispatch;
    DriverObject->MajorFunction[IRP_MJ_WRITE] = HYPCIWriteDispatch;
    DriverObject->MajorFunction[IRP_MJ_CLEANUP] = HYPCICleanupDispatch;
    DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = HYPCISystemControlDispatch;

    DriverObject->DriverExtension->AddDevice = HYPCIAddDevice;
    DriverObject->DriverUnload = HYPCIUnload;

    return status;
}

还了,下一篇我们在介绍相关Dispatch的作用吧。

评论

0条评论

发表评论

电子邮件地址不会被公开。