reactos操作系统实现(88)

IRP I/O request packet 的缩写,即 I/O 请求包。驱动与驱动之间通过 IRP 进行通信。而使用驱动的应用层调用的 CreatFile,ReadFile,WriteFile,DeviceIoControl 等函数,说到底也是使用 IRP 和驱动进行通信。

一个 IRP 由两部分组成。首先是头部或者叫包的固定部分,是一个 IRP 结构。紧跟在这个头部之后的是 I/O栈位置,这是一个 IO_STACK_LOCATION 结构的数组,这个数组中元素的个数是根据情况而定的,由 IoAllocateIrp( IN CCHAR StackSize , IN BOOLEAN ChargeQuota ) 时的参数 StackSize 决定。而 StackSize 通常由 IRP 发往的目标 DEVICE_OBJECT StackSize 决定。而这个 StackSize 是由设备对象连入所在的设备栈时,根据在设备栈中位置决定的。我们先看看 IRP 结构和 IO_STACK_LOCATION 结构的定义。实现代码如下:

#001 typedef struct _IRP {

标志IRP类型。

#002 CSHORT Type;

IRP的长度和IRP栈的长度。

#003 USHORT Size;

指向内存描述符列表。

#004 struct _MDL *MdlAddress;

IRP包特征标志,比如直接I/O,还是缓存I/O等等。

#005 ULONG Flags;

保存驱动程序相关的数据结构。其中,与WDM驱动程序相关的指针是AssociatedIrp.SystemBuffer SystemBuffer指针指向一个数据缓冲区,该缓冲区位于内核模式的非分页内存中。对于IRP_MJ_READIRP_MJ_WRITE操作,如果顶级设备指定DO_BUFFERED_IO标志,则I/O管理器就创建这个数据缓冲区。对于IRP_MJ_DEVICE_CONTROL操作,如果I/O控制功能代码指出需要缓冲区(见第九章),则I/O管理器就创建这个数据缓冲区。I/O管理器把用户模式程序发送给驱动程序的数据复制到这个缓冲区,这也是创建IRP过程的一部分。这些数据可以是与WriteFile调用有关的数据,或者是DeviceIoControl调用中所谓的输入数据。对于读请求,设备驱动程序把读出的数据填到这个缓冲区,然后I/O管理器再把缓冲区的内容复制到用户模式缓冲区。对于指定了METHOD_BUFFEREDI/O控制操作,驱动程序把所谓的输出数据放到这个缓冲区,然后I/O管理器再把数据复制到用户模式的输出缓冲区。

#006 union {

#007 struct _IRP *MasterIrp;

#008 volatile LONG IrpCount;

#009 PVOID SystemBuffer;

#010 } AssociatedIrp;

当前线程入口。

#011 LIST_ENTRY ThreadListEntry;

一个仅包含两个域的结构,驱动程序在最终完成请求时设置这个结构。

#012 IO_STATUS_BLOCK IoStatus;

等于一个枚举常量UserModeKernelMode,指定原始I/O请求的来源。驱动程序有时需要查看这个值来决定是否要信任某些参数。

#013 KPROCESSOR_MODE RequestorMode;

IRP是否被阻塞。

#014 BOOLEAN PendingReturned;

IRP栈的大小。

#015 CHAR StackCount;

当前栈的位置。

#016 CHAR CurrentLocation;

IRP是否被取消操作。

#017 BOOLEAN Cancel;

IoAcquireCancelSpinLock函数调用,指明它是那一个IRQ级别。

#018 KIRQL CancelIrql;

APC调用的环境索引。

#019 CCHAR ApcEnvironment;

内存分配方式,比如定额地增加,还是固定大小等等。

#020 UCHAR AllocationFlags;

保存用户I/O状态。

#021 PIO_STATUS_BLOCK UserIosb;

保存用户的事件。

#022 PKEVENT UserEvent;

APC、或分配的内存大小。

#023 union {

#024 struct {

#025 PIO_APC_ROUTINE UserApcRoutine;

#026 PVOID UserApcContext;

#027 } AsynchronousParameters;

#028 LARGE_INTEGER AllocationSize;

#029 } Overlay;

驱动程序取消例程的地址

#030 volatile PDRIVER_CANCEL CancelRoutine;

指向用户缓冲区。

#031 PVOID UserBuffer;

#032 union {

设备队列入口,或者设备上下环境指针。

#033 struct {

#034 _ANONYMOUS_UNION union {

#035 KDEVICE_QUEUE_ENTRY DeviceQueueEntry;

#036 _ANONYMOUS_STRUCT struct {

#037 PVOID DriverContext[4];

#038 } DUMMYSTRUCTNAME;

#039 } DUMMYUNIONNAME;

批向内核线程。

#040 PETHREAD Thread;

辅助缓冲区。

#041 PCHAR AuxiliaryBuffer;

I/O栈位置

