windows驱动开发-PCI和中断(三)

2024-05-15 07:52
文章标签 windows 开发 驱动 中断 pci

本文主要是介绍windows驱动开发-PCI和中断(三),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在前面我们用一个实际的案例来说明了INTx中断是如何编程的,但是现在几乎已经很少遇到INTx中断了,基本上都是MSI和MSIX中断。

MSI和MSIX

PCI 2.2 规范中引入了 (MSI) 的消息信号中断,作为基于线路的中断的替代方法。 使用 MSI 的设备通过将值写入特定内存地址来触发中断,而不是使用专用引脚触发中断。 PCI 3.0 定义了一种扩展形式的 MSI,称为 MSI-X,可实现更高的可编程性。 Windows Vista 和更高版本的 Windows 支持 MSI 和 MSI-X。 单个设备可以同时支持 MSI 和 MSI-X。 对于此类设备,操作系统将自动使用 MSI-X。

中断消息是设备写入特定地址以触发中断的特定值。 与基于行(边带信号)的中断不同,消息信号中断具有边缘语义。 设备发送消息,但未收到任何硬件确认,说明已收到中断。

对于 PCI 2.2,消息由地址和部分不透明的 16 位值组成。 为每个设备分配一个地址。 若要发送多条消息,设备可以使用消息值的低 4 位来区分消息。 因此,对于 PCI 2.2,设备最多可以支持 16 条消息。

对于 PCI 3.0,消息由地址和不透明的 32 位值组成。 每封不同的邮件都有其自己的唯一地址。 与 PCI 2.2 不同,设备不会修改值。 对于 PCI 3.0,设备最多可以支持 2,048 条不同的消息。 支持 PCI 3.0 MSI-X 的设备具有一个动态可编程的硬件表,其中包含设备中每个中断源的条目。 可以使用分配给设备的消息之一对此表中的每个条目进行编程,并且可以独立屏蔽。 驱动程序可以将中断消息的编程更改为表条目,以及某个条目是否已被屏蔽。 

驱动程序可以注册单个 InterruptMessageService 例程,该例程处理所有可能的消息或每条消息的单个 InterruptService 例程。

驱动程序可以处理设备发送的 MSI,如下所示:

  • 在驱动程序安装过程中,在注册表中启用 MSI。 还可以使用注册表指定要为设备分配的消息数;
  • (可选)通过响应 IRP_MN_FILTER_RESOURCE_REQUIREMENTS 请求来增加中断消息数并保存一些每条消息设置;
  • 在用于IRP_MN_START_DEVICE的驱动程序调度例程中,调用 IoConnectInterruptEx 以注册 InterruptService 或 InterruptMessageService 例程来为设备的中断提供服务。 使用 ioConnectInterruptEx 的 CONNECT_FULLY_SPECIFIED 版本为特定消息注册 InterruptService 例程,或使用 ioConnectInterruptEx 的 CONNECT_MESSAGE_BASED 版本为所有消息注册单个 InterruptMessageService 例程;
  • 驱动程序不再打算处理来自设备的中断后,请在禁用设备的中断后调用 IoDisconnectInterruptEx  删除任何已注册的中断服务例程;

设计为使用多个消息的驱动程序应检查分配预期的消息数。 如果即插即用 (PnP) 管理器无法分配请求的消息数,它会只向设备分配一条消息。 驱动程序可以通过以下方式之一检查实际分配的消息数:

  • PnP 管理器在其原始资源描述符列表中报告分配的消息数。 
  • 当 IoConnectInterruptEx 返回时,它将 Parameters-MessageBased.ConnectContext.InterruptMessageTable-MessageCount>> 设置为分配的消息数;
注册表中启用MSI

若要 (MSI) 接收消息信号中断,驱动程序的 INF 文件必须在安装期间在注册表中启用 MSI。 使用设备hardware key的Interrupt Management\MessageSignaledInterruptProperties子项启用 MSI 支持。

Interrupt Management\MessageSignaledInterruptProperties的 MSISupported 条目是一个REG_DWORD值,用于确定设备是否支持 MSI,将 MSISupported 设置为 1 以启用 MSI 支持。

还可以使用注册表指定要为其设备分配的最大 MSI 数。 Interrupt Management\MessageSignaledInterruptProperties 的 MessageNumberLimit 条目是一个REG_DWORD值,指定要分配的最大 MSI 数。

