Board logo

标题: uboot第一部分汇编启动代码分析详解 [打印本页]

作者: yuyang911220    时间: 2017-6-17 11:12     标题: uboot第一部分汇编启动代码分析详解

Uboot移植  代码分析
突然发现自己很久没有弄这块了,自己把uboot翻出来看了一会,感觉想写点什么,大家看看吧,觉得写的有用就顶下,觉得写的不对,就指出来,大家共同进步把。
        首先当我们想要移植一个uboot的时候,我们可以利用uboot里面提供的一些原有跟门自己使用芯片一样,只是外围电路不一样的的一些配置,比如我们做说s3c2410的一个uboot移植,我们可以复制一份uboot里面本来提供的smdk2410的原有代码复制一份改成我们自己的名字,比如我的tt2410,这样大部分地方是相同的,只是一些设计到外围硬件的程序需要大家来修改,这样我们对于uboot的移植就很是方便了。不过大部分主要是对uboot的代码进行分析,移植在其次。
        当我们打开uboot代码的时候,这个源代码里面有一个board的文件夹,在这个文件夹里面有一个smdk2410的文件夹,这个是源代码对2410 smdk的板子的支持,我们可以建立我们自己板子的支持,我们可以创建一个文件夹命名为tt2410,然后将smdk2410中间的文件全部复制过来,然后将smdk2410.c   这个文件更名为tt2410,然后需要修改一下makefile这个修改比较简单,就不需要我说了。其实我们添加对于我们自己板子支持很多地方的makefile是需要修改的,其实修改的方法很简单,除这个文件夹里面   是直接改名,其他地方的makefile大部分是直接将smdk2410的配置直接复制一份,然后改一个我们自己命名文件夹的对应的编译规则,大家只要打开看看基本上是知道makefile是怎样去修改,所以后面我对makefile的修改基本省略
        在我们刚刚建立的文件夹中间有一个名为u-boot.lds的文件,打开这个文件我们可以看到如下代码
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
        . = 0x00000000;
        . = ALIGN(4);
        .text      :
        {
          cpu/arm920t/start.o        (.text)
          *(.text)
        }
        . = ALIGN(4);
        .rodata : { *(.rodata) }
        . = ALIGN(4);
        .data : { *(.data) }
        . = ALIGN(4);
        .got : { *(.got) }
        . = .;
        __u_boot_cmd_start = .;
        .u_boot_cmd : { *(.u_boot_cmd) }
        __u_boot_cmd_end = .;
        . = ALIGN(4);
        __bss_start = .;
        .bss (NOLOAD) : { *(.bss) }
        _end = .;
}
其实这个东西是在我们编译器编译完成之后,连接器使用的一个文件,这个链接文件定义了程序的入口点,代码段、数据段等分配情况,我们主要看到这里有这样的一句话
= 0x00000000;
        . = ALIGN(4);
        .text      :
        {
          cpu/arm920t/start.o        (.text)
          *(.text)
        }
这段代码其实就是告诉我们程序最开始运行的代码其实就是cpu/arm920t/start.s 这个文件的程序,很多人不知道问什么要这么做。其实这样做的目的是让cpu上电一定要执行这段代码,第二点就是为么我们uboot工作的第一阶段。其实大家查资料可以知道,在我们芯片内部其实是有一段固化的代码,这段代码可以直接从nor或者nand中间读取程序,就我这个芯片而言,可以直接读取到4k的内容,但是我们的uboot程序不可能只有4k呀,所以我们必须指定在这个4k程序中间要将uboot所有的程序拷贝到ram中间,这样我们的uboot才能完整运行,所以uboot这样做是非常有必要的。
我们先来看看cpu/arm920t/start.s这个代码
首先第一句话_start:        b       start_code
程序跳转到start_code这个地方,我们去看看这个地方
mrs        r0,cpsr
        bic        r0,r0,#0x1f
        orr        r0,r0,#0xd3
        msr        cpsr,r0
这段代码设置cpu的工作模式为管理模式
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
        /* turn off the watchdog */
# if defined(CONFIG_S3C2400)
#  define pWTCON                0x15300000
#  define INTMSK                0x14400008        /* Interupt-Controller base addresses */
#  define CLKDIVN        0x14800014        /* clock divisor register */
#else
#  define pWTCON                0x53000000
#  define INTMSK                0x4A000008        /* Interupt-Controller base addresses */
#  define INTSUBMSK        0x4A00001C
#  define CLKDIVN        0x4C000014        /* clock divisor register */
# endif
        ldr     r0, =pWTCON
        mov     r1, #0x0
        str     r1, [r0]
        /*
         * mask all IRQs by setting all bits in the INTMR - default
         */
        mov        r1, #0xffffffff
        ldr        r0, =INTMSK
        str        r1, [r0]
# if defined(CONFIG_S3C2410)
        ldr        r1, =0x3ff
        ldr        r0, =INTSUBMSK
        str        r1, [r0]
# endif
        /* FCLK:HCLKCLK = 1:2:4 */
        /* default FCLK is 120 MHz ! */
        ldr        r0, =CLKDIVN
        mov        r1, #3
        str        r1, [r0]
然后这段其实很清楚上面因为上面基本上都用英文标出来了,首先我们先关闭看门狗,然后关中断,然后再是设置cpu的分频系数
bl        cpu_init_crit    然后调用这个函数
这个函数  mov        r0, #0
        mcr        p15, 0, r0, c7, c7, 0        /* flush v3/v4 cache */
        mcr        p15, 0, r0, c8, c7, 0        /* flush v4 TLB */
        /*
         * disable MMU stuff and caches
         */
        mrc        p15, 0, r0, c1, c0, 0
        bic        r0, r0, #0x00002300        @ clear bits 13, 9:8 (--V- --RS)
        bic        r0, r0, #0x00000087        @ clear bits 7, 2:0 (B--- -CAM)
        orr        r0, r0, #0x00000002        @ set bit 2 (A) Align
        orr        r0, r0, #0x00001000        @ set bit 12 (I) I-Cache
        mcr        p15, 0, r0, c1, c0, 0
这些主要就是做关闭idcache    然后关闭mmu
bl        lowlevel_init  这个函数其实做的就是对ram的一个初始化,这个这个初始化使用汇编的查表来完成的,所以大家看起来不是很好看,但是仔细看看还是看的出来
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
        ldr        r3, _bss_start
        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
这一段其实是对代码拷贝就是将uboot代码从flast里面拷贝到ram里面去,但是uboot的源码是只对norflash支持的 ,其实我们可以自己添加对nand的支持,很多人会想,我们怎样去区分nor还是nand启动的捏,其实有一个巧妙的方法
在cpu对内部的固化代码虽然可以直接对nor和nand直接读取,但是有一点,nor的写必须要添加代码才能,所以我们这个会发现一点,在前面4k的范围内,我们没有添加对nor写的程序的时候,我们在地址00000000h出写入一个数据再去读出来,如果我们写入数据,再读出来是我们写入的数据的话,那么  这个肯定是从nand启动的,因为nor cpu里面的固化代码是不能写的,只能写nand,所以我们利用这个巧妙的方式可以区分,我们cpu上电是从nor启动还是nand启动的。




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0