linux物理地址的静态映射

早先看linux驱动相关书籍的时候,隐约记得物理地址有动态映射和静态映射,当时写驱动都是想着自己动手写,所以一上手看着动态映射好用,就在自己的驱动上使用动态映射,将寄存器地址映射到内存上,即调用ioremap函数。在单线作战的时候ioremap确实好用,不需要改动内核的其他部分,直接将自己想用的物理地址映射到内存再操作。但很多时候当我们的设备需要在全局范围内被使用的时候,ioremap就会比较尴尬,其他c文件想要操作该设备的虚拟地址就会比较麻烦,而静态映射就会方便很多。

最近这两天在写一个蜂鸣器的驱动,这一次我尝试放弃单线作战,使用系统提供的蜂鸣器驱动程序(driver/input/misc/pwm-beeper.c),尝试理解内核驱动程序的思想。

在mach-smdk4x12.c文件添加平台设备

static struct platform_device samsung_bp_device = {
.name= "pwm-beeper",
.dev= {
.parent = &s3c_device_timer[1].dev,
.platform_data = 1,
},
.id= 1,
};

使用platform_device_register函数将设备注册进入平台总线,这样子,在驱动程序pwm-beeper.c通过总线获取到对应的设备信息。通常来讲,只要驱动程序通过platform总线成功获取到beeper设备的信息,驱动基本上就可以使用了。在这个驱动中,蜂鸣器对应的PWM管脚要设置成相应的功能,比如在4412中将GPIOD0_1设置成功能2,即PWM输出。这样子写一个应用程序测试,蜂鸣器基本上就可以用了。但是我在看蜂鸣器驱动pwm-beeper.c的过程中,没有看到有关物理地址映射的函数,我们都知道内核是无法直接读写物理地址的,一路追踪驱动中对地址的操作,最终在plat-samsung/include/plat/map-base.h看到#define S3C_ADDR_BASE 0xF6000000,PWM的地址是以S3C_ADDR_BASE为基址的一个偏移地址,咋一看蜂鸣器的驱动完全是在对一个define定义的立即数进行读写,那么这个define定义的地址到底是物理地址还是虚拟地址。从datasheet上来看PWM寄存器地址是0x139D0000,那么这个地址就应该是虚拟地址了,这引起了我对物理地址的静态映射的兴趣,因为静态映射之后的虚拟地址使用起来太方便了。下面描述一下物理地址的静态映射,因为涉及到MMU、页表等比较复杂的东西,所以只能粗略的讲讲。

物理地址的静态映射在系统启动过程中完成,在mach-exynos/common.c文件中可以看到静态映射的过程。以S3C_VA_TIMER为例将定义的虚拟地址、实际物理地址、申请地址大小和地址类型填入map_desc结构体中。

static struct map_desc exynos4_iodesc[] __initdata = {

{
.virtual = (unsigned long)S3C_VA_TIMER,
.pfn = __phys_to_pfn(EXYNOS4_PA_TIMER),
.length = SZ_16K,
.type = MT_DEVICE,
},

......

}

填充好的map_desc结构体最终通过函数iotable_init,将物理地址与虚拟地址的对应关系加到MMU页表中,页表中有了虚拟地址和物理地址的对应关系,这样虚拟地址能最终映射到实际的物理地址上,静态映射完成。

iotable_init(exynos4_iodesc, ARRAY_SIZE(exynos4_iodesc));


linux物理地址的静态映射,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。