zoukankan      html  css  js  c++  java
  • 访问内存过程小结

         本文总结一下,Linux下面几种访问内存的方式方法。相关资料转载自:Linux 内存与I/O访问

         X86体系结构下,内存空间分为I/O空间和内存空间,I/O空间通过特定的指令in、out来访问,内存空间采用mov等指令访问。

         arm体系结构下,内存空间和I/O空间统一划分,他们在一个地址空间内。

          在处理器和真实的内存空间之间,还有MMU这一神奇的部件存在,它辅助操作系统进行内存管理,提供虚拟地址和物理地址的映射关系转换、内存访问权限保护和cache缓存控制等硬件功能,操作系统借助MMU,实现虚拟地址空间的管理,使得上层应用程序不必考虑真实物理地址大小,面对一片“虚拟”的逻辑地址空间。

        123

    在Linux内核空间,kmalloc、__get_free_page,这两个函数申请的内存空间在物理地址上都是连续的,vmalloc申请的内存空间在物理地址上不是连续的。

    方法1:

    内核中,可以使用virt_to_phys()可以实现虚拟地址转换为物理地址,代码清单如下:

      #define _ _pa(x)  ((unsigned long)(x)-PAGE_OFFSET)
      extern inline unsigned long virt_to_phys(volatile void * address)
      {
        return _ _pa(address);
      }

       与之对应的函数是phys_to_virt(),用于将物理地址转化为虚拟地址。具体代码如下:

       #define  _ _pa(x)      ((unsigned long)(x)+PAGE_OFFSET)

    extern inline unsigned long virt_to_phys(volatile void * address)

       {

    return _ _pa (address);

       }

    注意:上述方法仅适用于内核空间地址对于常规内存的访问,对于高端内存的访问,需要通过kmap和kunmap来动态映射访问。

     

    方法2:

        通过ioremap函数将设备所处的物理地址空间映射到虚拟地址空间

         ioremap()原型:

               void *ioremap(unsigned long offset, unsigned long size);

         它返回一个特殊的虚拟地址,用来存取特定的物理地址页面,我们可以通过c指针来访问这些地址,

          iounmap()原型:

                void iounmap(void *addr);

          它用来释放通过ioremap映射的虚拟地址空间

      

    方法3:

        通过mmap结合 /dev/mem 来直接映射物理内存空间,这种可以在应用程序态访问内核态的东西

        /dev/mem 是物理内存的全镜像,可以用来访问物理I/O设备。通常只有root用户对其有读写权限

    [Note]:新内核版本限制了/dev/mem中的内存访问接口,

       /dev/kmem :kernel看到的虚拟内存全镜像,可以用来访问kernel的内容,查看kernel变量,用作rootkit等

        对于/dev/mem,我们可以把他当做一个字符设备,先open,再read或者write就行。 也可以直接通过命令来查看和修改物理内存内容,这个命令就是hexedit

       通过它,可以显示/dev/mem中的内容。执行 hexedit /dev/mem,显示结果如下:一行显示16个字节内容,从左到右分布是物理内存地址:4组十六进制内容,对应的ASCII内容。

    image

        按tab键进入修改模式,修改内容以粗体显示,按F2保存内容,按ctrl+c退出。

       下面的函数需要 sys/mman.h 头文件支持。

    1. void *mmap(void *stat,             //映射结果地址,通常设为NULL,表示系统自动选择映射成功后的地址

                        size_t length,           //映射大小,以字节为单位

                        int prot,                  // 映射区保护方式:可执行(PROT_EXEC),可读(PROT_READ),可写(PROT_WRITE)

                        int flag,                  // 特性选项:MAP_SHARED对映射区域的写入写回到fd中) MAP_PRIVATE(对映射区域的写入不写回到fd)

                        int fd,                    // 指定映射的文件描述符(本例中,为由open以可读写的方式打开/dev/mem)

                        off_t offset             // 被映射的偏移量 ,表示从哪个文件开始映射,一般设置为0,表示从头开始映射。offset必须为页大小的倍数(4K)

                         )

       映射成功,返回对于的虚拟地址空间,映射失败,返回MAP_FAILED,同时errno错误变量被设置。

    2. void munmap(void *addr,size_t length )  // 释放映射的虚拟内存空间 当调用进程终止时,该区域自动解除映射关系。关闭打开的文件描述符不会解除映射关系。

       解除映射成功,munmap返回0,失败返回-1,全局errno被设置。

    3. int  msync(void *addr,           //回写映射开始地址

                      size_t  length,        // 回写长度

                      int flags                // MS_ASYNC: 异步调用,立即返回,回写操作由系统管理

                                                 // MS_SYNC:同步调用,阻塞,直到回写完成后才返回

                      )

          msync将写入共享映射区的信息回写到磁盘上,不使用它,在munmap调用之前,无法确保写入映射区的内容真实写入磁盘中。

          回写成功,返回0,失败返回-1,同时设置全局错误变量errno 。

     

    Technorati 标签:
  • 相关阅读:
    ORACLE PL/SQL使用经验总结 [转]
    网页表单项Input的高级限制级用法 [转]
    Zend_Search_Lucene索引更新
    Zend Framework 1.10.1 开始使用 Zend_Search_Lucene
    使用zend Framework的lucene进行全文检索——中文分词
    SQL to Select a random row from a database table
    php源代码之函数集介绍
    Zend Framework之Search_Lucene实例
    array_multisort根据字段给数组排序
    php soap实例讲解
  • 原文地址:https://www.cnblogs.com/cherishui/p/4238690.html
Copyright © 2011-2022 走看看