linux下特定处理器的设备物理地址和虚拟物理地址的静态映射的实现


处理器:全志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()中被调用
 

你可能感兴趣的:(linux下特定处理器的设备物理地址和虚拟物理地址的静态映射的实现)