Linux系统中的地址映射

2023-12-23 06:40:32

一.? 简介

在前面的裸机开发实验 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
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。