理解IO_STACK_LOCATION是驱动入门的一个重要知识点,该结构体是理解驱动工作过程的核心知识之一。
闲话不多时,直接看代码,看完下面几段windows源码,你要还不能理解,直接来找我。
首先看几个宏定义:
#define IoGetNextIrpStackLocation( Irp ) (\
(Irp)->Tail.Overlay.CurrentStackLocation - 1 )
#define IoGetCurrentIrpStackLocation( Irp ) ( (Irp)->Tail.Overlay.CurrentStackLocation )
#define IoSkipCurrentIrpStackLocation( Irp ) \
(Irp)->CurrentLocation++; \
(Irp)->Tail.Overlay.CurrentStackLocation++;
#define IoCopyCurrentIrpStackLocationToNext( Irp ) { \
PIO_STACK_LOCATION irpSp; \
PIO_STACK_LOCATION nextIrpSp; \
irpSp = IoGetCurrentIrpStackLocation( (Irp) ); \
nextIrpSp = IoGetNextIrpStackLocation( (Irp) ); \
RtlCopyMemory( nextIrpSp, irpSp, FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine)); \
nextIrpSp->Control = 0; }
#define IoSizeOfIrp( StackSize ) \
((USHORT) (sizeof( IRP ) + ((StackSize) * (sizeof( IO_STACK_LOCATION )))))
define IopInitializeIrp( Irp, PacketSize, StackSize ) { \
RtlZeroMemory( (Irp), (PacketSize) ); \
(Irp)->Type = (CSHORT) IO_TYPE_IRP; \
(Irp)->Size = (USHORT) ((PacketSize)); \
(Irp)->StackCount = (CCHAR) ((StackSize)); \
(Irp)->CurrentLocation = (CCHAR) ((StackSize) + 1); \
(Irp)->ApcEnvironment = KeGetCurrentApcEnvironment(); \
InitializeListHead (&(Irp)->ThreadListEntry); \
(Irp)->Tail.Overlay.CurrentStackLocation = \
((PIO_STACK_LOCATION) ((UCHAR *) (Irp) + \
sizeof( IRP ) + \
( (StackSize) * sizeof( IO_STACK_LOCATION )))); }
PIRP
IopAllocateIrpPrivate(
IN CCHAR StackSize,
IN BOOLEAN ChargeQuota
)
{
//...
packetSize = IoSizeOfIrp(StackSize);
allocateSize = packetSize;
//...
irp = ExAllocatePoolWithTag(NonPagedPool, allocateSize, ' prI');
//...
IopInitializeIrp(irp, packetSize, StackSize);
//...
}
#define IoSetNextIrpStackLocation(Irp) \
{ \
Irp->CurrentLocation--;\ //序号向下滑动一项
Irp->Tail.Overlay.CurrentStackLocation--;\ //数组元素指针也向下滑动一项
}
#define IoGetCurrentIrpStackLocation(irp) irp->Tail.Overlay.CurrentStackLocation
#define IoGetNextIrpStackLocation(irp) irp->Tail.Overlay.CurrentStackLocation – 1
其中的IopAllocateIrpPrivate函数如下:
PIRP
IopAllocateIrpPrivate(
IN CCHAR StackSize,
IN BOOLEAN ChargeQuota
)
/*++
Routine Description:
This routine allocates an I/O Request Packet from the system nonpaged pool.
The packet will be allocated to contain StackSize stack locations. The IRP
will also be initialized.
Arguments:
StackSize - Specifies the maximum number of stack locations required.
ChargeQuota - Specifies whether quota should be charged against thread.
Return Value:
The function value is the address of the allocated/initialized IRP,
or NULL if one could not be allocated.
--*/
{
USHORT allocateSize;
UCHAR fixedSize;
PIRP irp;
UCHAR lookasideAllocation;
PNPAGED_LOOKASIDE_LIST lookasideList;
UCHAR mustSucceed;
PP_NPAGED_LOOKASIDE_NUMBER number;
USHORT packetSize;
PKPRCB prcb;
//
// If the size of the packet required is less than or equal to those on
// the lookaside lists, then attempt to allocate the packet from the
// lookaside lists.
//IopLargeIrpStackLocations的值是8
irp = NULL;
fixedSize = 0;
mustSucceed = 0;
packetSize = IoSizeOfIrp(StackSize);//((USHORT) (sizeof( IRP ) + ((StackSize) * (sizeof( IO_STACK_LOCATION )))))注意这里是Irp大小+设备栈大小的总大小
allocateSize = packetSize;
//如果栈层数小于等于8又不计较配额浪费,那么就从预置的irp容器分配
if ((StackSize <= (CCHAR)IopLargeIrpStackLocations) &&
((ChargeQuota == FALSE) || (IopLookasideIrpFloat < IopLookasideIrpLimit))) {
fixedSize = IRP_ALLOCATED_FIXED_SIZE;
number = LookasideSmallIrpList;
if (StackSize != 1) {
allocateSize = IoSizeOfIrp((CCHAR)IopLargeIrpStackLocations);//对齐8个栈层大小
number = LookasideLargeIrpList;
}
prcb = KeGetCurrentPrcb();
lookasideList = prcb->PPLookasideList[number].P;//尝试从该容器的P链表中分配出一个irp
lookasideList->L.TotalAllocates += 1;//该链表总的分配请求计数++
irp = (PIRP)ExInterlockedPopEntrySList(&lookasideList->L.ListHead,
&lookasideList->Lock);//分配内存
if (irp == NULL) {//如果分配失败
lookasideList->L.AllocateMisses += 1;//该链表的分配失败计数++
//再尝试从该容器的L链表中分配出一个irp
lookasideList = prcb->PPLookasideList[number].L;
lookasideList->L.TotalAllocates += 1;
irp = (PIRP)ExInterlockedPopEntrySList(&lookasideList->L.ListHead,
&lookasideList->Lock);
}
}
//
// If an IRP was not allocated from the lookaside list, then allocate
// the packet from nonpaged pool and charge quota if requested.
//
lookasideAllocation = 0;
if (!irp) {//如果仍然分配失败或者尚未分配
if (fixedSize != 0) {
lookasideList->L.AllocateMisses += 1;
}
//
// There are no free packets on the lookaside list, or the packet is
// too large to be allocated from one of the lists, so it must be
// allocated from nonpaged pool. If quota is to be charged, charge it
// against the current process. Otherwise, allocate the pool normally.
//
if (ChargeQuota) {
try {
irp = ExAllocatePoolWithQuotaTag(NonPagedPool, allocateSize,' prI');//直接从非分页池中分配
} except(EXCEPTION_EXECUTE_HANDLER) {
NOTHING;
}
} else {
//
// Attempt to allocate the pool from non-paged pool. If this
// fails, and the caller's previous mode was kernel then allocate
// the pool as must succeed.
//
irp = ExAllocatePoolWithTag(NonPagedPool, allocateSize, ' prI');
if (!irp) {
mustSucceed = IRP_ALLOCATED_MUST_SUCCEED;
if (KeGetPreviousMode() == KernelMode ) {
irp = ExAllocatePoolWithTag(NonPagedPoolMustSucceed,
allocateSize,
' prI');
}
}
}
if (!irp) {
return NULL;
}
} else {
if (ChargeQuota != FALSE) {
lookasideAllocation = IRP_LOOKASIDE_ALLOCATION;
InterlockedIncrement( &IopLookasideIrpFloat );
}
ChargeQuota = FALSE;
}
//
// Initialize the packet.
//
//分配完irp后,做一些基本字段的初始化
IopInitializeIrp(irp, packetSize, StackSize);
irp->AllocationFlags = (fixedSize | lookasideAllocation | mustSucceed);
if (ChargeQuota) {
irp->AllocationFlags |= IRP_QUOTA_CHARGED;
}
return irp;
}
#define IoSizeOfIrp(_StackSize) sizeof(IRP) + _StackSize * sizeof(IO_STACK_LOCATION)
关于IoCallDriver函数的相关源码如下:
#define IoCallDriver(a,b) \
IofCallDriver(a,b)
NTSTATUS
FASTCALL
IofCallDriver(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
)
{
if (pIofCallDriver != NULL) {
//
// This routine will either jump immediately to IovCallDriver or
// IoPerfCallDriver.
//
return pIofCallDriver(DeviceObject, Irp, _ReturnAddress());
}
return IopfCallDriver(DeviceObject, Irp);
}
extern PIO_CALL_DRIVER pIofCallDriver;
typedef
NTSTATUS
(FASTCALL *PIO_CALL_DRIVER) (
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp,
IN PVOID ReturnAddress
);
NTSTATUS
FORCEINLINE
IopfCallDriver(
IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp
)
/*++
Routine Description:
This routine is invoked to pass an I/O Request Packet (IRP) to another
driver at its dispatch routine.
Arguments:
DeviceObject - Pointer to device object to which the IRP should be passed.
Irp - Pointer to IRP for request.
Return Value:
Return status from driver's dispatch routine.
--*/
{
PIO_STACK_LOCATION irpSp;
PDRIVER_OBJECT driverObject;
NTSTATUS status;
//
// Ensure that this is really an I/O Request Packet.
//
ASSERT( Irp->Type == IO_TYPE_IRP );
//
// Update the IRP stack to point to the next location. //可见Irp的那个数组标号越大表示越顶层设备
//
Irp->CurrentLocation--;
if (Irp->CurrentLocation <= 0) {
KiBugCheck3( NO_MORE_IRP_STACK_LOCATIONS, (ULONG_PTR) Irp, 0, 0 );
}
irpSp = IoGetNextIrpStackLocation( Irp );
Irp->Tail.Overlay.CurrentStackLocation = irpSp;
//
// Save a pointer to the device object for this request so that it can
// be used later in completion.
//
irpSp->DeviceObject = DeviceObject;
//
// Invoke the driver at its dispatch routine entry point.
//
driverObject = DeviceObject->DriverObject;
//
// Prevent the driver from unloading.
// 用给定的驱动对象进行调用
status = driverObject->MajorFunction[irpSp->MajorFunction]( DeviceObject,
Irp );
return status;
}
看一下IO_STACK_LOCATION的定义:
在windbg中查看此结构的命令是:dt nt!_IO_STACK_LOCATION
typedef struct _IO_STACK_LOCATION {
UCHAR MajorFunction;
UCHAR MinorFunction;
UCHAR Flags;
UCHAR Control;
union {
struct {
PIO_SECURITY_CONTEXT SecurityContext;
ULONG Options;
USHORT POINTER_ALIGNMENT FileAttributes;
USHORT ShareAccess;
ULONG POINTER_ALIGNMENT EaLength;
} Create;
struct {
PIO_SECURITY_CONTEXT SecurityContext;
ULONG Options;
USHORT POINTER_ALIGNMENT Reserved;
USHORT ShareAccess;
PNAMED_PIPE_CREATE_PARAMETERS Parameters;
} CreatePipe;
struct {
PIO_SECURITY_CONTEXT SecurityContext;
ULONG Options;
USHORT POINTER_ALIGNMENT Reserved;
USHORT ShareAccess;
PMAILSLOT_CREATE_PARAMETERS Parameters;
} CreateMailslot;
struct {
ULONG Length;
ULONG POINTER_ALIGNMENT Key;
ULONG Flags;
LARGE_INTEGER ByteOffset;
} Read;
struct {
ULONG Length;
ULONG POINTER_ALIGNMENT Key;
ULONG Flags;
LARGE_INTEGER ByteOffset;
} Write;
struct {
ULONG Length;
PUNICODE_STRING FileName;
FILE_INFORMATION_CLASS FileInformationClass;
ULONG POINTER_ALIGNMENT FileIndex;
} QueryDirectory;
struct {
ULONG Length;
ULONG POINTER_ALIGNMENT CompletionFilter;
} NotifyDirectory;
struct {
ULONG Length;
ULONG POINTER_ALIGNMENT CompletionFilter;
DIRECTORY_NOTIFY_INFORMATION_CLASS POINTER_ALIGNMENT DirectoryNotifyInformationClass;
} NotifyDirectoryEx;
struct {
ULONG Length;
FILE_INFORMATION_CLASS POINTER_ALIGNMENT FileInformationClass;
} QueryFile;
struct {
ULONG Length;
FILE_INFORMATION_CLASS POINTER_ALIGNMENT FileInformationClass;
PFILE_OBJECT FileObject;
union {
struct {
BOOLEAN ReplaceIfExists;
BOOLEAN AdvanceOnly;
};
ULONG ClusterCount;
HANDLE DeleteHandle;
};
} SetFile;
struct {
ULONG Length;
PVOID EaList;
ULONG EaListLength;
ULONG POINTER_ALIGNMENT EaIndex;
} QueryEa;
struct {
ULONG Length;
} SetEa;
struct {
ULONG Length;
FS_INFORMATION_CLASS POINTER_ALIGNMENT FsInformationClass;
} QueryVolume;
struct {
ULONG Length;
FS_INFORMATION_CLASS POINTER_ALIGNMENT FsInformationClass;
} SetVolume;
struct {
ULONG OutputBufferLength;
ULONG POINTER_ALIGNMENT InputBufferLength;
ULONG POINTER_ALIGNMENT FsControlCode;
PVOID Type3InputBuffer;
} FileSystemControl;
struct {
PLARGE_INTEGER Length;
ULONG POINTER_ALIGNMENT Key;
LARGE_INTEGER ByteOffset;
} LockControl;
struct {
ULONG OutputBufferLength;
ULONG POINTER_ALIGNMENT InputBufferLength;
ULONG POINTER_ALIGNMENT IoControlCode;
PVOID Type3InputBuffer;
} DeviceIoControl;
struct {
SECURITY_INFORMATION SecurityInformation;
ULONG POINTER_ALIGNMENT Length;
} QuerySecurity;
struct {
SECURITY_INFORMATION SecurityInformation;
PSECURITY_DESCRIPTOR SecurityDescriptor;
} SetSecurity;
struct {
PVPB Vpb;
PDEVICE_OBJECT DeviceObject;
ULONG OutputBufferLength;
} MountVolume;
struct {
PVPB Vpb;
PDEVICE_OBJECT DeviceObject;
} VerifyVolume;
struct {
struct _SCSI_REQUEST_BLOCK *Srb;
} Scsi;
struct {
ULONG Length;
PSID StartSid;
PFILE_GET_QUOTA_INFORMATION SidList;
ULONG SidListLength;
} QueryQuota;
struct {
ULONG Length;
} SetQuota;
struct {
DEVICE_RELATION_TYPE Type;
} QueryDeviceRelations;
struct {
const GUID *InterfaceType;
USHORT Size;
USHORT Version;
PINTERFACE Interface;
PVOID InterfaceSpecificData;
} QueryInterface;
struct {
PDEVICE_CAPABILITIES Capabilities;
} DeviceCapabilities;
struct {
PIO_RESOURCE_REQUIREMENTS_LIST IoResourceRequirementList;
} FilterResourceRequirements;
struct {
ULONG WhichSpace;
PVOID Buffer;
ULONG Offset;
ULONG POINTER_ALIGNMENT Length;
} ReadWriteConfig;
struct {
BOOLEAN Lock;
} SetLock;
struct {
BUS_QUERY_ID_TYPE IdType;
} QueryId;
struct {
DEVICE_TEXT_TYPE DeviceTextType;
LCID POINTER_ALIGNMENT LocaleId;
} QueryDeviceText;
struct {
BOOLEAN InPath;
BOOLEAN Reserved[3];
DEVICE_USAGE_NOTIFICATION_TYPE POINTER_ALIGNMENT Type;
} UsageNotification;
struct {
SYSTEM_POWER_STATE PowerState;
} WaitWake;
struct {
PPOWER_SEQUENCE PowerSequence;
} PowerSequence;
#if ...
struct {
union {
ULONG SystemContext;
SYSTEM_POWER_STATE_CONTEXT SystemPowerStateContext;
};
POWER_STATE_TYPE POINTER_ALIGNMENT Type;
POWER_STATE POINTER_ALIGNMENT State;
POWER_ACTION POINTER_ALIGNMENT ShutdownType;
} Power;
#else
struct {
ULONG SystemContext;
POWER_STATE_TYPE POINTER_ALIGNMENT Type;
POWER_STATE POINTER_ALIGNMENT State;
POWER_ACTION POINTER_ALIGNMENT ShutdownType;
} Power;
#endif
struct {
PCM_RESOURCE_LIST AllocatedResources;
PCM_RESOURCE_LIST AllocatedResourcesTranslated;
} StartDevice;
struct {
ULONG_PTR ProviderId;
PVOID DataPath;
ULONG BufferSize;
PVOID Buffer;
} WMI;
struct {
PVOID Argument1;
PVOID Argument2;
PVOID Argument3;
PVOID Argument4;
} Others;
} Parameters;
PDEVICE_OBJECT DeviceObject;
PFILE_OBJECT FileObject;
PIO_COMPLETION_ROUTINE CompletionRoutine;
PVOID Context;
} IO_STACK_LOCATION, *PIO_STACK_LOCATION;
微软关于IO_STACK_LOCATION的详细文档:IO_STACK_LOCATION文档
以及IRP结构体(windbg中查看此结构体的命令是dt nt!_IRP):
typedef struct _IRP {
CSHORT Type;
USHORT Size;
PMDL MdlAddress;
ULONG Flags;
union {
struct _IRP *MasterIrp;
__volatile LONG IrpCount;
PVOID SystemBuffer;
} AssociatedIrp;
LIST_ENTRY ThreadListEntry;
IO_STATUS_BLOCK IoStatus;
KPROCESSOR_MODE RequestorMode;
BOOLEAN PendingReturned;
CHAR StackCount;
CHAR CurrentLocation;
BOOLEAN Cancel;
KIRQL CancelIrql;
CCHAR ApcEnvironment;
UCHAR AllocationFlags;
union {
PIO_STATUS_BLOCK UserIosb;
PVOID IoRingContext;
};
PKEVENT UserEvent;
union {
struct {
union {
PIO_APC_ROUTINE UserApcRoutine;
PVOID IssuingProcess;
};
union {
PVOID UserApcContext;
#if ...
_IORING_OBJECT *IoRing;
#else
struct _IORING_OBJECT *IoRing;
#endif
};
} AsynchronousParameters;
LARGE_INTEGER AllocationSize;
} Overlay;
__volatile PDRIVER_CANCEL CancelRoutine;
PVOID UserBuffer;
union {
struct {
union {
KDEVICE_QUEUE_ENTRY DeviceQueueEntry;
struct {
PVOID DriverContext[4];
};
};
PETHREAD Thread;
PCHAR AuxiliaryBuffer;
struct {
LIST_ENTRY ListEntry;
union {
struct _IO_STACK_LOCATION *CurrentStackLocation;
ULONG PacketType;
};
};
PFILE_OBJECT OriginalFileObject;
} Overlay;
KAPC Apc;
PVOID CompletionKey;
} Tail;
} IRP;
微软关于IRP的详细文档:IRP文档
这篇文章讲的也很优秀:WINDOWS驱动之IRP结构
你还有什么疑问吗?