arm 启动流程 2016.08.11

Posted liushuhe1990

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了arm 启动流程 2016.08.11相关的知识,希望对你有一定的参考价值。

arm 启动流程

刘术河 2016.08.11

 

linux-2.6.39-at91archarmkernelhead.S

//获取机器ID,与uboot传进来的比较,返回匹配的ID

bl __lookup_processor_type @ r5=procinfo r9=cpuid

ldr r13, =__mmap_switched @ address to jump to after mmu has been enabled

b start_kernel

linux-2.6.39-at91initMain.c

start_kernel.c

setup_arch(&command_line);

struct machine_desc *mdesc;

//在这里确定是哪个特定的开发板

mdesc = setup_machine(machine_arch_type);

for (p = __arch_info_begin; p < __arch_info_end; p++)

{

if (nr == p->nr) {

printk("Machine: %s ", p->name);

return p;

}

}

//__arch_info_beginvmlinux.lds.S->SECTIONS->do_initcalls里面定义

//__arch_info_begin = .;

//*(.arch.info.init)

//__arch_info_end = .;

rest_init();

kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);

kernel_init

do_basic_setup();

do_initcalls();

{

initcall_t *fn;

for (fn = __early_initcall_end; fn < __initcall_end; fn++)

do_one_initcall(*fn);

//这里会调用customize_machine

}

/*************************************************************************************/

//分析内核识别单板过程

linux-2.6.39-at91archarmkernelhead.S

//获取机器ID,与uboot传进来的比较,返回匹配的ID

bl __lookup_processor_type @ r5=procinfo r9=cpuid

ldr r13, =__mmap_switched @ address to jump to after mmu has been enabled

b start_kernel

linux-2.6.39-at91initMain.c

start_kernel.c

setup_arch(&command_line);

struct machine_desc *mdesc;

//在这里确定是哪个特定的开发板

mdesc = setup_machine(machine_arch_type);

for (p = __arch_info_begin; p < __arch_info_end; p++)

{

if (nr == p->nr) {

printk("Machine: %s ", p->name);

return p;

}

}

//__arch_info_beginvmlinux.lds.S->SECTIONS->do_initcalls里面定义

//__arch_info_begin = .;

//*(.arch.info.init)

//__arch_info_end = .;

 

//这是9g20的单板结构体

MACHINE_START(STAMP9G20, "taskit Stamp9G20")

/* Maintainer: taskit GmbH */

.boot_params = AT91_SDRAM_BASE + 0x100,

.timer = &at91sam926x_timer,

.map_io = stamp9g20evb_map_io,

.init_irq = init_irq,

.init_machine = stamp9g20evb_board_init,

MACHINE_END

//分析MACHINE_START

linux-2.6.39-at91archarmincludeasmmachArch.h

#define MACHINE_START(_type,_name)

static const struct machine_desc __mach_desc_##_type

 __used

 __attribute__((__section__(".arch.info.init"))) = {

.nr = MACH_TYPE_##_type,

.name = _name,

#define MACHINE_END

};

//可见MACHINE_START(STAMP9G20, "taskit Stamp9G20")被替换为

