Windows驱动之CM_RESOURCE_LIST

文章目录

  • Windows驱动之CM_RESOURCE_LIST
    • 1. CM_RESOURCE_LIST
    • 2. 资源提取

Windows驱动之CM_RESOURCE_LIST

当总线检测到了硬件设备插入之后,就会产生电信号的中断,导致驱动程序调用IoInvalidDeviceRelations,这个时候PNP管理器就会向总线驱动发送IRP_MN_QUERY_DEVICE_RELATION的请求,总线驱动接收到这个请求之后,就会开始枚举自己的子设备,随着IRP_MN_QUERY_DEVICE_RELATION的返回值返回子设备信息。

PNP管理器查询到了子设备信息之后,针对每个子设备,开始调用IRP_MN_QUERY_ID, IRP_MN_QUERY_DEVICE_TEXT来获取设备的描述信息。

接着PNP会继续调用IRP_MN_QUERY_RESOURCESIRP_MN_QUERY_RESOURCE_REQUIREMENTS来获取资源,然后加载设备驱动,并调用IRP_MN_FILTER_RESOURCE_REQUIREMENTS来过滤自己的资源信息。

一切事情准备妥当之后,开始调用IRP_MN_START_DEVICE启动设备,这个IRP将会携带PNP管理器给设备分配的资源信息,那么这个资源是什么样的呢?

1. CM_RESOURCE_LIST

我们看一下IRP_MN_START_DEVICE这个IRP附带的参数信息。

VOID
NTAPI
PnpStartDevice()
{
    //...
    RtlZeroMemory(&Stack, sizeof(IO_STACK_LOCATION));
    Stack.MajorFunction = IRP_MJ_PNP;
    Stack.MinorFunction = IRP_MN_START_DEVICE;

    Stack.Parameters.StartDevice.AllocatedResources =
         DeviceNode->ResourceList;
    Stack.Parameters.StartDevice.AllocatedResourcesTranslated =
         DeviceNode->ResourceListTranslated;

    Status = IopSynchronousCall(DeviceObject, &Stack, &Dummy);
    //...
}

从这里可以看到有两个资源:

  1. Stack.Parameters.StartDevice.AllocatedResources 适应硬件使用的资源信息。
  2. Stack.Parameters.StartDevice.AllocatedResourcesTranslated适应系统使用资源信息。

其中资源的结构如下:

typedef struct _CM_RESOURCE_LIST {
  ULONG                       Count;
  CM_FULL_RESOURCE_DESCRIPTOR List[1];
} CM_RESOURCE_LIST, *PCM_RESOURCE_LIST;

typedef struct _CM_FULL_RESOURCE_DESCRIPTOR {
  INTERFACE_TYPE           InterfaceType;
  ULONG                    BusNumber;
  CM_PARTIAL_RESOURCE_LIST PartialResourceList;
} CM_FULL_RESOURCE_DESCRIPTOR, *PCM_FULL_RESOURCE_DESCRIPTOR;

typedef struct _CM_PARTIAL_RESOURCE_LIST {
  USHORT                         Version;
  USHORT                         Revision;
  ULONG                          Count;
  CM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptors[1];
} CM_PARTIAL_RESOURCE_LIST, *PCM_PARTIAL_RESOURCE_LIST;

