搞明白IRP这个东东了

按照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 返回。

 

 

 

你可能感兴趣的:(windows,kernel)