`
yuanjinxiu
  • 浏览: 660156 次
文章分类
社区版块
存档分类
最新评论

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 }

分享到:
评论

相关推荐

    ReactOS-0.4.13-release-14-g2494cfc-iso.zip

    ReactOS项目致力于为大家开发一个免费而且完全兼容 Microsoft Windows XP 的操作系统。ReactOS 旨在通过使用类似构架和提供完整公共接口实现与 NT 以及 XP 操作系统二进制下的应用程序和驱动设备的完全兼容。 ...

    Windows 内核情景分析--采用开源代码ReactOS (上册) part02

    本书通过分析ReactOS的源代码介绍了Windows内核各个方面的结构、功能、算法与具体实现。全书从“内存管理”、“进程”、“进程间通信”、“设备驱动”等多个方面进行分析介绍,所有的分析都有ReactOS的源代码(以及...

    Windows 内核情景分析--采用开源代码ReactOS (上册) part01

    本书通过分析ReactOS的源代码介绍了Windows内核各个方面的结构、功能、算法与具体实现。全书从“内存管理”、“进程”、“进程间通信”、“设备驱动”等多个方面进行分析介绍,所有的分析都有ReactOS的源代码(以及...

    JS-OS:Web上的统一操作系统

    JS操作系统 Web上的统一操作系统。 使用的技术: HTML CSS JavaScript React-JS 如何在本地运行: 克隆仓库git clone https://github.com/NJACKWinterOfCode/JS-OS.git 进入JS-OS光盘进入JS-OS cd JS-OS 安装...

    漫谈兼容内核.zip

    漫谈兼容内核之一:ReactOS怎样实现系统调用 漫谈兼容内核之二:关于kernel-win32的对象管理 漫谈兼容内核之三:Kernel-win32的文件操作 漫谈兼容内核之四:Kernel-win32的进程管理 漫谈兼容内核之五:Kernel-win32...

    LKM-光纤:高级操作系统和虚拟化项目(20172018)课程在罗马大学萨皮恩扎市举行

    在本文档中,我们以Windows NT和ReactOS提供的Fibers实现为参考,介绍了可加载内核模块(LKM)实现。 虽然用户空间实现通常因其开销少且易于调试而成为首选,但是内核空间实现允许更深入地了解内核子系统的工作方式...

    漫谈Linux兼容内核

    01:ReactOS怎样实现系统调用.pdf 02:关于kernel -win32的对象管理.pdf 03:关于kernel-win32的文件操作.pdf 04:Kernel-win32的进程管理.pdf 05:Kernel-win32的系统调用机制.pdf 06:二进制映像的类型识别.pdf 07...

    harmonyos2-reactive-extra:流星React额外包

    React式对象实现。 结帐 用法 var obj = new ReactiveObject ( { 'foo' : '1' } ) ; obj . defineProperty ( 'bar' , 2 ) ; obj . foo = '2' ; obj . undefineProperty ( 'foo' ) ; // Don't use 'delete obj.foo' ...

    DLL注入之远线程方式

    远线程注入 每个进程都有自己的虚拟地址空间,对32位进程来说,这个地址空间的大小为4GB。...如下摘自ReactOS 3.14的代码所示,CreateRemoteThread实际实现的功能就是调用NtCreateThread创建一个属于目标进程的线程。

    睿思bi开源版后台系统,基于Springboot构建,快速分析数据及可视化,0代码编写rsbi-os.zip

    【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、...

    Windows之漫谈兼容内核

    漫谈兼容内核之一:ReactOS怎样实现系统调用 漫谈兼容内核之二:关于kernel-win32的对象管理 漫谈兼容内核之三:Kernel-win32的文件操作 漫谈兼容内核之四:Kernel-win32的进程管理 漫谈兼容内核之五:Kernel-win32...

    winampify::high_voltage:具有操作系统外观的界面和经典音频播放器Winamp的重新实现的Spotify Web客户端

    艺术家,专辑和曲目都以文件和文件夹的形式呈现,并且可以在Winamp重新实现轻松地进行操作和播放。现场环境动机构建软件应该保持乐趣。 这个项目主要是一个沙箱,我可以尝试并提高对React和TypeScript的了解。 这也...

    React Native 的 UIDevice 类包装器

    isIpad() 设备型号为 iPad Device.isIphone() 设备型号为 iPhone Properties Device.model 设备型号,如 iPhone 或 iPad Device.deviceName 设备名称,如 John Smith 的 iPhone Device.systemName设备操作系统名称...

    CredBandit

    内存转储是通过使用NTFS事务完成的,NTFS事务使我们可以将转储写入内存,并且MiniDumpWriteDump API已被ReactOS的MiniDumpWriteDump实现改编所取代。 然后,BOF使用base64对内存中的数据进行编码,将其分块,然后...

    漫谈兼容内核.7z

    谈兼容内核之一:ReactOS怎样实现系统调用.pdf 漫谈兼容内核之二:关于kernel -win32的对象管理.pdf 漫谈兼容内核之三:关于kernel-win32的文件操作.pdf 漫谈兼容内核之四:Kernel-win32的进程管理.pdf 漫谈兼容内核...

    phoebe:菲比

    在许多情况下,操作员习惯于处理遥测,实时图表,警报等,这可以帮助他们确定有问题的机器并做出React以解决任何潜在的问题。 但是,一个问题浮现在脑海:如果机器可以自动调整自身并为用户提供自我修复功能,那...

    hyperglass:超级玻璃是试图使互联网变得更好的网络外观玻璃

    功能,主题,UI / API文本,错误消息,命令内置支持: Arista EOS 鸟思科IOS-XR 思科IOS / IOS-XE 思科NX-OS FRRouting 了华为瞻博JunOS 米克罗蒂克诺基亚SR OS TNSR 虚拟操作系统对任何其他配置支持(可选)通过SSH...

    sentinel-crawler:Xenomorph Crawler, a Concise, Declarative and Observable Distributed Crawler(Node Go Java Rust) For Web, RDB, OS, also can act as a Monitor(with Prometheus) or ETL for Infrastructure 多语言执行器,分布式爬虫

    xe-crawlerxe-crawler 是遵循声明式、可监测理念的分布式爬虫,其计划提供 Node.js、Go、Python 多种实现,能够对于静态 Web 页面、动态 Web 页面、关系型数据库、操作系统等异构多源数据进行抓取。xe-crawler 希望...

    图像dct变换matlab代码-SJTU-IE307-hw1:ConductedbyProf.XieRong

    实现分块功能可以采用手动循环的对每个块依次操作,也可以使用Matlab提供的分块处理功能blkproc。 选择两张大小相同的图像,分别进行DFT变换后,置换两幅图像的幅度和相位信息后再作反变换,观察并分析结果。 主要...

Global site tag (gtag.js) - Google Analytics