在u-boot
的最後提到傳遞引數給核心,呼叫如下 //
呼叫核心,暫存器
r0=0,r1=
機器型別,
r2=引數塊位址
thekernel (0, bd->bi_arch_number, bd->bi_boot_params);
而這兩個引數是如何傳遞給
kernel
的分析如下(只涉及到非彙編部分) 一.
u-boot
傳遞tag
到kernel
的解析
在setup_arch
函式的parse_tags
中對傳遞過來的
taglist
進行了解析
對每一項的
tag使用
parse_tag
分析,
for (t = &__tagtable_begin; t < &__tagtable_end; t++)
if (tag->hdr.tag == t->tag)
其中__tagtable_begin,__tagtable_end
在vmlinux.ld
中也有定義,這裡看
tagtable
的建立過程
#define __tagtalbe(tag,fn)/
static struct tagtable __tagtable_##fn __tag=
#define __tag __userd __attribute__((__section__(「.taglist.init」)))
對於上述巨集中的
fn,就是
tagtable
結構中的
parse
指標所指向的函式。 而在
setup.c
中,已經通過
__tagtalbe(atag_***,***)
建立起所有可能的
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"))) = ;
假設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_initcall
和module_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的段1
是core_initcall,段2
是postcore_initcall,段3
是arch_initcall,段4
是subsys_initcall,段5
是fs_initcall,段6
是device_initcall段7
是late_initcall
uboot移植之uboot和kernel的引數傳遞
從uboot啟動核心的形式thekernel 0,machid,bd bi boot params 可以看出uboot給核心傳遞了3個引數,第1個是0,第2個是機器碼,第3個是引數列表在sdram的起始位置 剛好滿足一下呼叫核心的條件 r0 0。r1 機器型別id r2 啟動引數標記列表在ram 中...
uboot 引導kernel雜談
記錄最近除錯uboot的心得,供後續總結!總結 uboot 主要作用是用來引導kernel啟動,傳遞引數給kernel。大致分為2個階段 第一階段 主要是start.s 彙編階段,主要完成如下設定 1,設定cpu 中斷向量表 2,設定cpu速度,時鐘以及終端 3,初始化sdram 記憶體 4,將ub...
uboot與kernel的flash分割槽
1.我們可以在uboot中修改flash分割槽。2.我們也可以在kernel中修改flash分割槽,但是需要與uboot中的分割槽表一致。3.我們可以通過uboot用引數傳給kernel分割槽資訊,這樣只需要維護uboot的分割槽表即可。這要對bootloader對核心重新分割槽 這需要重新設定一下...