对于从 PCI 2.2开始可用的多消息 MSI ,MessageNumberLimit 必须为 1、2、4、8 或 16。 对于从 PCI 3.0开始可用的 MSI-X 设备 MessageNumberLimit 可以是最多 2,048 个数字。

在驱动程序的 INF 文件中使用 INF AddReg 指令 在设备的硬件密钥下设置注册表项。 

下面的代码示例演示如何为设备设置Interrupt Management\MessageSignaledInterruptProperties 下的 MSISupported 条目。 请注意,在添加 MSISupported 值时,AddReg 指令会自动创建Interrupt Management和Interrupt Management\MessageSignaledInterruptProperties:

[mydevice.HW]
AddReg = mydevice_addreg[mydevice_addreg]
HKR,Interrupt Management\MessageSignaledInterruptProperties,MSISupported,0x00010001,1
中断资源描述符 

即插即用 (PnP) 管理器使用两个通道将中断消息分配给设备。

首先,PnP 管理器向驱动程序发送 一个IRP_MN_FILTER_RESOURCE_REQUIREMENTS 请求,其中包含它打算分配给设备的硬件资源列表,包括中断消息。 驱动程序可以修改此列表以更改中断消息数以及一些每条消息设置。 然后,在 PnP 管理器实际分配资源后,它会发送 IRP_MN_START_DEVICE 请求,并提供分配给驱动程序设备的硬件资源(包括中断消息)的完整列表。

IRP_MN_FILTER_RESOURCE_REQUIREMENTS请求提供IO_RESOURCE_DESCRIPTOR结构的列表。 如果设备具有 PCI 2.2 规范中定义的 MSI (消息信号中断) 功能结构,则 PnP 管理器将提供单个中断消息描述符。 如果设备具有 PCI 3.0 规范中定义的 MSI-X 功能结构,则 PnP 管理器为每个中断消息提供一个结构。 中断消息描述符的type = CmResourceTypeInterrupt , Flags = CM_RESOURCE_INTERRUPT_LATCHED |CM_RESOURCE_INTERRUPT_MESSAGE。 驱动程序还可以通过更改 结构的 u.Interrupt 成员来更改中断相关性等设置。 请注意,在使用 MSI 时,中断都具有相同的相关性,而使用 MSI-X 时,它们可能具有不同的相关性。 

对于 MSI,如 PCI 2.2 中定义, u.Interrupt.MaximumVector - u.Interrupt.MinimumVector + 1 是为设备分配的中断消息数。 驱动程序可以通过修改 u.Interrupt.MinimumVector 来更改中断消息数。 对于 MSI 中断消息, u.Interrupt.MaximumVector 始终CM_RESOURCE_INTERRUPT_MESSAGE_TOKEN。 若要分配 MessageCount 中断消息,请将 u.Interrupt.MinimumVector 设置为等于CM_RESOURCE_INTERRUPT_MESSAGE_TOKEN - MessageCount + 1。

对于 PCI 3.0 中定义的 MSI-X,驱动程序可以通过在列表中添加或删除条目来更改分配的中断消息数。 请注意,在响应 IRP_MN_START_DEVICE 请求时,不得随后删除以这种方式添加的中断消息资源。 对于 MSI-X,PnP 管理器为每个消息中断提供一个描述符,此描述 符的 u.Interrupt.MinimumVector 和 u.Interrupt.MaximumVector 成员都设置为CM_RESOURCE_INTERRUPT_MESSAGE_TOKEN。

即插即用管理器分配设备的所有硬件资源(包括中断消息)后,会将IRP_MN_START_DEVICE请求发送到驱动程序。 此请求提供两个 CM_PARTIAL_RESOURCE_DESCRIPTOR 结构列表,分别用于原始资源和已翻译的资源。 对于中断消息,PnP 管理器为每个分配的内存地址提供一个结构,type = 为CmResourceTypeInterrupt,Flags = CM_RESOURCE_INTERRUPT_LATCHED |CM_RESOURCE_INTERRUPT_MESSAGE。

请注意,使用 MSI 时,驱动程序仅接收一个中断资源描述符,因为所有消息共享相同的地址。 u.MessageInterrupt.Raw 的 MessageCount 成员可用于确定分配的消息数。 使用 MSI-X 时,驱动程序将接收每个中断消息的单独资源描述符。

