• uboot启动流程涉及reset汇编函数


    一.   uboot启动流程中函数

    之前了解了uboot链接脚本文件 u-boot.lds。

    从 u-boot.lds 中我们已经知道了入口点是 arch/arm/lib/vectors.S 文件中的 _start

    本文了解 一下,uboot启动过程中涉及的 reset 函数。本文继上一篇文章学习,地址如下:

    uboot启动流程-uboot链接脚本u-boot.lds_凌肖战的博客-CSDN博客

    二.   reset 函数源码详解

    u-boot.lds 中,我们已经知道了入口点是 arch/arm/lib/vectors.S 文件中的 _start,代码如下: 

    1. 38 /*
    2. 39 *************************************************************
    3. 40 *
    4. 41 * Exception vectors as described in ARM reference manuals
    5. 42 *
    6. 43 * Uses indirect branch to allow reaching handlers anywhere in
    7. 44 * memory.
    8. 45 **************************************************************
    9. 46 */
    10. 47
    11. 48 _start:
    12. 49
    13. 50 #ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
    14. 51 .word CONFIG_SYS_DV_NOR_BOOT_CFG
    15. 52 #endif
    16. 53
    17. 54 b reset
    18. 55 ldr pc, _undefined_instruction
    19. 56 ldr pc, _software_interrupt
    20. 57 ldr pc, _prefetch_abort
    21. 58 ldr pc, _data_abort
    22. 59 ldr pc, _not_used
    23. 60 ldr pc, _irq
    24. 61 ldr pc, _fiq

    48 _start 开始的是中断向量表,其中 54~61 行就是中断向量表,和我们裸机例程里面一样。

    1.   start.S 文件中的 reset 函数

    第 54 行跳转到 reset 函数里面, reset 函数在 arch/arm/cpu/armv7/start.S 里面,代码如下:
    1. 32 .globl reset
    2. 33 .globl save_boot_params_ret
    3. 34
    4. 35 reset:
    5. 36 /* Allow the board to save important registers */
    6. 37 b save_boot_params

    start.S 文件的第 35 行就是 reset 函数。

    37 行从 reset 函数跳转到了 save_boot_params 函数,而 save_boot_params 函数同样定义start.S 里面,定义如下:

    100      ENTRY ( save_boot_params )
    101       b save_boot_params_ret @ back to my caller

    2.   start.S文件中的save_boot_params_ret 函数

    save_boot_params 函数也是只有一句跳转语句,跳转到 save_boot_params_ret 函数,
    save_boot_params_ret 函数代码如下:
    1. 38 save_boot_params_ret:
    2. 39 /*
    3. 40 * disable interrupts (FIQ and IRQ), also set the cpu to SVC32
    4. 41 * mode, except if in HYP mode already
    5. 42 */
    6. 43 mrs r0, cpsr
    7. 44 and r1, r0, #0x1f @ mask mode bits
    8. 45 teq r1, #0x1a @ test for HYP mode
    9. 46 bicne r0, r0, #0x1f @ clear all mode bits
    10. 47 orrne r0, r0, #0x13 @ set SVC mode
    11. 48 orr r0, r0, #0xc0 @ disable FIQ and IRQ
    12. 49 msr cpsr,r0

    save_boot_params_ret 函数中,第43行~49行,将处理器设置为SVC模式,并且关闭FIQ和IRQ。

    继续分析 start.S 下面的代码:

    1. 56 #if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
    2. 57 /* Set V=0 in CP15 SCTLR register - for VBAR to point to vector */
    3. 58 mrc p15, 0, r0, c1, c0, 0 @ Read CP15 SCTLR Register
    4. 59 bic r0, #CR_V @ V = 0
    5. 60 mcr p15, 0, r0, c1, c0, 0 @ Write CP15 SCTLR Register
    6. 61
    7. 62 /* Set vector address in CP15 VBAR register */
    8. 63 ldr r0, =_start
    9. 64 mcr p15, 0, r0, c12, c0, 0 @Set VBAR
    10. 65 #endif

    56 行,如果没有定义 CONFIG_OMAP44XX CONFIG_SPL_BUILD 的话条件成立,此处条件成立。
    58 行读取 CP15 c1 寄存器的值到 r0 寄存器中,根据 17.1.4 小节可知,这里是读取 SCTLR 寄存器的值。

    59 行,CR_V arch/arm/include/asm/system.h 中有如下所示定义:

    #define CR_V (1 << 13) /* Vectors relocated to 0xffff0000 */

    因此,第 59 行的目的就是清除 SCTLR 寄存器中的 bit13 SCTLR 寄存器结构 如下:

    可以看出, bit13 V 位,此位是向量表控制位,当为 0 的时候向量表基地址为 0X00000000 ,软件可以重定位向量表。为 1 的时候向量表基地址为 0XFFFF0000 ,软件不能 重定位向量表。这里将 V 清零,目的就是为了接下来的向量表重定位。

    60 行将 r0 寄存器的值重写写入到寄存器 SCTLR 中。

    63 行设置 r0 寄存器的值为 _start _start 就是整个 uboot 的入口地址,其值为 0X87800000 相当于 uboot 的起始地址,因此 0x87800000 也是向量表的起始地址。
    64 行将 r0 寄存器的值 ( 向量表值 ) 写入到 CP15 c12 寄存器中,也就是 VBAR 寄存器。
    因此,第 58~64 行就是设置向量表重定位的。

    继续分析 start.S 下面的代码:

    1. 67 /* the mask ROM code should have PLL and others stable */
    2. 68 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
    3. 69 bl cpu_init_cp15
    4. 70 bl cpu_init_crit
    5. 71 #endif
    6. 72
    7. 73 bl _main
    68 行如果没有定义 CONFIG_SKIP_LOWLEVEL_INIT 的话条件成立。我们没有定义
    CONFIG_SKIP_LOWLEVEL_INIT ,因此条件成立,执行下面的语句。
    68 行~ 73行的内容比较简单,就是分别调用函数 cpu_init_cp15 cpu_init_crit _main
    函数 cpu_init_cp15 用来设置 CP15 相关的内容,比如关闭 MMU 啥的,此函数同样在 start.S
    文件中定义的。可以自行查看, 函数 cpu_init_cp15 都是一些和 CP15 有关的内容,我们不用关心,有兴趣的可以详细的看 一下。

    函数 cpu_init_crit 也在是定义在 start.S 文件中,函数内容如下:

    1. 268 ENTRY(cpu_init_crit)
    2. 269 /*
    3. 270 * Jump to board specific initialization...
    4. 271 * The Mask ROM will have already initialized
    5. 272 * basic memory. Go here to bump up clock rate and handle
    6. 273 * wake up conditions.
    7. 274 */
    8. 275 b lowlevel_init @ go setup pll,mux,memory
    9. 276 ENDPROC(cpu_init_crit)
    可以看出函数 cpu_init_crit 内部仅仅是调用了函数 lowlevel_init ,接下来就是详细的分析一
    lowlevel_init _main 这两个函数。

  • 相关阅读:
    OpenShift 4 - 从 FreeIPA/RHIdM 向 RHSSO 同步用户和组
    2327. 知道秘密的人数;1722. 执行交换操作后的最小汉明距离;2537. 统计好子数组的数目
    数商云SCM供应链协同系统:招标功能亮点|构建数字化采购体系降低汽车零部件成本
    【Leetcode】二分查找合集
    【redis-02】redis的五种数据类型和对应的操作方法,补充RedisUtil模板
    Linux 基金会年度报告——没有人能离开 Linux 支持环境;树莓派翻新版将创建“新的”分支系统;AWS 发生中断,导致业务交付出现问题 | 开源日报
    【Web前端】CSS-定位详解
    【Java面试】来讲一讲你对String的理解
    设计模式之结构型模式
    【python】将python脚本打包成可执行的.exe文件 推荐使用auto-py-to-exe
  • 原文地址:https://blog.csdn.net/wojiaxiaohuang2014/article/details/133420474