分类: LINUX
2010-09-02 10:47:57
为什么要分析源代码?分析优秀的源代码本身就是一个学习的过程,也是进行深入研究的必经之路。不过在此我们的主要目的并非要研究U-boot或Bootloader技术本身,而仅仅是为了成功的并且恰当的将U-Boot移植到我们的开发板上。只有结合源代码了解了U-boot的系统引导过程,才能在移植和调试过程中保持清晰的思路,才能在碰到困难和问题时从根本上加以解决。 在动手分析之前,至少应该对U-Boot的源代码结构有基本的了解,很多参考书都有这方面的介绍,华清远见的《嵌入式Linux系统开发技术详解——基于ARM》的讲解就比较清晰。 本文以lubbock开发板为例,以系统启动的流程为线索进行纵向分析:后续的移植工作也将以此开发板为模板。Lubbock使用PXA255处理器。 首先要找到程序入口点。从board/lubbock/u-boot.lds可以发现,u-boot的程序入口为_start,在cpu/pxa/start.o当中。因此首先要分析start.S程序,U-Boot中所有的PXA系列的处理器都从这里开始执行第一条语句。 .globl _start _start: b reset ldr pc, _undefined_instruction ldr pc, _software_interrupt ldr pc, _prefetch_abort ldr pc, _data_abort ldr pc, _not_used ldr pc, _irq ldr pc, _fiq 0x0地址开始是ARM异常向量表,学过ARM体系结构与编程的都明白,非常简单,不多废话。一上电的第一条指令是跳转到reset复位处理程序: reset: /* 进入SVC模式 */ #ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_crit /* we do sys-critical inits */ #endif #ifndef CONFIG_SKIP_RELOCATE_UBOOT relocate: ...... 一般不要定义CONFIG_SKIP_LOWLEVEL_INIT,因此,接下来跳转到cpu_init_crit处开始执行: cpu_init_crit: /* 屏蔽所有中断 */ /* 设置时钟源,关闭除FFUART,SRAM,SDRAM,FLASH以外的外设时钟 */ ...... #ifdef CFG_CPUSPEED ldr r0, CC_BASE /* 时钟控制寄存器基址 */ ldr r1, cpuspeed /* cpuspeed: .word CFG_CPUSPEED */ str r1, [r0, #CCCR] mov r0, #2 mcr p14, 0, r0, c6, c0, 0 setspeed_done: #endif /* CFG_CPUSPEED */ /* 跳转到lowlevel_init,这里ip即r12,用作暂存寄存器 */ mov ip, lr bl lowlevel_init mov lr, ip /* Memory interfaces are working. Disable MMU and enable I-cache. */ ldr r0, =0x2001 ...... /* 关闭MMU,使能I-Cache(可选) */ mov pc, lr /* 这里是从cpu_init_crit返回到relocate标号 */ 可见,在cpu_init_crit中的主要工作是设置时钟,配置处理器主频(这时CPU的工作频率还没有改变),调用lowlevel_init函数进行底层初始化(包括调整处理器工作频率、系统总线频率、存储器时钟频率以及存储系统的初始化等工作),随后关闭MMU并使能I-Cache,再返回。 lowlevel_init函数在board/lubbock/lowlevel_init.S中定义,其流程都是按照PXA27X的开发手册来的,所以不再赘述。仅指出,其中的寄存器在include/asm-arm/arch-pxa/pxa-regs.h头文件中定义,寄存器初始化值在include/configs/lubbock.h中定义。另外,在后面的实际移植工作中,由于目标板XSBASE270使用的PXA270处理器,可使用adsvix开发板的lowlevel_init.S文件(lubbock中没有开启turbo模式)。 接着程序的执行线索进行分析。从cpu_init_crit返回后就开始relocate(重定位),即将U-boot从FLASH存储器搬运到SDRAM中TEXT_BASE开始的存储空间(TEXT_BASE在board/lubbock/config.mk中定义),并初始化堆栈(清零.bss段),以在SDRAM中开始进入到Bootloader stage 2的C程序入口。Relocate部分开始的代码如下: /* 之前已定义的部分变量有: _TEXT_BASE: .word TEXT_BASE _armboot_start: .word _start _bss_start: .word __bss_start _bss_end: .word _end */ relocate: /* relocate U-Boot to RAM */ adr r0, _start /* r0 <- current position of code */ ldr r1, _TEXT_BASE /* test if we run from flash or RAM */ cmp r0, r1 /* don't reloc during debug */ beq stack_setup ldr r2, _armboot_start /* 读入_start到r2 */ ldr r3, _bss_start /* 读入__bss_start到r3 */ sub r2, r3, r2 /* r2 <- size of armboot */ add r2, r0, r2 /* r2 <- source end address */ copy_loop: ldmia r0!, {r3-r10} /* copy from source address [r0] */ stmia r1!, {r3-r10} /* copy to target address [r1] */ cmp r0, r2 /* until source end addreee [r2] */ ble copy_loop /* Set up the stack */ stack_setup: ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */ sub r0, r0, #CFG_MALLOC_LEN /* malloc area */ sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */ #ifdef CONFIG_USE_IRQ sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ) #endif sub sp, r0, #12 /* leave 3 words for abort-stack */ clear_bss: ldr r0, _bss_start /* find start of bss segment */ ldr r1, _bss_end /* stop here */ mov r2, #0x00000000 /* clear */ clbss_l:str r2, [r0] /* clear loop... */ add r0, r0, #4 cmp r0, r1 ble clbss_l ldr pc, _start_armboot _start_armboot: .word start_armboot 这是很经典的一段代码,相信学习凡是过ARM编程的,都分析过这段代码,所以也不再赘述。之所以列出这段代码,一是为了找到C程序入口start_armboot,二是为了给出U-Boot的一个存储器映射图: 这个图可以帮助我们更好地理解后续的C语言代码以及U-Boot对内存的分配与使用情况。
chinaunix网友2010-09-04 14:37:01
Download More than 1000 free IT eBooks: http://free-ebooks.appspot.com