首页 理论教育深入剖析Linux内核与设备驱动:TI芯片地址映射实现详解

深入剖析Linux内核与设备驱动:TI芯片地址映射实现详解

【摘要】:图4-24DM 3730物理空间设置IO空间映射的目的就是将这些物理地址映射到整个内核的地址空间中。首先来看ioremap虚拟地址返回是如何实现的。DM 3730等TI芯片就是通过该方法来实现该功能的。注意__arm_ioremap_caller使用的是vmalloc的空间进行映射,在相应版本内核中vmalloc的空间和TI芯片的IO映射空间是完全分开的,所以这里要直接返回相应的虚拟地址。

1.芯片相关的内核地址空间分配和映射

现在看看具体芯片在地址映射这部分是如何实现的。内存部分的映射完全可以通过启动参数以及一些宏定义实现。通过mem和vmalloc这两个内核提供的启动参数以及VMALLOC_START和VMALLOC_END两个宏,可以将lowmem和vmalloc的空间定下来。相关的宏定义DM 3730和DM 816X的内核代码如下:

978-7-111-49426-3-Chapter04-98.jpg

vmalloc的空间是在lowmem之后的8MB开始的,当然vmalloc的空间不是随意大小的,会有最小空间的限制,默认限制如下:

978-7-111-49426-3-Chapter04-99.jpg

当然相应的大小可以由启动参数vmalloc进行设置,但是也不能小于16MB。有了总的内存设置(启动参数mem),有了vmalloc空间的结束设置和最小空间限制,内存的映射基本就解决了。如果内存容量超出了这些空间,还有pkmap可以进行映射。当然之前说明新的内核中(DM 3730和DM 816X没有相应版本的实现)VMALLOC_END已经直接由ARM内核设定为0xff000000了,这样的调整对于实现没有太大的影响,因为这是地址空间的调整,具体映射的内容可以在映射模块内部解决兼容性的问题。

2.IO空间在内核中的映射

接下来的重点是IO空间的映射。首先,来看看DM 3730的物理空间是如何设置的,如图4-24所示。图4-24引自《DM 3730芯片手册》中第204页的表,由于表比较大,这里只截取一部分。

978-7-111-49426-3-Chapter04-100.jpg

图4-24 DM 3730物理空间设置

IO空间映射的目的就是将这些物理地址映射到整个内核的地址空间中。下面来看看DM3730内核中映射关系是怎样的。在arch/arm/plat-omap/include/mach/io.h中定义映射关系如下:

978-7-111-49426-3-Chapter04-101.jpg

978-7-111-49426-3-Chapter04-102.jpg

可见映射是从0xf8000000开始的,正好是在vmalloc之后,这样就不会有空间重叠的问题。从物理地址的角度和图4-24中描述的地址也是吻合的,只是代码中每部分的空间只保留使用的部分,不像物理上预留了更多的空间。

有了这样的映射关系之后,就要解决两个问题:一个是ioremap如何返回正确的虚拟地址;另外一个就是实际的映射建立。(www.chuimin.cn)

首先来看ioremap虚拟地址返回是如何实现的。在ARM的io.h中有如下定义:

978-7-111-49426-3-Chapter04-103.jpg

可见,可以通过定义特别的arch_ioremap来实现ioremap的重定向。DM 3730等TI芯片就是通过该方法来实现该功能的。下面来看看细节,在arch/arm/plat-omap/include/mach/io.h中有如下定义:

978-7-111-49426-3-Chapter04-104.jpg

最终由omap_ioremap来实现ioremap的功能,看看omap_ioremap的代码就清楚了。代码如下:

978-7-111-49426-3-Chapter04-105.jpg

978-7-111-49426-3-Chapter04-106.jpg

其中所做的工作就是,如果是映射关系中的物理地址就直接转换为相应的虚拟地址并返回,否则就使用ARM内核提供的__arm_ioremap_caller进行映射。注意__arm_ioremap_caller使用的是vmalloc的空间进行映射,在相应版本内核中vmalloc的空间和TI芯片的IO映射空间是完全分开的,所以这里要直接返回相应的虚拟地址。新内核的iotable_init是通过vmal-loc空间的静态分配来将这部分地址在初始化的时候保留,这样就可以直接使用ARM内核的ioremap而不需要进行重定向了。新内核的该功能进一步减少了不同处理器之间的差别,减少了移植的工作量。

具体映射的建立则是从板级相关的初始化接口map_io开始。对于DM 3730相应的map_io为omap3_map_io,其内容如下:

978-7-111-49426-3-Chapter04-107.jpg

重点是在omap34xx_map_common_io中,该函数及相关函数详细说明。其代码如下:

978-7-111-49426-3-Chapter04-108.jpg

IO空间页表的映射是通过ARM内核提供的iotable_init实现的。映射之后就进行寄存器的访问以及片内RAM的初始化,片内RAM的初始化由于和内存管理相关,还是放在内存管理的实现中进行说明。而对于具体的映射属性是通过omap34xx_io_desc数组定义的,具体的数组内容可以通过实际代码来了解细节。