关于windows驱动中的IO_STACK_LOCATION

理解IO_STACK_LOCATION是驱动入门的一个重要知识点,该结构体是理解驱动工作过程的核心知识之一。

闲话不多时,直接看代码,看完下面几段windows源码,你要还不能理解,直接来找我。

首先看几个宏定义:


#define IoGetNextIrpStackLocation( Irp ) (\
    (Irp)->Tail.Overlay.CurrentStackLocation - 1 )


#define IoGetCurrentIrpStackLocation( Irp ) ( (Irp)->Tail.Overlay.CurrentStackLocation )

#define IoSkipCurrentIrpStackLocation( Irp ) \
    (Irp)->CurrentLocation++; \
    (Irp)->Tail.Overlay.CurrentStackLocation++;

#define IoCopyCurrentIrpStackLocationToNext( Irp ) { \
    PIO_STACK_LOCATION irpSp; \
    PIO_STACK_LOCATION nextIrpSp; \
    irpSp = IoGetCurrentIrpStackLocation( (Irp) ); \
    nextIrpSp = IoGetNextIrpStackLocation( (Irp) ); \
    RtlCopyMemory( nextIrpSp, irpSp, FIELD_OFFSET(IO_STACK_LOCATION, CompletionRoutine)); \
    nextIrpSp->Control = 0; }


#define IoSizeOfIrp( StackSize ) \
    ((USHORT) (sizeof( IRP ) + ((StackSize) * (sizeof( IO_STACK_LOCATION )))))


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 )))); }


PIRP
IopAllocateIrpPrivate(
    IN CCHAR StackSize,
    IN BOOLEAN ChargeQuota
    )
{
    //...
    packetSize = IoSizeOfIrp(StackSize);
    allocateSize = packetSize;
    //...
    irp = ExAllocatePoolWithTag(NonPagedPool, allocateSize, ' prI');
    //...
    IopInitializeIrp(irp, packetSize, StackSize);
    //...
}




#define IoSetNextIrpStackLocation(Irp) \

{ \

   Irp->CurrentLocation--;\    //序号向下滑动一项

   Irp->Tail.Overlay.CurrentStackLocation--;\     //数组元素指针也向下滑动一项

}


#define IoGetCurrentIrpStackLocation(irp)  irp->Tail.Overlay.CurrentStackLocation



#define IoGetNextIrpStackLocation(irp)  irp->Tail.Overlay.CurrentStackLocation – 1


其中的IopAllocateIrpPrivate函数如下:

PIRP
IopAllocateIrpPrivate(
    IN CCHAR StackSize,
    IN BOOLEAN ChargeQuota
    )

/*++

Routine Description:

    This routine allocates an I/O Request Packet from the system nonpaged pool.
    The packet will be allocated to contain StackSize stack locations.  The IRP
    will also be initialized.

Arguments:

    StackSize - Specifies the maximum number of stack locations required.

    ChargeQuota - Specifies whether quota should be charged against thread.

Return Value:

    The function value is the address of the allocated/initialized IRP,
    or NULL if one could not be allocated.

--*/

{
    USHORT allocateSize;
    UCHAR fixedSize;
    PIRP irp;
    UCHAR lookasideAllocation;
    PNPAGED_LOOKASIDE_LIST lookasideList;
    UCHAR mustSucceed;
    PP_NPAGED_LOOKASIDE_NUMBER number;
    USHORT packetSize;
    PKPRCB prcb;

    //
    // If the size of the packet required is less than or equal to those on
    // the lookaside lists, then attempt to allocate the packet from the
    // lookaside lists.
    //IopLargeIrpStackLocations的值是8

    irp = NULL;
    fixedSize = 0;
    mustSucceed = 0;
    packetSize = IoSizeOfIrp(StackSize);//((USHORT) (sizeof( IRP ) + ((StackSize) * (sizeof( IO_STACK_LOCATION )))))注意这里是Irp大小+设备栈大小的总大小
    allocateSize = packetSize;
    //如果栈层数小于等于8又不计较配额浪费,那么就从预置的irp容器分配
    if ((StackSize <= (CCHAR)IopLargeIrpStackLocations) &&
        ((ChargeQuota == FALSE) || (IopLookasideIrpFloat < IopLookasideIrpLimit))) {
        fixedSize = IRP_ALLOCATED_FIXED_SIZE;
        number = LookasideSmallIrpList;
        if (StackSize != 1) {
            allocateSize = IoSizeOfIrp((CCHAR)IopLargeIrpStackLocations);//对齐8个栈层大小
            number = LookasideLargeIrpList;
        }

        prcb = KeGetCurrentPrcb();
        lookasideList = prcb->PPLookasideList[number].P;//尝试从该容器的P链表中分配出一个irp
        lookasideList->L.TotalAllocates += 1;//该链表总的分配请求计数++
        irp = (PIRP)ExInterlockedPopEntrySList(&lookasideList->L.ListHead,
                                               &lookasideList->Lock);//分配内存
        if (irp == NULL) {//如果分配失败
            lookasideList->L.AllocateMisses += 1;//该链表的分配失败计数++
            //再尝试从该容器的L链表中分配出一个irp
            lookasideList = prcb->PPLookasideList[number].L;
            lookasideList->L.TotalAllocates += 1;
            irp = (PIRP)ExInterlockedPopEntrySList(&lookasideList->L.ListHead,
                                                   &lookasideList->Lock);
        }
    }

    //
    // If an IRP was not allocated from the lookaside list, then allocate
    // the packet from nonpaged pool and charge quota if requested.
    //

    lookasideAllocation = 0;
    if (!irp) {//如果仍然分配失败或者尚未分配
        if (fixedSize != 0) {
            lookasideList->L.AllocateMisses += 1;
        }

        //
        // There are no free packets on the lookaside list, or the packet is
        // too large to be allocated from one of the lists, so it must be
        // allocated from nonpaged pool. If quota is to be charged, charge it
        // against the current process. Otherwise, allocate the pool normally.
        //

        if (ChargeQuota) {
            try {
                irp = ExAllocatePoolWithQuotaTag(NonPagedPool, allocateSize,' prI');//直接从非分页池中分配

            } except(EXCEPTION_EXECUTE_HANDLER) {
                NOTHING;
            }

        } else {

            //
            // Attempt to allocate the pool from non-paged pool.  If this
            // fails, and the caller's previous mode was kernel then allocate
            // the pool as must succeed.
            //

            irp = ExAllocatePoolWithTag(NonPagedPool, allocateSize, ' prI');
            if (!irp) {
                mustSucceed = IRP_ALLOCATED_MUST_SUCCEED;
                if (KeGetPreviousMode() == KernelMode ) {
                    irp = ExAllocatePoolWithTag(NonPagedPoolMustSucceed,
                                                allocateSize,
                                                ' prI');
                }
            }
        }

        if (!irp) {
            return NULL;
        }

    } else {
        if (ChargeQuota != FALSE) {
            lookasideAllocation = IRP_LOOKASIDE_ALLOCATION;
            InterlockedIncrement( &IopLookasideIrpFloat );
        }
        ChargeQuota = FALSE;
    }

    //
    // Initialize the packet.
    //
    //分配完irp后,做一些基本字段的初始化
    IopInitializeIrp(irp, packetSize, StackSize);
    irp->AllocationFlags = (fixedSize | lookasideAllocation | mustSucceed);
    if (ChargeQuota) {
        irp->AllocationFlags |= IRP_QUOTA_CHARGED;
    }

    return irp;
}

#define IoSizeOfIrp(_StackSize)  sizeof(IRP) + _StackSize * sizeof(IO_STACK_LOCATION)

关于IoCallDriver函数的相关源码如下:


#define IoCallDriver(a,b)   \
        IofCallDriver(a,b)

NTSTATUS
FASTCALL
IofCallDriver(
    IN PDEVICE_OBJECT DeviceObject,
    IN OUT PIRP Irp
    )
{
    if (pIofCallDriver != NULL) {

        //
        // This routine will either jump immediately to IovCallDriver or
        // IoPerfCallDriver.
        //
        return pIofCallDriver(DeviceObject, Irp, _ReturnAddress());
    }

    return IopfCallDriver(DeviceObject, Irp);
}

extern PIO_CALL_DRIVER        pIofCallDriver;

typedef
NTSTATUS
(FASTCALL *PIO_CALL_DRIVER) (
    IN      PDEVICE_OBJECT  DeviceObject,
    IN OUT  PIRP            Irp,
    IN      PVOID           ReturnAddress
    );



NTSTATUS
FORCEINLINE
IopfCallDriver(
    IN PDEVICE_OBJECT DeviceObject,
    IN OUT PIRP Irp
    )

/*++

Routine Description:

    This routine is invoked to pass an I/O Request Packet (IRP) to another
    driver at its dispatch routine.

Arguments:

    DeviceObject - Pointer to device object to which the IRP should be passed.

    Irp - Pointer to IRP for request.

Return Value:

    Return status from driver's dispatch routine.

--*/

{
    PIO_STACK_LOCATION irpSp;
    PDRIVER_OBJECT driverObject;
    NTSTATUS status;

    //
    // Ensure that this is really an I/O Request Packet.
    //

    ASSERT( Irp->Type == IO_TYPE_IRP );

    //
    // Update the IRP stack to point to the next location.  //可见Irp的那个数组标号越大表示越顶层设备
    //
    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 );

    return status;
}

看一下IO_STACK_LOCATION的定义:
在windbg中查看此结构的命令是:dt nt!_IO_STACK_LOCATION

typedef struct _IO_STACK_LOCATION {
  UCHAR                  MajorFunction;
  UCHAR                  MinorFunction;
  UCHAR                  Flags;
  UCHAR                  Control;
  union {
    struct {
      PIO_SECURITY_CONTEXT     SecurityContext;
      ULONG                    Options;
      USHORT POINTER_ALIGNMENT FileAttributes;
      USHORT                   ShareAccess;
      ULONG POINTER_ALIGNMENT  EaLength;
    } Create;
    struct {
      PIO_SECURITY_CONTEXT          SecurityContext;
      ULONG                         Options;
      USHORT POINTER_ALIGNMENT      Reserved;
      USHORT                        ShareAccess;
      PNAMED_PIPE_CREATE_PARAMETERS Parameters;
    } CreatePipe;
    struct {
      PIO_SECURITY_CONTEXT        SecurityContext;
      ULONG                       Options;
      USHORT POINTER_ALIGNMENT    Reserved;
      USHORT                      ShareAccess;
      PMAILSLOT_CREATE_PARAMETERS Parameters;
    } CreateMailslot;
    struct {
      ULONG                   Length;
      ULONG POINTER_ALIGNMENT Key;
      ULONG                   Flags;
      LARGE_INTEGER           ByteOffset;
    } Read;
    struct {
      ULONG                   Length;
      ULONG POINTER_ALIGNMENT Key;
      ULONG                   Flags;
      LARGE_INTEGER           ByteOffset;
    } Write;
    struct {
      ULONG                   Length;
      PUNICODE_STRING         FileName;
      FILE_INFORMATION_CLASS  FileInformationClass;
      ULONG POINTER_ALIGNMENT FileIndex;
    } QueryDirectory;
    struct {
      ULONG                   Length;
      ULONG POINTER_ALIGNMENT CompletionFilter;
    } NotifyDirectory;
    struct {
      ULONG                                                Length;
      ULONG POINTER_ALIGNMENT                              CompletionFilter;
      DIRECTORY_NOTIFY_INFORMATION_CLASS POINTER_ALIGNMENT DirectoryNotifyInformationClass;
    } NotifyDirectoryEx;
    struct {
      ULONG                                    Length;
      FILE_INFORMATION_CLASS POINTER_ALIGNMENT FileInformationClass;
    } QueryFile;
    struct {
      ULONG                                    Length;
      FILE_INFORMATION_CLASS POINTER_ALIGNMENT FileInformationClass;
      PFILE_OBJECT                             FileObject;
      union {
        struct {
          BOOLEAN ReplaceIfExists;
          BOOLEAN AdvanceOnly;
        };
        ULONG  ClusterCount;
        HANDLE DeleteHandle;
      };
    } SetFile;
    struct {
      ULONG                   Length;
      PVOID                   EaList;
      ULONG                   EaListLength;
      ULONG POINTER_ALIGNMENT EaIndex;
    } QueryEa;
    struct {
      ULONG Length;
    } SetEa;
    struct {
      ULONG                                  Length;
      FS_INFORMATION_CLASS POINTER_ALIGNMENT FsInformationClass;
    } QueryVolume;
    struct {
      ULONG                                  Length;
      FS_INFORMATION_CLASS POINTER_ALIGNMENT FsInformationClass;
    } SetVolume;
    struct {
      ULONG                   OutputBufferLength;
      ULONG POINTER_ALIGNMENT InputBufferLength;
      ULONG POINTER_ALIGNMENT FsControlCode;
      PVOID                   Type3InputBuffer;
    } FileSystemControl;
    struct {
      PLARGE_INTEGER          Length;
      ULONG POINTER_ALIGNMENT Key;
      LARGE_INTEGER           ByteOffset;
    } LockControl;
    struct {
      ULONG                   OutputBufferLength;
      ULONG POINTER_ALIGNMENT InputBufferLength;
      ULONG POINTER_ALIGNMENT IoControlCode;
      PVOID                   Type3InputBuffer;
    } DeviceIoControl;
    struct {
      SECURITY_INFORMATION    SecurityInformation;
      ULONG POINTER_ALIGNMENT Length;
    } QuerySecurity;
    struct {
      SECURITY_INFORMATION SecurityInformation;
      PSECURITY_DESCRIPTOR SecurityDescriptor;
    } SetSecurity;
    struct {
      PVPB           Vpb;
      PDEVICE_OBJECT DeviceObject;
      ULONG          OutputBufferLength;
    } MountVolume;
    struct {
      PVPB           Vpb;
      PDEVICE_OBJECT DeviceObject;
    } VerifyVolume;
    struct {
      struct _SCSI_REQUEST_BLOCK *Srb;
    } Scsi;
    struct {
      ULONG                       Length;
      PSID                        StartSid;
      PFILE_GET_QUOTA_INFORMATION SidList;
      ULONG                       SidListLength;
    } QueryQuota;
    struct {
      ULONG Length;
    } SetQuota;
    struct {
      DEVICE_RELATION_TYPE Type;
    } QueryDeviceRelations;
    struct {
      const GUID *InterfaceType;
      USHORT     Size;
      USHORT     Version;
      PINTERFACE Interface;
      PVOID      InterfaceSpecificData;
    } QueryInterface;
    struct {
      PDEVICE_CAPABILITIES Capabilities;
    } DeviceCapabilities;
    struct {
      PIO_RESOURCE_REQUIREMENTS_LIST IoResourceRequirementList;
    } FilterResourceRequirements;
    struct {
      ULONG                   WhichSpace;
      PVOID                   Buffer;
      ULONG                   Offset;
      ULONG POINTER_ALIGNMENT Length;
    } ReadWriteConfig;
    struct {
      BOOLEAN Lock;
    } SetLock;
    struct {
      BUS_QUERY_ID_TYPE IdType;
    } QueryId;
    struct {
      DEVICE_TEXT_TYPE       DeviceTextType;
      LCID POINTER_ALIGNMENT LocaleId;
    } QueryDeviceText;
    struct {
      BOOLEAN                                          InPath;
      BOOLEAN                                          Reserved[3];
      DEVICE_USAGE_NOTIFICATION_TYPE POINTER_ALIGNMENT Type;
    } UsageNotification;
    struct {
      SYSTEM_POWER_STATE PowerState;
    } WaitWake;
    struct {
      PPOWER_SEQUENCE PowerSequence;
    } PowerSequence;
#if ...
    struct {
      union {
        ULONG                      SystemContext;
        SYSTEM_POWER_STATE_CONTEXT SystemPowerStateContext;
      };
      POWER_STATE_TYPE POINTER_ALIGNMENT Type;
      POWER_STATE POINTER_ALIGNMENT      State;
      POWER_ACTION POINTER_ALIGNMENT     ShutdownType;
    } Power;
#else
    struct {
      ULONG                              SystemContext;
      POWER_STATE_TYPE POINTER_ALIGNMENT Type;
      POWER_STATE POINTER_ALIGNMENT      State;
      POWER_ACTION POINTER_ALIGNMENT     ShutdownType;
    } Power;
#endif
    struct {
      PCM_RESOURCE_LIST AllocatedResources;
      PCM_RESOURCE_LIST AllocatedResourcesTranslated;
    } StartDevice;
    struct {
      ULONG_PTR ProviderId;
      PVOID     DataPath;
      ULONG     BufferSize;
      PVOID     Buffer;
    } WMI;
    struct {
      PVOID Argument1;
      PVOID Argument2;
      PVOID Argument3;
      PVOID Argument4;
    } Others;
  } Parameters;
  PDEVICE_OBJECT         DeviceObject;
  PFILE_OBJECT           FileObject;
  PIO_COMPLETION_ROUTINE CompletionRoutine;
  PVOID                  Context;
} IO_STACK_LOCATION, *PIO_STACK_LOCATION;

微软关于IO_STACK_LOCATION的详细文档:IO_STACK_LOCATION文档

以及IRP结构体(windbg中查看此结构体的命令是dt nt!_IRP):

typedef struct _IRP {
  CSHORT                    Type;
  USHORT                    Size;
  PMDL                      MdlAddress;
  ULONG                     Flags;
  union {
    struct _IRP     *MasterIrp;
    __volatile LONG IrpCount;
    PVOID           SystemBuffer;
  } AssociatedIrp;
  LIST_ENTRY                ThreadListEntry;
  IO_STATUS_BLOCK           IoStatus;
  KPROCESSOR_MODE           RequestorMode;
  BOOLEAN                   PendingReturned;
  CHAR                      StackCount;
  CHAR                      CurrentLocation;
  BOOLEAN                   Cancel;
  KIRQL                     CancelIrql;
  CCHAR                     ApcEnvironment;
  UCHAR                     AllocationFlags;
  union {
    PIO_STATUS_BLOCK UserIosb;
    PVOID            IoRingContext;
  };
  PKEVENT                   UserEvent;
  union {
    struct {
      union {
        PIO_APC_ROUTINE UserApcRoutine;
        PVOID           IssuingProcess;
      };
      union {
        PVOID                 UserApcContext;
#if ...
        _IORING_OBJECT        *IoRing;
#else
        struct _IORING_OBJECT *IoRing;
#endif
      };
    } AsynchronousParameters;
    LARGE_INTEGER AllocationSize;
  } Overlay;
  __volatile PDRIVER_CANCEL CancelRoutine;
  PVOID                     UserBuffer;
  union {
    struct {
      union {
        KDEVICE_QUEUE_ENTRY DeviceQueueEntry;
        struct {
          PVOID DriverContext[4];
        };
      };
      PETHREAD     Thread;
      PCHAR        AuxiliaryBuffer;
      struct {
        LIST_ENTRY ListEntry;
        union {
          struct _IO_STACK_LOCATION *CurrentStackLocation;
          ULONG                     PacketType;
        };
      };
      PFILE_OBJECT OriginalFileObject;
    } Overlay;
    KAPC  Apc;
    PVOID CompletionKey;
  } Tail;
} IRP;

微软关于IRP的详细文档:IRP文档

这篇文章讲的也很优秀:WINDOWS驱动之IRP结构
你还有什么疑问吗?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值