Linux启动中setup_arch分析

时间:2021-02-10 17:31:45

[ 注:内核版本Linux-2.6.30 ]

setup_arch执行是由start_kernel来调用的:

start_kernel [ init/main.c ] --> setup_arch(&command_line) [arch/arm/kernel/setup.c

void __init setup_arch(char **cmdline_p)
{
struct tag *tags = (struct tag *)&init_tags;
struct machine_desc *mdesc;
char *from = default_command_line; /* [Voice] configuration in defconfig file */

unwind_init();

setup_processor();
mdesc = setup_machine(machine_arch_type); /* [Voice] This get from include/generated/mach-types.h */
machine_name = mdesc->name;

if (mdesc->soft_reboot)
reboot_setup("s");

if (__atags_pointer) /* [Voice] unsigned int __atags_pointer __initdata;*/
tags = phys_to_virt(__atags_pointer);
else if (mdesc->boot_params)
tags = phys_to_virt(mdesc->boot_params);

/*
* If we have the old style parameters, convert them to
* a tag list.
*/
if (tags->hdr.tag != ATAG_CORE)
convert_to_tag_list(tags);
if (tags->hdr.tag != ATAG_CORE)
tags = (struct tag *)&init_tags;

if (mdesc->fixup)
mdesc->fixup(mdesc, tags, &from, &meminfo);

if (tags->hdr.tag == ATAG_CORE) {
if (meminfo.nr_banks != 0)
squash_mem_tags(tags);
save_atags(tags);
parse_tags(tags);
}

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;

memcpy(boot_command_line, from, COMMAND_LINE_SIZE);
boot_command_line[COMMAND_LINE_SIZE-1] = '\0';
parse_cmdline(cmdline_p, from);
paging_init(mdesc);
request_standard_resources(&meminfo, mdesc);

#ifdef CONFIG_SMP
smp_init_cpus();
#endif

cpu_init();

/*
* Set up various architecture-specific pointers
*/
init_arch_irq = mdesc->init_irq;
system_timer = mdesc->timer;
init_machine = mdesc->init_machine;

#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
conswitchp = &dummy_con;
#endif
#endif
early_trap_init();
}

以下进行逐行分析:

1. default_command_line

     static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;

     其中的CONFIG_CMDLINE来自于board的默认配置选项。

2. setup_processor();

     首先读取cpuid,read_cpuid_id() --> read_cpuid(CPUID_ID), 其中CPUID_ID为0, 而read_cpuid为一个汇编代码。如下:

#define read_cpuid(reg) \
({ \
unsigned int __val; \
asm("mrc p15, 0, %0, c0, c0, " __stringify(reg) \
: "=r" (__val) \
: \
: "cc"); \
__val; \
})

     然后执行lookup_processor_type(); 其定义在:[ arch/arm/kernel/head-common.S ]

     cpu_name, elf_platform, elf_hwcap 变量得到赋值

    接着是: cacheid_init()

            读取CPU的cachetype和arch结构,如果arch结构小于ARMv6,则cacheid = CACHEID_VIVT。

    最后执行:cpu_proc_init()

            [此处比较迷茫]

3. mdesc = setup_machine(machine_arch_type)

    machine_arch_type来自于文件:include/generated/mach-types.h [ 此文件是生成文件 ]

    这个只是对应一个number,然后通过这个number去查找到相关信息。每一种板子对应于一个特定的number。然后相关的描述来于MACHINE_STARTMACHINE_END

    接着:setup_machine --> lookup_machine_type(nr) [ 定义于head.S ]

            machine_name 变量得到赋值

4. phys_to_virt(mdesc->bootparams)

    phys_to_virt(mdesc->bootparams) --> __phys_to_virt((usigned long)(x)) --> ((x) - PHYS_OFFSET + PAGE_OFFSET)

    #ifndef PHYS_OFFSET
    #define PHYS_OFFSET (CONFIG_DRAM_BASE)
    #endif

    #ifndef PAGE_OFFSET
    #define PAGE_OFFSET (PHYS_OFFSET)
    #endif   

5. _text, _etext, _edata, _end 

    这四个参数来自于文件:[ arch/arm/kernel/vmlinux.lds.S ]

            init_mm部份参数得到赋值

6. parse_cmdline(cmdline_p, from)


7. paging_init(mdesc)

     pageing_init() sets up the page tables, initialises the zone memory maps, and sets up the zero page, bad page and bad page tables.


8. request_standard_resources(&meminfo, mdesc)


9. cpu_init()


10. CONFIG_VT && CONFIG_DUMMY_CONSOLE

       conswitchp = &dummy_con; [ conswitchp ==> drivers/char/vt.c;dummy_con ==> driver/video/console/dummycon.c ]


11. early_trap_init() [ arch/arm/kernel/traps.c ]