处理器:全志A31; Linux内核3.3
A31 定义的machine信息在mach-sun6i/core.c下面:
MACHINE_START(SUN6I, "sun6i").atag_offset= 0x100,
.reserve= sun6i_reserve,
.fixup= sun6i_fixup,
.map_io= sun6i_map_io,
.init_early= sun6i_init_early,
.init_irq= gic_init_irq,
.timer= &sun6i_timer,
.handle_irq= gic_handle_irq,
.init_machine= sun6i_init,
#ifdef CONFIG_ZONE_DMA
.dma_zone_size= SZ_64M,
#endif
.restart= sun6i_restart,
MACHINE_END
这个结构体的内容说明的是一个处理器的基本信息,主要的有设备类型即机器码等。这里的map_io就是对处理器的设备物理地址和虚拟地址建立固定的映射关系。
这样的好处在于,设备物理地址固定,使得虚拟地址固定,驱动里面就不需要再使用动态的映射,直接操作虚拟地址即可。
static void __init sun6i_map_io(void){iotable_init(sun6i_io_desc, ARRAY_SIZE(sun6i_io_desc));}
map_io的调用流程如下:Start_kernel -> setup_arch() --> paging_init() --> devicemaps_init(),最终调用上述结构体中的sun6i_map_io.
iotable_init的处理过程就是将对应处理器所具有的设备物理地址进行映射:
static struct map_desc sun6i_io_desc[] __initdata = {{IO_ADDRESS(AW_SRAM_A1_BASE), __phys_to_pfn(AW_SRAM_A1_BASE), AW_SRAM_A1_SIZE, MT_MEMORY_ITCM},{IO_ADDRESS(AW_SRAM_A2_BASE), __phys_to_pfn(AW_SRAM_A2_BASE), AW_SRAM_A2_SIZE, MT_DEVICE_NONSHARED},{IO_ADDRESS(AW_IO_PHYS_BASE), __phys_to_pfn(AW_IO_PHYS_BASE), AW_IO_SIZE, MT_DEVICE_NONSHARED},{IO_ADDRESS(AW_BROM_BASE), __phys_to_pfn(AW_BROM_BASE), AW_BROM_SIZE, MT_DEVICE_NONSHARED},};//固定虚拟地址和物理地址的映射
IO_ADDRESS(AW_SRAM_A1_BASE):该宏其实是将实际的设备物理地址转换为一个虚拟物理地址,处理的过程PH_ADD+0xf0000000的线性映射。
__phys_to_pfn(AW_SRAM_A1_BASE):该宏是将实际的设备物理地址转为物理页地址。
在调用iotable_init的结果就是建立了上述的映射关系,故其他内核驱动模块初始化时,直接调用固定的虚拟物理地址。
#defineAW_DE_FE0_BASE0x01e00000#defineAW_DE_FE1_BASE0x01e20000#defineAW_DE_BE1_BASE0x01e40000
虚拟的设备物理地址#defineAW_VIR_DE_FE0_BASE0xf1e00000#defineAW_VIR_DE_FE1_BASE0xf1e20000#defineAW_VIR_DE_BE1_BASE0xf1e40000
map_io通过Start_kernel -> setup_arch() --> paging_init() --> devicemaps_init()中被调用