zoukankan      html  css  js  c++  java
  • (转)S5PV210之UBOOT2011.06启动过程解析

    //主题:S5PV210之UBOOT-2011.06启动过程解析

    //作者:kevinjz2010@gmail.com

    //版权:kevinjz原创

    //平台:S5PV210 ARMV7 TINY210

    //发布日期:2012-05-24

    //最后修改:2012-11-27

    //注意事项:欢迎转载,但不得在转载的时候擅自修改、删除文章的任何部分

    //-------------------------------------------------------------------------------------------------

            本文使用的UBOOT版本:u-boot for tiny210 ver3.1 (by liukun321咕唧咕唧)

            源码地址:http://blog.csdn.net/liukun321/article/details/7438880#comments

            感谢作者liukun321的辛勤劳动啊,呵呵!

    一、配置与使用

            1、在系统根目录下的Makefile中的第601行,通过下列语句:

            sinclude$(obj).boards.depend

            $(obj).boards.depend: boards.cfg

                    awk'(NF && $$1 !~ /^#/) { print $$1 ": " $$1 "_config;$$(MAKE)" }' $< > $@

            读取了boards.cfgboards.cfg中关于tiny210_onfig的配置项,其中.boards.depend是隐藏文件;

            2、在Makefile的160行添加: 

            + ifeq($(ARCH), arm)

            + CROSS_COMPILE= arm-none-linux-gnueabi-

            + endif

            这样配置好了默认的编译器;

            3、在根目录下执行:

            $make tiny210_config

            $make -j all

            即可在根目录得到tiny210-uboot.bin,可用于SD卡启动和NAND启动;

            4、烧入SD卡的时候使用下面命令:

            $sudodd iflag=dsync oflag=dsync if=tiny210-uboot.bin of=/dev/sdb seek=1

            dd命令用于对SD进行烧写,根据三星手册《S5PV210_iROM_ApplicationNote_Preliminary_20091126》,将tiny210-uboot.bin烧写到,SD卡的第一个Block,保留第0个block不用,每个block=512B。

            5、从SD卡启动后可以就可以将UBOOT烧写到nand里了:

            $tftp 21000000 tiny210-uboot.bin

            $nand erase 0 40000

            $nand write 21000000 0 40000

            6、注意:若要启动linux内核,需要在/arch/arm/mach-s5pv210/include/mach/memory.h中将SECTION_SIZE_BITS 及NODE_MEM_SIZE_BITS改成29,对应一个内存区512M。tiny210和mini210在硬件上挂载内存上是不同的。tiny210将512M内存全部挂在0x20000000开始1区,而mini210将256M挂在0x20000000-0x2fffffff,另外256M挂在0x40000000-0x4fffffff。这也涉及到uboot的config头文件中对210内存控制寄存器的不同设置。要注意!!另外要注意,该UBOOT只能引导uImage,所以在正常编译完内核之后要,要make uImage!

    二、启动流程分析

            按照三星《S5PV210_UM_REV1.1》手册上说明的启动流程,S5PV210上电将从IROM处执行固化的启动代码,对时钟等初始化、对启动设备进行判断,并从启动设备中复制BL1(最大16KB)到IRAM(0xd002_0000处,其中0xd002_0010之前的16个字节储存的BL1的校验信息和BL1尺寸)中,并对BL1进行校验,校验OK转入BL1进行执行;BL1继续初始化,并将BL2复制到IRAM中并对其校验,OK后转入BL2;BL2则要进行比较复杂的初始化,包括DRAM的初始化,完成后将OS代码复制到DRAM中,并转入到OS中执行并完成启动引导。

            但是,上述的IRAM只有96K大小,对于日益复杂的uboot来说,肯定是不够的,所以使用UBOOT启动引导的时候,也没全按三星手册上说的执行,具体如下:      

            首先解释一下我认为的BL0、BL1、BL2:

            BL0:是指S5PV210的IROM中固化的启动代码;

            BL1:是指在IRAM中执行的UBOOT的部分代码;

            BL2:是指在内存中执行的的UBOOT的完整代码;

            此版本的UBOOT,其实会编译两个UBOOT.bin,即最终生成的tiny210-uboot.bin包括两部分,前段是spl(重用u-boot中既有的驱动,来生成更小的secondaryprogramloader)文件夹内的tiny210-spl.bin,后段是用于在RAM中执行的完整UBOOT代码。所以学习UBOOT代码是也要两个部分来看。

             1、第一步与三星手册上一致,执行IROM内固化的代码,即BL0,BL0会将存储于启动设备的UBOOT代码的前16KB:tiny210-spl.bin复制到IRAM。(tiny210-spl.bin设置为24KB了,但实际绝不会超过16KB,后面全填充的0,所以拷不完也OK。这里是liukun321为了统一MMC与NAND启动而作的修改,也许改成16K就应该OK了,应为IROM里的代码最多拷贝16K进IRAM嘛,一会改改试试。所以呢实际上执行BL1就是执行tiny210-spl.bin。在UBOOT的代码中并不会看到tiny210-spl.bin和完整的UBOOT代码分开两套文件进行编写,都在同样的文件中,只是通过宏定义来控制执行流程,SPL文件夹内由自己的Makefile文件。

            2、第一步入口程序是/arch/arm/cpu/armv7/start.S中的_start,设置异常向量地址(地址由ARM 架构决定,不能改变),执行reset,进入SVC32模式,并调用cpu_init_crit对ARM的CP15寄存器进行设置,如清空TLB,关闭MMU等,进入/board/samsung/tiny210/lowlevel_init.S中的lowlevel_init中,进行低级初始化,主要是对时钟、内存、串口、nand等进行初始化,为下一步的代码拷贝做准备。

            3、从lowlevel_init出来之后执行call_board_init_f,通过读取OMR_OFFSET寄存器的值,对启动设备进行判断,看看是从mmc启动还是nand启动,判断好后跳入mmc_boot.c或nand_cp.c中,将UBOOT代码拷贝到内存中,地址为_TEXT_BASE:在tiny210.h中定义为0x23e0_0000,换成别的地方也可以,比如3000_0000(注:在跳转到内存中执行之前,所有的语句都是基于PC寻址的,也就是说和代码具体存放的地址没有关系,进行跳转的时候都会计算出跳转目标相对与PC的位置,在跳转过去。)。这里有一个很大的问题,稍后讨论。拷贝完成后直接冲0x23e0_0000出开始执行。那么执行的是什么呢,那先看看拷贝的是什么吧!

            a.nand启动

            在/arch/arm/cpu/armv7/s5pc1xx/nand_cp.c中,第105行:

            for(i = (0x6000>>page_shift); i < (size>>page_shift);i++, buf+=(1<<page_shift)) {

            nandll_read_page(buf,i, large_block);

            }

            指定了拷贝的起始page是nand起始24K之后的第一个PAGE,偏移0x6000的位置,该地址上存储的是完整的UBOOT在RAM中执行的完整启动代码;

            b.mmc启动

            在/arch/arm/cpu/armv7/s5pc1xx/mmc_boot.c中,第49行:

            #defineMOVI_BL2_POS ((eFUSE_SIZE / MOVI_BLKSIZE) +MOVI_BL1_BLKCNT + MOVI_ENV_BLKCNT)

            经计算MOVI_BL2_POS位于第24.5K的位置,也即第49个block,偏移0x6200的位置,该地址上存储的同样是UBOOT在RAM中执行的完整启动代码;

            注:针对第一点提出的将24K偏移改成16K,经过验证:改成16KB并不可行,其实这里不仅仅是BL1的容量的问题,UBOOT_SPL.BIN实际上只有4K不到,所以对于nand启动来说4KB就足够了,但是对于MMC启动来说却不行,因为SD卡的布局并不一样,它在BL1与BL2之间还插入了16KB的ENV区,所以只能是24K,而对NAND的ENV区在BL2之后了。

            所以,无论是MMC启动还是NAND启动,将代码copy到DRAM中并跳转之后,执行的是DRAM中的_start入口函数,重新执行一遍UBOOT,但是一些宏定义已经发生变化,如CONFIG_SPL_BUILD被取消定义,相应的代码也不会执行。

              4、因为第一编执行UBOOT的时候ARM的状态都已经初始化OK了,包括时钟,内存等,第二遍执行时只是跳转到内存中执行了,所以这里判断是否在DRAM中执行,如果在内存中执行,则可以直接跳到call_board_init_f去进行班级初始化。当然,源码并不是这样执行的,而是重新执行RESET、LOWLEVEL_INIT等函数,但我验证过,可以不用执行。有兴趣的同志也可以验证一下。

              5 、进入board_init_f以后将:

              a、对gd_t数据结构(include/asm/global_data.h中定义)进行初始化,并填入相关数据,如内存大小、UBOOT镜像长度等;

              b、对打印CPU信息、UBOOT版本信息等,并对串口、console进一步初始化,输出nand信息,对内存大小进行计算,并打印出来。

              c、为UBOOT的重定向设置物理地址,重定向后UBOOT可使用的end地址为0x3fff_0000,

              UBOOT镜像起始地址为0x3ff8_5000。

              打印调试信息:

    TLBtable at: 3fff0000

    Topof RAM usable for U-Boot at: 3fff0000

    Reserving424k for U-Boot at: 3ff85000

    Reserving928k for malloc() at: 3fe9d000

    Reserving24 Bytes for Board Info at: 3fe9cfe8

    Reserving120 Bytes for Global Data at: 3fe9cf70

    NewStack Pointer is: 3fe9cf60

    第一个疑问:

    第201行:

    /*Pointer is writable since we allocated a register for it */

    gd= (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);

    打印CONFIG_SYS_INIT_SP_ADDR的值为0x20ff_ff80,为啥gd_t数据结构会在这个位置,之后好像没有看到重定向gd数据结构的代码!

            6、完成board_init_f中的处理后,转入start.S中的relocate_code函数进行代码搬运及重定向。搬运完成之后,清空BSS后转入board.c中的board_init_r函数执行。

            第二个疑问:

            这里重定向的意义是什么?以前S3C6410或S3C2410的UBOOT中对代码进行重定向是将代码从FLASH或nand或MMC中复制到内存中,但是这里之前的代码已经将UBOOT从nand或mmc复制到了DRAM中,而且目前也是运行在DRAM中。那么为什么在之前的代码中不直接将UBOOT复制到0x3ff8_5000,就可以省去relocate_code步骤?我尝试将CONFIG_SYS_TEXT_BASEdefine为0x3ff8_5000过之后,UBOOT可以启动,但所有的CMD都丢失了,比如:Unknowncommand 'printenv' - try 'help'?目前也没搞明白哪里出问题了!

            7、在board_init_r中,会清空malloc()区的内存,对nand、MMC等进行初始化,执行env_relocate()对环境变量进行初始化(第6步中的问题不知道是不是由于这个函数没有处理好引起的,研究了半天也没发现问题),如果将环境变量保存在NAND中,则会将其读入到内存中来。如果出现什么问题的话,就使用默认的环境变量代替。此步还会对网络、中断等进行初始化。全部初始化完成之后则跳入/common/main.c中的main_loop()中执行,等待用户命令或自动加载内核。

    三、总结

            本文对S5PV210平台UBOOT的启动流程做了分析,并对一些有疑问的地方做了验证,比如哪一块代码会执行两遍,哪一块代码第二编制行的时候可以省去等。

            验证的方法一般就是电灯或者判断代码执行的位置等。另外,调试过程需要多次的进行烧写,如果每次都敲命令进行烧写的华会很费时间的,所以最好是在/common/main.c中写一个自己的的菜单,并且将烧写任务设为一个命令就行了,这样会轻松一些。

            本文到这里也只是初步了解了一下UBOOT的启动流程,很多具体的代码还有很多不明白的地方,比如nand、mmc、网卡的驱动啥的,慢慢在具体分析吧。还有,上面的两个问题,尤其是第二个问题,知道的同志吱一声,讨论讨论哈!

     原文出处:http://blog.csdn.net/xiaoxizi198807/article/details/7599859

  • 相关阅读:
    Java实现 LeetCode 400 第N个数字
    Java实现 LeetCode 400 第N个数字
    Java实现 LeetCode 399 除法求值
    Java实现 LeetCode 399 除法求值
    Java实现 LeetCode 399 除法求值
    Java实现 LeetCode 398 随机数索引
    Java实现 LeetCode 398 随机数索引
    Java实现 LeetCode 398 随机数索引
    linux中的cd ..和cd -命令有什么区别?
    GCC使用
  • 原文地址:https://www.cnblogs.com/lihaiping/p/sdkv210.html
Copyright © 2011-2022 走看看