玩转pandaboard之u-boot的编译及代码结构

本文以linaro提供的针对pandaboard的u-boot为例(之后用来加载Android),阐述u-boot编译及代码结构。 

  1. U-boot是神马
    简单说来就是嵌入式设备的BIOS, 用来初始化嵌入式设备上的各种硬件资源,并引导linux kernel的加载及启动。
    详细描述请从http://www.denx.de/wiki/U-Boot上获得你所想要的一切信息。
    另外, http://www.ibm.com/developerworks/cn/linux/l-btloader/也是一篇不可多得的介绍bootloader的文章!

  2. pandaboard u-boot的编译
    相关代码如何下载,请参照《玩转pandaboard之初体验》
    • 首先通过device/linaro/pandaboard/目录下的各个mk文件把u-boot及对应kernel的编译融入到Android的整个编译体系当中。
      这里就不多说了,熟悉Android编译体系结构的同学一看就明白(或者找到相应的变量, 在build/目录下grep,就一定能找到你想要的结果)
    • 与u-boot编译相关的参数都在BoardConfig.mk中指定了, 从中可以看出, TI已经基本放弃了x-load, 转而使用u-boot自带的SPL来作为second stage的bootloader
      (第一是, ROM boot, 第三则是u-boot自身)
      UBOOT_CONFIG := omap4_panda_config
      TARGET_USE_XLOADER := false
      XLOADER_CONFIG := omap4430panda_config
    • 首先,使用make omap_panda_config来初始化u-boot的config环境
      这里需要注意从Makefile中可以看出, make指令会去解析你所输入的xxxxx_config的参数, 然后找到对应的board的相关配置信息.
      比如,这里会调用mkconfig, 读取boards.cfg中的信息, 来确定相关的信息(ARCH, CPU, SoC, Vendor, Target)

    • 然后调用, make CROOSS_COMPILE=xxxxx来编译u-boot,
      请注意,这里目前使用的最新的Codesourcery的CodeBench, 会有编译错误, 从网上的资料来说是因为它使用了gcc4.6.1, 其中有bug(会导致编译oma4的clock.c出错)
      ,我又先后尝试了几个之前的版本, 发现arm-2011.03-41-arm-none-linux-gnueabi.bin这个版本的最近的能够编译成功的版本.

  3. pandaboard u-boot的代码结构
    1. 目录结构
      /arch                   Architecture 相关的文件
        /arm                  ARM architecture相关的文件
          /cpu                CPU 相关
          /include         
            /armv7          Files specific to ARM v7 CPUs
              /omap4       omap4相关的一些相关的文件
              *.c
              ...
          /lib                ARM Architecture相关的库文件
      /api                    Machine/arch无关的与用户提供的app相关的一些接口
      /board/ti/panda   panda板卡相关的文件
      /common            平台独立一些工具
      /disk                   经过config之后,与平台相关的磁盘分区代码
      /doc                    简单一些文档
      /drivers             设备驱动代码
      /examples        
      /fs                     各种嵌入式文件系统的代码
      /include            
      /lib                    平台无关的各种库
        /libfdt              flattened device trees 库
        /lzma              LZMA decompression 库
        /lzo                 LZO decompression 库
      /net                   支持network相关的代码
      /post                 上电之后的自我检测
      /rtc                    Real Time Clock 驱动
      /tools                 帮助生成uboot image的一些工具, mkimage!
      /spl                   重用u-boot中既有的驱动, 来生成更小的secondary program loader. 目前omap4就已经使用它取代原来的x-loader. 也就是使用mkimage通过spl的编译结果生成的MLO
      /README        重要的文件, 里面有个中板卡及kernel相关的配置的说明. 这个文档中也有简单如何增加新的board支持的说明及uboot各种命令及参数的说明!!!

      所有经过make omap4_panda_config之后, 所有的跟板卡相关的设置信息都会在"include/configs/omap4_panda.h".
      其中会引用其它一些板卡相关的configs头文件, 两者中包含了CPU/board/Serial port/console/linux内核/内存/autoboot/Device Tree/网络等的设置信息
      同时,为其它相关的代码生成对应的.depend,其中包含各种相关的文件引用

    2. 来看看pandaboard的各种config设定,
      include/configs/omap4-common.h include/configs/omap4-panda.h
      其中有各种编译参数, 生成的image地址, 硬件端口的设置等
      比如, SPL的启用,及mkimage生成uboot.img时指定的TEXT地址都在其中
      /* Defines for SPL */
      #define CONFIG_SPL
      #define CONFIG_SPL_TEXT_BASE        0x40303080
      #define CONFIG_SPL_MAX_SIZE     (38 * 1024)
      #define CONFIG_SPL_STACK        LOW_LEVEL_SRAM_STACK
      
      /*
       * 64 bytes before this address should be set aside for u-boot.img's
       * header. That is 80E7FFC0--0x80E80000 should not be used for any
       * other needs.
       */
      #define CONFIG_SYS_TEXT_BASE        0x80E80000
      这里相关的地址为什么定义为这个区间, 是跟各个板卡的RAM map相关的, pandaboard的ram划分参看的27.4.2 Memory Maps
      Table 2-1. Global Memory Space Mapping

    3. spl相关代码是独立与其它的uboot object来编译的, 有它自己的一些include及相关设定, 并通过mkimage生成对应的MLO

      /home/test/pandaboard/u-boot-linaro-stable/u-boot-linaro_2012.04.2/tools/mkimage -T omapimage \
              -a 0x40303080 -d /home/test/pandaboard/u-boot-linaro-stable/u-boot-linaro_2012.04.2/spl/u-boot-spl.bin /home/
      test
      /pandaboard/u-boot-linaro-stable/u-boot-linaro_2012.04.2/ MLOSection CHSETTINGS offset 40 length cCHSETTINGS (c0c0c0c1) valid:0 version:1 reserved:0 flags:0GP Header: Size 8270 LoadAddr 40303080make[1]: Leaving directory `/home/test/pandaboard/u-boot-linaro-stable/u-boot-linaro_2012.04.2/spl'
       
       
  4. 关于根目录下的Makefile
    请参看

  5. 关于uboot及spl中用到的ld script
    请参看http://zqwt.012.blog.163.com/blog/static/120446842010320101137932/
    其中解释下文中作者没明白的事情
           . = .; //这里没有搞清楚为什么要这样做!
           __u_boot_cmd_start = .;
    /*把当前位置赋值给__u_boot_cmd_start,即定义了.u_boot_cmd段空间的开始位置 */
     
           .u_boot_cmd : { *(.u_boot_cmd) }
           __u_boot_cmd_end = .;
    /*把当前位置赋值给__u_boot_cmd_end,即定义了.u_boot_cmd段空间的结束位置
    注意这个问题是由一个ld与binutil联动生成address  map造成的
    参见: http://git.linaro.org/gitweb?p=boot/u-boot-linaro-stable.git;a=commit;h=807d5d7319330e336ab34a5623c5e0d73b87d540
    及 http://sourceware.org/ml/binutils/2005-08/msg00412.html

    最终的解释在gnu ld的官方manual里面就有http://sourceware.org/binutils/docs-2.22/ld/Location-Counter.html#index-dot-outside-sections-517
    在两个section之间, 加入以下的赋值, 是为了告诉ld, 在ld工作时(即处理ld script之前), 不会在ld script 中的". = ." 之后的section中, 再插入新的section. 从而导致链接出错误的地址及map
    . = .;

    以及http://lionwq.spaces.eepw.com.cn/articles/article/item/18928
    其中关于链接地址及运行时地址的心得很有用
    既然程序有了两种地址,就涉及到一些跳转指令的区别,这里正好写下来,以后万一忘记了也可查看,以前不少东西没记下来现在忘得差不多了。。。
    ARM汇编中,常有两种跳转方法:b跳转指令、ldr指令向PC赋值。
    我自己经过归纳如下:
    (1)       b step1 :b跳转指令是相对跳转,依赖当前PC的值,偏移量是通过该指令本身的bit[23:0]算出来的,这使得使用b指令的程序不依赖于要跳到的代码
    的位置,只看指令本身。
    (2)       ldr pc, =step1 :该指令是从内存中的某个位置(step1)读出数据并赋给PC,同样依赖当前PC的值,但是偏移量是那个位置(step1)的连接地址
    (运行时的地址),所以可以用它实现从Flash到RAM的程序跳转。
    (3)       此外,有必要回味一下adr伪指令,U-boot中那段relocate代码就是通过adr实现当前程序是在RAM中还是flash中。仍然用我当时的注释:
    relocate: /* 把U-Boot重新定位到RAM */
        adr r0, _start /* r0是代码的当前位置 */ 
    /* adr伪指令,汇编器自动通过当前PC的值算出 如果执行到_start时PC的值,放到r0中:
    当此段在flash中执行时r0 = _start = 0;当此段在RAM中执行时_start = _TEXT_BASE(在board/smdk2410/config.mk中指定的值为0x33F80000,
    即u-boot在把代码拷贝到RAM中去执行的代码段的开始) */
        ldr r1, _TEXT_BASE /* 测试判断是从Flash启动,还是RAM */ 
    /* 此句执行的结果r1始终是0x33FF80000,因为此值是又编译器指定的(ads中设置,或-D设置编译器参数) */
        cmp r0, r1 /* 比较r0和r1,调试的时候不要执行重定位 */

    pandaboard的uboot的lds在arch/arm/cpu/u-boot.lds(最新的u-boot为所有的arm提供这么一个通用的script, 具体可以参看该文件的git log)及arch/arm/cpu/armv7/omap-common/u-boot-spl.lds

  6. 各种与pandaboard相关的配置文件
    arch/arm/include/asm/arch-omap4/*
    arch/arm/cpu/armv7/omap-common/*
    board/ti/panda/*
    arch/arm/cpu/armv7/omap4/*
    arch/arm/cpu/armv7/omap-common/*
    include/configs/omap4_common.h, include/configs/omap4_panda.h
    详细请参看<玩转pandaboard之u-boot启动过程详述>


其它,

  1. uboot使用-march=armv5来编译, 而不是使用armv7来编译pandaboard的uboot.
    具体原因我没能找到,但是从一些代码注释中,可以看出为了应付armv7的新的指令, uboot是如何做的
    参见arch/arm/include/asm/armv7.h
    /*
     * CP15 Barrier instructions
     * Please note that we have separate barrier instructions in ARMv7
     * However, we use the CP15 based instructtions because we use
     * -march=armv5 in U-Boot
     */
    #define CP15ISB asm volatile ("mcr     p15, 0, %0, c7, c5, 4" : : "r" (0))
    #define CP15DSB asm volatile ("mcr     p15, 0, %0, c7, c10, 4" : : "r" (0))
    #define CP15DMB asm volatile ("mcr     p15, 0, %0, c7, c10, 5" : : "r" (0))
    

    比如, 这里ISB, DSB, DMB都是armv7才提供的barrier instructions, uboot使用armv5类似的直接控制CP15的方式来实现它们.

  2. MLO的生成, 是由spl编译出的u-boot-spl.bin等文件, 由mkimage按照omapimage的配置生成的
    具体MLO是什么请参照http://www.embedded-bits.co.uk/2011/writeanmlo
    请注意beagleboard的spl起始地址是0x40200800, 而pandaboard是0x40303080(see omap4_common.h)


参考资料:

      http://free-electrons.com/doc/u-boot.pdf  很好的关于u-boot的介绍

      <玩转pandaboard之u-boot再体验>

      http://omappedia.org/wiki/Bootloader_Project, 很好一个关于TI的板卡bringup的文章!!!

      http://www.denx.de/en/pub/Documents/Presentations/EWC2012_Roeder_Zundel_Fastboot.pdf 关于SPL的比较详细介绍, 同时,代码目录doc/README.SPL也有详细的介绍

     

你可能感兴趣的:(android,system,tools,boot)