嵌入式系统学习(七)-bootloader修改实例

来源:互联网 发布:淘宝如何绑定支付宝 编辑:程序博客网 时间:2024/06/06 01:04

从 github 中下载 Nanopi2 的 uboot 源码后,从源代码根目录中找到 u-boot.lds 文件,可以看到以下内容:


以上片断可以分析出,整个 uboot 程序从 arch/arm/cpu/slsiap/s5p4418/start.o 开始执行,且执行的入口为 _stext。

打开 arch/arm/cpu/slsiap/s5p4418/start.S,在第 20 行找到入口:

入口的内容是用户异常向量表,根据第一个表项,可以找到复位向量入口 reset。该入口在同一文件的第76 行。

由于代码较长,这里仅对关键步骤进行分析。

* 将 CPU 设置为 SVC32 模式。

* 初始化 CP15 协处理器。

这里的初始化包括禁用一级的 I-Cache和 D-Cache。禁用 MMU。

* 在 91 行处进行跳转,进入 lowlevel_init 入口,开始板级特定的初始化。 lowlevel_init入口位于 arch/arm/cpu/slsiap/s5p4418/low_init.S 中。初始化内容包含获取 cpu id 等等。初始化完毕后,跳转回 start.S 的第 100 行继续执行。

接下来的步骤是确定运行环境,即 uboot目前是运行在 Flash 中还是在 DRAM中。如果是运行在 DRAM 中,则初始化 bss 段为 0,开启 mmu(开启的代码在arch/arm/cpu/slsiap/s5p4418/mmu_asm.S 和arch/arm/cpu/slsiap/s5p4418/mmu.c),重新初始化栈指针,并在第 140 行跳转 到board_init_f 入口执行。

board_init_f 入口在 commom/board_f.c,由于已经重新初始化栈指针,因 此 c 语言环境已经搭建好。board_init_f 则以 c 语言编写。函数返回时,返回 至 start.S 的第 142 行继续执行。初始化led,重新初始化串口,初始化堆,初 始化 mmc 通道,初始化环境变量,初始化控制台,初始化中断系统并启动它。

然后运行至第 156 行时,跳转至 board_init_r 入口。该入口在commom/board_r.c 中,亦以 c 语言编写。在这阶段中,uboot 识别 flash 空间长 度,初始化 led,重新初始化串口,初始化堆,初始化 mmc 通道,初始化环境变 量,初始化控制台,初始化中断系统并启动它。最后到 927 行运行run_main_loop(),最终调用 main_loop()。这个函数位于 commom/main.c 中。 以下就是 main_loop()的代码。

在这个函数里,最关键的一句是 autoboot_command(s); 这一个函数主要用 于延时启动内核。即延时 3 秒,若 3 秒内用户按下任意按键,则进入 uboot 的命 令行模式,否则就自动启动内核。进入 commom/autoboot.c 中的 autoboot_command(),如下图所示:

里面的 abortboot()函数就是延时中断启动系统的检测。如果在延时启动中 没 有 任 何 按 键 按 下 , 则 运 行 run_command_list 执 行 内 核 的 引 导 。 run_command_list()是一系列命令的解析过程。

解析时,调用过程如下:

*  commom/cmd_bootm.c 中的 do_bootm()

*  commom/bootm.c 中的 do_bootm_states()

*  commom/bootm_os.c 中的 boot_selected_os()

在 boot_selected_os()中,调用了一个函数,叫 boot_fn()。经过追踪, boot_fn()被定位到 arch/arm/lib/bootm.c 中的 do_bootm_linux()。

在这里有一个关键的函数 boot_jump_linux()。其实现如下图所示:


到这里可以清楚地看到,该函数为引导系统通过 announce_and_cleanup() 做了些初始化工作,最终通过调用 kernel_entry()来启动 linux 系统。到这里 为止,整个 uboot 就完成了所有工作,让出控制权。

上述的整个过程,都有特定的输出,如下图所示。



对 TF 卡烧写分区进行详细说明, 即 bootloader 地址,内核的地址以及文件系统的地址等。以烧写 Debian 系统为例,根据烧写脚本 fusing.sh 和 partmap.txt 可以看 出,在 TF 卡上,有以下的分区,每个分区各包含不同的内容:

分区起始地址

内容

0x0000_0000

MBR

0x0000_0200

NISH

0x0000_0400

2ndboot

0x0000_8000

NISH

0x0000_8200

UBoot

0x0010_0000

Boot 分区(包含内核)

0x0410_0000

根文件系统分区

由于 Boot 分区是 ext4 文件系统,而且内核是位于 Boot 分区上,因此内核并没有固定的烧写地址。

对在内存运 行地址进行详细说明,即 bootloader 地址,内核的地址以及文件系统的地 址等。根据 2ndboot 输出的内容可以猜测, 2ndboot 将 UBoot 复制到内存 0x42C0_0000 后继续执行。而在 Uboot 的代码中,可以查看到内核启动的环境变 量 bootargs。该变量指示了 UBoot 将内核 uImage.hdmi从 TF 卡的 ext4 文件系 统中复制到内存 0x4800_0000 的位置,而根文件系统则从 TF 卡的 ext4 文件系统 中复制到内存 0x4900_0000 的位置。最后从 0x4800_0000 开始启动内核。

内存起始地址

内容

0x42C0_0000

UBoot

0x4800_0000

内核:uImage.hdmi

0x4900_0000

文件系统:root.img

在 bootloader 启动显示中,添加个人信息实例:

(1)在 UBoot 目录下的 common/main.c 中找到 main_loop()函数,在该函数中找到 autoboot_command(s);一句。在该语句上面添加显示信息,如下图红框所示。

添加完毕后,重新编译 uboot,得到 uboot.bin。将 uboot.bin 烧写到 SD 卡中,并启动开发板,可以在启动过程中看到添加的信息,如下图红框所示。



0 0