Windows IRP
IRP(I/O Request Packet),是由IO manager发起的对device的IO请求。
当用户调用系统API,如createFile类似的函数,其实是会交给IO manager来做相应的处理。
首先IO Manager知道这次IO请求,涉及到的设备栈(Device Stack),每个Device都有相应的Driver。
IO Manager然后会组一个IRP的结构,包括IRP头,以及紧随其后的IO_STACK_LOCATION结构体数组。
相当于:
typedef struct _IRP{ struct IRP_HEADER irpHeader; ... IO_STACK_LOCATION ioStack[]; ... }
irpHeader有不少有用的信息,如:SystemBuffer,StackCount,CurrentLocation,Flags...
其中成员StackCount指定IO_STACK_LOCATION数组的个数,其实就是Device Stack里面每个device都会被分配一个IO_STACK_LOCATION。
typedef struct _IO_STACK_LOCATION { UCHAR MajorFunction; UCHAR MinorFunction; UCHAR Flags; UCHAR Control; union { // Parameters for IRP_MJ_CREATE struct { PIO_SECURITY_CONTEXT SecurityContext; ULONG Options; USHORT POINTER_ALIGNMENT FileAttributes; USHORT ShareAccess; ULONG POINTER_ALIGNMENT EaLength; } Create; ... } Parameters; PDEVICE_OBJECT DeviceObject; PFILE_OBJECT FileObject; . } IO_STACK_LOCATION, *PIO_STACK_LOCATION;
IO_STACK_LOCATON会有不少Input Parameter,如MajorFunction,MinorFunction...等,这些parameter是由上级device帮忙配置好的。
一般的流程就是,这级的device对应的driver根据上级帮忙配置的一些IO_STACK_LOCATION信息,完成相应的工作,然后配置好下一级的IO_STCAK_LOCATION.
调用IoCallDriver(NextDeviceObject,Irp),交给下一级的device.
事实上,如果某个device啥事都不想做,它可以直接skip原来分给它的IO_STACK_LOCATION,在IoCallDriver,只要相应调整下stackIndex类似的值,就可以让下一级的Device使用自己的IO_STACK_LOCATION内存了。
当然每个Device都可以配置IoSetCompletionRoutine,这样下一级完成的时候,会call自己设的completion routine,当然不设也没关系.
要理解IRP,其实首先需要理解device stack, IO Manager是怎么维护device stack的呢?
其实有相应的API, IoAttachDevice, IoDetachDevice。
NTSTATUS IoAttachDevice( _In_ PDEVICE_OBJECT SourceDevice, _In_ PUNICODE_STRING TargetDevice, _Out_ PDEVICE_OBJECT *AttachedDevice );
The IoAttachDevice routine attaches the caller's device object to a named target device object, so that I/O requests bound for the target device are routed first to the caller.
VOID IoDetachDevice(
_Inout_ PDEVICE_OBJECT TargetDevice
);
The IoDetachDevice routine releases an attachment between the caller's device object and a lower driver's device object.
在call这些API的时候,IO Manager就在做构建device stack的工作了。