windows内核原理与实现笔记之IO请求包
IRP 定义:
typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _IRP {
CSHORT Type;
USHORT Size;
PMDL MdlAddress;//该I/O请求的用户缓冲区的MDL,仅用于“直接I/O”类型
ULONG Flags;//用于记录各种标志
union {
struct _IRP *MasterIrp;//若这是一个关联IRP,则指向主IRP
LONG IrpCount;//若这是一个主IRP,则必须先完成多少个关联IRP
PVOID SystemBuffer;//该操作被缓冲起来,指向系统地址空间缓冲区的地址
} AssociatedIrp;
LIST_ENTRY ThreadListEntry;//链表向,可以加入到线程的未完成的I/O请求链表中
IO_STATUS_BLOCK IoStatus;//I/O操作的状态
KPROCESSOR_MODE RequestorMode;//内核模式I/O请求或用户模式I/O请求
BOOLEAN PendingReturned;//未完成返回
CHAR StackCount;//栈单元计数
CHAR CurrentLocation;//当前栈单元位置
BOOLEAN Cancel;//该I/O请求是否已被取消
KIRQL CancelIrql;//取消自旋锁在哪级IROQ上被获取
CCHAR ApcEnvironment;//用于当该IRP被初始化时保存APC环境
UCHAR AllocationFlags;//该IRP内存的分配控制状态
PIO_STATUS_BLOCK UserIosb;//用户的I/O状态块
PKEVENT UserEvent;//用户事件对象
union {
struct {
PIO_APC_ROUTINE UserApcRoutine;//当I/O请求完成时指向的APC例程
PVOID UserApcContext;//传递UserApcRoutine的环境参数
} AsynchronousParameters;
LARGE_INTEGER AllocationSize;//分配块的大小
} Overlay;
PDRIVER_CANCEL CancelRoutine;//若是可取消的I/O请求,该域包含了取消时调用的例程
PVOID UserBuffer;//调用者(即发起者)提供的输出缓冲区的地址
//以下Tail联合成员用于当I/O管理器处理该I/O请求时存放各种工作信息
union {
struct {
union {
KDEVICE_QUEUE_ENTRY DeviceQueueEntry;//设备队列项
struct {
PVOID DriverContext[4];//由驱动程序解释和使用
} ;
} ;
PETHREAD Thread;//指向发起者线程的ETHREAD
PCHAR AuxiliaryBuffer;//辅助缓冲区
struct {
LIST_ENTRY ListEntry;//存放到完成队列中的链表项
union {
struct _IO_STACK_LOCATION *CurrentStackLocation;//指向当前栈单元,驱动程序不可直接访问
ULONG PacketType;//Minipacket 的类型
};
};
PFILE_OBJECT OriginalFileObject;//指向原始的文件对象
} Overlay;
KAPC Apc;//特殊内核模式APC或发起者的APC
PVOID CompletionKey;//完成键,用于标识在不同文件句柄上的I/O请求
} Tail;
} IRP, *PIRP;
IRP对象从一个I/O请求被发起时开始存在,一直到该I/O请求被完成或者取消为止。
IRP对象的设计特点:
- 所有的I/O请求都被抽象成针对文件对象的操作,OriginalFileObject 记录了该文件对象,代表一个I/O 请求的目标
- 栈单元。由于可能由多个驱动程序一次参与到一个I/O请求的处理过程中,所以,一个IRP对象出了以上列出的IRP数据结构,其后还有一个称为栈单元的数组。每个参与处理的驱动程序都可以有它自己的栈单元。
- 支持取消。线程可以指定一个取消例程,以便当I/O请求被取消时可以执行相关的动作。
- I/O请求的完成。当一个驱动程序的分发例程认为它已经完成了该I/O请求时,会显式的告诉I/O管理器,此I/O请求已完成。
栈单元IO_STACK_LOCATION 定义:
typedef struct _IO_STACK_LOCATION {
UCHAR MajorFunction;//在该设备对象上的I/O请求主功能码
UCHAR MinorFunction; //在该设备对象上的I/O请求次功能码
UCHAR Flags;
UCHAR Control;
union {
struct {...} Create; //NtCreateFile 的参数
struct {...} CreatePipe;// NtCreaeNamedPipeFile 的参数
struct {...} CreateMailslot;// NtCreateMailslotFile 的参数
struct {...} Read;// NtReadFile 的参数
struct {...} Write;// NtWriteFile 的参数
struct {...} QueryDirectory;// NtQueryDirectory 的参数
struct {...} NotifyDirectory;// NtNotifyChangeDirectroyFile的参数
struct {...} QueryFile;// NtQueryInformationFile 的参数
struct {...} SetFile;// NtSetInformationFile 的参数
struct {...} QueryEa;// NtQueryEaFile 的参数
struct {...} SetEa;//NtSetEaFile 的参数
struct {...} QueryVolume;// NtQueryvolumeInformationFile 的参数
struct {...} SetVolume;// NtSetvolumeInformationFile 的参数
struct {...} FileSystemControl;// NtFsControlFile 的参数
struct {...} LockControl;// NtLock/NtUnlockFile 的参数
//NtFlushBuffersFile的参数
//NtCancelIoFile的参数
struct {...} DeviceIoControl;//NtDeviceIoControFile的参数
struct {...} QuerySecurity;// NtQuerySecurityObject 的参数
struct {...} SetSecurity;// NtSetSecurityObject 的参数
struct {...} MountVolume;// MountVolume的参数
struct {...} VerifyVolume;// VerifyVolume的参数
struct {...} Scsi;//SCSI 内部设备控制的参数
struct {...} QueryQuota;// NtQueryQuotaInformationFile 的参数
struct {...} SetQuota;//NtSetQuotaInformationFile 的参数
struct {...} QueryDeviceRelations;//IRP_MN_QUERY_DEVICE_RELATIONS的参数
struct {...} QueryInterface;//IRP_MN_QUERY_INTERFACE的参数
struct {...} DeviceCapabilities;//IRP_MN_QUERY_CAPABILITIES的参数
struct {...} FilterResourceRequirements;
//IRP_MN_FILTER_RESOURCE_REQUITEMENTS的参数
struct {...} ReadWriteConfig;//IRP_MN_READ_CONFIG和IRP_MN_WRITE_CONFIG的参数
struct {...} SetLock;//IRP_MN_SET_LOCK 的参数
struct {...} QueryId;//IRP_MN_QUERY_ID的参数
struct {...} QueryDeviceText;//IRP_MN_QUERY_DEVICE_TEXT的参数
struct {...} UsageNotification;//IRP_MN_DEVICE_USAGE_NOTIFICATION的参数
struct {...} WaitWake;//IRP_MN_WAIT_WAKE的参数
struct {...} PowerSequence;//IRP_MN_POWER_SEQUENCE的参数
struct {...} Power;//IRP_MN_SET_POWER、IRP_MN_QUERY_POWER的参数
struct {...} StartDevice;//StartDevice 的参数、Cleanup的参数
struct {...} WMI;//WMI IRP的参数
struct {...} Others;//其他,由驱动程序自己定义和解释
} Parameters;
PDEVICE_OBJECT DeviceObject;
PFILE_OBJECT FileObject;
PIO_COMPLETION_ROUTINE CompletionRoutine;
PVOID Context;
} IO_STACK_LOCATION, *PIO_STACK_LOCATION;
Control 域包含了栈单元的控制标志,该域对驱动程序是只读的,请参考宏定义
#define SL_PENDING_RETURNED 0x01
#define SL_ERROR_RETURNED 0x02
#define SL_INVOKE_ON_CANCEL 0x20
#define SL_INVOKE_ON_SUCCESS 0x40
#define SL_INVOKE_ON_ERROR 0x80
DeviceObject :指向与该栈单元相对应的设备对象
FileObject: 指向与DeviceObject相关联的文件对象
CompletionRoutine:是该栈单元对应的驱动程序通过IoSetCompletionRoutine设置的完成例程
Context :由驱动程序指定的、传递给CompletionRoutine 的参数
IRP与文件对象、设备对象和驱动程序之间的关系,如下图:
IRP对象是通过IoAllocateIrp 分配的,IoAllocateIrp 转发给pIoAllocateIrp 函数指针。pIoAllocateIrp 在初始化时指向IopAllocateIrpPrivate。所以,IRP对象实际是在IopAllocateIrpPrivate 完成的,通过IopFreeIrp 释放IRP对象。