uboot引导linux启动

uboot引导linux启动

uboot的使命在于启动操作系统,在uboot启动流程文章中,我们已经对uboot从复位到进入命令行模式的过程进行了一个梳理(uboot启动分析-CSDN博客),下面,我们主要讲解uboot启动linux操作系统的流程。

uboot启动linux的相关命令

在uboot命令行模式中,我们执行bootz命令即可启动linux,或者倒计时结束时会自动执行bootcmd中的命令,其实也是执行了bootz命令。bootargs用于设置控制台设备,根文件系统等信息,最终会传递给linux内核。uboot中可配置的信息如下:

bootz【zImage地址】 【initrd[:size]】 【设备树地址】
​
bootargs=console=ttymxc0,115200 root=/dev/nfs rw nfsroot=192.168.139.100:/home/yj/linux/nfs/rootfs,proto=tcp,nfsvers=3 ip=192.168.139.50:192.168.139.100:192.168.1.1:255.255.0.0::eth0:off
​
bootcmd=tftp 80800000 zImage; tftp 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000

总括

uboot启动linux主要由以下三个部分组成:处理bootargs传参、传入设备树地址参数、调用linux入口

  • bootargs是uboot中的一个环境变量,用于记录传递给linux的参数。uboot在调用linux入口之前会在设备树的/chosen节点下创建一个属性bootargs,这样就可以通过设备树将bootargs的内容传递给linux。而linux在启动的时候也会去/chosen下寻找该属性,并进行相关配置。

  • 设备树的地址是在bootz命令中指定的参数,这样uboot就知道这个地址了,然后将这个地址作为第三个参数调用linux入口。因为linux在起始位置出留出了r0,r1,r2三个ABI给uboot,见内核注释如下:

    ; Uboot - kernel ABI
            ;    r0 = [0] No uboot interaction, [1] cmdline in r2, [2] DTB in r2    【标识r2参数的值】
            ;    r1 = magic number (board identity, unused as of now                【magic id,有设备树的情况不用】
            ;    r2 = pointer to uboot provided cmdline or external DTB in mem      【设备树地址】
            ; These are handled later in setup_arch()
  • 调用linux入口,即可转到linux中运行,uboot的使命就结束了。

其中,不论是bootargs还是r2的传参形式,都属于linux留有这样的一个接口,而uboot利用这个接口进行参数的传递。

详解

uboot启动linux的过程相对来说还是比较简单的,以下解析可能并不完整,但对于目前来说所要解释的部分都有提及。

uboot启动linux的两种方式

uboot中有两种方法启动linux,一种是倒计时结束,自动启动,执行bootcmd中的命令列表,可以看到,是执行了bootz;另一种进入命令行模式,使用bootz命令。其实两者都是使用bootz命令,bootz命令最终会执行其回调函数do_bootz。下面是两种方式的代码追踪:

uboot中命令的体现是struct cmd_tbl_a结构体,其中保存了该命令的名字,回调函数等信息。定义一个命令可以使用uboot实现的特定宏,传入名字回调函数等信息,它就会在某个特殊的段里定义一个struct cmd_tbl_a结构,表示该命令。

命令的执行过程主要就是根据命令名在特殊段中寻找该命令,得到该命令的结构体信息,之后调用该命令。

do_bootz

上文说到,执行bootz命令会执行do_bootz函数,do_bootz函数就是uboot启动linux的函数实现。首先看一下整个流程的图解:

这一部分是重点。可以看到,我们先是将zImage,dtb设备树镜像加载到内存指定位置,之后调用bootz命令,传入其内存地址。其实uboot中有一系列boot启动命令例如bootz、bootm、boot等,适用于不同情况,例如bootz是用于加载zImage类型的镜像的,可能在加载linux前会按照zImage格式读取头部信息做一些校验等;bootm用于启动uImage镜像等。可以看到,bootz命令后面其实也是执行的bootm的相关函数。

images

在bootz中,有一个bootm_headers_t结构体类型的全局变量images,记录了boot启动时的一些重要的全局变量信息,比如os镜像信息,ep为镜像开始地址,ft_addr为设备树起始地址等;另外还define了一些阶段,用于在程序中根据state阶段来执行不同的启动部分。images变量贯穿整个uboot启动linux的过程,很重要。

bootz_start

首先执行bootz_start开始引导,其中做一些初始化校验以及其他images的获取。bootz_start先清空images变量,然后设置images->ep为zImages镜像地址,之后调用bootz_setup函数获取镜像的zImages头,以做镜像的magic校验和获取镜像的大小。最后,会调用bootm_find_images函数查找其他的镜像,比如ramdisk以及设备树镜像,将相关信息保存在images全局变量中。

在bootz_start函数结束后,还会关中断(不知是否是linux镜像对启动的要求),以及images.os.os = IH_OS_LINUX确定引导系统为linux。之后便会调用do_bootm_states来执行inux启动的各个部分。

do_bootm_states

这里调用该函数使用了阶段BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO。在该函数中,首先根据os类型寻找os对应的启动函数,linux的启动函数是do_bootm_linux,之后的很多部分都是在该函数中做的。在do_bootm_linux中的BOOTM_STATE_OS_PREP阶段会将bootargs环境变量添加到设备树的chosen节点中作为一个属性BOOTM_STATE_OS_GO阶段会调用函数boot_jump_linux来跳转到linux中运行,主要是会传入r0,r1,r2三个参数,r2为设备树s地址,来调用(void (*)(int, int, uint))images->ep函数。到这里,就进入linux里了,uboot引导linux启动结束。

  • 25
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值