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


    一.  uboot启动流程涉及函数

    之前文章简单分析了 uboot启动流程的开始,从链接脚本文件 u-boot.lds 中,我们已经知道了入口点是 arch/arm/lib/vectors.S 文件中的 _start函数。

    _start函数调用了 reset 函数,reset 函数内部:最终调用了 save_boot_params_ret 函数。

    save_boot_params_ret 函数:

    ①  将处理器设置为SVC模式,并且关闭FIQ和IRQ.

    ②  设置中断向量。

    ③  初始化CP15 (cpu_init_cp15),   调用了 cpu_init_crit 函数。

    其中, cpu_init_crit 函数 调用了函数 lowlevel_init函数。

    本文继续简单分析 lowlevel_init函数(即cpu_init_crit 函数 所调用的函数)做了什么?

    本文继上一篇文章的分析,地址如下:

    uboot启动流程涉及reset函数_凌肖战的博客-CSDN博客

    二.     lowlevel_init 函数详解

    lowlevel_init 函数在文件 arch/arm/cpu/armv7/lowlevel_init.S 中定义,内容如下:

    1. 18 ENTRY(lowlevel_init)
    2. 19 /*
    3. 20 * Setup a temporary stack. Global data is not available yet.
    4. 21 */
    5. 22 ldr sp, =CONFIG_SYS_INIT_SP_ADDR
    6. 23 bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
    7. 24 #ifdef CONFIG_SPL_DM
    8. 25 mov r9, #0
    9. 26 #else
    10. 27 /*
    11. 28 * Set up global data for boards that still need it. This will be
    12. 29 * removed soon.
    13. 30 */
    14. 31 #ifdef CONFIG_SPL_BUILD
    15. 32 ldr r9, =gdata
    16. 33 #else
    17. 34 sub sp, sp, #GD_SIZE
    18. 35 bic sp, sp, #7
    19. 36 mov r9, sp
    20. 37 #endif
    21. 38 #endif
    22. 39 /*
    23. 40 * Save the old lr(passed in ip) and the current lr to stack
    24. 41 */
    25. 42 push {ip, lr}
    26. 43
    27. 44 /*
    28. 45 * Call the very early init function. This should do only the
    29. 46 * absolute bare minimum to get started. It should not:
    30. 47 *
    31. 48 * - set up DRAM
    32. 49 * - use global_data
    33. 50 * - clear BSS
    34. 51 * - try to start a console
    35. 52 *
    36. 53 * For boards with SPL this should be empty since SPL can do all
    37. 54 * of this init in the SPL board_init_f() function which is
    38. 55 * called immediately after this.
    39. 56 */
    40. 57 bl s_init
    41. 58 pop {ip, pc}
    42. 59 ENDPROC(lowlevel_init)

    22 行设置 sp 指向 CONFIG_SYS_INIT_SP_ADDR CONFIG_SYS_INIT_SP_ADDR
    include/configs/mx6ullevk.h 文件中,在 mx6ullevk.h 中定义如下:

    1. 234 #define CONFIG_SYS_INIT_RAM_ADDR IRAM_BASE_ADDR
    2. 235 #define CONFIG_SYS_INIT_RAM_SIZE IRAM_SIZE
    3. 236
    4. 237 #define CONFIG_SYS_INIT_SP_OFFSET \
    5. 238 (CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE)
    6. 239 #define CONFIG_SYS_INIT_SP_ADDR \
    7. 240 (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)

    上面的宏 IRAM_BASE_ADDR IRAM_SIZE 在文件 arch/arm/include/asm/arch-mx6/imx-regs.h 中有定义,其实就是 IMX6UL/IM6ULL ocram 的首地址和大小,如下所示:
    1. 71 #define IRAM_BASE_ADDR 0x00900000
    2. ......
    3. 408 #if !(defined(CONFIG_MX6SX) || defined(CONFIG_MX6UL) || \
    4. 409 defined(CONFIG_MX6SLL) || defined(CONFIG_MX6SL))
    5. 410 #define IRAM_SIZE 0x00040000
    6. 411 #else
    7. 412 #define IRAM_SIZE 0x00020000
    8. 413 #endif

    如果 408 行的条件成立的话 IRAM_SIZE=0X40000 ,当定义了 CONFIG_MX6SX 、CONFIG_MX6U CONFIG_MX6SLL CONFIG_MX6SL 中的任意一个的话条件就不成立, .config文件 中定义了 CONFIG_MX6UL ,所以条件不成立, IRAM_SIZE=0X20000=128KB

    可以得到如下值:
    CONFIG_SYS_INIT_RAM_ADDR = IRAM_BASE_ADDR = 0x00900000
    CONFIG_SYS_INIT_RAM_SIZE = 0x00020000 =128KB

    还需要知道 GENERATED_GBL_DATA_SIZE 的值,在文件 include/generated/generic-asm-offsets.h 中有定义,如下:
    1. 9 #define GENERATED_GBL_DATA_SIZE 256
    2. 10 #define GENERATED_BD_INFO_SIZE 80
    3. 11 #define GD_SIZE 248

    可以看出,GENERATED_GBL_DATA_SIZE=256。
    综上所述, CONFIG_SYS_INIT_SP_ADDR 值如下:
    1. CONFIG_SYS_INIT_SP_OFFSET = 0x00020000256 = 0x1FF00
    2. CONFIG_SYS_INIT_SP_ADDR = 0x00900000 + 0X1FF00 = 0X0091FF00

    如下图所示,为 sp指针的值:

    此时 sp 指向 0X91FF00 ,这属于 IMX6UL/IMX6ULL 的内部 ram
    通过 lowlevel_init.S文件可以看出
    23 行对 sp 指针做 8 字节对齐处理!
    34 行, sp 指针减去 GD_SIZE GD_SIZE 同样在 generic-asm-offsets.h 中定了,大小为
    248
    35 行对 sp 8 字节对齐,此时 sp 的地址为 0X0091FF00-248=0X0091FE08 ,此时 sp ,如下:

    lowlevel_init.S 文件中的 lowlevel_init 函数:

    第 36 行将 sp 地址保存在 r9 寄存器中。
    42 行将 ip lr 压栈
    第 57 行调用 s_init 函数
    58 行,将第 36 行入栈的 ip lr 进行出栈,并将 lr 赋给 pc

    下一篇文章分析:

    lowlevel_init函数调用的函数:s_init 函数

    save_boot_params_ret函数调用的函数: _main

  • 相关阅读:
    MongoDB常用命令总结及安装介绍
    【c++】逆波兰表达式求值(详解)
    nginx实时流量拷贝ngx_http_mirror_module
    PMP备考大全:经典题库(敏捷管理第1期)
    在职阿里3年,一个27岁女软件测试工程师的心声
    万字详解 Google Play 上架应用标准包格式 AAB
    win11安装pytorch-gpu遇到的坑
    Linux系统 -目录结构与配网
    分享我做Dotnet9博客网站时积累的一些资料
    套餐内商品的排列顺序(字符串的排列),剑指offer,力扣
  • 原文地址:https://blog.csdn.net/wojiaxiaohuang2014/article/details/133420660