处理器:全志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的结果就是建立了上述的映射关系,故其他内核驱动模块初始化时,直接调用固定的虚拟物理地址。
#define AW_DE_FE0_BASE 0x01e00000 #define AW_DE_FE1_BASE 0x01e20000 #define AW_DE_BE1_BASE 0x01e40000
虚拟的设备物理地址 #define AW_VIR_DE_FE0_BASE 0xf1e00000 #define AW_VIR_DE_FE1_BASE 0xf1e20000 #define AW_VIR_DE_BE1_BASE 0xf1e40000
map_io通过Start_kernel -> setup_arch() --> paging_init() --> devicemaps_init()中被调用