linux内核移植关键结构

最近看了一下linux中有关ARM的体系结构有关的内容。在针对每一开发板时都会有这样一个宏,以2410例。其实是一个结构体,该结构体与体系结构上的移植关系非常密切。

MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch to SMDK2410 */
 /* Maintainer: Jonas Dietsche */
 .phys_io = S3C2410_PA_UART,
 .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 .boot_params = S3C2410_SDRAM_PA + 0x100,
 .map_io = smdk2410_map_io,
 .init_irq = s3c24xx_init_irq,
 .init_machine = smdk_machine_init,
 .timer = &s3c24xx_timer,
MACHINE_END

 

MACHINE_START定义在include/asm-arm/mach/arch.h中

#define MACHINE_START(_type,_name) /
static const struct machine_desc __mach_desc_##_type /
 __attribute_used__ /
 __attribute__((__section__(".arch.info.init"))) = { /
 .nr = MACH_TYPE_##_type, /
 .name = _name,
#define MACHINE_END /
};

 
将前面定义的MACHINE_START展开后得到,

static const struct machine_desc __mach_desc_SMDK2410
 __attribute_used__
 __attribute__((__section__(".arch.info.init"))) = {
 .nr = MACH_TYPE_SMDK2410, /* architecture number */
 .name = "SMDK2410", /* architecture name */
 /* Maintainer: Jonas Dietsche */
 .phys_io = S3C2410_PA_UART, /* start of physical io */
 .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
 .boot_params = S3C2410_SDRAM_PA + 0x100, /* tagged list */
 .map_io = smdk2410_map_io, /* IO mapping function */
 .init_irq = s3c24xx_init_irq,
 .init_machine = smdk_machine_init,
 .timer = &s3c24xx_timer,
}

其中MACH_TYPE_SMDK2410为机器号,该值将与我们在bootloader中传递给linux入口参数的机器号比较,如果在引导过程中出现无法识别机器号,这是问题就应该出在这里了。

MACH_TYPE_SMDK2410定义在arch/include/asm-arm/mach-types.h内,值为193.
/* arch/include/asm-arm/mach-types.h */
#define MACH_TYPE_SMDK2410             193

注意:mach-types.h在未编译之前时不存在的,在头文件由arch/arm/tool/mach-types里面定义的数据结合脚本在编译时生成的。

/* arch/arm/tool/mach-types */
smdk2410  ARCH_SMDK2410  SMDK2410  193

 

其它结构:

phys_io:IO空间的开始地址

io_pg_offst:IO对于的虚拟地址

boot_params:为我们bootloader产生的TAG列表的开始地址,这两者要一致。

map_io:实现对IO空间的映射

init_irq:对中断进行初始化


由上发现,MACHINE_START主要是定义了"struct machine_desc"的类型,放在 section(".arch.info.init"),是初始化数据,Kernel 起来之后将被丢弃。


各个成员函数在不同时期被调用:
1. .init_machine 在 arch/arm/kernel/setup.c 中被 customize_machine 调用,放在 arch_initcall() 段里面,会自动按顺序被调用。

2. init_irq在start_kernel() --> init_IRQ() --> init_arch_irq() 被调用
init_irq这个成员在系统初始化的时候会被赋值给init_arch_irq全局变量,如下:

/* arch/arm/kernel/setup.c */
void __init setup_arch(char **cmdline_p)
{
 ……
 cpu_init();
 
/*
  * Set up various architecture-specific pointers
  */

 init_arch_irq = mdesc->init_irq;
 system_timer = mdesc->timer;
 init_machine = mdesc->init_machine;
 ……
}


注: 可以看到这里不仅初始化了init_arch_irq 全局变量,同时初始化了system_timer,init_machine等全局变量。这是kernel支持多平台的一种机制。当然这里 system_timer和init_machine我不多描述,有兴趣的可以大家自己去看。机制和init_arch_irq大同小异。
 
init_arch_irq函数指针定义在体系架构无关的arch/arm/kernel/irq.c内
/* arch/arm/kernel/irq.c */
void (*init_arch_irq)(void) __initdata = NULL;
 
并且在init_IRQ函数内会去执行它。

/* arch/arm/kernel/irq.c */
void __init init_IRQ(void)
{
 int irq;
 for (irq = 0; irq < NR_IRQS; irq++)
  irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_DELAYED_DISABLE |
   IRQ_NOPROBE;
#ifdef CONFIG_SMP
 bad_irq_desc.affinity = CPU_MASK_ALL;
 bad_irq_desc.cpu = smp_processor_id();
#endif
 init_arch_irq();
}

 
那init_IRQ在哪里被调用呢? 我们猜想肯定是在系统初始化的时会调用它。
实际结果也正是,init_IRQ会在init/main.c里的start_kernel函数内被调用:
asmlinkage void __init start_kernel(void)
{
 ……
 trap_init();
 rcu_init();
 init_IRQ();
 pidhash_init();
 clockevents_init();
 init_timers();
 ……
}
这样,我们定义的新平台irq初始化函数就会在系统启动时被调用,对我们的硬件中断进行初始化后再去使用它。

3. map_io 在 setup_arch() --> paging_init() --> devicemaps_init()被调用
其他主要都在 setup_arch() 中用到。

 

你可能感兴趣的:(linux内核移植关键结构)