reactos操作系统实现(85)

前端之家收集整理的这篇文章主要介绍了reactos操作系统实现(85)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

内核里也需要访问用户应用程序内存,那么有什么方法呢?在@H_502_5@ReactOS主要有两种方法:一种是使用缓冲@H_502_5@I/O方法,在驱动程序运行前,@H_502_5@I/O管理器把写数据复制到这个缓冲区,并在请求完成时把读数据复制回到用户空间;另一种是使用直接@H_502_5@I/O,这是优先的技术,因为它减少数据复制。这是通过@H_502_5@I/O管理器传递一个内存描述符列表(@H_502_5@MDL--@H_502_5@ @H_502_5@Memory descriptor list)来实现的,这个描述符列表是描述用户空间缓冲区。@H_502_5@

@H_502_5@MDL的实现代码如下:@H_502_5@

@H_502_5@#001 PMDL

@H_502_5@#002 NTAPI

@H_502_5@#003 IoAllocateMdl(IN PVOID VirtualAddress,

@H_502_5@#004 IN ULONG Length,

@H_502_5@#005 IN BOOLEAN SecondaryBuffer,

@H_502_5@#006 IN BOOLEAN ChargeQuota,

@H_502_5@#007 IN PIRP Irp)

@H_502_5@#008 {

