TI AM3517 EVM X-Loader启动流程分析

来源:互联网 发布:淘宝尼克服女装品牌 编辑:程序博客网 时间:2024/05/22 22:32

之前做了一个关于TI德州仪器AM3505 zcn的项目,我们的板子是参照德仪的LOGIC板子来的。德仪的ARM启动流程大概分为三级启动:SRAM内部启动代码(固化在A8内部的)---》x-Loader---》Uboot,接下来就是引导系统了,我也是刚刚接触这个方面的东西的,把我看X-Loader的一些经验写下来,供大家参考。

分析X-loader的时候,大家可能会有点没有头绪,刚接触,可能连入口函数都会找不到,我刚开始就是这样子的,不要紧。X-loader的大部分代码是汇编代码,可能不懂汇编的同学最好预先补充一下汇编的知识,其实,准备一个PDF的汇编指令大全就ok了,不懂再去百度。

在茫茫多的代码中,我们想知道最终执行的时候是从哪里开始执行的,我们可以首先看编译的连接文件:

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")OUTPUT_ARCH(arm)ENTRY(_start)SECTIONS{. = 0x00000000;. = ALIGN(4);.text      :{  cpu/omap3/start.o(.text)  *(.text)}. = ALIGN(4);.rodata : { *(.rodata) }. = ALIGN(4);.data : { *(.data) }. = ALIGN(4);.got : { *(.got) }. = ALIGN(4);__bss_start = .;.bss : { *(.bss) }_end = .;}
这里面定义了编译输出文件的架构OUTPUT_ARCH(arm),和编译的入口函数ENTRY(_start),其他的我这里暂时不讨论。这样我们就得到了入口函数了:

_start.globl _start_start:breset ldrpc, _hangldrpc, _hangldrpc, _hangldrpc, _hangldrpc, _hangldrpc, _hangldrpc, _hang

接下来你可以用代码查看工具加载X-loader工程,我用的是source insight,全局搜索一下_start你就可以在Start.S这个汇编文件中找到_start这个入口。接下来就是分析工作了。

这里看到进入入口后,首先就会跳转到reset入口

在reset里面会有两个重要的函数

第一个:

bl      cpy_clk_code

这个函数主要完成了Copy DPLL codeinto SRAM ,也就是复制代码的作用。然后就返回了,第二个重要的函数:

bl  cpu_init_crit

  首先它关闭了CPU的一些功能:TLB、ICache、MMU,最后会跳转bllowlevel_init,这里的连续跳转假如你搞不清楚,你可以查看http://blog.csdn.net/caoyicheng1/article/details/21291015
打开这个函数,你会发现它非常重要,在里面会跳转到一个C函数

bl      s_init         /* go setup pll,mux,memory */

其实从注释上你就可以看出他是用来设置pll、引脚、和内存的,里面有一连串的C语言连接函数,这里我还是把代码贴出来吧,我相信里面的注释加上名字会让你明白这些函数都做了些什么的,你要结合用户手册和芯片手册,不然有可能会有点迷糊。