#042 _ANONYMOUS_STRUCT struct {

#043 LIST_ENTRY ListEntry;

#044 _ANONYMOUS_UNION union {

#045 struct _IO_STACK_LOCATION *CurrentStackLocation;

#046 ULONG PacketType;

#047 } DUMMYUNIONNAME;

#048 } DUMMYSTRUCTNAME;

原来文件对象。

#049 struct _FILE_OBJECT *OriginalFileObject;

#050 } Overlay;

APC队列。

#051 KAPC Apc;

I/O完成设置用户关键数据。

#052 PVOID CompletionKey;

#053 } Tail;

#054 } IRP;

#055 typedef struct _IRP *PIRP;

上面学习了IRP的结构,知道了IRP保存的基本内容,也就是说知道了有什么相关东西,这就相当有了原材料,那么怎么样加工和处理这些原材料呢?那就得去分析IRP相关的操作函数,也就是IRP的相关算法。下面就从IRP分配开始,实现代码如下:

#001 PIRP

#002 NTAPI

#003 IoAllocateIrp(IN CCHAR StackSize,

#004 IN BOOLEAN ChargeQuota)

#005 {

#006 PIRP Irp = NULL;

计算IRP占用的大小,包括IRP的头部和IRP栈空间。

#007 USHORT Size = IoSizeOfIrp(StackSize);

#008 PKPRCB Prcb;

#009 UCHAR Flags = 0;

#010 PNPAGED_LOOKASIDE_LIST List = NULL;

#011 PP_NPAGED_LOOKASIDE_NUMBER ListType = LookasideSmallIrpList;

#012

如果设置为定额分配方式,就添加这个标志位。

#013 /* Set Charge Quota Flag */

#014 if (ChargeQuota) Flags |= IRP_QUOTA_CHARGED;

#015

#016 /* FIXME: Implement Lookaside Floats */

#017

#018 /* Figure out which Lookaside List to use */

#019 if ((StackSize <= 8) && (ChargeQuota == FALSE))

#020 {

设置为固定分配大小空间。

#021 /* Set Fixed Size Flag */

#022 Flags = IRP_ALLOCATED_FIXED_SIZE;

#023

需要使用一个大列表方式。

#024 /* See if we should use big list */

#025 if (StackSize != 1)

#026 {

#027 Size = IoSizeOfIrp(8);

#028 ListType = LookasideLargeIrpList;

#029 }

#030

获取当前处理器控制块。

#031 /* Get the PRCB */

#032 Prcb = KeGetCurrentPrcb();

#033

获取后备列表。

#034 /* Get the P List First */

#035 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].P;

#036

从后备列表里分配一个IRP包。

#037 /* Attempt allocation */

#038 List->L.TotalAllocates++;

#039 Irp = (PIRP)InterlockedPopEntrySList(&List->L.ListHead);

#040

#041 /* Check if the P List failed */

#042 if (!Irp)

#043 {

#044 /* Let the balancer know */

#045 List->L.AllocateMisses++;

#046

#047 /* Try the L List */

#048 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[ListType].L;

#049 List->L.TotalAllocates++;

#050 Irp = (PIRP)InterlockedPopEntrySList(&List->L.ListHead);

#051 }

#052 }

#053

如果没有从后备列表里分配到IRP,就需要从内存里分配。

#054 /* Check if we have to use the pool */

#055 if (!Irp)

#056 {

从后备列表里分配失败。

#057 /* Did we try lookaside and fail? */

#058 if (Flags & IRP_ALLOCATED_FIXED_SIZE) List->L.AllocateMisses++;

#059

定额增加分配的方式。

#060 /* Check if we should charge quota */

#061 if (ChargeQuota)

#062 {

#063 /* Irp = ExAllocatePoolWithQuotaTag(NonPagedPool, Size, TAG_IRP); */

#064 /* FIXME */

#065 Irp = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_IRP);

#066 }

#067 else

#068 {

非定额增加分配的方式。

#069 /* Allocate the IRP With no Quota charge */

#070 Irp = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_IRP);

#071 }

#072

#073 /* Make sure it was sucessful */

#074 if (!Irp) return(NULL);

#075 }

#076 else

#077 {

#078 /* In this case there is no charge quota */

#079 Flags &= ~IRP_QUOTA_CHARGED;

#080 }

#081

现在初始化IRP一些属性。

#082 /* Now Initialize it */

#083 IoInitializeIrp(Irp, Size, StackSize);

#084

设置IRP分配的标志。

#085 /* Set the Allocation Flags */

#086 Irp->AllocationFlags = Flags;

#087

返回分配成功的IRP包。

#088 /* Return it */

#089 IOTRACE(IO_IRP_DEBUG,

#090 "%s - Allocated IRP %p with allocation flags %lx/n",

#091 __FUNCTION__,

#092 Irp,

#093 Flags);

#094 return Irp;

#095 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值