第一、二期衔接——5.3 u-boot分析与使用—源码分析

u-boot分析与使用—源码分析


一、前言

在linux系统下,执行makeu-boot进行编译时,输出以下信息:
在这里插入图片描述
可以看到,除了关注脚本文件,也要关注cpu/arm920t/start.o文件
通过前面的分析可知,u-boot的主要目的如下:

  1. 从FLASH读出内核
  2. 启动内核

抱着这个目的,我们cpu/arm920t/start.o文件入手进行分析

二、第一阶段

这个阶段分析的是cpu/arm920t/start.o文件中的汇编代码实现的功能
展示的代码并不是完整的代码,是根据前言中的目的来进行分析与展示

1、设置CPU为管理模式

可以看到汇编文件一开始会跳到reset:执行
在这里插入图片描述

2、关看门狗

在这里插入图片描述

3、关中断

在这里插入图片描述

4、设置时钟

在这里插入图片描述

5、根据情况判断是否初始化SDARM

  1. 比较r0+_start的值与_TEXT_BASE的值不相等则跳去执行cpu_init_crit
  2. cpu_init_crit进行:关闭flush、清除caches、关闭MMU、跳去执行lowlevel_init
  3. lowlevel_init,对SDRAM进行相关初始化
    在这里插入图片描述

6、设置栈(只有设置栈之后才可以调用C函数)

在这里插入图片描述

7、根据情况判断是否提前清bss段

  1. 比较r0+_start的值与_TEXT_BASE的值不相等则跳去执行clean_bss
  2. clean_bss进行:清除操作

就算这里不清除,后面汇编代码也会清除。
在这里插入图片描述

8、重定位

  1. CopyCode2Ram中判断为NOR启动还是NAND启动
  2. 从NOR启动,copy工作简单
  3. 从NAND启动先初始化NAND FLASH,后进行copy

在这里插入图片描述

9、调用start_armboot(u-boot的第二阶段)

在这里插入图片描述

10、总结

到此为止,u-boot的第一阶段的分析已经结束。
总体的流程如下:

  1. 设置为管理模式
  2. 关看门狗
  3. 关中断
  4. 设置时钟
  5. 根据情况判断是否初始化SDARM
  6. 设置栈(只有设置栈之后才可以调用C函数)
  7. 根据情况判断是否提前清bss段
  8. 重定位
  9. 调用start_armboot(u-boot的第二阶段)
  • 其中1~8步骤的设置称为硬件相关的设置,主要通过汇编代码完成
  • 9步骤后的设置才是启动内核的代码实现,比较复杂,需要通过C语言实现

三、第二阶段分析

这里抱着启动内核的目标,分析start_armboot()函数,所在的位置为u-boot-1.1.6/lib_arm/board.c

1、进行一系列的初始化工作

  1. 通过如下函数进行对应的初始化如CPU初始化、板载资源的初始化、中断初始化等等
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
		if ((*init_fnc_ptr)() != 0) {
			hang ();
		}
	}
  1. 分析板载资源初始化
    2_1. 进行把对应IO口拉高
    2_2. 根据判断结果设置机器ID
    2_3. 设置启动参数
    在这里插入图片描述

2、初始化NOR FLASH

在这里插入图片描述

3、在内存中分配堆区

在这里插入图片描述

4、初始化NAND FLASH

在这里插入图片描述

5、设置环境变量

在这里插入图片描述

6、进入到main_lopp()死循环过程

运行到这个函数这里,就可以
在这里插入图片描述

6.1 资源的加载与版本号的设置

在这里插入图片描述

6.2 设置超时时间并打印一些信息

在这里插入图片描述

6.3 获取环境变量bootcmd,以便后面内核的启动

这个参数当我们启动bootloader时,执行print指令输出的信息有它的显示,这个参数与内核的启动有关,后面会进行介绍。
在这里插入图片描述
在这里插入图片描述

6.4 在超时时间内判断键盘是否有输入,无的话

如果此时键盘无输入,则会与如下信息:最明显的就是打印"Booting Linux ...\n"

  • 实际运行bootlloader的界面
    在这里插入图片描述

  • 此时会运行run_command(s, 0),根据上面的到的**bootcmd环境变量来启动内核**
    如何启动我这里只说结论,具体的分析过程可以看韦老师的分析博客【Uboot到底如何启动内核】

    1. nand read.jffs2 0x30007FC0 kernel等价于:nand read.jffs20x30007FC0 0x00060000 0x00200000
    1. bootm 0x30007FC0 关键函数do_bootm(),具体做了如下:读取头部,将内核移动到加载地址,启动内核
      在这里插入图片描述

6.5 在超时时间内判断键盘是否有输入,有的话,此时如果想启动内核的话,需要通过输入命令实现

6.5.1 进入菜单 run_command("menu", 0);
  • 实际运行的显示
    在这里插入图片描述
    在这里插入图片描述
6.5.2 等待此时键盘输入的命令,若按下’q’
  • 如果此时按下的是’q’,则程序会卡死在这个界面,并且等待命令的输入:
    在这里插入图片描述
    在这里插入图片描述

7、总结

第二阶段的作用大致如下:

  1. 进行CPU、中断、设置启动参数等初始化
  2. 初始化NOR FLASH、NAND FLASH,以便后面代码的重定位
  3. 设置好环境变量
  4. 进入bootloader启动界面,根据超时时间进行对应操作
    4.1 超时时间内键盘不输入过了超时时间则启动内核
    4.2 超时时间内键盘输入进入菜单界面,根据命令进行相关操作
    其中,在4.1和4.2中都有执行了相同的函数run_command(),下面来分析它。

8、分析run_command()

8.1 处理多条命令情况

在这里插入图片描述

8.2 拆分命令

如果此时命令为md.w 0则拆分后结果如下:
在这里插入图片描述

8.3 分析find_cmd()

这个函数的作用是对拆分后得到的命令进行匹配
在这里插入图片描述

8.4 分析cmd_tbl_s结构体

  • 原型如下:在这里插入图片描述
  • 在链接脚本中有如下段.u_boot_cmd : { *(.u_boot_cmd) }
    通过搜索.u_boot_cmd,并进行以下关键词搜索得到如下结果:
    在这里插入图片描述
  • cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}进行拆分得到:
    在这里插入图片描述

四、总结

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章