• 涨姿势系列之——内核环境下内存映射函数


    同样是看别人代码时发现的,作者使用了MmGetPhysicalAddress和MmMapIoSpace这两个函数,之前从来没看过这两个函数还以为是作者自己写的呢。后来查了一下WDK原来是有文档的函数。作者是用这个函数把缓存模型I/O的地址取物理地址之后再映射出虚拟地址,虽然我没发现这么做有什么意义,因为对于缓冲I/O模式来说,IRP中给出的缓冲区地址已经是I/O管理器进行复制之后的结果了,不需要再进行什么映射,我也没搞懂作者是要干吗,不过可以学习一下这两个函数的使用。

    PHYSICAL_ADDRESS
      MmGetPhysicalAddress(
        IN PVOID  BaseAddress
        );

    这个返回的就是直接的物理地址了。

    typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;

    可见 PHYSICAL_ADDRESS就是LARGE_INTEGER了。

     来看一下这个函数的源码吧,来自WRK。可见是通过获取PTE来取得物理地址的。宏的内容没有跟进去看了,但是想想就可以知道实现方法了,无非就是分页机制的原理。

     1 PHYSICAL_ADDRESS
     2 MmGetPhysicalAddress (
     3     __in PVOID BaseAddress
     4     )
     5 
     6 {
     7     PMMPTE PointerPte;
     8     PHYSICAL_ADDRESS PhysicalAddress;
     9 
    10     if (MI_IS_PHYSICAL_ADDRESS(BaseAddress)) 
    11     {
    12         PhysicalAddress.QuadPart = MI_CONVERT_PHYSICAL_TO_PFN (BaseAddress);
    13     }
    14     else 
    15     {
    16 
    17         PointerPte = MiGetPdeAddress (BaseAddress);
    18         if (PointerPte->u.Hard.Valid == 0) 
    19         {
    20             KdPrint(("MM:MmGetPhysicalAddressFailed base address was %p",
    21                       BaseAddress));
    22             ZERO_LARGE (PhysicalAddress);
    23             return PhysicalAddress;
    24         }
    25 
    26         if (MI_PDE_MAPS_LARGE_PAGE (PointerPte)) 
    27         {
    28             PhysicalAddress.QuadPart = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte) +
    29                                            MiGetPteOffset (BaseAddress);
    30         }
    31         else 
    32         {
    33             PointerPte = MiGetPteAddress (BaseAddress);
    34 
    35             if (PointerPte->u.Hard.Valid == 0) 
    36             {
    37                 KdPrint(("MM:MmGetPhysicalAddressFailed base address was %p",
    38                           BaseAddress));
    39                 ZERO_LARGE (PhysicalAddress);
    40                 return PhysicalAddress;
    41             }
    42             PhysicalAddress.QuadPart = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte);
    43         }
    44     }
    45 
    46     PhysicalAddress.QuadPart = PhysicalAddress.QuadPart << PAGE_SHIFT;
    47     PhysicalAddress.LowPart += BYTE_OFFSET(BaseAddress);
    48 
    49     return PhysicalAddress;
    50 }

    接下来看下这个函数

    PVOID 
      MmMapIoSpace(
        IN PHYSICAL_ADDRESS  PhysicalAddress,
        IN SIZE_T  NumberOfBytes,
        IN MEMORY_CACHING_TYPE  CacheType
        );

    同样是一个在WDK中有文档的函数,作用是把一个物理地址映射出来一个虚拟地址。PVOID返回值就是得到的虚拟地址。NumberOfBytes是映射的长度。所以这两个函数可以很好的配合使用啊,我的想法是在A进程中获取一个虚拟地址对应的物理地址,然后在B进程中把这个物理地址映射出来就可以使用啦,这样就突破每个进程的独立地址空间的局限啦。

    顺带再说下,对于Windows内存管理不了解的童鞋可以不明白为啥获得物理地址后不直接使用,因为对于我们来说是不能直接使用物理地址的,我们平时接触到的都是经过分段+分页机制转化后的虚拟地址,而唯一能接触到物理地址的地方我想就是CR3寄存器中保存的PDE的基址了。

  • 相关阅读:
    从属性赋值到MVVM模式详解
    C#综合揭秘——细说事务
    Action与Trigger
    C#综合揭秘——细说多线程(下)
    继承BitmapSource并使用独立存储来缓存远程的图片
    Windows Phone 7 MVVM模式数据绑定和传递参数
    Lambda表达式总结
    Windows Phone页面导航和独立存储开发总结
    RegisterHotKey设置系统级热键《转》
    隐藏统计代码或者任何不想被看见的东西《转》
  • 原文地址:https://www.cnblogs.com/Ox9A82/p/5554492.html
Copyright © 2020-2023  润新知