一:当我们开启了MMU之后,使用的都是虚拟地址,这时就需要考虑物理地址到虚拟地址的映射问题。建立映射表的三个关键部分是:
(1)映射表
(2)映射表建立函数
(3)映射表建立函数被调用
1:映射表
(1)映射表是具体的物理地址和虚拟地址的起始地址定义,在我们前面使用静态映射来操作LED时有介绍,三星版本的移植的内核,其主映射表在arch/arm/plat-s5p/include/plat/map-s5p.h和arch/arm/plat-samsung/include/plat/map-base.h中
arch/arm/plat-s5p/include/plat/map-s5p.h的主要内容如下
arch/arm/plat-samsung/include/plat/map-base.h的主要内容如下:
在这里,我们指定了虚拟地址的基地址,也就是宏S3C_ADDR_BASE 0XFD000000,在我们开启了MMU之后,其映射的虚拟地址都是根据这个基地址+偏移量来得到的某个具体的寄存器的,这样当我们建立了映射之后,就可以直接操作虚拟地址来操作我们对应的寄存器,在这里,也只是映射了需要用到的寄存器的虚拟地址,假如要添加,则只需在map-s5p.h中添加相应的映射即可。
(2)GPIO相关的主映射表位于:arch/arm/machs5pv210/include/mach/regs-gpio.h
GPIO的具体寄存器定义位于:arch/arm/mach-s5pv210/include/mach/gpio-bank.h
需要注意的是,不同版本的内核其映射表的位置是不同的,,但是一般都在arch/arm/xxx/map_xx.h文件中
2:映射表的建立过程
上面,我们介绍了内核通过宏定义定义了很多寄存器对应虚拟地址的基地址,那么这些宏是在哪被调用的呢,映射表又是如何被调用的呢。
答案就是kernel/arch/arm/mach-s5pv210/mach-smdkc110.c中的smdkc110_map_io函数。它的调用层级如下:
smdkc110_map_io
s5p_init_io
iotable_init
iotable_init(s5p_iodesc, ARRAY_SIZE(s5p_iodesc));
iotable_init函数就是最终实现建立虚拟地址映射的函数。其中S5P_iodesc是一个数组,它里面包括了我们上面用大量的宏定义得到的映射表。也就是说我们上面创建的宏都在这里被使用到了。
所以当我们需要添加新的虚拟地址映射时只需要做两步
(1)在我们的map-s5p.h或者是map-base.h中添加相应的宏定义
(2)在我们的s5p_iodesc中添加相应的数组元素
3:映射表建立函数的调用过程