The Staff of Mage

----以此作为下次重装软件的SOP

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

上篇讲到了barebox的安装,并针对pcm038做了编译,这次以pcm038为例大致分析下barebox的结构。

 

barebox的启动文件是startup.c,通常arm的启动代码都用汇编语言写成,不过用c语言也没什么差--批一层羊皮而已,没错,就是在c语言里调用汇编语句,来看一下入口函数:

 

代码
void __naked __section(.text_entry) exception_vectors(void)
{
__asm__ __volatile__ (
"b reset\n" /* reset */
"ldr pc, =undefined_instruction\n" /* undefined instruction */
"ldr pc, =software_interrupt\n" /* software interrupt (SWI) */
"ldr pc, =prefetch_abort\n" /* prefetch abort */
"ldr pc, =data_abort\n" /* data abort */
"ldr pc, =not_used\n" /* (reserved) */
"ldr pc, =irq\n" /* irq (interrupt) */
"ldr pc, =fiq\n" /* fiq (fast interrupt) */
);
}

 

 

这个函数内容没啥可说的,就是arm异常表的一个映射,注意__section(.text_entry) 这个前缀,它指定该函数会被link到.text_entry区域,在arch/arm下的Makefile里可以看到:

lds-$(CONFIG_GENERIC_LINKER_SCRIPT) := arch/arm/lib/barebox.lds      (CONFIG_GENERIC_LINKER_SCRIPT在menuconfig可以看到被选中)

打开arch/arm/lib/barebox.lds,可以看到:

代码
1 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
2 OUTPUT_ARCH(arm)
3 ENTRY(exception_vectors)
4 SECTIONS
5 {
6 . = 0xa7f00000;
7
8 . = ALIGN(4);
9 .text :
10 {
11 _stext = .;
12 _text = .;
13 *(.text_entry*)
14
15
16
17
18
19 *(.text_bare_init*)
20 *(.text*)
21 }
22
23 . = ALIGN(4);
24 .rodata : { *(.rodata*) }
25
26 _etext = .; /* End of text and rodata section */
27
28 . = ALIGN(4);
29 .data : { *(.data*) }
30
31 . = ALIGN(4);
32 .got : { *(.got*) }
33
34 . = .;
35 __barebox_cmd_start = .;
36 .barebox_cmd : { KEEP(*(SORT_BY_NAME(.barebox_cmd*))) }
37 __barebox_cmd_end = .;
38
39 __barebox_initcalls_start = .;
40 .barebox_initcalls : { KEEP(*(.initcall.0)) KEEP(*(.initcall.1)) KEEP(*(.initcall.2)) KEEP(*(.initcall.3)) KEEP(*(.initcall.4)) KEEP(*(.initcall.5)) KEEP(*(.initcall.6)) KEEP(*(.initcall.7)) KEEP(*(.initcall.8)) }
41 __barebox_initcalls_end = .;
42
43 __usymtab_start = .;
44 __usymtab : { KEEP(*(__usymtab)) }
45 __usymtab_end = .;
46
47 . = ALIGN(4);
48 __bss_start = .;
49 .bss : { *(.bss*) }
50 _end = .;
51 }

可以看到入口处即为__section(.text_entry) 。

 

然后找到b reset的reset函数:

void __naked __bare_init reset(void)

{...}

注意这个_bare_init,对应的是__section(.text_bare_init.text),在上面的link文件中可以看到紧跟__section(.text_entry)。这是因为从nand flash等设备启动时,i.MX27会拷贝nand flash的前2K内容到buffer,如果reset函数不放在前面的话可能拷不到这个buffer中,就没办法执行了,另从中可以知道如果在map文件中__section(.text_bare_init.text)的结尾偏移首地址2KB的话,那么barebox就没法运行了。

 

reset函数中清空cache,disable掉mmu后跳去执行board_init_lowlevelCONFIG_MACH_DO_LOWLEVEL_INIT可以在menuconfig中看到被选中)。board_init_lowlevel就是板子特定的文件了,现在转去arch/arm/boards/pcm038/lowlevel.c

 

board_init_lowlevel函数建立板子运行的基本条件如时钟,SDRAM初始化等,然后判断自己是否运行在SDRAM中。在nand buffer中运行的时候PC是在[0xD800 0000~0xD800 0800),这个由cpu决定,之所以不是从0开始是因为CPU选中nand启动时对reset入口地址做了重映射。由于这部分代码都是相当地址寻址,所以同link文件指定的入口地址无关。

 

board_init_lowlevel函数发现自己还不在SDRAM中,就把自己(2KB的buffer)拷到SDRAM中,然后跳去SDRAM (函数入口insdram)执行,跳转的方式是取绝对地址:

r = (unsigned int)&insdram;
 __asm__ __volatile__("mov pc, %0" : : "r"(r));

这个r就跟link文件有关了,是在入口0xa7f00000+__section(.text_bare_init.text)insdram对应的offset,具体地址可以从map文件中看到。

 

跳到insdram后首要做的事就是把bootloader整个文件拷到SDRAM,这个过程就是清空nand buffer->读nand->写SDRAM的循环,读完之后以后的函数就不用加_bare_init前缀了,反正不管你放哪里都能执行了。注意board_init_lowlevel_return还是要加,因为CONFIG_MACH_DO_LOWLEVEL_INIT没enable的话就在reset里直接跳去执行它了。

 

insdram最后调用board_init_lowlevel_return,设定下stack,再多余的判断一次自己是否在SDRAM(仅对当前的设定多余),然后就调用barebox的入口函数--start_barebox

 

start_barebox首先读取__barebox_initcalls_start开头的一堆函数指针,然后挨个去执行它,执行完后调用environment设定,接着就是一个死循环run_shell。那驱动/文件系统呢,跑哪里去了?答案就在__barebox_initcalls_start开头的函数指针处。barebox有9个宏定义,分别是pure_initcall/core_initcall/postcore_initcall/console_initcall/postconsole_initcall/fs_initcall/device_initcall/late_initcall,是__define_initcall的按顺序定义,至于__define_initcall,它被定义到.initcall.n,即上面link指定的从__barebox_initcalls_start__barebox_initcalls_end对应的空间,也就是start_barebox一开始读取一堆函数指针的地址空间。

 

之后的事情就是一个个的查找那些xxxx_initcall然后来做具体的分析了。 

 

posted on 2010-12-04 23:07  nus1998  阅读(1330)  评论(0编辑  收藏  举报