u-boot到kernel的参数传递

本文详细解析了U-Boot如何将参数传递给Linux Kernel的过程,包括TAG的解析、machine_start的匹配以及INITCALLS的调用顺序,涉及寄存器设置、tagtable解析和板级初始化等关键步骤。

       U-BOOT的最后提到传递参数给内核,调用如下 

//调用内核,寄存器R0=0,R1=机器类型,R2=参数块地址

       theKernel (0, bd->bi_arch_number, bd->bi_boot_params);

而这两个参数是如何传递给kernel的分析如下(只涉及到非汇编部分)

 

一.u-boot传递TAGkernel的解析

       setup_arch函数的parse_tags中对传递过来的TAGLIST进行了解析

       对每一项的tag使用parse_tag分析,

       for (t = &__tagtable_begin; t < &__tagtable_end; t++)

              if (tag->hdr.tag == t->tag) {

                     t->parse(tag);

                     break;

              }

       其中__tagtable_begin,__tagtable_endvmlinux.ld中也有定义,这里看tagtable的建立过程

       #define __tagtalbe(tag,fn)/

       Static struct tagtable __tagtable_##fn __tag={tag,fn}

       #define __tag __userd __attribute__((__section__(“.taglist.init”)))

对于上述宏中的fn,就是tagtable结构中的parse指针所指向的函数。

       而在setup.c中,已经通过__tagtalbe(ATAG_XXX,XXX)建立起所有可能的tagtable,所以可以通过遍历__tagtable_begin~__tagtable_end找到对应的tagtable,并调用对应的parse进行解析并配置

       对于如何在指定地址找到传递过来的TAGLIST(U-BOOT传递过来的TAGLIST位于SDRAM+0x100位置上,一般情况下这么设定)如下,

       setup_arch中定义struct tag* tags=(struct tag*)&init_tags

init_tags struct init_tags结构定义的一个default init_tags,将此变量存储于“.init.data”段中,在vmlinux.ld中有定义

       同时在setup_arch中,

       if (__atags_pointer)

              tags = phys_to_virt(__atags_pointer);

       else if (mdesc->boot_params)

              tags = phys_to_virt(mdesc->boot_params);

       将传递过来的boot_params的物理地址转换成虚拟地址赋值给tags,boot_params的物理地址为SDRAM+0x100

附带一句,由于taglist中有cmd,解析完taglist后,会调用parse_cmdline解析传递过来的命令

 

二.MACHINE_START

       u-boot传递参数给kernel时,包括机器类型和TAGLIST。机器类型就用来决定相应的machine_desc结构。

       #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                           /

};

假设MACH_TYPE_A,对应的结构为__mach_desc_A,

       MACHINE_START(A, "A")

//这里由于U-BOOT传递过来的机器型号与machine_start中的NR进行匹配

//如果匹配,则返回对应的machine_desc结构

       /* Maintainer: Atmel */

       .phys_io = AT91_BASE_SYS,

       .io_pg_offst = (AT91_VA_BASE_SYS >> 18) & 0xfffc,

       .boot_params       = AT91_SDRAM_BASE + 0x100, //其余参量在setup_arch中用到,如boot_params就决定taglist地址

       .timer            = &at91sam926x_timer, 

       .map_io        =board_map_io, // ------devicemaps_init()

       .init_irq  = board_init_irq, //init_arch_irq

       .init_machine       = board_init,//customize_machine-----将该函数放在arch_initcall段里,自动调用

MACHINE_END

       通过得到machine_desc结构之后,就可以具体对板级做相应的初始化,特别是.init_machine=board_init中,对各个硬件做了相关配置初始化。

 

三.INITCALLS

另外写点关于__initcall__

vmlinux.lds.init中定义了__initcall_

  __initcall_start = .;

*(.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)

  __initcall_end = .;

 

经常在驱动中能看到宏 subsys_initcallmodule_init

#define subsys_initcall(fn) __define_initcall(“4”,fn,4)

#define __define_initcall(level,fn,id) /

       static initcall_t __initcall_##fn##id __attribute_used__/

       __attribute__((__section(“.initcall”level”.init”)))=fn

这里是将fn存放在__section 名为 .initcall4.init

initcall_t 则是函数指针

在系统启动过程中会根据上面的initcall表逐个init,而subsys_initcall初始化的函数位于.initcall4.init段中

调用的代码大致如下,在函数do_initcalls

       initcall_t *call

       for(call=__initcall_start;call<__initcall_end;call++)

              result=(*call)();

 

同样的,#define module_init(x) __initcall(x)

#define __initcall(fn) device_initcall(fn)

#define device_initcall(fn) __define_initcall(“6”,fn,6)

module_init初始化的函数位于initcall6.init段中

 

init.h中,还能看到 initcall的段1core_initcall,2postcore_initcall,

3arch_initcall,段4subsys_initcall,段5fs_initcall,段6device_initcall

7late_initcall

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值