按照ms的步骤走了一遍,搞明白了,整点笔记记录一下,别忘了。
IRP的结构:
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的部分实现
可以看到当calldriver时候,IoCallDriver 会将当前栈-1 ,同时将下一个STACK_LOCATION 最为当前栈单元,通过设备对象找到其关联的驱动对象,调用MJ函数,IoCallDriver 返回。