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

2019-07-13 05:22发布

文章目录

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堆内存。
  • 静态映射的好处是执行效率高,坏处是始终占用虚拟地址空间;动态映射的好处是按需使用虚拟地址空间,坏处是每次使用前后都需要代码去建立映射&销毁映射(还得学会使用那些内核函数的使用)。