参考内容点此跳转

本文重点在于分析 uboot 启动流程以及 uboot 自身的细节,比如栈空间的划分、如何设置 tag 、如何添加一个自定义命令等。但是不涉及基本的硬件驱动的分析,比如内存初始化、时钟初始化、mmu 、nandflash 等等这些详细细节不是我们的重点。

u-boot 版本:  uboot 1.1.6

使用的开发板: JZ2440V3

一、链接脚本

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

  1. ENTRY(_start)
  2. SECTIONS
  3. {
  4. . = 0x00000000;  //起始地址
  5. . = ALIGN(4);  //4字节对齐
  6. .text      :  //test指代码段,上面3行标识是不占用任何空间的
  7. {
  8. cpu/arm920t/start.o   (.text)  //这里把start.o放在第一位就表示把start.s编译时放到最开始,这就是为什么把uboot烧到起始地址上它肯定运行的是start.s
  9. *(.text)
  10. }
  11. . = ALIGN(4);  //前面的 “.” 代表当前值,是计算一个当前的值,是计算上面占用的整个空间,再加一个单元就表示它现在的位置
  12. .rodata : { *(.rodata) }
  13. . = ALIGN(4);
  14. .data : { *(.data) }
  15. . = ALIGN(4);
  16. .got : { *(.got) }
  17. . = .;
  18. __u_boot_cmd_start = .;
  19. .u_boot_cmd : { *(.u_boot_cmd) }
  20. __u_boot_cmd_end = .;
  21. . = ALIGN(4);
  22. __bss_start = .;
  23. .bss : { *(.bss) }
  24. _end = .;
  25. }

链接地址为 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、设置异常向量

  1. .globl _start  /*声明一个符号可被其它文件引用,相当于声明了一个全局变量,.globl与.global相同*/
  2. _start: b       reset  /* 复位,b是不带返回的跳转(bl是带返回的跳转),意思是无条件直接跳转到reset标号出执行程序*/
  3. ldr pc, _undefined_instruction  /* 未定义指令向量 ldr相当于mov操作*/
  4. ldr pc, _software_interrupt  /* 软件中断向量 */
  5. ldr pc, _prefetch_abort  /* 预取指令异常向量 */
  6. ldr pc, _data_abort  /* 数据操作异常向量 */
  7. ldr pc, _not_used  /* 未使用 */
  8. ldr pc, _irq  /* irq中断向量 */
  9. ldr pc, _fiq  /* fiq中断向量 */
  10. /* 中断向量表入口地址 */
  11. _undefined_instruction: .word undefined_instruction  /*就是在当前地址,即_undefined_instruction 处存放 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  //word伪操作用于分配一段字内存单元(分配的单元都是字对齐的),并用伪操作中的expr初始化
  17. _fiq:           .word fiq  /* now 16*4=64 */
  18. .balignl 16,0xdeadbeef

第一条 b reset ,决定了U-Boot启动后将自动跳转到标号“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、进入管理SVC模式

  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、关看门狗

  1. #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
  2. ldr     r0, =pWTCON
  3. mov     r1, #0x0
  4. str     r1, [r0]

4、屏蔽中断

  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、设置时钟

  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

  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 

  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 控制器

  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. /* everything is fine now */
  17. mov pc, lr
  18. .ltorg
  19. /* the literal pools origin */
  20. SMRDATA:
  21. .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
  22. .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
  23. .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
  24. .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
  25. .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
  26. .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
  27. .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
  28. .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
  29. .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
  30. .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
  31. .word 0x32
  32. .word 0x30
  33. .word 0x30

写裸机代码的入门操作,初始化 sdram 寄存器。

9、代码重定位

  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. ldr r2, _armboot_start
  7. ldr r3, _bss_start
  8. sub r2, r3, r2      /* r2 <- size of armboot            */
  9. add r2, r0, r2      /* r2 <- source end address         */
  10. copy_loop:
  11. ldmia   r0!, {r3-r10}       /* copy from source address [r0]    */
  12. stmia   r1!, {r3-r10}       /* copy to   target address [r1]    */
  13. cmp r0, r2          /* until source end addreee [r2]    */
  14. ble copy_loop

adr 位置无关码,获取_start实际当前位于的地方,_TEXT_BASE 为 0x33f80000 ,这里判断的是代码是否直接运行在 sdram 里了,如果是就不需要重定位了。

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

33f80048 <_bss_start>:
      33f80048:    33fb064c

0x33fb064c - 0x33f80000 = 193K ,什么意思呢?(整个 uboot 除了 bss 段) > 4k,如果是 nandflash 启动的话,SRAM只会复制NAND Flash存储器的前4K字节过去执行,我们需要复制的代码为193K,显然需要初始化 nandflash 并从里面读取 uboot 到内核,而我们到这里还没有初始化NandFlash,,从而得到默认 uboot是从norflash启动,不支持 nandflash 启动。

10、设置栈

  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. clear_bss:
  10. ldr r0, _bss_start      /* find start of bss segment        */
  11. ldr r1, _bss_end        /* stop here                        */
  12. mov     r2, #0x00000000     /* clear                            */
  13. clbss_l:str r2, [r0]        /* clear loop...                    */
  14. add r0, r0, #4
  15. cmp r0, r1
  16. ble clbss_l

TEXT_BASE = 0x33F80000 其它的宏在 smdk2410.h (include\configs):

  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 */
  1. 0x34000000:
  2. (512K)               存放 uboot
  3. 0x33F80000:         TEXT_BASE
  4. (64K+128K == 192K)   malloc区
  5. 0x33F50000:
  6. (128bytes)           global data区,后边会提到主要放的gd、bd全局结构体
  7. 0x33F4FF80:
  8. (8K)                 IRQ+FIQ的栈
  9. 0x33F4DF80:
  10. (12byte)             abort-stack,栈溢出
  11. 0x33F4DF74:          sp

11、清 BSS 段

  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. clbss_l:str r2, [r0]        /* clear loop...                    */
  6. add r0, r0, #4
  7. cmp r0, r1
  8. ble clbss_l

三、第二阶段

  1. ldr pc, _start_armboot
  2. start_armboot:  .word start_armboot

跳转到 sdram 里的 start_armboot 函数执行。

总结:


(三) u-boot 启动分析_第一阶段相关推荐

  1. STM32三种BOOT启动模式详解(全网最全)

    一.三种boot启动模式 一般来说就是指我们下好程序后,重启芯片时,SYSCLK的第4个上升沿,BOOT引脚的值将被锁存.用户可以通过设置BOOT1和BOOT0引脚的状态,来选择在复位后的启动模式. ...

  2. 探究 STM32 的三种 BOOT(启动) 模式并实例验证

    目录 一.什么是 Boot 模式 二.实例验证 三.总结 四.参考资料 说明 STM32 的三种 Boot 模式的差异,并在之前第11-12周"C语言各种变量的存储地址"作业代码基 ...

  3. python开发基础戴歆第四章_第一阶段:Python开发基础 day04 课后练习

    第一阶段:Python开发基础 day04 课后作业 1.简述python的五大数据类型的作用.定义方式.使用方法 数字类型 字符串类型 列表 字典 布尔型 答:数字类型分为整型(int)和浮点型(f ...

  4. java第一阶段知识_第一阶段 Java语言(下)

    本课程是Android入门教程之Java核心技术阶段,是Java开发高级部分,安卓开发中的基础知识,讲解以下内容: (一)反射与内省 讲解了什么是反射,反射在应用中的作用,相关反射的API,如Clas ...

  5. python开发基本流程_第一阶段:Python开发基础 day06  Python基础语法入门--流程控制(二)...

    一.上节课内容回顾 三种格式化输出 占位符 format格式化 f-String格式化 基本运算符 算术运算符 比较运算符 逻辑运算符 赋值运算符 身份运算符 运算符的优先级 流程控制之if判断 单分 ...

  6. Android 源码分析(三) Service 启动分析

    //android-8.0.0_r1\frameworks\base\core\java\android\content\Context.java/** * startService是Context的 ...

  7. 商业分析_第一篇 价格弹性

    目录 价格弹性 1. 需求价格弹性 1.1 概念 1.2 Ed的性质 1.3 Ed的变动范围 1.3 影响产品需求弹性大小的因素: 1.4 需求价格弹性的政策含义 1.5 弧弹性和点弹性 1.6 弹性 ...

  8. UBOOT源码分析的第一阶段start.S分析(3)

    之前我们更新到了lowlevel_init代码处了. 看到lowlever_init这里的代码还是有点多哈. 但是看英语的注释我们也能看懂每一部分的代码到底是干什么的. 第42行 push {lr}, ...

  9. uboot源码分析(基于S5PV210)之启动第一阶段

    目录 一.start.S引入 1.u-boot.lds中找到start.S入口 2.SourceInsight中如何找到文件 3.SI中找文件技巧 二.start.S解析 1.不简单的头文件包含 2. ...

最新文章

  1. python观察日志(part24)--列表和numpy数组扁平化
  2. 【转】4.1触碰jQuery:AJAX异步详解
  3. java矩阵类_java矩阵类,矩阵的乘法
  4. Android多个音频源采集,android音频采集
  5. AnySDK项目实战教程
  6. 理解 TCP(二):报文结构 1
  7. 【C++】指针与引用的区别
  8. SQL SERVER 和EXCEL的数据导入导出
  9. 数据--第32课 -二叉树的定义
  10. ajax跨域例子,ajax跨域例子
  11. 三菱FX Q FX5U PLC 程序加密,使用ST结构化文
  12. 为什么四个字节的float表示的范围比八个字节的long要广
  13. 侠客行,我是谁,谁是我
  14. 求偏微分方程的数值解(有限差分法、配置法、Galerkin方法)
  15. 双稳态电路的两个稳定状态是什么_555定时器原理知多少?四种应用电路分享
  16. a-upload 上传文件到阿里oss
  17. 渠道、数据、技术,谁才是网络信贷市场的决胜因素?
  18. 通过YUV空间调节图像的色度和饱和度
  19. 面向异构众核超级计算机的大规模稀疏计算性能优化研究
  20. Glide(二)Glide的with,load,into

热门文章

  1. 1.3 OC与OD门(硬件基础系列)
  2. PVE7更新AQC107网卡驱动,解决奇葩问题。
  3. 海康摄像头二次开发详解,包含海康摄像头登录、海康云台控制、视频下载等功能
  4. Shiro登录的使用以及原理(一)
  5. PARI/GP 语言:从入门到实现大素数判定与大数分解
  6. 岁月温柔-21 妈妈转到省医院第2天
  7. 聊聊职场 - 个人发展
  8. 计算机网络实验三——IP网络规划与路由设计
  9. 2018计算机系统结构全国卷,2018年10月高等教育自学考试全国统一命题考试02325计算机系统结构试卷及答案.doc...
  10. digest 词根 gest