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_RESOURCES
和 IRP_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);
//...
}
從這裏可以看到有兩個資源:
Stack.Parameters.StartDevice.AllocatedResources
適應硬件使用的資源信息。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的模型如下: