uboot之内核的启动

一、uboot和内核到底是什么?

    uboot的本质就是一个复杂点的裸机程序。

    操作系统内核在本质上也是一个裸机程序,和uboot、和其他裸机程序并没有本质区别。

    区别就是操作系统运行起来后在软件上分为内核层和应用层,分层后两层的权限是不同的,内存访问和设备上更加精细

    (内核可以随便访问各种硬件,而应用程序只能访问限制的硬件和内存地址)。

二、部署在SD卡中特定分区内

   1、 一个完整的软件+硬件的嵌入式系统,静止时(未上电时)bootloader、kernel、rootfs等必须的软件都以镜像的

    形式存储在启动介质中(x210中是iNand/SD卡);运行时都是在DDR中运行的,与存储介质无关。上面2个状态都是

    稳点状态,第3个状态是动态过程,即从静止态到运行态的过程,也就是启动过程。

    2、动态启动过程中就是一个从SD卡逐步搬迁DDR内存中,并且运行启动代码进行相关的硬件初始化和软件架构的建

    立,最终达到运行时稳定状态。

扫描二维码关注公众号,回复: 1103352 查看本文章

    3、静止时u-boot.bin zImage rootfs都在SD卡中,他们不可能随意存在SD卡的任意位置,因此需要对SD卡进行一个

     分区,然后将各种镜像各自存在各自的分区中,这样在启动过程中uboot、内核等就知道到哪里去找谁。(uboot和

     kernel中的分区表必须一致,同时和SD卡的实际使用的分区要一致)。

    4、内核的启动条件

        (1)、uboot在第一阶段中进行重定位时将第二阶段(整个uboot镜像)加载到DDR的0xc3e00000地址处,这个

        地址就是uboot的链接地址。

        (2)、内核也有类似要求,uboot启动内核时将内存SD卡读取放到DDR中(其实就是个重定位的过程),不能随

        意放置,必须放在内核的链接地址处,否则启动不起来。譬如我们使用的内核链接地址是0x30008000。

        (3)、uboot是无条件启动的,而内核启动需要uboot帮kernel重定位(从SD卡到DDR),uboot还要给内核提供

        启动参数。

    5、启动内核的步骤

        (1)、将内核镜像从启动介质中加载到DDR中。

        (2)、去DDR中启动内核镜像。

    6、uboot还支持远程启动

        (1)、内核镜像不烧录到开发板的SD卡中,而是放在主机的服务器中,然后需要启动时uboot通过网络从服务器

        中下载镜像到开发板的DDR中。

    7、zImage和uImage之间的区别连系

        (1)、uboot经过编译直接生成的elf格式的可执行程序是u-boot,这个程序类似于windows下的exe格式,在操

        作系统下是可以直接执行的。但是这种格式不能烧录,烧录下载的是u-boot.bin,这个东西就叫镜像(image)。

        (2)、linux内核经过编译后也会生成一个elf格式的可执行程序,叫vmlinux或vmlinuz,这个就是未加工的原版

        内核elf文件。嵌入式系统部署时并不是烧录这个,而是用交叉编译工具将这个东西加工成镜像格式,经过加工成

        烧录镜像的文件叫Image(制作时把78M精简成了7.5M)。

        (3)、原则上是可以直接烧录Image,但是linux作者觉得还是太大了所以对Image进行了压缩,并且在压缩后的

        文件前端加上了一些解压代码,构成了zImage。

        (4)、而uImage是由zImage加工得到的。这个过程是在zImage的头部加上64字节的头信息即可。

        (5)、原则上uboot启动时应该给他uImage格式的内核镜像,单实际上uboot也支持zImage。有些uboot支持

        zImage启动,有些不支持,但是所有uboot都支持uImage启动。

    8、zImage启动

        (1)、LINUX_ZIMAGE_MAGIC这个是一个定义的魔数,这个数等于0x016f2818,表示这个镜像是一个zImage。

        也就是说zImage格式的镜像中在头部的一个固定位置存放了这个数作为格式标记。如果我们拿到了一个image,去

        他的那个位置去取4字节判断它是否等于LINUX_ZIMAGE_MAGIC,则可以知道这个镜像是不是一个zImage。

    9、uImage启动

        (1)、  uImage方式是uboot本身发明的支持linux启动的镜像格式,但是后来这种方式被一种新的方式替代,

        这个新的方式就是设备树方式(在do_bootm方式中叫FIT),uImage的启动校验主要在boot_get_kernel函数中,

        主要任务就是校验uImage的头信息,并且得到真正的kernel的起始位置去启动。

    10、镜像的entrypoint

        (1)ep就是entrypoint的缩写,就是程序入口。一个镜像文件的起始执行部分不是在镜像的开头(镜像开头有n个字

        节的头信息),真正的镜像文件执行时第一句代码在镜像的中部某个字节处,相当于头是有一定的偏移量的。这个

        偏移量记录在头信息中。

        (2)一般执行一个镜像都是:第一步先读取头信息,然后在头信息的特定地址找MAGIC_NUM,由此来确定镜像

        种类;

        第二步对镜像进行校验;第三步再次读取头信息,由特定地址知道这个镜像的各种信息(镜像长度、镜像种类、

        入口地址);第四步就去entrypoint处开始执行镜像。

        (3)theKernel = (void (*)(int, int, uint))ep;将ep赋值给theKernel,则这个函数指向就指向了内存中加载的OS镜

        像的真正入口地址(就是操作系统的第一句执行的代码)。

    11、机器码的再次确定

        (1)uboot在启动内核时,机器码要传给内核。uboot传给内核的机器码是怎么确定的?第一顺序备选是环境变量

        machid,第二顺序备选是gd->bd->bi_arch_num(x210_sd.h中硬编码配置的)。

   12、tag方式传参

        (1)struct tag,tag是一个数据结构,在uboot和linux kernel中都有定义tag数据机构,而且定义是一样的。

        (2)tag_header和tag_xxx。tag_header中有这个tag的size和类型编码,kernel拿到一个tag后先分析tag_header

        得到tag的类型和大小,然后将tag中剩余部分当作一个tag_xxx来处理。

        (3)tag_start与tag_end。kernel接收到的传参是若干个tag构成的,这些tag由tag_start起始,到tag_end结束。

        (4)tag传参的方式是由linux kernel发明的,kernel定义了这种向我传参的方式,uboot只是实现了这种传参方式

        从而可以支持给kernel传参。

总结:第一步:将内核搬移到DDR中

第二步:校验内核格式、CRC等

第三步:准备传参

第四步:跳转执行内核

涉及到的主要函数是:do_boom和do_bootm_linux

uboot能启动的内核格式:zImage uImage fdt方式  

跳转与函数指针的方式运行内核

欢迎各位指出不足之处


猜你喜欢

转载自blog.csdn.net/qq_41003024/article/details/80396594