函数@H_502_5@IoAllocateMdl前两个参数定义了虚拟地址和内存区的大小,是建立@H_502_5@MDL所必须的。如果@H_502_5@MDL不与@H_502_5@IRP相关联,则第三个参数就为@H_502_5@FALSE。第四个参数定义是否需要减少进程的份额,并只用于位于驱动程序链最上层的驱动程序或是单层的驱动程序(。每一个进程都要获得一定份额的系统资源。当进程为自己分配资源时,这个份额就会减小。如果份额用完,就不能再为其分配相应的资源。最后一个参数定义了一个非必要的指向@H_502_5@IRP的指针,通过这个指针@H_502_5@MDL可以与@H_502_5@IRP关联。例如,对于直接@H_502_5@I/O@H_502_5@I/O管理器为用户缓冲区建立@H_502_5@MDL,并将其地址送至@H_502_5@IRP.MdlAddress@H_502_5@

@H_502_5@

@H_502_5@#009 PMDL Mdl = NULL,p;

@H_502_5@#010 ULONG Flags = 0;

@H_502_5@#011 ULONG Size;

@H_502_5@#012

@H_502_5@

如果申请的内存超过@H_502_5@2G,就返回失败。@H_502_5@

@H_502_5@#013 /* Fail if allocation is over 2GB */

@H_502_5@#014 if (Length & 0x80000000) return NULL;

@H_502_5@#015

@H_502_5@

计算需要使用多少页内存。@H_502_5@

@H_502_5@#016 /* Calculate the number of pages for the allocation */

@H_502_5@#017 Size = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddress,Length);

@H_502_5@#018 if (Size > 23)

@H_502_5@#019 {

@H_502_5@

大于@H_502_5@23页,就计算实际使用的大小页。@H_502_5@

@H_502_5@#020 /* This is bigger then our fixed-size MDLs. Calculate real size */

@H_502_5@#021 Size *= sizeof(PFN_NUMBER);

@H_502_5@#022 Size += sizeof(MDL);

@H_502_5@#023 if (Size > MAXUSHORT) return NULL;

@H_502_5@#024 }

@H_502_5@#025 else

@H_502_5@#026 {

如果小于等于@H_502_5@23页,就直接使用@H_502_5@23页的大小。@H_502_5@

@H_502_5@#027 /* Use an internal fixed MDL size */

@H_502_5@#028 Size = (23 * sizeof(PFN_NUMBER)) + sizeof(MDL);

@H_502_5@#029 Flags |= MDL_ALLOCATED_FIXED_SIZE;

@H_502_5@#030

@H_502_5@

从后备列表里找到合适的内存。@H_502_5@

@H_502_5@#031 /* Allocate one from the lookaside list */

@H_502_5@#032 Mdl = IopAllocateMdlFromLookaside(LookasideMdlList);

@H_502_5@#033 }

@H_502_5@#034

@H_502_5@

如果前面没有找到相应的@H_502_5@MDL内存,就重新分配一个。@H_502_5@

@H_502_5@#035 /* Check if we don't have an mdl yet */

@H_502_5@#036 if (!Mdl)

@H_502_5@#037 {

@H_502_5@#038 /* Allocate one from pool */

@H_502_5@#039 Mdl = ExAllocatePoolWithTag(NonPagedPool,Size,TAG_MDL);

@H_502_5@#040 if (!Mdl) return NULL;

@H_502_5@#041 }

@H_502_5@#042

@H_502_5@

通过内存管理器的函数@H_502_5@MmInitializeMdl初始化@H_502_5@MDL@H_502_5@

@H_502_5@#043 /* Initialize it */

@H_502_5@#044 MmInitializeMdl(Mdl,VirtualAddress,Length);

@H_502_5@#045 Mdl->MdlFlags |= Flags;

@H_502_5@#046

@H_502_5@

检查@H_502_5@IRP是否存在,如果存在就把@H_502_5@MDL的地址放到@H_502_5@IRP包里。@H_502_5@

@H_502_5@#047 /* Check if an IRP was given too */

@H_502_5@#048 if (Irp)

@H_502_5@#049 {

@H_502_5@#050 /* Check if it came with a secondary buffer */

@H_502_5@#051 if (SecondaryBuffer)

@H_502_5@#052 {

@H_502_5@#053 /* Insert the MDL at the end */

@H_502_5@#054 p = Irp->MdlAddress;

@H_502_5@#055 while (p->Next) p = p->Next;

@H_502_5@#056 p->Next = Mdl;

@H_502_5@#057 }

@H_502_5@#058 else

@H_502_5@#059 {

@H_502_5@#060 /* Otherwise,insert it directly */

@H_502_5@#061 Irp->MdlAddress = Mdl;

@H_502_5@#062 }

@H_502_5@#063 }

@H_502_5@#064

@H_502_5@

最后返回@H_502_5@MDL的地址。@H_502_5@

@H_502_5@#065 /* Return the allocated mdl */

@H_502_5@#066 return Mdl;

@H_502_5@#067 }

@H_502_5@

@H_502_5@

@H_502_5@MDL描述符表里,还有这样的需求,当作一个@H_502_5@MDL表已经映射过一次@H_502_5@MDL了,那么当用户再次想去分配这个@H_502_5@MDL时,就需要使用函数@H_502_5@IoBuildPartialMdl来再次映射@H_502_5@MDL了。其实出现这种情况,就是当驱动程序使用了一个@H_502_5@MDL@H_502_5@IRP包发送给另外一个驱动程序,然后这个驱动程序又需要从@H_502_5@IRP包里的@H_502_5@MDL再分配一个@H_502_5@MDL出来。这个函数的实现代码如下:@H_502_5@

@H_502_5@#001 /*

@H_502_5@#002 * @implemented

@H_502_5@#003 */

@H_502_5@#004 VOID

@H_502_5@#005 NTAPI

@H_502_5@#006 IoBuildPartialMdl(IN PMDL SourceMdl,

@H_502_5@#007 IN PMDL TargetMdl,

@H_502_5@#008 IN PVOID VirtualAddress,

@H_502_5@#009 IN ULONG Length)

@H_502_5@#010 {

@H_502_5@

取目标@H_502_5@MDL地址。@H_502_5@

@H_502_5@#011 PPFN_NUMBER TargetPages = (PPFN_NUMBER)(TargetMdl + 1);

@H_502_5@

取源@H_502_5@MDL地址。@H_502_5@

@H_502_5@#012 PPFN_NUMBER SourcePages = (PPFN_NUMBER)(SourceMdl + 1);

@H_502_5@#013 ULONG Offset;

@H_502_5@#014 ULONG FlagsMask = (MDL_IO_PAGE_READ |

@H_502_5@#015 MDL_SOURCE_IS_NONPAGED_POOL |

@H_502_5@#016 MDL_MAPPED_TO_SYSTEM_VA |

@H_502_5@#017 MDL_IO_SPACE);

@H_502_5@#018

@H_502_5@

计算偏移位置。@H_502_5@

@H_502_5@#019 /* Calculate the offset */

@H_502_5@#020 Offset = (ULONG)((ULONG_PTR)VirtualAddress -

@H_502_5@#021 (ULONG_PTR)SourceMdl->StartVa) -

@H_502_5@#022 SourceMdl->ByteOffset;

@H_502_5@#023

@H_502_5@

计算源@H_502_5@MDL是否有足够的长度。@H_502_5@

@H_502_5@#024 /* Check if we don't have a length and calculate it */

@H_502_5@#025 if (!Length) Length = SourceMdl->ByteCount - Offset;

@H_502_5@#026

@H_502_5@

设置进程、虚拟地址和需要内存的大小。@H_502_5@

@H_502_5@#027 /* Write the process,start VA and byte data */

@H_502_5@#028 TargetMdl->StartVa = (PVOID)PAGE_ROUND_DOWN(VirtualAddress);

@H_502_5@#029 TargetMdl->Process = SourceMdl->Process;

@H_502_5@#030 TargetMdl->ByteCount = Length;

@H_502_5@#031 TargetMdl->ByteOffset = BYTE_OFFSET(VirtualAddress);

@H_502_5@#032

@H_502_5@

重新计算页面的空间。@H_502_5@

@H_502_5@#033 /* Recalculate the length in pages */

@H_502_5@#034 Length = ADDRESS_AND_SIZE_TO_SPAN_PAGES(VirtualAddress,Length);

@H_502_5@#035

@H_502_5@

设置@H_502_5@MDL的标志。@H_502_5@

@H_502_5@#036 /* Set the MDL Flags */

@H_502_5@#037 TargetMdl->MdlFlags &= (MDL_ALLOCATED_FIXED_SIZE | MDL_ALLOCATED_MUST_SUCCEED);

@H_502_5@#038 TargetMdl->MdlFlags |= SourceMdl->MdlFlags & FlagsMask;

@H_502_5@#039 TargetMdl->MdlFlags |= MDL_PARTIAL;

@H_502_5@#040

@H_502_5@#041 /* Set the mapped VA */

@H_502_5@#042 TargetMdl->MappedSystemVa = (PCHAR)SourceMdl->MappedSystemVa + Offset;

@H_502_5@#043

@H_502_5@

开始从源@H_502_5@MDL里拷贝数据到新的@H_502_5@MDL@H_502_5@

@H_502_5@#044 /* Now do the copy */

@H_502_5@#045 Offset = ((ULONG_PTR)TargetMdl->StartVa - (ULONG_PTR)SourceMdl->StartVa) >>

@H_502_5@#046 PAGE_SHIFT;

@H_502_5@#047 SourcePages += Offset;

@H_502_5@#048 RtlCopyMemory(TargetPages,SourcePages,Length * sizeof(PFN_NUMBER));

@H_502_5@#049 }

@H_502_5@

前面都是创建@H_502_5@MDL的,下面这个函数就是删除@H_502_5@MDL所占用的资源,实现如下:@H_502_5@

@H_502_5@#001 VOID

@H_502_5@#002 NTAPI

@H_502_5@#003 IoFreeMdl(PMDL Mdl)

@H_502_5@#004 {

@H_502_5@

让内存管理器删除所有@H_502_5@MDL@H_502_5@

@H_502_5@#005 /* Tell Mm to reuse the MDL */

@H_502_5@#006 MmPrepareMdlForReuse(Mdl);

@H_502_5@#007

@H_502_5@

检查是否重新分配的内存,如果是就需要删除掉,否则就放回到后备列表,以便下一次使用。@H_502_5@

@H_502_5@#008 /* Check if this was a pool allocation */

@H_502_5@#009 if (!(Mdl->MdlFlags & MDL_ALLOCATED_FIXED_SIZE))

@H_502_5@#010 {

@H_502_5@#011 /* Free it from the pool */

@H_502_5@#012 ExFreePoolWithTag(Mdl,TAG_MDL);

@H_502_5@#013 }

@H_502_5@#014 else

@H_502_5@#015 {

@H_502_5@#016 /* Free it from the lookaside */

@H_502_5@#017 IopFreeMdlFromLookaside(Mdl,LookasideMdlList);

@H_502_5@#018 }

@H_502_5@#019 }

@H_502_5@#020

原文链接:https://www.f2er.com/react/308443.html

猜你在找的React相关文章