zoukankan      html  css  js  c++  java
  • linux内存操作--ioremap和mmap学习笔记

    最近做一些相关的视频输出,对于保留framebuffer内存使用情况不是很清楚,现在找了一些资料整理出,准备使用。if (希望看到使用)  goto   用法;

    对于一个系统来讲,会有非常多的外设,那么这些外设的管理都是通过CPU完毕。那么CPU在这个过程中是怎样找到外设的呢?

    虽然在一个系统中会有诸多的外设,在每一个外设的接口电路中会有多个port。可是假设系统可以每一个port都被赋予一个详细的地址值。那么在系统中就能轻易的找到不论什么一个外设。系统在管理的时候。无论是内存还是外设都须要分配一个内存地址。对于一个32bit的系统来讲,可寻址的范围为2^32=4G的地址空间。

    既然说到地址空间,就要明白地址空间的种类:物理地址、总线地址、虚拟地址。

    (1)物理地址

    CPU地址总线传来的地址,由硬件电路控制其详细含义。

    物理地址中非常大一部分是留给内存条中内存的。但也常被映射到其它存储器上(如显存、bios等)。

    在程序指令中的虚拟地址经过段映射和页面映射后。就生成了物理地址,这个物理地址被放到CPU的地址线上。

    (2)总线地址

    总线的地址线或在地址周期上产生的信号。

    外设使用的是地址总线,cpu使用的是物理地址。

    物理地址和总线地址之间的关系有系统设计决定的。

    在X86平台上,物理地址就是总线地址。这是由于它们共享同样的地址空间。在其它平台上,可能须要转换/映射。

    (3)虚拟地址

    现代操作系统普遍採用虚拟内存管理(virtual memory management)机制,这须要MMU的支持。

    MMU一般是CPU的一部分,假设处理器没有MMU,或者有MMU但没有启用,CPU运行单元发出的内存地址将直接传到芯片引脚上,被内存芯片(物理内存)接收。这成为物理地址。假设处理器启用了MMU,CPU运行单元发出的内存地址将被MMU截获,从CPU到MMU的地址称为虚拟地址,而MMU将这个地址翻译成还有一个地址发到CPU芯片的外部地址引脚上。也就是讲虚拟地址映射成物理地址。

          linux中,进程的4GB内存分为用户空间和内核空间。

    用户空间分布为1~3GB剩下的1GB为内核空间。程序猿仅仅能使用虚拟地址。

    系统中每一个进程有各自的私实用户控件(0~3GB),这个空间对系统中的其它进程是不可见的。

    编址方式

      外设都是通过读写设备上的寄存器来进行工作的,外设寄存器也称为“IOport”,而IOport的编址方式有两种,独立编址和统一编址。

    统一编址:外设接口中的IO寄存器(即IOport)与主存单元一样看待,每一个port占用一个存储单元的地址,将主存的一部分划出来用作IO地址空间。

     统一编址的原理是将IO的port地址存储器寻址的地址空间范围之内,此方法也成为存储器映像编址。

    CPU訪问一个port的操作与訪问内存的操作同样,也使用訪问内存的指令。

    独立编址是为port地址单独开辟一部分地址空间,其訪问指令也须要使用单独的指令(不同于内存訪问指令)

       依据CPU体系结构的不同,CPU对IOport的编址方式有两种:

      (1)I/O映射方式(I/O-mapped)
      典型地,如X86处理器为外设专门实现了一个单独的地址空间,称为"I/O地址空间"或者"I/Oport空间",CPU通过专门的I/O指令(如X86的IN和OUT指令)来訪问这一空间中的地址单元。


      (2)内存映射方式(Memory-mapped)
      RISC指令系统的CPU(如ARM、PowerPC等)通常仅仅实现一个物理地址空间,外设I/Oport成为内存的一部分。

    此时,CPU能够象訪问一个内存单元那样訪问外设I/Oport,而不须要设立专门的外设I/O指令。
      可是,这两者在硬件实现上的差异对于软件来说是全然透明的,驱动程序开发者能够将内存映射方式的I/Oport和外设内存统一看作是"I/O内存"资源。
     一般来说,在系统执行时,外设的I/O内存资源的物理地址是已知的。由硬件的设计决定。可是CPU通常并没有为这些已知的外设I/O内存资源的物理地址提前定义虚拟地址范围。驱动程序并不能直接通过物理地址訪问I/O内存资源。而必须将它们映射到核心虚地址空间内(通过页表),然后才干依据映射所得到的核心虚地址范围,通过訪内指令訪问这些I/O内存资源。

    void * __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags) 
    入口: phys_addr:要映射的起始的IO地址。 
    size:要映射的空间的大小。 
    flags:要映射的IO空间的和权限有关的标志; 
    功能: 将一个IO地址空间映射到内核的虚拟地址空间上去。便于訪问; 
    实现:对要映射的IO地址空间进行推断。低PCI/ISA地址不须要又一次映射。也不同意用户将IO地址空间映射到正在使用的RAM中,最后申请一 个 vm_area_struct结构。调用remap_area_pages填写页表,若填写过程不成功则释放申请的vm_area_struct空 间;
    意义:
    比方isa设备和pci设备,或者是fb。硬件的跳线或者是物理连接方式决定了硬件上的内存影射到的cpu物理地址。

     
    在内核訪问这些地址必须分配给这段内存以虚拟地址,这正是__ioremap的意义所在 ,须要注意的是,物理内存已经"存在"了,无需alloc page给这段地址了. 

    为了使软件訪问I/O内存,必须为设备分配虚拟地址.这就是ioremap的工作.这个函数专门用来为I/O内存区域分配虚拟地址(空间).对于直接映射的I/O地址ioremap不做不论什么事情。

    有了ioremap(和iounmap),设备就能够訪问不论什么I/O内存空间,不论它是否直接映射到虚拟地址空间.可是,这些地址永远不能直接使用(指物理地址),而要用readb这样的函数。

    使用I/O内存首先要申请,然后才干映射,使用I/Oport首先要申请,或者叫请求,对于I/Oport的请求意思是让内核知道你要訪问这个port,这样内核知道了以后它就不会再让别人也訪问这个port了.毕竟这个世界僧多粥少啊.申请I/Oport的函数是request_region, 申请I/O内存的函数是request_mem_region。request_mem_region函数并没有做实际性的映射工作,仅仅是告诉内核要使用一块内存地址。声明占有。也方便内核管理这些资源。重要的还是ioremap函数,ioremap主要是检查传入地址的合法性,建立页表(包含訪问权限),完毕物理地址到虚拟地址的转换。


    用法:

    内核中的使用,往往是为某个设备预留一块内存,当使用的时候须要在board中定义这个设备的内存resource。通过 platform_get_resource获得设备的起始地址后。能够对其进行request_mem_region和ioremap等操作,以便应用程序对其进行操作。

    版权声明:本文博客原创文章,博客,未经同意,不得转载。

  • 相关阅读:
    【剑指Offer】面试题14- I. 剪绳子
    【剑指Offer】面试题56
    【LeetCode】202. 快乐数
    【LeetCode】1095. 山脉数组中查找目标值
    【LeetCode】260. 只出现一次的数字 III
    【剑指Offer】面试题56
    【LeetCode】33. 搜索旋转排序数组
    【LeetCode】23. 合并K个排序链表
    【LeetCode】46. 全排列
    mysql可视化工具下载地址2017.6.27
  • 原文地址:https://www.cnblogs.com/blfshiye/p/4632136.html
Copyright © 2011-2022 走看看