void __init setup_arch(char **cmdline_p)
{
const struct machine_desc mdesc;
setup_processor();
mdesc = setup_machine_fdt(__atags_pointer);
if (!mdesc)
mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type);
machine_desc = mdesc;
machine_name = mdesc->name;
dump_stack_set_arch_desc("%s", mdesc->name);
if (mdesc->reboot_mode != REBOOT_HARD)
reboot_mode = mdesc->reboot_mode;
init_mm.start_code = (unsigned long) _text;
init_mm.end_code = (unsigned long) _etext;
init_mm.end_data = (unsigned long) _edata;
init_mm.brk = (unsigned long) _end;
/ populate cmd_line too for later use, preserving boot_command_line */
strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
*cmdline_p = cmd_line;
parse_early_param();
early_paging_init(mdesc, lookup_processor_type(read_cpuid_id()));
setup_dma_zone(mdesc);
sanity_check_meminfo();
arm_memblock_init(mdesc);
paging_init(mdesc);
request_standard_resources(mdesc);
if (mdesc->restart)
arm_pm_restart = mdesc->restart;
unflatten_device_tree();
arm_dt_init_cpu_maps();
psci_init();
#ifdef CONFIG_SMP
if (is_smp()) {
if (!mdesc->smp_init || !mdesc->smp_init()) {
if (psci_smp_available())
smp_set_ops(&psci_smp_ops);
else if (mdesc->smp)
smp_set_ops(mdesc->smp);
}
smp_init_cpus();
smp_build_mpidr_hash();
}
#endif
if (!is_smp())
hyp_mode_check();
reserve_crashkernel();
#ifdef CONFIG_MULTI_IRQ_HANDLER
handle_arch_irq = mdesc->handle_irq;
#endif
#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
conswitchp = &dummy_con;
#endif
#endif
if (mdesc->init_early)
mdesc->init_early();
}
首先来看const struct machine_desc mdesc; machine_desc结构体用于描述当前平台体系架构的初始化工作。
struct machine_desc {
unsigned int nr; / architecture number */
const char name; / architecture name /
unsigned long atag_offset; / tagged list (relative) */
const char *const dt_compat; / array of device tree * ‘compatible’ strings /
unsigned int nr_irqs; / number of IRQs /
#ifdef CONFIG_ZONE_DMA
phys_addr_t dma_zone_size; / size of DMA-able area /
#endif
unsigned int video_start; / start of video RAM /
unsigned int video_end; / end of video RAM /
unsigned char reserve_lp0 :1; / never has lp0 /
unsigned char reserve_lp1 :1; / never has lp1 /
unsigned char reserve_lp2 :1; / never has lp2 /
enum reboot_mode reboot_mode; / default restart mode /
unsigned l2c_aux_val; / L2 cache aux value /
unsigned l2c_aux_mask; / L2 cache aux mask */
void (*l2c_write_sec)(unsigned long, unsigned);
struct smp_operations smp; / SMP operations */
bool (*smp_init)(void);
void (*fixup)(struct tag *, char **);
void (*dt_fixup)(void);
void (*init_meminfo)(void);
void (reserve)(void);/ reserve mem blocks */
void (map_io)(void);/ IO mapping function */
void (*init_early)(void);
void (*init_irq)(void);
void (*init_time)(void);
void (*init_machine)(void);
void (*init_late)(void);
#ifdef CONFIG_MULTI_IRQ_HANDLER
void (*handle_irq)(struct pt_regs *);
#endif
void (*restart)(enum reboot_mode, const char *);
};
其每一个成员都非常重要,结合setup_arch来进行逐个分析。
setup_processor(); 检测处理器类型,并初始化处理器相关的底层变量,内核启动时处理器信息就是通过该函数打印,如我的开发板信息CPU: ARMv7 Processor [412fc09a] revision 10 (ARMv7), cr=10c53c7d
machine_desc 定义在板级文件中,主要进行片上资源的初始化工作, 如mach-imx/mach-imx6q.c中
DT_MACHINE_START(IMX6Q, “Freescale i.MX6 Quad/DualLite (Device Tree)”)
.smp = smp_ops(imx_smp_ops),
.map_io = imx6q_map_io,
.init_irq = imx6q_init_irq,
.init_machine = imx6q_init_machine,
.init_late = imx6q_init_late,
.dt_compat = imx6q_dt_compat,
MACHINE_END
imx6q_dt_compat定义如下
static const char * const imx6q_dt_compat[] __initconst = {
“fsl,imx6dl”,
“fsl,imx6q”,
NULL,
};
machine_desc匹配函数
mdesc = setup_machine_fdt(__atags_pointer);
if (!mdesc)
mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type);
在setup_machine_fdt函数中匹配machine_desc结构,在of_flat_dt_match_machine函数中根据设备树根节点下的compatiable属性中的内容和machine_desc中的dt_compat属性进行比对,获取到machine_desc结构。继续在 early_init_dt_scan_nodes()中处理设备树运行时配置信息,函数内容如下:
of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
【1】处理设备树种的chosen节点信息,将节点中bootargs属性的值, 存入全局变量: boot_command_line
of_scan_flat_dt(early_init_dt_scan_root, NULL);
【2】处理根节点下的address-cells 和 size-cells属性并 存入全局变量: dt_root_addr_cells, dt_root_size_cells
of_scan_flat_dt(early_init_dt_scan_memory, NULL);
【3】解析/memory中的reg属性, 提取出"base, size", 最终调用memblock_add(base, size);