在 Windows 8 中,操作系统不支持每个设备功能超过 2048 条中断消息的资源请求。 在 Windows 7 和 Windows Vista 中,操作系统不支持每个设备功能超过 910 条中断消息的资源请求。 如果设备驱动程序超出此限制,设备可能无法启动。 若要使驱动程序能够在包含许多逻辑处理器的计算机中运行,驱动程序应避免为每个处理器请求多个中断。

在系统重新平衡中断资源期间,PnP 管理器可能会要求驱动程序从资源要求列表中选择一组首选的备用中断资源。 但是,PnP 管理器不能始终向驱动程序分配驱动程序首选的资源。 因此,驱动程序必须容忍从资源要求列表中分配任何一组备用中断资源,而不会失败。 例如,为设备分配的消息中断数可能少于驱动程序请求的次数。 在最坏的情况下,驱动程序必须准备好仅使用一个基于线路的中断来操作设备。

动态配置 MSI-X

Windows Vista Service Pack 1 (SP1) 、Windows Server 2008 及更高版本的操作系统支持动态修改 MSI-X 中断消息的属性。 PCI 3.0 规范定义的 MSI-X.PCI 总线驱动程序公开GUID_MSIX_TABLE_CONFIG_INTERFACE接口,以允许 PCI 设备的驱动程序修改总线硬件中断表中的设置。

驱动程序通过向总线驱动程序发送 IRP_MN_QUERY_INTERFACE 请求来使用该接口, 其中 InterfaceType 参数等于 GUID_MSIX_TABLE_CONFIG_INTERFACE。 总线驱动程序提供指向 PCI_MSIX_TABLE_CONFIG_INTERFACE 结构的指针,该结构提供指向修改中断表的三个例程的指针:

  • SetTableEntry 将消息 ID 分配给硬件表条目;
  • MaskTableEntry 屏蔽与硬件表条目对应的中断;
  • UnmaskTableEntry 取消屏蔽对应于硬件表条目的中断;
PCI_MSIX_MASKUNMASK_ENTRY PciMsixMaskmaskEntry;NTSTATUS PciMsixMaskmaskEntry([in] PVOID Context,[in] ULONG TableEntry
)
{...}PCI_MSIX_MASKUNMASK_ENTRY PciMsixMaskunmaskEntry;NTSTATUS PciMsixMaskunmaskEntry([in] PVOID Context,[in] ULONG TableEntry
)
{...}PCI_MSIX_SET_ENTRY PciMsixSetEntry;NTSTATUS PciMsixSetEntry([in] PVOID Context,[in] ULONG TableEntry,[in] ULONG MessageNumber
)
{...}

默认情况下,中断表配置为使第一个条目的消息 ID 为零,第二个条目具有消息 ID 1,依此依此。 如果表条目数超过消息数,则向每个附加表条目分配消息 ID 为零。 (消息 ID 是描述驱动程序的消息信号中断的IO_INTERRUPT_MESSAGE_INFO结构的 MessageInfo 成员中中断项的索引。IoConnectInterruptEx 例程提供指向此结构的指针)。

IoConnectInterruptEx 

这个函数比较有意思

#define IoConnectInterruptEx WdmlibIoConnectInterruptExNTSTATUS WdmlibIoConnectInterruptEx([in, out] PIO_CONNECT_INTERRUPT_PARAMETERS Parameters
);typedef struct _IO_CONNECT_INTERRUPT_PARAMETERS {ULONG Version;union {IO_CONNECT_INTERRUPT_FULLY_SPECIFIED_PARAMETERS FullySpecified;IO_CONNECT_INTERRUPT_LINE_BASED_PARAMETERS      LineBased;IO_CONNECT_INTERRUPT_MESSAGE_BASED_PARAMETERS   MessageBased;};
} IO_CONNECT_INTERRUPT_PARAMETERS, *PIO_CONNECT_INTERRUPT_PARAMETERS;

使用 CONNECT_FULLY_SPECIFIED 的 IoConnectInterruptEx