void s_init(void){watchdog_init();#ifdef CONFIG_3430_AS_3410/* setup the scalability control register for * 3430 to work in 3410 mode */__raw_writel(0x5ABF,CONTROL_SCALABLE_OMAP_OCP);#endiftry_unlock_memory();//这里是定义(初始化)CPU引脚set_muxconf_regs();delay(100);prcm_init();per_clocks_enable();/* enable the DDRPHY clk */sr32((OMAP34XX_CTRL_BASE + 0x588), 15, 15, 0x1);/* enable the EMIF4 clk */sr32((OMAP34XX_CTRL_BASE + 0x588), 14, 14, 0x1);/* Enable the peripheral clocks */sr32((OMAP34XX_CTRL_BASE + 0x59C), 0, 4, 0xF);sr32((OMAP34XX_CTRL_BASE + 0x59C), 8, 10, 0x7);/* bring cpgmac out of reset */sr32((OMAP34XX_CTRL_BASE + 0x598), 1, 1, 0x1);/* Configure the EMIF4 for our DDR */config_emif4_ddr();}

这里我粗略的说一些bl和ldr的区别:
BL是相对跳转,即当前跳转地址,是根据pc的当前运行地址,用汇编编译器算出来的;一旦遇到一个 B 指令,ARM 处理器将立即跳转到给定的目标地址,从那里继续执行。注意存储在跳转指令中的实际值是相对当前PC 值的一个偏移量,而不是一个绝对地址,它的值由汇编器来计算(参考寻址方式中的相对寻址)。它是 24 位有符号数,左移两位后有符号扩展为 32 位,表示的有效偏移为 26 位(前后32MB 的地址空间),同样的,BL、BX都是相对跳转。
LDR伪指令是将第二操作直接赋值给第一操作数,当执行ldr pc,=Main时是将Main的绝对地址赋值给了PC。这样可以实现从芯片内部SRAM跳转到C代码中,在xloader的config.mk中有TEXT_BASE指定的地址,也就实现了从SRAM跳转到外部存储器也就是DDR(SDRAM)中去执行了。

执行完这个C函数后,会有几个连续的返回跳转。最后进入Start.S中的relocate:入口,这个入口就是所谓的重定位代码。

relocate:/* relocate U-Boot to RAM    *///目前代码运行的地址adrr0, _start/* r0 <- current position of code   *///代码在flash or RAM的addrldrr1, _TEXT_BASE/* test if we run from flash or RAM *///假如现在运行的代码就是在SDRAM中,就跳过代码copy的环节cmp r0, r1                  /* no need to relocate if XIP       */beq stack_setup/* skip txt cpy if XIP(SRAM, SDRAM) */ldrr2, _armboot_startldrr3, _bss_startsubr2, r3, r2/* r2 <- size of armboot            */addr2, r0, r2/* r2 <- source end address         */


假如我们的代码run from SDRAM,那么就会跳过后面的代码拷贝阶段,其实不跳过就是执行了拷贝(重定位),跳过了,证明代码已经在SDRAM中运行了。

后面就是连续的设置堆栈和清BBS段了,接下来就要调用C语言函数了。

接下来会进入跳转Uboot的最后一步,进入一个C函数

ldr     pc, _start_armboot     /* jump to C code                   */

 

_start_armboot: .word start_armboot

在这个C函数里面先执行了一个函数指针数组

init_fnc_t **init_fnc_ptr; int i;uchar *buf;   for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {if ((*init_fnc_ptr)() != 0) {hang ();}}

你可以点进去看看他们到底做了些什么,CPU初始化,板子的初始化,还有串口的初始化,nand的初始化之类的。。。

接下来x-loader需要判断板子的启动方式,这里我就不多说了,大家自己去看。

当你看到如下字段:

/* go run U-Boot and never return */  printf("Starting OS Bootloader...\n"); ((init_fnc_t *)CFG_LOADADDR)();

整个x-loader的工作已经做完了!

其实看起来很多,分析完了之后,做的工作很少,你需要根据你的硬件的具体情况去做移植。下面利用网上的资料总结一下:

(1)x-loader第一个运行文件是位于/cpu/omap3/下的汇编程序start.S。

        (2)在start.S中会调用 /board/am3517evm/platform.S中的lowlevel_init函数,该函数又会调用C语言函数s_init(位于/board/am3517evm/Am3517evm.c中),该函数会依次完成下列工作:

               (a)关闭看门狗2(watchdog_init()函数);

        (b)解锁存储器(try_unlock_memory()函数),这是OMAP系列MPU的保护机制,不解锁的话将无法写一些寄存器;

              (c)配置相关资源引脚的模式(set_muxconf_regs());

        (d)配置各个模块时钟(prcm_init()):Core_DPLL:332MHz;MPU_DPLL:380MHz;PER_DPLL:432MHz;

              (e)配置外部RAM(config_emif4_ddr()):

        (3)之后x-loader进入第二阶段,入口函数是/lib/board.c程序中的start_armboot();

        (4)x-loader第二阶段的主要功能是通过读取sys_boot~-sys_boot0引脚的值判断是从NANDFLASH还是从SD卡启动,并从判断结果中拷贝u-boot到RAM中并运行。



OK!~~OVER


                                             
0 0