按照ms的步骤走了一遍,搞明白了,整点笔记记录一下,别忘了。
IRP的结构:
- typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _IRP {
- CSHORT Type;
- USHORT Size;
- //
- // Define the common fields used to control the IRP.
- //
- //
- // Define a pointer to the Memory Descriptor List (MDL) for this I/O
- // request. This field is only used if the I/O is "direct I/O".
- //
- PMDL MdlAddress;
- //
- // Flags word - used to remember various flags.
- //
- ULONG Flags;
- //
- // The following union is used for one of three purposes:
- //
- // 1. This IRP is an associated IRP. The field is a pointer to a master
- // IRP.
- //
- // 2. This is the master IRP. The field is the count of the number of
- // IRPs which must complete (associated IRPs) before the master can
- // complete.
- //
- // 3. This operation is being buffered and the field is the address of
- // the system space buffer.
- //
- union {
- struct _IRP *MasterIrp;
- __volatile LONG IrpCount;
- PVOID SystemBuffer;
- } AssociatedIrp;
- //
- // Thread list entry - allows queueing the IRP to the thread pending I/O
- // request packet list.
- //
- LIST_ENTRY ThreadListEntry;
- //
- // I/O status - final status of operation.
- //
- IO_STATUS_BLOCK IoStatus;
- //
- // Requestor mode - mode of the original requestor of this operation.
- //
- KPROCESSOR_MODE RequestorMode;
- //
- // Pending returned - TRUE if pending was initially returned as the
- // status for this packet.
- //
- BOOLEAN PendingReturned;
- //
- // Stack state information.
- //
- CHAR StackCount;
- CHAR CurrentLocation;
- //
- // Cancel - packet has been canceled.
- //
- BOOLEAN Cancel;
- //
- // Cancel Irql - Irql at which the cancel spinlock was acquired.
- //
- KIRQL CancelIrql;
- //
- // ApcEnvironment - Used to save the APC environment at the time that the
- // packet was initialized.
- //
- CCHAR ApcEnvironment;
- //
- // Allocation control flags.
- //
- UCHAR AllocationFlags;
- //
- // User parameters.
- //
- PIO_STATUS_BLOCK UserIosb;
- PKEVENT UserEvent;
- union {
- struct {
- union {
- PIO_APC_ROUTINE UserApcRoutine;
- PVOID IssuingProcess;
- };
- PVOID UserApcContext;
- } AsynchronousParameters;
- LARGE_INTEGER AllocationSize;
- } Overlay;
- //
- // CancelRoutine - Used to contain the address of a cancel routine supplied
- // by a device driver when the IRP is in a cancelable state.
- //
- __volatile PDRIVER_CANCEL CancelRoutine;
- //
- // Note that the UserBuffer parameter is outside of the stack so that I/O
- // completion can copy data back into the user's address space without
- // having to know exactly which service was being invoked. The length
- // of the copy is stored in the second half of the I/O status block. If
- // the UserBuffer field is NULL, then no copy is performed.
- //
- PVOID UserBuffer;
- //
- // Kernel structures
- //
- // The following section contains kernel structures which the IRP needs
- // in order to place various work information in kernel controller system
- // queues. Because the size and alignment cannot be controlled, they are
- // placed here at the end so they just hang off and do not affect the
- // alignment of other fields in the IRP.
- //
- union {
- struct {
- union {
- //
- // DeviceQueueEntry - The device queue entry field is used to
- // queue the IRP to the device driver device queue.
- //
- KDEVICE_QUEUE_ENTRY DeviceQueueEntry;
- struct {
- //
- // The following are available to the driver to use in
- // whatever manner is desired, while the driver owns the
- // packet.
- //
- PVOID DriverContext[4];
- } ;
- } ;
- //
- // Thread - pointer to caller's Thread Control Block.
- //
- PETHREAD Thread;
- //
- // Auxiliary buffer - pointer to any auxiliary buffer that is
- // required to pass information to a driver that is not contained
- // in a normal buffer.
- //
- PCHAR AuxiliaryBuffer;
- //
- // The following unnamed structure must be exactly identical
- // to the unnamed structure used in the minipacket header used
- // for completion queue entries.
- //
- struct {
- //
- // List entry - used to queue the packet to completion queue, among
- // others.
- //
- LIST_ENTRY ListEntry;
- union {
- //
- // Current stack location - contains a pointer to the current
- // IO_STACK_LOCATION structure in the IRP stack. This field
- // should never be directly accessed by drivers. They should
- // use the standard functions.
- //
- struct _IO_STACK_LOCATION *CurrentStackLocation;
- //
- // Minipacket type.
- //
- ULONG PacketType;
- };
- };
- //
- // Original file object - pointer to the original file object
- // that was used to open the file. This field is owned by the
- // I/O system and should not be used by any other drivers.
- //
- PFILE_OBJECT OriginalFileObject;
- } Overlay;
- //
- // APC - This APC control block is used for the special kernel APC as
- // well as for the caller's APC, if one was specified in the original
- // argument list. If so, then the APC is reused for the normal APC for
- // whatever mode the caller was in and the "special" routine that is
- // invoked before the APC gets control simply deallocates the IRP.
- //
- KAPC Apc;
- //
- // CompletionKey - This is the key that is used to distinguish
- // individual I/O operations initiated on a single file handle.
- //
- PVOID CompletionKey;
- } Tail;
- } IRP, *PIRP;
1) Irp = IoAllocateIrp( IN CCHAR StackSize, IN BOOLEAN ChargeQuota);
分配一个IRP,看看ms是怎么做的吧:
a. ) packetSize = IoSizeOfIrp(StackSize);
#define IoSizeOfIrp( StackSize ) /
((USHORT) (sizeof( IRP ) + ((StackSize) * (sizeof( IO_STACK_LOCATION )))))
计算 IRP的大小,看来一个IRP包括IRP头本身和stack location × StackSize,
b.) irp = ExAllocatePoolWithTag(NonPagedPool, allocateSize, ' prI');
分别空间,并且是分配在非分页内存池中。
c) IopInitializeIrp(irp, allocateSize, StackSize);
初始化一个IRP。
#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 )))); }
一个IRP初始化是 当前栈要+1,然后指到分配空间的最后,一个IRP初始化之后,在内存中应该是这个样子:
----------------
| |
|IRP头
|
|
|Tail.Overlay.CurrentStackLocation
| |
|
|------------
|
|
|
| |
|
|
|
| |
|
|
---------------- <----------------------|
2) PIO_STACK_LOCATION irpSp = IoGetNextIrpStackLocation(Irp);
#define IoGetNextIrpStackLocation( Irp ) (/
(Irp)->Tail.Overlay.CurrentStackLocation - 1 )
由于刚开始CurrentStackLocation 指向处于分配范围之外的地址,所以此处 -1 得到真正的第一个STACK_LOCATION
3) IoCallDriver(DeviceObject, Irp);
将IRP发送到目的驱动
这是IoCallDriver的部分实现
- 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 );
可以看到当calldriver时候,IoCallDriver 会将当前栈-1 ,同时将下一个STACK_LOCATION 最为当前栈单元,通过设备对象找到其关联的驱动对象,调用MJ函数,IoCallDriver 返回。