const struct machine_desc __mach_desc_STAMP9G20

 __used

 __attribute__((__section__(".arch.info.init"))) = {

.nr = MACH_TYPE_STAMP9G20,

.name = "taskit Stamp9G20",

//这个MACH_TYPE_STAMP9G20 = 1824,如果要用9g20uboot传入的机器号就必须是1824

当匹配时,就会返回这个machine_desc结构体指针

//注意MACHINE_START是在单板描述符上,强制加了.nr .name 最终是

/* Maintainer: taskit GmbH */

.nr = MACH_TYPE_STAMP9G20,

.name = "taskit Stamp9G20",

.boot_params = AT91_SDRAM_BASE + 0x100,

.timer = &at91sam926x_timer,

.map_io = stamp9g20evb_map_io,

.init_irq = init_irq,

.init_machine = stamp9g20evb_board_init,

/*************************************************************************************/

//分析内核调用单板初始化函数过程

static int __init customize_machine(void)

{

/* customizes platform devices, or adds new ones */

if (machine_desc->init_machine)

machine_desc->init_machine();

return 0;

}

arch_initcall(customize_machine);

//搜索arch_initcall定义

#define arch_initcall(fn) __define_initcall("3",fn,3)

__define_initcall:

#define __define_initcall(level,fn,id)

static initcall_t __initcall_##fn##id __used

__attribute__((__section__(".initcall" level ".init"))) = fn

    结果为:__initcall_customize_machine3;

被放在段 .initcall3.init

搜索 .initcall3.init  查看在哪里定义

linux-2.6.39-at91includeasm-genericVmlinux.lds.h

#define INITCALLS

*(.initcallearly.init)

VMLINUX_SYMBOL(__early_initcall_end) = .;

   *(.initcall0.init)

   *(.initcall0s.init)

   *(.initcall1.init)

   *(.initcall1s.init)

   *(.initcall2.init)

   *(.initcall2s.init)

   *(.initcall3.init)

   *(.initcall3s.init)

   *(.initcall4.init)

   *(.initcall4s.init)

   *(.initcall5.init)

   *(.initcall5s.init)

*(.initcallrootfs.init)

   *(.initcall6.init)

   *(.initcall6s.init)

   *(.initcall7.init)

   *(.initcall7s.init)

*(.initcall8.init)

*(.initcall8s.init)

//设置被包含在INITCALLS宏里

//搜索INITCALLS

#define INIT_CALLS

VMLINUX_SYMBOL(__initcall_start) = .;

INITCALLS

VMLINUX_SYMBOL(__initcall_end) = .;

//搜索INIT_CALLS

linux-2.6.39-at91archarmkernelvmlinux.lds.S

SECTIONS

{

_stext = .;

_sinittext = .;

 

INIT_CALLS

__init_end = .;

}

//到这里我们就分析清楚了 machine的初始化函数是存放在

INIT_CALLS->*(.initcall3.init)中,

//INIT_CALLS被包含在vmlinux.lds.S文件

SECTIONS->_stext = .; __init_end = .;之间

//回到do_initcalls函数,这里调用所有__early_initcall_end---__initcall_end之间的函数指针

do_initcalls();

{

initcall_t *fn;

for (fn = __early_initcall_end; fn < __initcall_end; fn++)

do_one_initcall(*fn);

customize_machine;

}

//__early_initcall_endINITCALL定义

VMLINUX_SYMBOL(__early_initcall_end) = .;

//__initcall_endvmlinux.lds.SSECTIONS定义

__init_end = .;

 

//do_initcalls会调用customize_machine函数初始化单板初始化函数

static int __init customize_machine(void)

{

/* customizes platform devices, or adds new ones */

if (machine_desc->init_machine)

machine_desc->init_machine();

 

return 0;

}

MACHINE_START(STAMP9G20, "taskit Stamp9G20")

/* Maintainer: taskit GmbH */

.boot_params = AT91_SDRAM_BASE + 0x100,

.timer = &at91sam926x_timer,

.map_io = stamp9g20evb_map_io,

.init_irq = init_irq,

.init_machine = stamp9g20evb_board_init,

MACHINE_END

//就是这样调用

machine_desc->init_machine();

stamp9g20evb_board_init();

 

 

//分析机器号的生成

linux-2.6.39-at91archarm ools

目录下有3个文件

gen-mach-types  

mach-types

Makefile

 

//查看makefile

include/generated/mach-types.h: $(src)/gen-mach-types $(src)/mach-types

@echo ‘  Generating [email protected]

@mkdir -p $(dir [email protected])

$(Q)$(AWK) -f $^ > [email protected] || { rm -f [email protected]; /bin/false; }

 

可见会生成一个文件include/generated/mach-types.h

它的材料是  gen-mach-types mach-types

//查看mach-types

stamp9g20 MACH_STAMP9G20 STAMP9G20 1824

 

 

//查看gen-mach-types

BEGIN { nr = 0 }

/^#/ { next }

/^[ ]*$/ { next }

 

NF == 4 {

  machine_is[nr] = "machine_is_"$1;

  config[nr] = "CONFIG_"$2;

  mach_type[nr] = "MACH_TYPE_"$3;

  num[nr] = $4; nr++

}

 

NF == 3 {

  machine_is[nr] = "machine_is_"$1;

  config[nr] = "CONFIG_"$2;

  mach_type[nr] = "MACH_TYPE_"$3;

  num[nr] = ""; nr++

}

 

  printf("/* see arch/arm/kernel/arch.c for a description of these */ ");

  for (i = 0; i < nr; i++)

    if (num[i] ~ /..*/)

      printf("#define %-30s %d ", mach_type[i], num[i]);

//可见include/generated/mach-types.h内容是在

printf("#define %-30s %d ", mach_type[i], num[i]); 打印出来的   

 

例如:stamp9g20 MACH_STAMP9G20 STAMP9G20 1824

会被打印为

#define         MACH_TYPE_STAMP9G20      1824

//MACH_TYPE_STAMP9G20    这个值就是MACHINE_START(STAMP9G20, "taskit Stamp9G20")要用到的

//内核就是这样启动特定的开发板的           

   

   

   

5.总结:启动流程

satrt_kernel

setup_arch()     //确定启动那个开发板,返回一个machine_desc结构体指针

rest_init()       //这里才是真正的调用机器的初始化,1.注册设备  2.注册驱动

kernel_init()

do_basic_setup()

driver_init()    //创建设备节点,注册各种总线

do_initcalls()   //1.这里真正调用开发板的init_machine函数,里面会  注册设备

              //2.这里会调用驱动注册函数

 for(fn = _early_initcall_end;fn < _initcall_end;fn++)

 {

do_one_initcall(*fn);

 }

以上是关于arm 启动流程 2016.08.11的主要内容,如果未能解决你的问题,请参考以下文章

ARM处理器启动流程

ARM处理器启动流程

ARM Linux从Bootloaderkernel到filesystem启动流程

ARMS5PV210芯片的启动流程

uboot启动流程

Zynq启动流程