Linux系统中的地址映射

发布时间:2023年12月23日

一.? 简介

在前面的裸机开发实验 LED灯实验中 ,其实就是操作 IMX6ULL芯片的寄存器。

Linux 驱动开发也可以操作寄存器,但是,Linux不能直接对寄存器物理地址进行读写操作,例如,寄存器 A的物理地址为 0X01010101。?裸机开发时可以直接对 0X01010101这个物理地址进行操作,但是,Linux 开发则不行。因为 Linux会使能 MMU。

MMU 全称叫做 Memory Manage Unit,也就是内存管理单元。在老版本的 Linux 中要求处理器必须有 MMU,但是现在 Linux 内核已经支持无 MMU 的处理器了。

二.? Linux系统中的地址映射

1.? MMU(即内存管理单元)

MMU也就是内存管理单元。主要完成的功能如下:

①? 完成虚拟空间到物理空间的映射。
②? 内存保护,设置存储器的访问权限,设置虚拟存储空间的缓冲特性。
地址映射

我们重点来看一下第 ① 点,也就是虚拟空间到物理空间的映射,也叫做地址映射。

首先了
解两个地址概念:虚拟地址 (VA,Virtual Address) 、物理地址 (PA PhyscicalAddress) 。对于 32
的处理器来说,虚拟地址范围是 2^32=4GB ,我所使用的开发板DDR3的容量是 256MB ,这? 256MB 内存就是物理内存,经过 MMU 可以将其映射到整个 4GB 的虚拟空间。
注意:不单单是 DDR,外设的寄存器的地址也是物理地址!!
如下图 所示:

物理内存只有 512MB ,虚拟内存有 4GB ,那么肯定存在多个虚拟地址映射到同一个物理地址上去,虚拟地址范围比物理地址范围大的问题处理器自会处理,这里我们不要去深究,因为 MMU 是很复杂的一个东西。

2.? 内存映射涉及函数

Linux 内核启动的时候会初始化 MMU ,设置好内存映射,设置好以后 CPU 访问的都是虚
拟 地 址 。
例如, I.MX6ULL GPIO1_IO03 引 脚 的 复 用 寄 存 器 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 的地址为 0X020E0068 。如果没有开启 MMU 的话, 直接向 0X020E0068 这个寄存器地址写入数据就可以配置 GPIO1_IO03 的复用功能。
现在开启 MMU ,并且设置了内存映射,因此,就不能直接向 0X020E0068 这个地址写入数据了。我们必 须得到 0X020E0068 这个物理地址在 Linux 系统里面对应的虚拟地址。
这里就涉及到了物理内 存和虚拟内存之间的转换,需要用到两个函数: ioremap()函数 iounmap 函数。

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 类型的指针,指向映射后的虚拟空间首地址。

iounmap 函数

卸载驱动时,需要使用 iounmap 函数释放掉 ioremap 函数所做的映射, iounmap 函数原
型如下:
void iounmap (volatile void __iomem *addr)
iounmap 只有一个参数 addr ,此参数就是要取消映射的虚拟地址空间首地址。

三.? 举例说明

假如,我们要获取 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);
SW_MUX_GPIO1_IO03_BASE 是寄存器物理地址, SW_MUX_GPIO1_IO03 是映射后
的虚拟地址。对于 I.MX6ULL 来说一个寄存器是 4 字节 (32 ) 的,因此映射的内存长度为 4
映射完成以后直接对 SW_MUX_GPIO1_IO03 进行读写操作即可。

假如,我们现在要取消掉 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 寄存器的地址映射,使用如下代码 即可:
iounmap(SW_MUX_GPIO1_IO03);

这里了解 Linux地址映射,主要为 LED灯驱动开发准备。

文章来源:https://blog.csdn.net/wojiaxiaohuang2014/article/details/135163048
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。