4. 嵌入式linux驱动-虚拟地址映射

1. 什么是虚拟地址

  所谓虚拟地址映射就是从虚拟地址映射到物理地址,MMU开启后,CPU访问的地址都是虚拟地址。不光linux采用虚拟地址,windows等其他操作系统也采用虚拟地址而不直接使用物理地址。

2. 为什么要使用虚拟地址

  直接使用物理地址的存在的问题:

  • 安全风险。每个进程都可以访问0-4G的任意的内存空间,这也就意味着任意一个进程都能够去读写系统相关内存区域,如果是一个 木马病毒,那么他就能随意的修改内存空间,让设备直接瘫痪。
  • 地址不确定。众所周知,编译完成后的程序是存放在硬盘上的,当运行的时候,需要将程序搬到内存当中去运行,如果直接使用物理地址的话,我们无法确定内存现在使用到哪里了,也就是说拷贝的实际内存地址每一次运行都是不确定的,比如:第一次执行a.out时候,内存当中一个进程都没有运行,所以搬移到内存地址是0x00000000,但是第二次的时候,内存已经有10个进程在运行了,那执行a.out的时候,内存地址就不一定了。
  • 效率低下。如果直接使用物理内存的话,一个进程就是作为一个整体(内存块)操作的,如果出现物理内存不够用的时候,我们一般的办法是将不常用的进程拷贝到磁盘的交换分区中,好腾出内存,但是如果是物理地址的话,就需要将整个进程一起拷走,这样,在内存和磁盘之间拷贝时间太长,效率较低。

3. 两种映射方式

  虚拟地址映射分为静态映射动态映射

3-1. 静态映射

  所谓的映射表其实是头文件中的宏定义。

  • 在内核启动时建立静态映射表,在内核关机时销毁,中间一直有效,优点是执行效率高,缺点是始终占用虚拟地址空间,空间利用率低。
  • 不同版本内核静态映射表位置,文件名可能不同。
  • 不同的SOC静态映射表位置,文件名可能不同。

  使用方法:
  地址映射表中虚拟地址定义如下

#define S5PV210_GPJ0CON    0xFD050240
#define S5PV210_GPJ0DAT    0xFD050244

  在驱动程序中使用

// 地址定义
#define GPJ0CON  S5PV210_GPJ0CON
#define GPJ0DAT  S5PV210_GPJ0DAT
// 寄存器定义
#define rGPJ0CON*((volatile unsigned int *)GPJ0CON)
#define rGPJ0DAT*((volatile unsigned int *)GPJ0DAT)
// 操作寄存器
rGPJ0CON = 0x11111111;    // 设置寄存器的相应位
rGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));    // 亮
rGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));    // 灭

3-2. 动态映射

  驱动程序根据需要随时动态建立使用和销毁映射,映射是短期临时的。
  使用方法:

// 物理地址定义
#define GPJ0CON_PA	0xE0200240
#define GPJ0DAT_PA 	0xE0200244
// 定义映射后的指针(地址)
unsigned int *pGPJ0CON;
unsigned int *pGPJ0DAT;
/************************** 建立映射 ******************************/
// 先申请内存
if (!request_mem_region(GPJ0CON_PA, 4, "GPJ0CON"))
	return -EINVAL;
if (!request_mem_region(GPJ0DAT_PA, 4, "GPJ0CON"))
	return -EINVAL;
// 再进行地址映射
pGPJ0CON = ioremap(GPJ0CON_PA, 4);
pGPJ0DAT = ioremap(GPJ0DAT_PA, 4);

/************************** 使用虚拟地址 ******************************/
// 操作寄存器
*pGPJ0CON = 0x11111111;    // 设置寄存器的相应位
*pGPJ0DAT = ((0<<3) | (0<<4) | (0<<5));    // 亮
*pGPJ0DAT = ((1<<3) | (1<<4) | (1<<5));    // 灭
/************************** 解除映射 ******************************/
// 先解除映射
iounmap(pGPJ0CON);
iounmap(pGPJ0DAT);
// 再释放内存
release_mem_region(GPJ0CON_PA, 4);
release_mem_region(GPJ0DAT_PA, 4);

3-3. 如何选择两种映射方法

  • 两种映射并不排他,可以同时使用。
  • 静态映射类似于C语言中全局变量,动态方式类似于C语言中malloc堆内存。
  • 静态映射的好处是执行效率高,坏处是始终占用虚拟地址空间;动态映射的好处是按需使用虚拟地址空间,坏处是每次使用前后都需要代码去建立映射&销毁映射(还得学会使用那些内核函数的使用)。

猜你喜欢

转载自blog.csdn.net/zhangyzh656/article/details/82849473
今日推荐