您的位置:首页 > 其它

搞明白IRP这个东东了

2009-12-12 11:34 239 查看
按照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 返回。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: