windows内核开发学习笔记十六: IO_STACK_LOCATION

windows内核开发学习笔记十六: IO_STACK_LOCATION 

IO_STACK_LOCATION 结构定义了一个I/O stack location, 是每个IRP关联的 I/O stack的其中一个入口。 在IRP中的每个I/O stack location 都有一些通用的成员和一些与请求相关的成员。任何内核模式程序在创建一个IRP时,同时还创建了一个与之关联的IO_STACK_LOCATION结构数组:数组中的每个堆栈单元都对应一个将处理该IRP的驱动程序,另外还有一个堆栈单元供IRP的创建者使用。堆栈单元中包含该IRP的类型代码和参数信息以及完成函数的地址。例如如下设备关系:

å¨è¿éæå¥å¾çæè¿°

typedef struct _IO_STACK_LOCATION {
  UCHAR  MajorFunction;
  UCHAR  MinorFunction;
  UCHAR  Flags;
  UCHAR  Control;
  union {
        //
        // IRP_MJ_CREATE 的参数
        //
        struct {
            PIO_SECURITY_CONTEXT  SecurityContext;
            ULONG  Options;
            USHORT POINTER_ALIGNMENT  FileAttributes;
            USHORT  ShareAccess;
            ULONG POINTER_ALIGNMENT  EaLength;
        } Create;
        //
        // IRP_MJ_READ 的参数
        //
        struct {
            ULONG  Length;
            ULONG POINTER_ALIGNMENT  Key;
            LARGE_INTEGER  ByteOffset;
        } Read;
        //
        // IRP_MJ_WRITE 的参数
        //
        struct {
            ULONG  Length;
            ULONG POINTER_ALIGNMENT  Key;
            LARGE_INTEGER  ByteOffset;
        } Write;
        //
        // IRP_MJ_QUERY_INFORMATION 的参数
        //
        struct {
            ULONG  Length;
            FILE_INFORMATION_CLASS POINTER_ALIGNMENT  FileInformationClass;
        } QueryFile;
        //
        // IRP_MJ_SET_INFORMATION 的参数
        //
        struct {
            ULONG  Length;
            FILE_INFORMATION_CLASS POINTER_ALIGNMENT  FileInformationClass;
            PFILE_OBJECT  FileObject;
            union {
                struct {
                    BOOLEAN  ReplaceIfExists;
                    BOOLEAN  AdvanceOnly;
                };
                ULONG  ClusterCount;
                HANDLE  DeleteHandle;
            };
        } SetFile;
        //
        // IRP_MJ_QUERY_VOLUME_INFORMATION 的参数
        //
        struct {
            ULONG  Length;
            FS_INFORMATION_CLASS POINTER_ALIGNMENT  FsInformationClass;
        } QueryVolume;
        //
        // IRP_MJ_DEVICE_CONTROL and IRP_MJ_INTERNAL_DEVICE_CONTROL 的参数
        //
        struct {
            ULONG  OutputBufferLength;
            ULONG POINTER_ALIGNMENT  InputBufferLength;
            ULONG POINTER_ALIGNMENT  IoControlCode;
            PVOID  Type3InputBuffer;
        } DeviceIoControl;
        //
        // Nonsystem service parameters.
        //
        // IRP_MN_MOUNT_VOLUME 的参数
        //
        struct {
            PVOID  DoNotUse1;
            PDEVICE_OBJECT  DeviceObject;
        } MountVolume;
        //
        // IRP_MN_VERIFY_VOLUME 的参数
        //
        struct {
            PVOID  DoNotUse1;
            PDEVICE_OBJECT  DeviceObject;
        } VerifyVolume;
        //
        // Scsi using IRP_MJ_INTERNAL_DEVICE_CONTROL 的参数
        //
        struct {
            struct _SCSI_REQUEST_BLOCK  *Srb;
        } Scsi;
        //
        // IRP_MN_QUERY_DEVICE_RELATIONS 的参数
        //
        struct {
            DEVICE_RELATION_TYPE  Type;
        } QueryDeviceRelations;
        //
        // Parameters for IRP_MN_QUERY_INTERFACE 
        //
        struct {
            CONST GUID  *InterfaceType;
            USHORT  Size;
            USHORT  Version;
            PINTERFACE  Interface;
            PVOID  InterfaceSpecificData;
        } QueryInterface;
        //
        // Parameters for IRP_MN_QUERY_CAPABILITIES 
        //
        struct {
            PDEVICE_CAPABILITIES  Capabilities;
        } DeviceCapabilities;
        //
        // Parameters for IRP_MN_FILTER_RESOURCE_REQUIREMENTS 
        //
        struct {
            PIO_RESOURCE_REQUIREMENTS_LIST  IoResourceRequirementList;
        } FilterResourceRequirements;
        //
        // Parameters for IRP_MN_READ_CONFIG and IRP_MN_WRITE_CONFIG 
        //
        struct {
            ULONG  WhichSpace;
            PVOID  Buffer;
            ULONG  Offset;
            ULONG  POINTER_ALIGNMENT Length;
        } ReadWriteConfig;
        //
        // Parameters for IRP_MN_SET_LOCK 
        //
        struct {
            BOOLEAN  Lock;
        } SetLock;
        //
        // Parameters for IRP_MN_QUERY_ID 
        //
        struct {
            BUS_QUERY_ID_TYPE  IdType;
        } QueryId;
        //
        // Parameters for IRP_MN_QUERY_DEVICE_TEXT 
        //
        struct {
            DEVICE_TEXT_TYPE  DeviceTextType;
            LCID POINTER_ALIGNMENT  LocaleId;
        } QueryDeviceText;
        //
        // Parameters for IRP_MN_DEVICE_USAGE_NOTIFICATION 
        //
        struct {
            BOOLEAN  InPath;
            BOOLEAN  Reserved[3];
            DEVICE_USAGE_NOTIFICATION_TYPE POINTER_ALIGNMENT Type;
        } UsageNotification;
        //
        // Parameters for IRP_MN_WAIT_WAKE 
        //
        struct {
            SYSTEM_POWER_STATE  PowerState;
        } WaitWake;
        //
        // Parameter for IRP_MN_POWER_SEQUENCE 
        //
        struct {
            PPOWER_SEQUENCE  PowerSequence;
        } PowerSequence;
        //
        // Parameters for IRP_MN_SET_POWER and IRP_MN_QUERY_POWER 
        //
#if (NTDDI_VERSION >= NTDDI_VISTA)
        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
        //
        // Parameters for IRP_MN_START_DEVICE 
        //
        struct {
            PCM_RESOURCE_LIST  AllocatedResources;
            PCM_RESOURCE_LIST  AllocatedResourcesTranslated;
        } StartDevice;
        //
        // Parameters for WMI Minor IRPs 
        //
        struct {
            ULONG_PTR  ProviderId;
            PVOID  DataPath;
            ULONG  BufferSize;
            PVOID  Buffer;
        } WMI;
        //
        // Others - driver-specific
        //
        struct {
            PVOID  Argument1;
            PVOID  Argument2;
            PVOID  Argument3;
            PVOID  Argument4;
        } Others;
    } Parameters;
  PDEVICE_OBJECT  DeviceObject;
  PFILE_OBJECT  FileObject;
  .
  .
  .
} IO_STACK_LOCATION, *PIO_STACK_LOCATION;

结构成员说明:

  • MajorFunction:用于表示将要执行的I/O 类型的一个IRP major function code 。MajorFunction(UCHAR) : 是该IRP的主功能码。这个代码应该为类似IRP_MJ_READ一样的值,并与驱动程序对象中MajorFunction表的某个派遣函数指针相对应。如果该代码存在于某个特殊驱动程序的I/O堆栈单元中,它有可能一开始是,例如IRP_MJ_READ,而后被驱动程序转换成其它代码,并沿着驱动程序堆栈发送到低层驱动程序。
  • MinorFunction:MajorFunction的一个功能子集代码,PnP管理器, 电源管理器, 文件系统驱动程序,SCSI一类的驱动程序在某些请求下设置这个成员。MinorFunction(UCHAR) : 是该IRP的副功能码。它进一步指出该IRP属于哪个主功能类。例如,IRP_MJ_PNP请求就有约一打的副功能码,如IRP_MN_START_DEVICE、IRP_MN_REMOVE_DEVICE,等等。
  • Flags:一些与特定请求相关的值,这些值几乎只被文件系统独占使用。可移动媒介设备驱动程序为读请求检查这个标志是否被设置为SL_OVERRIDE_VERIFY_VOLUME,以确定是否在(即使)设备对象的 Flags 设置为DO_VERIFY_VOLUME的情况下继续执行读操作。(Removable-media device drivers check whether this member is set with SL_OVERRIDE_VERIFY_VOLUME for read requests to determine whether to continue the read operation even if the device object's Flags is set with DO_VERIFY_VOLUME.[求从句不要太长]) 在一个可移动介质的设备上使用的中间层驱动必须为所有进来的IRP_MJ_READ 请求拷贝这个成员到下一层的驱动程序的I/O stack location中。
  • Control:驱动仅有只读这个成员的权限。驱动程序可以检查这个成员以确定它是否被设置为SL_PENDING_RETURNED。
  • Parameters:一个依赖于MajorFunction and MinorFunction的主功能号,次要功能号的联合体参数(union),下列表格展示了Parameters 的union使用和IRP功能号的关系。Parameters(union) : 是几个子结构的联合,每个请求类型都有自己专用的参数,而每个子结构就是一种参数。这些子结构包括Create(IRP_MJ_CREATE请求)、Read(IRP_MJ_READ请求)、StartDevice(IRP_MJ_PNP的IRP_MN_START_DEVICE子类型),等等。

Member name

IRPs that use this member

Create

IRP_MJ_CREATE

Read

IRP_MJ_READ

Write

IRP_MJ_WRITE

QueryFile

IRP_MJ_QUERY_INFORMATION

SetFile

IRP_MJ_SET_INFORMATION

QueryVolume

IRP_MJ_QUERY_VOLUME_INFORMATION

DeviceIoControl

IRP_MJ_DEVICE_CONTROL and IRP_MJ_INTERNAL_DEVICE_CONTROL

MountVolume

IRP_MN_MOUNT_VOLUME

VerifyVolume

IRP_MN_VERIFY_VOLUME

Scsi

IRP_MJ_INTERNAL_DEVICE_CONTROL (SCSI)

QueryDeviceRelations

IRP_MN_QUERY_DEVICE_RELATIONS

QueryInterface

IRP_MN_QUERY_INTERFACE

DeviceCapabilities

IRP_MN_QUERY_CAPABILITIES

FilterResourceRequirements

IRP_MN_FILTER_RESOURCE_REQUIREMENTS

ReadWriteConfig

IRP_MN_READ_CONFIG and IRP_MN_WRITE_CONFIG

SetLock

IRP_MN_SET_LOCK

QueryId

IRP_MN_QUERY_ID

QueryDeviceText

IRP_MN_QUERY_DEVICE_TEXT

UsageNotification

IRP_MN_DEVICE_USAGE_NOTIFICATION

WaitWake

IRP_MN_WAIT_WAKE

PowerSequence

IRP_MN_POWER_SEQUENCE

Power

IRP_MN_SET_POWER and IRP_MN_QUERY_POWER

StartDevice

IRP_MN_START_DEVICE

WMI

WMI minor IRPs

Others

Driver-specific IRPs

  • DeviceObject:指向一个驱动程序创建的设备对象DEVICE_OBJECT 结构,此结构代表了驱动为哪些目标物理,逻辑,虚拟设备处理IRP。是与该堆栈单元对应的设备对象的地址。该域由IoCallDriver函数负责填写。
  • FileObject:一个FILE_OBJECT 结构的指针,此结构代表了DeviceObject 关联的文件对象(如果存在)。 是内核文件对象的地址,IRP的目标就是这个文件对象。驱动程序通常在处理清除请求(IRP_MJ_CLEANUP)时使用FileObject指针,以区分队列中与该文件对象无关的IRP。
  • CompletionRoutine(PIO_COMPLETION_ROUTINE) : 是一个I/O完成例程的地址,该地址是由与这个堆栈单元对应的驱动程序的更上一层驱动程序设置的。你绝对不要直接设置这个域,应该调用IoSetCompletionRoutine函数,该函数知道如何参考下一层驱动程序的堆栈单元。设备堆栈的最低一级驱动程序并不需要完成例程,因为它们必须直接完成请求。然而,请求的发起者有时确实需要一个完成例程,但通常没有自己的堆栈单元。这就是为什么每一级驱动程序都使用下一级驱动程序的堆栈单元保存自己完成例程指针的原因。
  • Context(PVOID) : 是一个任意的与上下文相关的值,将作为参数传递给完成例程。

 

补充说明以下几个事项:

  • 对每个IRP而言, 一个driver stack中的每个驱动程序都有一个 IO_STACK_LOCATION ,每一个IRP的 I/O stack locations 附加在 IRP 结构之后。每一个高层级的驱动程序负责为每一个IRP的低一层驱动程序设置I/O stack location 。驱动程序对每一个IRP都必须使用IoGetCurrentIrpStackLocation 去获取一个它自己拥有的stack location 。更高层的驱动程序可以使用  IoGetNextIrpStackLocation 以获取底下一层的驱动程序的stack location。
  • 高层级的驱动程序在传递IRP给低层的驱动程序时,必须在调用IoCallDriver 前设置stack location的内容 。如果驱动程序试图传递输入的IRP给下一层驱动程序(而不做任何修改),派发例程应当使用 IoSkipCurrentIrpStackLocation 或者是IoCopyCurrentIrpStackLocationToNext 为下一层驱动程序设置I/O stack location。
  • 高级别的驱动程序调用 IoCallDriver 传递 DeviceObject 成员到下一层的驱动程序的目标设备对象中,在下一层的驱动程序的I/O stack location中。当IRP完成调用IoCompletionroutine 时,IO管理器将传递每个高层级的驱动程序的IoCompletion 例程到它拥有的设备对象中。
  • 如果一个高层级的驱动程序申请创建了IRP以创建它自己的请求,如果没有为自己申请一个stack location 也没有在自己新申请的IRP拥有的stack location中安装 DeviceObject指针,他的IoCompletion 当被设置一个NULL DeviceObject 指针。
  • 在某些情况下,一个在大容量储存设备上应用的高级别驱动程序,有责任为底层设备驱动分割大的传输请求。例如,SCSI类型的驱动程序必须检查 Parameters.Read.Length 和Parameters.Write.Length, 以确定请求的传输是否超过了了底层HBA的传输能力。如果是这样的话需要分割初始请求的 Length 为一系列一段段的传输请求以满足最初IRP的请求。
  •  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jyl_sh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值