一、地址映射
MMU 全称叫做 Memory Manage Unit,也就是内存管理单元。在老版本的 Linux 中要求处理器必须有 MMU,但是现在Linux 内核已经支持无 MMU 的处理器了。MMU主要功能:
①、完成虚拟空间到物理空间的映射。
②、内存保护,设置存储器的访问权限,设置虚拟存储空间的缓冲特性。
对于 32 位的处理器,虚拟地址范围是 2^32=4GB,我们的阿尔法开发板上有 512MB 的 DDR3,这 512MB 的内存就是物理内存(RAM),经过 MMU 可以将其映射到整个 4GB 的虚拟空间。虚拟地址范围比物理地址范围大的问题处理器自会处理,这里我们不要去深究。
二、物理内存与虚拟内存的转换
Linux 内核启动的时候会初始化 MMU,设置好内存映射,设置好以后 CPU 访问的都是虚拟地址。
1、ioremap 函数
ioremap 函数用于获取指定物理地址空间对应的虚拟地址空间。
假如我们要获取 I.MX6ULL 的 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 寄存器对应的虚拟地址,使用如下代码即可:
#define SW_MUX_GPIO1_IO03_BASE (0X020E0068) // 物理地址
static void __iomem* SW_MUX_GPIO1_IO03;
SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4); // 虚拟地址,对于 I.MX6ULL 来说一个寄存器是 4 字节(32 位)的,因此映射的内存长度为 4。
2、iounmap 函数
卸载驱动的时候需要使用 iounmap 函数释放掉 ioremap 函数所做的映射。
iounmap 只有一个参数 addr,此参数就是要取消映射的虚拟地址空间首地址,即SW_MUX_GPIO1_IO03。
iounmap(SW_MUX_GPIO1_IO03);
三、I/O 内存访问函数
这里涉及到两个概念:I/O 端口和 I/O 内存。
- I/O 端口: 当外部寄存器或内存映射到 IO 空间时,例如我们学习单片机的时候讲的 GPIO 引脚。
- I/O 内存: 当外部寄存器或内存映射到内存空间时。
但是对于 ARM 来说没有 I/O 空间这个概念(ARM 处理器通过内存映射 I/O 来控制 I/O 设备,而不是使用独立的I/O地址空间),因此 ARM 体系下只有 I/O 内存(可以直接理解为内存)。
使用 ioremap 函数将寄存器的物理地址映射到虚拟地址以后,我们就可以直接通过指针访问这些地址,但是 Linux 内核不建议这么做,如果直接操作虚拟内存可能出现一些意想不到的问题,因此这里推荐使用提供的两个函数进行操作。
1、读操作函数
参数 addr 就是要读取写内存地址,返回值就是读取到的数据。文章来源:https://www.toymoban.com/news/detail-450531.html
// 分别是1字节、2字节、4字节( 8bit、16bit 和 32bit )读操作
1 u8 readb(const volatile void __iomem *addr)
2 u16 readw(const volatile void __iomem *addr)
3 u32 readl(const volatile void __iomem *addr)
2、写操作函数
参数 value 是要写入的数值,addr 是要写入的地址。文章来源地址https://www.toymoban.com/news/detail-450531.html
// 8bit、16bit 和 32bit 写操作
1 void writeb(u8 value, volatile void __iomem *addr)
2 void writew(u16 value, volatile void __iomem *addr)
3 void writel(u32 value, volatile void __iomem *addr)
到了这里,关于【Linux驱动开发】004 物理内存与虚拟内存的转换的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!