静态映射
在做代码移植时,看到一些寄存器操作相关的代码,发现一些宏定义在新版本的代码中已经没有了。这些宏主要是芯片各个IP的寄存器物理地址的宏定义。众所周知,在操作系统启动完,并启用MMU的情况下,是无法直接读写寄存器物理地址来操作芯片的IP的。无论是在用户态还是在内核态,都需要把物理地址映射成虚拟地址,再通过虚拟地址去访问寄存器资源。
在arch/arm/include/mach/hardware.h头文件定义了内存资源和I/O资源的物理地址和虚拟地址的映射宏:
/*****************************************************************
IO Mapping
All registers (128MB) and flash (max 128MB) should fit within
256MB @ 0xF0000000
Mem address Range
Virt = 0xF0000000 to 0xFFFFFFFF
Phys = 0x10000000 to 0x1FFFFFFF
IO address Range
Virt = 0xF7000000 to 0xFEFFFFFF
Phys = 0x16000000 to 0x1EFFFFFF
*****************************************************************/
#define IO_BASE 0xF0000000 // VA of IO
#define MEM_ADDRESS(x) ((x&0x00ffffff)+IO_BASE)
#define IO_ADDRESS(x) ((x&0x0fffffff)+IO_BASE)
#define PHY_ADDRESS(x) ((x&0x0fffffff)+0x10000000)
相当于操作系统在启动之处就把0x16000000到0x1EFFFFFF的物理地址映射到了0xF7000000到0xFEFFFFFF这个线性区间了。所以可以直接通过IO_ADDRESS这个宏直接读写芯片的I/O资源。而这部分映射的原理(流程)是怎么样的呢?
1 静态映射
首先介绍下静态映射,相比于静态映射,动态映射是直接通过ioremap等函数创建一段I/O外设到内核虚拟地址的映射表。是我们平时使用得比较多的,也比较熟悉的。静态映射是在系统启动过程中在内存中拿出一段内存用于映射I/O资源的物理地址。这种映射方式用map_desc结构体定义了具体的资源映射,可以根据实际来定义。
static struct map_desc aspeed_std_desc[] __initdata =
{
{ AST_AHBC_VA_BASE, __phys_to_pfn(AST_AHBC_BASE), SZ_64K, MT_DEVICE},
{ AST_MAC1_VA_BASE, __phys_to_pfn(AST_MAC1_BASE), SZ_64K, MT_DEVICE},
{ AST_USB20_VA_BASE, __phys_to_pfn(AST_USB20_BASE), SZ_4K, MT_DEVICE},
{ AST_USB11_VA_BASE, __phys_to_pfn(AST_USB11_BASE), SZ_64K, MT_DEVICE},
{ AST_IC_VA_BASE, __phys_to_pfn(AST_IC_BASE), SZ_64K, MT_DEVICE},
{ AST_SDRAMC_VA_BASE, __phys_to_pfn(AST_SDRAMC_BASE), SZ_4K, MT_DEVICE},
{ AST_SCU_VA_BASE, __phys_to_pfn(AST_SCU_BASE), SZ_4K, MT_DEVICE},
{ AST_CRYPTO_VA_BASE, __phys_to_pfn(AST_CRYPTO_BASE), SZ_4K, MT_DEVICE},
{ AST_JTAG_VA_BASE, __phys_to_pfn(AST_JTAG_BASE), SZ_4K, MT_DEVICE},
{ AST_GRAPHIC_VA_BASE, __phys_to_pfn(AST_GRAPHIC_BASE), SZ_4K, MT_DEVICE},
{ AST_ADC_VA_BASE, __phys_to_pfn(AST_ADC_BASE), SZ_4K, MT_DEVICE},
{ AST_AHB_TO_PBUS_VA_BASE, __phys_to_pfn(AST_AHB_TO_PBUS_BASE), SZ_64K, MT_DEVICE},
{ AST_MDMA_VA_BASE, __phys_to_pfn(AST_MDMA_BASE), SZ_64K, MT_DEVICE},
{ AST_2D_VA_BASE, __phys_to_pfn(AST_2D_BASE), SZ_64K, MT_DEVICE},
{ AST_GPIO_VA_BASE, __phys_to_pfn(AST_GPIO_BASE), SZ_4K, MT_DEVICE},
{ AST_RTC_VA_BASE, __phys_to_pfn(AST_RTC_BASE), SZ_4K, MT_DEVICE},
{ AST_TIMER_VA_BASE, __phys_to_pfn(AST_TIMER_BASE), SZ_4K, MT_DEVICE},
{ AST_WDT_VA_BASE, __phys_to_pfn(AST_WDT_BASE), SZ_4K, MT_DEVICE},
{ AST_PWM_VA_BASE, __phys_to_pfn(AST_PWM_BASE), SZ_4K, MT_DEVICE},
{ AST_I2C_VA_BASE, __phys_to_pfn(AST_I2C_BASE), SZ_4K, MT_DEVICE},
{ AST_DMA_VA_BASE, __phys_to_pfn(AST_DMA_BASE), SZ_4K, MT_DEVICE},
{ AST_MCTP_VA_BASE, __phys_to_pfn(AST_MCTP_BASE), SZ_4K, MT_DEVICE},
{ AST_LPC_PLUS_VA_BASE, __phys_to_pfn(AST_LPC_PLUS_BASE), SZ_4K, MT_DEVICE},
{ AST_VIDEO_VA_BASE, __phys_to_pfn(AST_VIDEO_BASE), SZ_128K, MT_DEVICE},
{ AST_PECI_VA_BASE, __phys_to_pfn(AST_PECI_BASE), SZ_4K, MT_DEVICE},
{ AST_VUART0_VA_BASE, __phys_to_pfn(AST_VUART0_BASE), SZ_4K, MT_DEVICE},
{ AST_VUART1_VA_BASE, __phys_to_pfn(AST_VUART1_BASE), SZ_4K, MT_DEVICE},
{ AST_LPC_VA_BASE, __phys_to_pfn(AST_LPC_BASE), SZ_4K, MT_DEVICE},
{ AST_USB1_VA_BASE, __phys_to_pfn(AST_USB1_BASE), SZ_4K, MT_DEVICE},
}
struct machine_desc结构体中有个函数指针:
void (*map_io)(void);/* IO mapping function */
arch/arm/mach-aspeed/setup.c下面的aspeed_map_common_io完成静态映射的动作:
void
__init aspeed_map_common_io(void)
{
iotable_init(aspeed_std_desc, ARRAY_SIZE(aspeed_std_desc));
return;
}
aspeed_map_common_io在加载设备树的时候会赋值给map_io:
const struct machine_desc * __init setup_machine_fdt(void *dt_virt)
{
const struct machine_desc *mdesc, *mdesc_best = NULL;
#if defined(CONFIG_ARCH_MULTIPLATFORM) || defined(CONFIG_ARM_SINGLE_ARMV7M)
DT_MACHINE_START(GENERIC_DT, "Generic DT based system")
.l2c_aux_val = 0x0,
.l2c_aux_mask = ~0x0,
#if defined(CONFIG_SOC_ASPEED)
.map_io = aspeed_map_common_io,
.init_machine = aspeed_init,
#endif
MACHINE_END
mdesc_best = &__mach_desc_GENERIC_DT;
#endif
...
...
}
真正调用的地方是在paging_init函数会调用devicemaps_init,而devicemaps_init会调用map_io函数:
static void __init devicemaps_init(const struct machine_desc *mdesc)
{
...
if (mdesc->map_io)
mdesc->map_io();
else
debug_ll_io_init();
...
}
调用函数链如下:
Start_kernel --> setup_arch --> paging_init --> devicemaps_init中通过MACHINE_START宏来初始化machine_desc结构体。

浙公网安备 33010602011771号