Windows驅動之CM_RESOURCE_LIST

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這個纔是一個資源的真實描述,其他的,只是對於這個資源的管理信息,這個結構可以導致描述如下:

在這裏插入圖片描述
最終的結構信息是最右所示的信息,如果我們查看這個結構體的話,類似依次從左往右展開。

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;
	//<local variable declarations>								
	for (ULONG i = 0; i < nres; ++i, ++resource)
	{
		switch (resource->Type)
		{
		case CmResourceTypePort:
			//<save port info in local variables>
			break;
		case CmResourceTypeInterrupt:
			//<save interrupt info in local variables>
			break;
		case CmResourceTypeMemory:
			//<save memory info in local variables>
			break;
		case CmResourceTypeDma:
			//<save DMA info in local variables>
			break;
		}
	}
	//<use local variables to configure driver & hardware>						
	IoSetDeviceInterfaceState(&pdx->ifname, TRUE);
}

總共包括四種資源,分別爲:

資源類型 處理概述
Port 可能映射端口範圍;應在設備擴展中保存端口範圍基址
Memory 映射內存範圍;應在設備擴展中保存內存範圍基址
Dma 調用IoGetDmaAdapter函數創建適配器對象
Interrupt 調用IoConnectInterrupt函數創建中斷對象,中斷對象指向ISR(中斷服務例程)

其中,Memory的傳輸需要CPU的參與,所以適合傳輸少量數據;而DMA使用的是DMA控制器,這樣的話DMA控制器直接控制數據傳輸,無需CPU參與,使用大量的數據傳輸,MDA的模型如下:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章