搞明白IRP这个东东了

时间:2022-09-08 15:08:59

按照ms的步骤走了一遍,搞明白了,整点笔记记录一下,别忘了。

IRP的结构:

  1. typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _IRP {  
  2.     CSHORT Type;  
  3.     USHORT Size;  
  4.   
  5.     //  
  6.     // Define the common fields used to control the IRP.  
  7.     //  
  8.   
  9.     //  
  10.     // Define a pointer to the Memory Descriptor List (MDL) for this I/O  
  11.     // request.  This field is only used if the I/O is "direct I/O".  
  12.     //  
  13.   
  14.     PMDL MdlAddress;  
  15.   
  16.     //  
  17.     // Flags word - used to remember various flags.  
  18.     //  
  19.   
  20.     ULONG Flags;  
  21.   
  22.     //  
  23.     // The following union is used for one of three purposes:  
  24.     //  
  25.     //    1. This IRP is an associated IRP.  The field is a pointer to a master  
  26.     //       IRP.  
  27.     //  
  28.     //    2. This is the master IRP.  The field is the count of the number of  
  29.     //       IRPs which must complete (associated IRPs) before the master can  
  30.     //       complete.  
  31.     //  
  32.     //    3. This operation is being buffered and the field is the address of  
  33.     //       the system space buffer.  
  34.     //  
  35.   
  36.     union {  
  37.         struct _IRP *MasterIrp;  
  38.         __volatile LONG IrpCount;  
  39.         PVOID SystemBuffer;  
  40.     } AssociatedIrp;  
  41.   
  42.     //  
  43.     // Thread list entry - allows queueing the IRP to the thread pending I/O  
  44.     // request packet list.  
  45.     //  
  46.   
  47.     LIST_ENTRY ThreadListEntry;  
  48.   
  49.     //  
  50.     // I/O status - final status of operation.  
  51.     //  
  52.   
  53.     IO_STATUS_BLOCK IoStatus;  
  54.   
  55.     //  
  56.     // Requestor mode - mode of the original requestor of this operation.  
  57.     //  
  58.   
  59.     KPROCESSOR_MODE RequestorMode;  
  60.   
  61.     //  
  62.     // Pending returned - TRUE if pending was initially returned as the  
  63.     // status for this packet.  
  64.     //  
  65.   
  66.     BOOLEAN PendingReturned;  
  67.   
  68.     //  
  69.     // Stack state information.  
  70.     //  
  71.   
  72.     CHAR StackCount;  
  73.     CHAR CurrentLocation;  
  74.   
  75.     //  
  76.     // Cancel - packet has been canceled.  
  77.     //  
  78.   
  79.     BOOLEAN Cancel;  
  80.   
  81.     //  
  82.     // Cancel Irql - Irql at which the cancel spinlock was acquired.  
  83.     //  
  84.   
  85.     KIRQL CancelIrql;  
  86.   
  87.     //  
  88.     // ApcEnvironment - Used to save the APC environment at the time that the  
  89.     // packet was initialized.  
  90.     //  
  91.   
  92.     CCHAR ApcEnvironment;  
  93.   
  94.     //  
  95.     // Allocation control flags.  
  96.     //  
  97.   
  98.     UCHAR AllocationFlags;  
  99.   
  100.     //  
  101.     // User parameters.  
  102.     //  
  103.   
  104.     PIO_STATUS_BLOCK UserIosb;  
  105.     PKEVENT UserEvent;  
  106.     union {  
  107.         struct {  
  108.             union {  
  109.                 PIO_APC_ROUTINE UserApcRoutine;  
  110.                 PVOID IssuingProcess;  
  111.             };  
  112.             PVOID UserApcContext;  
  113.         } AsynchronousParameters;  
  114.         LARGE_INTEGER AllocationSize;  
  115.     } Overlay;  
  116.   
  117.     //  
  118.     // CancelRoutine - Used to contain the address of a cancel routine supplied  
  119.     // by a device driver when the IRP is in a cancelable state.  
  120.     //  
  121.   
  122.     __volatile PDRIVER_CANCEL CancelRoutine;  
  123.   
  124.     //  
  125.     // Note that the UserBuffer parameter is outside of the stack so that I/O  
  126.     // completion can copy data back into the user's address space without  
  127.     // having to know exactly which service was being invoked.  The length  
  128.     // of the copy is stored in the second half of the I/O status block. If  
  129.     // the UserBuffer field is NULL, then no copy is performed.  
  130.     //  
  131.   
  132.     PVOID UserBuffer;  
  133.   
  134.     //  
  135.     // Kernel structures  
  136.     //  
  137.     // The following section contains kernel structures which the IRP needs  
  138.     // in order to place various work information in kernel controller system  
  139.     // queues.  Because the size and alignment cannot be controlled, they are  
  140.     // placed here at the end so they just hang off and do not affect the  
  141.     // alignment of other fields in the IRP.  
  142.     //  
  143.   
  144.     union {  
  145.   
  146.         struct {  
  147.   
  148.             union {  
  149.   
  150.                 //  
  151.                 // DeviceQueueEntry - The device queue entry field is used to  
  152.                 // queue the IRP to the device driver device queue.  
  153.                 //  
  154.   
  155.                 KDEVICE_QUEUE_ENTRY DeviceQueueEntry;  
  156.   
  157.                 struct {  
  158.   
  159.                     //  
  160.                     // The following are available to the driver to use in  
  161.                     // whatever manner is desired, while the driver owns the  
  162.                     // packet.  
  163.                     //  
  164.   
  165.                     PVOID DriverContext[4];  
  166.   
  167.                 } ;  
  168.   
  169.             } ;  
  170.   
  171.             //  
  172.             // Thread - pointer to caller's Thread Control Block.  
  173.             //  
  174.   
  175.             PETHREAD Thread;  
  176.   
  177.             //  
  178.             // Auxiliary buffer - pointer to any auxiliary buffer that is  
  179.             // required to pass information to a driver that is not contained  
  180.             // in a normal buffer.  
  181.             //  
  182.   
  183.             PCHAR AuxiliaryBuffer;  
  184.   
  185.             //  
  186.             // The following unnamed structure must be exactly identical  
  187.             // to the unnamed structure used in the minipacket header used  
  188.             // for completion queue entries.  
  189.             //  
  190.   
  191.             struct {  
  192.   
  193.                 //  
  194.                 // List entry - used to queue the packet to completion queue, among  
  195.                 // others.  
  196.                 //  
  197.   
  198.                 LIST_ENTRY ListEntry;  
  199.   
  200.                 union {  
  201.   
  202.                     //  
  203.                     // Current stack location - contains a pointer to the current  
  204.                     // IO_STACK_LOCATION structure in the IRP stack.  This field  
  205.                     // should never be directly accessed by drivers.  They should  
  206.                     // use the standard functions.  
  207.                     //  
  208.   
  209.                     struct _IO_STACK_LOCATION *CurrentStackLocation;  
  210.   
  211.                     //  
  212.                     // Minipacket type.  
  213.                     //  
  214.   
  215.                     ULONG PacketType;  
  216.                 };  
  217.             };  
  218.   
  219.             //  
  220.             // Original file object - pointer to the original file object  
  221.             // that was used to open the file.  This field is owned by the  
  222.             // I/O system and should not be used by any other drivers.  
  223.             //  
  224.   
  225.             PFILE_OBJECT OriginalFileObject;  
  226.   
  227.         } Overlay;  
  228.   
  229.         //  
  230.         // APC - This APC control block is used for the special kernel APC as  
  231.         // well as for the caller's APC, if one was specified in the original  
  232.         // argument list.  If so, then the APC is reused for the normal APC for  
  233.         // whatever mode the caller was in and the "special" routine that is  
  234.         // invoked before the APC gets control simply deallocates the IRP.  
  235.         //  
  236.   
  237.         KAPC Apc;  
  238.   
  239.         //  
  240.         // CompletionKey - This is the key that is used to distinguish  
  241.         // individual I/O operations initiated on a single file handle.  
  242.         //  
  243.   
  244.         PVOID CompletionKey;  
  245.   
  246.     } Tail;  
  247.   
  248. } 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的部分实现

  1. Irp->CurrentLocation--;  
  2.   
  3.    if (Irp->CurrentLocation <= 0) {  
  4.        KiBugCheck3( NO_MORE_IRP_STACK_LOCATIONS, (ULONG_PTR) Irp, 0, 0 );  
  5.    }  
  6.   
  7.    irpSp = IoGetNextIrpStackLocation( Irp );  
  8.    Irp->Tail.Overlay.CurrentStackLocation = irpSp;  
  9.   
  10.    //  
  11.    // Save a pointer to the device object for this request so that it can  
  12.    // be used later in completion.  
  13.    //  
  14.   
  15.    irpSp->DeviceObject = DeviceObject;  
  16.   
  17.   
  18.    //  
  19.    // Invoke the driver at its dispatch routine entry point.  
  20.    //  
  21.   
  22.    driverObject = DeviceObject->DriverObject;  
  23.   
  24.    //  
  25.    // Prevent the driver from unloading.  
  26.    //  
  27.   
  28.   
  29.    status = driverObject->MajorFunction[irpSp->MajorFunction]( DeviceObject,  
  30.                                                              Irp );  

 

可以看到当calldriver时候,IoCallDriver 会将当前栈-1 ,同时将下一个STACK_LOCATION  最为当前栈单元,通过设备对象找到其关联的驱动对象,调用MJ函数,IoCallDriver 返回。