一、地址映射
先简单了解一下MMU这个神器,MMU全称叫做Memory Manage Unit,也就是内存管理单元。在老版本的Linux中要求处理器必须有MMU,但是现在Linux内核已经支持无MMU的处理器了。MMU主要完成的功能如下:
- ①、完成虚拟空间到物理空间的映射。
- ②、内存保护,设置存储器的访问权限,设置虚拟存储空间的缓冲特性。
我们虚拟空间到物理空间的映射,也叫做地址映射。对于32位的处理器来说,虚拟地址范围是2^32=4GB,但物理内存却没有这么大,经过MMU可以将其映射到整个4GB的虚拟空间,如下图所示:
物理内存只有512MB,虚拟内存有4GB,那么肯定存在多个虚拟地址映射到同一个物理地址上去,虚拟地址范围比物理地址范围大的问题处理器自会处理,这里不需要去深究。
1、ioremap函数
ioremap函数用于获取指定物理地址空间对应的虚拟地址空间,定义在
arch/arm/include/asm/io.h文件中,定义如下:
#define ioremap(cookie,size)__arm_ioremap((cookie),(size),
MT_DEVICE)
void __iomem* __arm_ioremap(phys_addr_t phys_addr,size_t size,
unsigned int mtype)
{
return arch_ioremap_caller(phys_addr,size,mtype,builtin_return_address(0));
}
ioremap是个宏,有两个参数:cookie和size,真正起作用的是函数__arm_ioremap,此函数有三个参数和一个返回值,这些参数和返回值的含义如下:
- phys_addr:要映射给的物理起始地址。
- size:要映射的内存空间大小。
- mtype:ioremap的类型,可以选择MT_DEVICE、MT_DEVICE_NONSHARED、MT_DEVICE_CACHED和MT_DEVICE_WC,ioremap函数选择MT_DEVICE。
- 返回值:__iomem类型的指针,指向映射后的虚拟空间首地址。
2、iounmap函数
卸载驱动的时候需要使用iounmap函数释放掉ioremap函数所做的映射,iounmap函数原型如下:
void iounmap (volatile void _iomem *addr)
iounmap只有一个参数addr,此参数就是要取消映射的虚拟地址空间首地址。
二、I/O内存访问函数
这里说的I/O是输入输出的意思,并不是单片机的时候讲的GPIO引脚。这里涉及到两个概念:I/O端口和I/O内存。当外部寄存器或内存映射到IO空间时,称为I/O端口。当外部寄存器或内存映射到内存空间时,称为I/O内存。但是对于ARM来说没有I/O空间这个概念,因此ARM体系下只有I/O内存(可以直接理解为内存)。使用ioremap函数将寄存器的物理地址映射到虚拟地址以后,就可以直接通过指针访问这些地址,但是Linux内核不建议这么做,而是推荐使用一组操作函数来对映射后的内存进行读写操作。
1、读操作函数
u8 readb(const volatile void __iomem *addr)
u16 readw(const volatile void __iomem *addr)
u32 readl(const volatile void __iomem *addr)
readb、readw和readl这三个函数分别对应8bit、16bit和32bit读操作,参数addr就是要读取写内存地址,返回值就是读取到的数据。
2、写操作函数
u8 writeb(u8 value, const volatile void __iomem *addr)
u16 writew(u16 value, const volatile void __iomem *addr)
u32 writel(u32 value, const volatile void __iomem *addr)
writeb、writew和writel这三个函数分别对应8bit、16bit和32bit读操作,参数addr就是要读取写内存地址,返回值就是读取到的数据。