ioremap()

Posted Li-Yongjun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ioremap()相关的知识,希望对你有一定的参考价值。

活动地址:CSDN21天学习挑战赛

前言

之前,我们使用 devmem 命令的方式,直接操作寄存器,控制 LED 的亮灭。
今天,我们在内核中使用 ioremap() 来实现该功能。

物理地址 vs 虚拟地址

在嵌入式 Linux 中,通常会将外设的寄存器地址,映射到物理内存地址上,方便统一管理。
但是,不管是内核空间代码,还是用户空间代码,访问的都是虚拟地址

*(int *)0x87800000 = 100;

上述代码,将地址为 0x87800000 的内存赋值 100。但是,你需要知道的是,这个 0x87800000 地址,是个虚拟内存地址,它和实际物理内存地址 0x87800000 没有半毛钱关系。虚拟地址 0x87800000 会经过 mmc 映射到物理地址上,这个物理地址是多少,我们不用关心,也无法左右,可能是 0x00008888,也可能是 0x77776666,都不影响程序运行。
如果我们想要人为地和某个物理地址有联系该怎么办呢?比如说想要读写某一寄存器。这时候就要用到 ioremap() 了。

ioremap()

Linux 在 asm/io.h 中声明了 ioremap 函数,用来将 I/O 内存资源的物理地址映射到核心虚拟地址空间(内核空间:3GB~4GB)中,原型如下

#define ioremap(offset, size)		__ioremap((offset), (size), 0)
void __iomem *__ioremap(unsigned long phys_addr, size_t size, unsigned long flags);

参数:
phys_addr:要映射的起始的 I/O 地址
size:要映射的空间的大小
flags:要映射的 I/O 空间和权限有关的标志

返回值:
返回映射后的内核虚拟地址(3G-4G)

接着便可以通过读写该返回的内核虚拟地址去访问这段 I/O 内存资源。

示例

led_drv.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/io.h>

#define GPIO_CLR_REG ((__u32)0x3f200028)
#define GPIO_SET_REG ((__u32)0x3f20001C)
static volatile __u32 *gpio_led_reg;

static int led_init(void)

	printk("led on\\n");

	gpio_led_reg = (__u32 *)ioremap(GPIO_CLR_REG, 4);
	writel(0x7F, gpio_led_reg);

	return 0;


static void led_exit(void)

	printk("led off\\n");

	gpio_led_reg = (__u32 *)ioremap(GPIO_SET_REG, 4);
	writel(0x7F, gpio_led_reg);


module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("Dual BSD/GPL");

Makefile

obj-m = led_drv.o

KDIR=/home/liyongjun/project/board/buildroot/RPi3/build/linux-custom
CROSS_COMPILE=/home/liyongjun/project/board/buildroot/RPi3/host/bin/arm-buildroot-linux-uclibcgnueabihf-

all:
	make -C $(KDIR) M=$(PWD) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) modules
clean:
	make -C $(KDIR) M=$(PWD) ARCH=arm CROSS_COMPILE=$(CROSS_COMPILE) clean

运行

编译后将 led_drv.ko 上传到树莓派,在树莓派上安装、卸载。

# insmod led_drv.ko 
[ 3168.850425] led on

# rmmod led_drv.ko 
[ 3242.458328] led off

以上是关于ioremap()的主要内容,如果未能解决你的问题,请参考以下文章

初学Linux,linux中使用ioremap函数可以映射一个数组吗?

ioremap()

ioremap()

linux中ioremap和mmap的区别

ioremap将物理地址映射为虚拟地址问题?

Linux 字符设备驱动—— ioremap() 函数解析