• 回味经典——uboot1.1.6 之 第一阶段


    转自:http://blog.csdn.net/lizuobin2/article/details/52054293

    最近打算移植一个比较新的 uboot 到开发板,回想起来上一次移植 uboot1.1.6 已经差不多是一年前了,手头保留了一些当时移植分析时的笔记,但是没有归纳梳理,在移植新版 uboot 之前,再来回味一下经典。本文重点在于分析 uboot 启动流程以及 uboot 自身的细节,比如栈空间的划分、如何设置 tag 、如何添加一个自定义命令等。但是不涉及基本的硬件驱动的分析,比如内存初始化、时钟初始化、mmu 、nandflash 等等这些细节不是我们的重点。

        

    一、链接脚本

        uboot1.1.6 的链接脚本 u-boot.lds 位于 u-boot-1.1.6oardsmdk2410 目录下:

    [cpp] view plain copy
    1. ENTRY(_start)  
    2. SECTIONS  
    3. {  
    4.     . = 0x00000000;  
    5.   
    6.     . = ALIGN(4);  
    7.     .text      :  
    8.     {  
    9.       cpu/arm920t/start.o   (.text)  
    10.       *(.text)  
    11.     }  
    12.   
    13.     . = ALIGN(4);  
    14.     .rodata : { *(.rodata) }  
    15.   
    16.     . = ALIGN(4);  
    17.     .data : { *(.data) }  
    18.   
    19.     . = ALIGN(4);  
    20.     .got : { *(.got) }  
    21.   
    22.     . = .;  
    23.     __u_boot_cmd_start = .;  
    24.     .u_boot_cmd : { *(.u_boot_cmd) }  
    25.     __u_boot_cmd_end = .;  
    26.   
    27.     . = ALIGN(4);  
    28.     __bss_start = .;  
    29.     .bss : { *(.bss) }  
    30.     _end = .;  
    31. }  
        链接地址为 0 ?显然不应该,实际编译的时候执行的大概是这样一条语句:

        arm-Linux-ld -Bstatic -T u-boot.lds -Ttext 0x33F80000 start.o ...

        0x33F80000 在 board/smdk2410/config.mk 中定义,为 TEXT_BASE = 0x33F80000 (链接地址)

        整个 uboot 的入口 _start 包含在 cpu/arm920t/start.S 中


    二、第一阶段

        uboot 的第一阶段主要工作是作基本的初始化工作,例如关看门狗、初始化时钟、初始化 sdram 以及代码重定位,为第二阶段做准备。这里的代码都是没有经过移植的源代码~!


      1、设置异常向量

    [cpp] view plain copy
    1. .globl _start  
    2. _start: b       reset  
    3.     ldr pc, _undefined_instruction  
    4.     ldr pc, _software_interrupt  
    5.     ldr pc, _prefetch_abort  
    6.     ldr pc, _data_abort  
    7.     ldr pc, _not_used  
    8.     ldr pc, _irq  
    9.     ldr pc, _fiq  
    10.   
    11. _undefined_instruction: .word undefined_instruction  
    12. _software_interrupt:    .word software_interrupt  
    13. _prefetch_abort:    .word prefetch_abort  
    14. _data_abort:        .word data_abort  
    15. _not_used:      .word not_used  
    16. _irq:           .word irq  
    17. _fiq:           .word fiq  
    18.   
    19.     .balignl 16,0xdeadbeef  
        第一条 b reset ,因为刚开始运行时代码都是在片内 sram 里,我们在 sram 里调来跳去的话就需要用位置无关码,那么 b 就是最佳选择,因为它是相对跳转。
        ldr    pc, _undefined_instruction

        _undefined_instruction:.word undefined_instruction

        感觉真是在卖弄,两条指令连起来的结果就是,CPU 会跳转到 undefined_instruction 链接地址处去执行(sdram里)。

        那么其实,一条 ldr pc,=undefined_instruction 就够了,它是位置有关码,绝对跳转。

        或许,uboot 的作者别有用意我没看透,不知道这是不是个伏笔。在u-boot2015里,就只有一个 reset 一个异常入口了。

     

      2、进入管理模式

    [cpp] view plain copy
    1. reset:  
    2.     /* 
    3.      * set the cpu to SVC32 mode 
    4.      */  
    5.     mrs r0,cpsr  
    6.     bic r0,r0,#0x1f  
    7.     orr r0,r0,#0xd3  
    8.     msr cpsr,r0  
        ARM每种工作模式除R0~R15共16个寄存器外,还有第17个寄存器CPSR,叫做 当前程序状态寄存器,CPSR中一些位被用于标识各种状态,一些位被用于标识当前出于什么工作模式。

        

        有时候我们会碰到 CPSR_C ,它其实就是 CPSR 的低 8 位而已。


        I:1-禁止irq中断 0-允许irq中断

        F:1-禁止fiq中断 1-允许fiq中断

        T:1-Thumb 0-arm 指令集

        M0-M4 : 工作模式


        说了这么多,前边两条指令,先将 cpsr 低 5位 清零,然后或上 1101 0011B

        禁止了 irq 和 fiq 中断,工作在 arm 指令集,管理模式。

      3、关看门狗

    [cpp] view plain copy
    1. #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)  
    2.     ldr     r0, =pWTCON  
    3.     mov     r1, #0x0  
    4.     str     r1, [r0]  
      4、屏蔽中断
    [cpp] view plain copy
    1.     /* 
    2.      * mask all IRQs by setting all bits in the INTMR - default 
    3.      */  
    4.     mov r1, #0xffffffff  
    5.     ldr r0, =INTMSK  
    6.     str r1, [r0]  
    7. # if defined(CONFIG_S3C2410)  
    8.     ldr r1, =0x3ff  
    9.     ldr r0, =INTSUBMSK  
    10.     str r1, [r0]  
    11. # endif  
        前边通过 cpsr 禁止 irq 和 fiq 使 cpu 不接受来自中断控制器的中断请求,而这里通过中断屏蔽使中断发生时,中断控制寄存器自身就不会上报给 cpu 双保险。
      5、设置时钟
    [cpp] view plain copy
    1. /* FCLK:HCLK:PCLK = 1:2:4 */  
    2. /* default FCLK is 120 MHz ! */  
    3. ldr r0, =CLKDIVN  
    4. mov r1, #3  
    5. str r1, [r0]  
     6、关 I/D cache 关 TLB
    [cpp] view plain copy
    1. /* 
    2.  * flush v4 I/D caches 
    3.  */  
    4. mov r0, #0  
    5. mcr p15, 0, r0, c7, c7, 0   /* flush v3/v4 cache */  
    6. mcr p15, 0, r0, c8, c7, 0   /* flush v4 TLB */  



        协处理器 p15 在2410的数据手册附录有介绍

        或者参考:http://blog.sina.com.cn/s/blog_858820890102v1gc.html

      7、关 mmu 

    [cpp] view plain copy
    1. /* 
    2.  * disable MMU stuff and caches 
    3.  */  
    4. mrc p15, 0, r0, c1, c0, 0  
    5. bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)  
    6. bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)  
    7. orr r0, r0, #0x00000002 @ set bit 2 (A) Align  
    8. orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache  
    9. mcr p15, 0, r0, c1, c0, 0  
        这里主要涉及 P15 的 C1寄存器,用到的各位:


      8、初始化 sdram 控制器

    [cpp] view plain copy
    1. .globl lowlevel_init  
    2. lowlevel_init:  
    3.     /* memory control configuration */  
    4.     /* make r0 relative the current location so that it */  
    5.     /* reads SMRDATA out of FLASH rather than memory ! */  
    6.     ldr     r0, =SMRDATA  
    7.     ldr r1, _TEXT_BASE  
    8.     sub r0, r0, r1  
    9.     ldr r1, =BWSCON /* Bus Width Status Controller */  
    10.     add     r2, r0, #13*4  
    11. 0:  
    12.     ldr     r3, [r0], #4  
    13.     str     r3, [r1], #4  
    14.     cmp     r2, r0  
    15.     bne     0b  
    16.   
    17.     /* everything is fine now */  
    18.     mov pc, lr  
    19.   
    20.     .ltorg  
    21. /* the literal pools origin */  
    22.   
    23. SMRDATA:  
    24.     .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))  
    25.     .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))  
    26.     .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))  
    27.     .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))  
    28.     .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))  
    29.     .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))  
    30.     .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))  
    31.     .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))  
    32.     .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))  
    33.     .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)  
    34.     .word 0x32  
    35.     .word 0x30  
    36.     .word 0x30  
        写裸机代码的入门操作,初始化 sdram 寄存器。

      9、代码重定位

    [cpp] view plain copy
    1. relocate:               /* relocate U-Boot to RAM       */  
    2.     adr r0, _start      /* r0 <- current position of code   */  
    3.     ldr r1, _TEXT_BASE      /* test if we run from flash or RAM */  
    4.     cmp     r0, r1                  /* don't reloc during debug         */  
    5.     beq     stack_setup  
    6.   
    7.     ldr r2, _armboot_start  
    8.     ldr r3, _bss_start  
    9.     sub r2, r3, r2      /* r2 <- size of armboot            */  
    10.     add r2, r0, r2      /* r2 <- source end address         */  
    11.   
    12. copy_loop:  
    13.     ldmia   r0!, {r3-r10}       /* copy from source address [r0]    */  
    14.     stmia   r1!, {r3-r10}       /* copy to   target address [r1]    */  
    15.     cmp r0, r2          /* until source end addreee [r2]    */  
    16.     ble copy_loop  
        adr 位置无关码,获取_start实际当前位于的地方,_TEXT_BASE 为 0x33f80000 ,这里判断的是代码是否直接运行在 sdram 里了,如果是就不需要重定位了。

        拷贝范围:_start 至 _bss_start 前,拷贝到 0x33f80000 处。

          33f80048 <_bss_start>:
          33f80048:    33fb064c

        0x33fb064c - 0x33f80000 > 192K ,什么意思呢?整个 uboot 除了 bss 段 > 4k,如果是 nandflash 启动的话需要从 nandflash 里读取 uboot 到内核,而这里是直接从 0 地址开始读,并读取 > 193k 的东西,显然 uboot 运行在 Norflash 才可以。默认 uboot 不支持 nandflash 启动。

      10、设置栈

    [cpp] view plain copy
    1. stack_setup:  
    2.     ldr r0, _TEXT_BASE      /* upper 128 KiB: relocated uboot   */  
    3.     sub r0, r0, #CFG_MALLOC_LEN /* malloc area                      */  
    4.     sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */  
    5. #ifdef CONFIG_USE_IRQ  
    6.     sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)  
    7. #endif  
    8.     sub sp, r0, #12     /* leave 3 words for abort-stack    */  
    9.   
    10. clear_bss:  
    11.     ldr r0, _bss_start      /* find start of bss segment        */  
    12.     ldr r1, _bss_end        /* stop here                        */  
    13.     mov     r2, #0x00000000     /* clear                            */  
    14.   
    15. clbss_l:str r2, [r0]        /* clear loop...                    */  
    16.     add r0, r0, #4  
    17.     cmp r0, r1  
    18.     ble clbss_l  
        TEXT_BASE = 0x33F80000 其它的宏在 Smdk2410.h (includeconfigs):
    [cpp] view plain copy
    1. #define CFG_MALLOC_LEN      (CFG_ENV_SIZE + 128*1024)  
    2. #define CFG_ENV_SIZE        0x10000 /* Total Size of Environment Sector */  
    3. #define CFG_GBL_DATA_SIZE   128  
    4. #define CONFIG_STACKSIZE_IRQ    (4*1024)    /* IRQ stack */  
    5. #define CONFIG_STACKSIZE_FIQ    (4*1024)    /* FIQ stack */  
    [cpp] view plain copy
    1. 0x34000000:  
    2. (512K)              存放 uboot  
    3. 0x33F80000:  <span style="white-space:pre">       </span>TEXT_BASE  
    4. (64K+128K == 192K)  <span style="white-space:pre">        </span>mallo区  
    5. 0x33F50000:  
    6. (128bytes)          global data区,后边会提到主要放的gd、bd全局结构体  
    7. 0x33F4FF80:           
    8. (4*1024*2)          IRQ+FIQ的栈  
    9. 0x33F4DF80:  
    10. (12byte)            abort-stack,栈溢出  
    11. 0x33F4DF74:         sp  

      11、清 BSS 段
    [cpp] view plain copy
    1. clear_bss:  
    2.     ldr r0, _bss_start      /* find start of bss segment        */  
    3.     ldr r1, _bss_end        /* stop here                        */  
    4.     mov     r2, #0x00000000     /* clear                            */  
    5.   
    6. clbss_l:str r2, [r0]        /* clear loop...                    */  
    7.     add r0, r0, #4  
    8.     cmp r0, r1  
    9.     ble clbss_l  


    三、第二阶段

    [cpp] view plain copy
    1. ldr pc, _start_armboot  
    2.   
    3. start_armboot:  .word start_armboot  
        跳转到 sdram 里的 start_armboot 函数执行。

  • 相关阅读:
    使用JMeter进行RESTful API测试
    DVWA reCAPTCHA key: Missing
    SQL注入之DVWA平台测试mysql注入
    DVWA之SQL注入演练(low)
    浅谈CSRF攻击方式
    WAMPSERVER-服务器离线无法切换到在线状态问题的解决
    SQL注入攻击和防御
    WebScarab安装
    Intellij idea 自动完成的变量名称首字母变为小写
    在IDEA中代码自动提示第一个字母大小写必须匹配的解决
  • 原文地址:https://www.cnblogs.com/alan666/p/8312542.html
Copyright © 2020-2023  润新知