ioremap和mmap作为linux内存的关键操作

对于一个系统来讲,会有很多的外设,那么这些外设的管理都是通过cpu完成。那么cpu在这个过程中是如何找到外设的呢?
尽管在一个系统中会有诸多的外设,在每个外设的接口电路中会有多个端口。但是如果系统能够每个端口都被赋予一个具体的地址值,那么在系统中就能轻易的找到任何一个外设。系统在管理的时候,不管是内存还是外设都需要分配一个内存地址。对于一个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),这个空间对系统中的其他进程是不可见的。
编址方式
外设都是通过读写设备上的寄存器来进行工作的,外设寄存器也称为“io端口”,而io端口的编址方式有两种,独立编址和统一编址。
统一编址:外设接口中的io寄存器(即io端口)与主存单元一样看待,每个端口占用一个存储单元的地址,将主存的一部分划出来用作io地址空间。统一编址的原理是将io的端口地址存储器寻址的地址空间范围之内,此方法也成为存储器映像编址。cpu访问一个端口的操作与访问内存的操作相同,也使用访问内存的指令。独立编址是为端口地址单独开辟一部分地址空间,其访问指令也需要使用单独的指令(不同于内存访问指令)。
根据cpu体系结构的不同,cpu对io端口的编址方式有两种:
(1)i/o映射方式(i/o-mapped)
典型地,如x86处理器为外设专门实现了一个单独的地址空间,称为i/o地址空间或者i/o端口空间,cpu通过专门的i/o指令(如x86的in和out指令)来访问这一空间中的地址单元。
(2)内存映射方式(memory-mapped)
risc指令系统的cpu(如arm、powerpc等)通常只实现一个物理地址空间,外设i/o端口成为内存的一部分。此时,cpu可以象访问一个内存单元那样访问外设i/o端口,而不需要设立专门的外设i/o指令。
但是,这两者在硬件实现上的差异对于软件来说是完全透明的,驱动程序开发人员可以将内存映射方式的i/o端口和外设内存统一看作是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/o端口首先要申请,或者叫请求,对于i/o端口的请求意思是让内核知道你要访问这个端口,这样内核知道了以后它就不会再让别人也访问这个端口了.毕竟这个世界僧多粥少啊.申请i/o端口的函数是request_region, 申请i/o内存的函数是request_mem_region。request_mem_region函数并没有做实际性的映射工作,只是告诉内核要使用一块内存地址,声明占有,也方便内核管理这些资源。重要的还是ioremap函数,ioremap主要是检查传入地址的合法性,建立页表(包括访问权限),完成物理地址到虚拟地址的转换。
使用方法:
内核中的使用,往往是为某个设备预留一块内存,当使用的时候需要在board中定义这个设备的内存resource。通过 platform_get_resource获得设备的起始地址后,可以对其进行request_mem_region和ioremap等操作,以便应用程序对其进行操作。

大学毕业设计一席谈之四十八 词频统计(1)
如何利用apollo实现配置文件的灰度发布?
一图读懂北斗导航的关键数据与历史
IGBT 和 GaN、SiC 和硅 FET 的统一视图和价格-性能分析
18W PD快充芯片U6615S有效缩短充电时长
ioremap和mmap作为linux内存的关键操作
至芯FPGA课程之综合理论分享
罗技推出众多新品亮相Macworld2013展会
EPC推出功率级集成电路,专为48V DC/DC转换而设计
触控一体机在医疗领域中具有着很大的市场潜力
如何做好一名高级维修工
你知道医疗应用的爬电要求?
程序员怎样向自由职业过渡
上海航芯指纹芯片及解决方案
5个秘诀,助你成功设计智能看门狗
三星GALAXY Z FOLD 2已获得稳定的ONE UI 3.0更新
如何正确选择电池 碳性电池/碱性电池/锂铁电池有哪些不同?
菜鸟驿站发布“新物种”——智能科技产品菜鸟小盒
立体声线路放大器NJU72010 简介
5G商用发令枪正式打响我国电信运营商正积极布局5G网络建设