一、地址映射

我们知道 STM32 无法跑 Linux 系统,是由于它内部没有 MMU(内存管理单元),MMU 主要完成的功能如下:

(1)完成虚拟空间到物理空间的映射。

(2)内存保护,设置存储器的访问权限,设置虚拟存储空间的缓冲特性。

Linux 内核启动的时候会初始化 MMU,设置好内存映射,设置好以后 CPU 访问的都是虚拟地址 。

emmc 驱动开发_内核


如:I.MX6ULL 的 GPIO1_IO03 引脚的复用寄存器 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 地址为 0x020E0068。如果没有开启 MMU,直接向 0x020E0068 地址处写入数据即可配置复用功能。但现在开启了 MMU 并设置了内存映射,因此就不能直接向 0X020E0068 这个地址写入数据了。我们必须得到 0x020E0068 这个物理地址在 Linux 系统里面对应的虚拟地址,这里就涉及到了物理内存和虚拟内存之间的转换,需要用到两个函数:ioremap 和 iounmap。

1、ioremap 函数

用于获取指定物理地址空间对应的虚拟地址空间。

函数原型:void __iomem * ioremap(cookie,size) 			// cookie-物理起始地址  size-映射字节数
返回值:__iomem 类型的指针,指向映射后的虚拟空间首地址

我们要获取 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);

2、iounmap 函数

卸载驱动时需要使用 iounmap 函数释放掉 ioremap 函数所做的映射。

函数原型:void iounmap (volatile void __iomem *addr)

__iomem 是什么意思?

【答】:用来表示指针是指向一个 I/O 的内存空间,检查地址空间的有效性。

#define __iomem __attribute((noderef,address_space(2)))

attribute 用来修饰变量,这个变量必须是非解除参考(noderef),即这个变量地址必须是有效的,而且所在的地址空间必须是 2,即 I/O 存储空间。

二、 I/O 内存访问函数

可直接通过指针访问这些地址,但是 Linux 内核不建议这么做,而是推荐使用操作函数对映射后的内存进行读写操作。

1、读操作函数

u32 readl(const volatile void __iomem *addr)   // 32bit 读操作,返回值是读到的值

2、写操作函数

void writel(u32 value, volatile void __iomem *addr)   // 32bit 写操作