typedef struct _CM_PARTIAL_RESOURCE_DESCRIPTOR {
    UCHAR  Type;
    UCHAR  ShareDisposition;
    USHORT  Flags;
    union {
        struct {
            PHYSICAL_ADDRESS  Start;
            ULONG  Length;
        } Generic;
        struct {
            PHYSICAL_ADDRESS  Start;
            ULONG  Length;
        } Port;
        struct {
#if defined(NT_PROCESSOR_GROUPS)
            USHORT  Level;
            USHORT  Group;
#else
            ULONG  Level;
#endif
            ULONG  Vector;
            KAFFINITY Affinity;
        } Interrupt;

        // This member exists only on Windows Vista and later
        struct {
            union {
               struct {
#if defined(NT_PROCESSOR_GROUPS)
                   USHORT  Group;
#else
                   USHORT  Reserved;
#endif
                   USHORT  MessageCount;
                   ULONG  Vector;
                   KAFFINITY  Affinity;
               } Raw;

               struct {
#if defined(NT_PROCESSOR_GROUPS)
                   USHORT  Level;
                   USHORT  Group;
#else
                   ULONG  Level;
#endif
                   ULONG  Vector;
                   KAFFINITY  Affinity;
               } Translated;        
            };
        } MessageInterrupt;
        struct {
            PHYSICAL_ADDRESS  Start;
            ULONG  Length;
        } Memory;
        struct {
            ULONG  Channel;
            ULONG  Port;
            ULONG  Reserved1;
        } Dma;
        struct {  
            ULONG Channel;  
            ULONG RequestLine;  
            UCHAR TransferWidth;  
            UCHAR Reserved1;  
            UCHAR Reserved2;  
            UCHAR Reserved3;  
        } DmaV3;
        struct {
            ULONG  Data[3];
        } DevicePrivate;
        struct {
            ULONG  Start;
            ULONG  Length;
            ULONG  Reserved;
        } BusNumber;
        struct {
            ULONG  DataSize;
            ULONG  Reserved1;
            ULONG  Reserved2;
        } DeviceSpecificData;
        // The following structures provide support for memory-mapped
        // IO resources greater than MAXULONG
        struct {
            PHYSICAL_ADDRESS  Start;
            ULONG  Length40;
        } Memory40;
        struct {
            PHYSICAL_ADDRESS  Start;
            ULONG  Length48;
        } Memory48;
        struct {
            PHYSICAL_ADDRESS  Start;
            ULONG  Length64;
        } Memory64;
        struct {
            UCHAR Class;
            UCHAR Type;
            UCHAR Reserved1;
            UCHAR Reserved2;
            ULONG IdLowPart;
            ULONG IdHighPart;
        } Connection;          
    } u;
} CM_PARTIAL_RESOURCE_DESCRIPTOR, *PCM_PARTIAL_RESOURCE_DESCRIPTOR;

从这里看CM_PARTIAL_RESOURCE_DESCRIPTOR这个才是一个资源的真实描述,其他的,只是对于这个资源的管理信息,这个结构可以导致描述如下:

Windows驱动之CM_RESOURCE_LIST_第1张图片
最终的结构信息是最右所示的信息,如果我们查看这个结构体的话,类似依次从左往右展开。

2. 资源提取

IRP_MN_START_DEVICE响应函数中,我们就可以提取这些资源了,资源的提取伪代码如下:

NTSTATUS
StartDevice(PDEVICE_OBJECT fdo, PCM_PARTIAL_RESOURCE_LIST raw, PCM_PARTIAL_RESOURCE_LIST translated)
{
	PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;
	PCM_PARTIAL_RESOURCE_DESCRIPTOR resource = translated->PartialDescriptors;
	ULONG nres = translated->Count;
	//								
	for (ULONG i = 0; i < nres; ++i, ++resource)
	{
		switch (resource->Type)
		{
		case CmResourceTypePort:
			//
			break;
		case CmResourceTypeInterrupt:
			//
			break;
		case CmResourceTypeMemory:
			//
			break;
		case CmResourceTypeDma:
			//
			break;
		}
	}
	//						
	IoSetDeviceInterfaceState(&pdx->ifname, TRUE);
}

总共包括四种资源,分别为:

资源类型 处理概述
Port 可能映射端口范围;应在设备扩展中保存端口范围基址
Memory 映射内存范围;应在设备扩展中保存内存范围基址
Dma 调用IoGetDmaAdapter函数创建适配器对象
Interrupt 调用IoConnectInterrupt函数创建中断对象,中断对象指向ISR(中断服务例程)

其中,Memory的传输需要CPU的参与,所以适合传输少量数据;而DMA使用的是DMA控制器,这样的话DMA控制器直接控制数据传输,无需CPU参与,使用大量的数据传输,MDA的模型如下:
Windows驱动之CM_RESOURCE_LIST_第2张图片

你可能感兴趣的:(Windows驱动开发)