驱动程序可以使用 ioConnectInterruptEx CONNECT_FULLY_SPECIFIED 版本为特定中断注册 InterruptService 例程。 从 Windows Vista 开始,驱动程序可以使用CONNECT_FULLY_SPECIFIED版本。 通过链接到 Iointex.lib 库,驱动程序可以使用 Windows 2000、Windows XP 和 Windows Server 2003 中的 CONNECT_FULLY_SPECIFIED 版本。 

驱动程序将 parameters->Version 的值指定为 CONNECT_FULLY_SPECIFIED,并使用 Parameters->FullySpecified 的成员来指定操作的其他参数:

Parameters->FullySpecified.PhysicalDeviceObject 为 ISR 服务的设备指定 PDO。

Parameters->FullySpecified.ServiceRoutine 指向 InterruptService 例程,而 Parameters->FullySpecified。ServiceContext 指定系统作为 ServiceContext 参数传递给 InterruptService 的值。 驱动程序可以使用此来传递上下文信息。 

驱动程序提供指向 Parameters-> FullySpecified.InterruptObject中的 PKINTERRUPT 变量的指针。 IoConnectInterruptEx 例程将此变量设置为指向中断的中断对象,该对象可在删除 ISR 时使用。

驱动程序可以选择在 Parameters->FullySpecified.SpinLock 中指定旋转锁,供系统在与 ISR 同步时使用。 大多数驱动程序只需指定 NULL ,使系统能够代表驱动程序分配旋转锁。 

驱动程序必须在 Parameters->FullySpecified 的其他成员中指定中断的关键属性。 系统在将 IRP_MN_START_DEVICE IRP 发送到驱动程序时,在 CM_PARTIAL_RESOURCE_DESCRIPTOR 结构数组中提供必要的信息。

系统为每个中断提供一个类型成员等于 CmResourceTypeInterrupt的CM_PARTIAL_RESOURCE_DESCRIPTOR结构。 对于消息信号中断,设置 Flags 成员的CM_RESOURCE_INTERRUPT_MESSAGE位;否则,会将其清除。

CM_PARTIAL_RESOURCE_DESCRIPTOR 的 u.Interrupt 成员包含基于行的中断的说明,而 u.MessageInterrupt.Translated 成员包含消息信号中断的说明:

成员基于行的中断消息信号中断

ShareVector

ShareDisposition

ShareDisposition

vector

u.Interrupt.Vector

u.MessageInterrupt.Translated.Vector

Irql

u.Interrupt.Level

u.MessageInterrupt.Translated.Level

InterruptMode

type & CM_RESOURCE_INTERRUPT_LATCHED

type & CM_RESOURCE_INTERRUPT_LATCHED

ProcessorEnableMask

u.Interrupt.Affinity

u.MessageInterrupt.Translated.Affinity

 下面是实际的代码: 

IO_CONNECT_INTERRUPT_PARAMETERS params;// deviceExtension is a pointer to the driver's device extension. 
//     deviceExtension->IntObj is a PKINTERRUPT.
// deviceInterruptService is a pointer to the driver's InterruptService routine.
// IntResource is a CM_PARTIAL_RESOURCE_DESCRIPTOR structure of either type CmResourceTypeInterrupt or CmResourceTypeMessageInterrupt.
// PhysicalDeviceObject is a pointer to the device's PDO. 
// ServiceContext is a pointer to driver-specified context for the ISR.RtlZeroMemory( &params, sizeof(IO_CONNECT_INTERRUPT_PARAMETERS) );
params.Version = CONNECT_FULLY_SPECIFIED;
params.FullySpecified.PhysicalDeviceObject = PhysicalDeviceObject;
params.FullySpecified.InterruptObject = &devExt->IntObj;
params.FullySpecified.ServiceRoutine = deviceInterruptService;
params.FullySpecified.ServiceContext = ServiceContext;
params.FullySpecified.FloatingSave = FALSE;
params.FullySpecified.SpinLock = NULL;if (IntResource->Flags & CM_RESOURCE_INTERRUPT_MESSAGE) {// The resource is for a message-signaled interrupt. Use the u.MessageInterrupt.Translated member of IntResource.params.FullySpecified.Vector = IntResource->u.MessageInterrupt.Translated.Vector;params.FullySpecified.Irql = (KIRQL)IntResource->u.MessageInterrupt.Translated.Level;params.FullySpecified.SynchronizeIrql = (KIRQL)IntResource->u.MessageInterrupt.Translated.Level;params.FullySpecified.ProcessorEnableMask = IntResource->u.MessageInterrupt.Translated.Affinity;
} else {// The resource is for a line-based interrupt. Use the u.Interrupt member of IntResource.params.FullySpecified.Vector = IntResource->u.Interrupt.Vector;params.FullySpecified.Irql = (KIRQL)IntResource->u.Interrupt.Level;params.FullySpecified.SynchronizeIrql = (KIRQL)IntResource->u.Interrupt.Level;params.FullySpecified.ProcessorEnableMask = IntResource->u.Interrupt.Affinity;
}params.FullySpecified.InterruptMode = (IntResource->Flags & CM_RESOURCE_INTERRUPT_LATCHED ? Latched : LevelSensitive);
params.FullySpecified.ShareVector = (BOOLEAN)(IntResource->ShareDisposition == CmResourceShareShared);status = IoConnectInterruptEx(&params);if (!NT_SUCCESS(status)) {...
}

这篇关于windows驱动开发-PCI和中断(三)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/991242

相关文章

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优

利用Python开发Markdown表格结构转换为Excel工具

《利用Python开发Markdown表格结构转换为Excel工具》在数据管理和文档编写过程中,我们经常使用Markdown来记录表格数据,但它没有Excel使用方便,所以本文将使用Python编写一... 目录1.完整代码2. 项目概述3. 代码解析3.1 依赖库3.2 GUI 设计3.3 解析 Mark

利用Go语言开发文件操作工具轻松处理所有文件

《利用Go语言开发文件操作工具轻松处理所有文件》在后端开发中,文件操作是一个非常常见但又容易出错的场景,本文小编要向大家介绍一个强大的Go语言文件操作工具库,它能帮你轻松处理各种文件操作场景... 目录为什么需要这个工具?核心功能详解1. 文件/目录存javascript在性检查2. 批量创建目录3. 文件

Windows Server服务器上配置FileZilla后,FTP连接不上?

《WindowsServer服务器上配置FileZilla后,FTP连接不上?》WindowsServer服务器上配置FileZilla后,FTP连接错误和操作超时的问题,应该如何解决?首先,通过... 目录在Windohttp://www.chinasem.cnws防火墙开启的情况下,遇到的错误如下:无法与

基于Python开发批量提取Excel图片的小工具

《基于Python开发批量提取Excel图片的小工具》这篇文章主要为大家详细介绍了如何使用Python中的openpyxl库开发一个小工具,可以实现批量提取Excel图片,有需要的小伙伴可以参考一下... 目前有一个需求,就是批量读取当前目录下所有文件夹里的Excel文件,去获取出Excel文件中的图片,并

Python解析器安装指南分享(Mac/Windows/Linux)

《Python解析器安装指南分享(Mac/Windows/Linux)》:本文主要介绍Python解析器安装指南(Mac/Windows/Linux),具有很好的参考价值,希望对大家有所帮助,如有... 目NMNkN录1js. 安装包下载1.1 python 下载官网2.核心安装方式3. MACOS 系统安

Windows系统下如何查找JDK的安装路径

《Windows系统下如何查找JDK的安装路径》:本文主要介绍Windows系统下如何查找JDK的安装路径,文中介绍了三种方法,分别是通过命令行检查、使用verbose选项查找jre目录、以及查看... 目录一、确认是否安装了JDK二、查找路径三、另外一种方式如果很久之前安装了JDK,或者在别人的电脑上,想

基于Python开发PDF转PNG的可视化工具

《基于Python开发PDF转PNG的可视化工具》在数字文档处理领域,PDF到图像格式的转换是常见需求,本文介绍如何利用Python的PyMuPDF库和Tkinter框架开发一个带图形界面的PDF转P... 目录一、引言二、功能特性三、技术架构1. 技术栈组成2. 系统架构javascript设计3.效果图

Windows命令之tasklist命令用法详解(Windows查看进程)

《Windows命令之tasklist命令用法详解(Windows查看进程)》tasklist命令显示本地计算机或远程计算机上当前正在运行的进程列表,命令结合筛选器一起使用,可以按照我们的需求进行过滤... 目录命令帮助1、基本使用2、执行原理2.1、tasklist命令无法使用3、筛选器3.1、根据PID