背景

参考文章
1. 《u-boot FIT image介绍》
2. 《uboot启动kernel篇(一)——Legacy-uImage & FIT-uImage》

一、先谈谈uboot

uboot 是嵌入式领域中用到的操作系统内核引导工具。
因为嵌入式发展相对pc 领域要慢一点。所以我一般会把uboot当成是一个落后一点迷你一点的grub。(描述不是很准确,勿喷)

二、比较一下 Image 、zImage 、 Legacy uImage 和 FIT uImage 的区别

  1. 内核编译(make)之后会生成两个文件,一个Image,一个zImage,其中Image为内核映像文件,而zImage为内核的一种映像压缩文件,Image大约为4M,而zImage不到2M。



  2. Legacy uImage是 uboot 专用的映像文件。它是在zImage之前加上一个长度为 64 字节的“头”,说明这个内核的版本、加载位置、生成时间、大小等信息。从 0x40 (也就是第64位) 之后与zImage是一样的。

  3. FIT uImage 是在 Legacy uImage的基础上,为了满足Linux Flattened Device Tree(FDT)的标准,而重新改进和定义出来的一种映像文件格式。(下面再讲 FDT)



三、为什么会出现 Legacy uImage ,然后又出现 FIT uImage ?

  1. 最开始出现的是 Image,就一个普通的内核镜像。

  2. 然后为了节省空间,有了 zImage,进行了压缩可以节省空间。

  3. 至此,uboot 启动 一个Image或者 zImage,还必须要给它传递一些参数。



    • 镜像文件的类型,如kernel image、dtb文件、ramdisk image等等?
    • 镜像文件需要放在memory的哪个位置(加载地址)?
    • 镜像文件需要从memory哪个位置开始执行(执行地址)?
    • 镜像文件是否有压缩?
    • 镜像文件是否有一些完整性校验的信息(如CRC)?
  4. 这种方式的不足就在于,镜像本身没有带有这些参数的,用工具制作完镜像后,还需要另外再向uboot提供这些参数,才能正常启动(就是比较麻烦)。

  5. 如果可以把这些参数,在制作镜像的时候就一起弄到镜像里面,然后uboot 一读取镜像,就马上可以知道这些参数了。不需要在制作好镜像之后再另外告诉 uboot这些参数。这种带有以上参数的镜像格式就是 Legacy uImage。



  6. 最后一个 FIT uImage ,跟Linux Flattened Device Tree(FDT)有点关系。我直接贴一下其它文章吧。(大概意思就是说,当时arm linux的内核代码写得不太好,需要把一些和arm 硬件相关的内容,挪到Device Tree那里,硬件的细节可以直接透过它传递给Linux,而不再需要在kernel中进行大量的冗余编码。)

    Linus Torvalds在2011年3月17日的ARM Linux邮件列表宣称“this whole ARM thing is a f*cking pain in the ass”,引发ARM Linux社区的地震,随后ARM社区进行了一系列的重大修正。在过去的ARM Linux中,arch/arm/plat-xxx和arch/arm/mach-xxx中充斥着大量的垃圾代码,相当多数的代码只是在描述板级细节,而这些板级细节对于内核来讲,不过是垃圾,如板上的platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data。读者有兴趣可以统计下常见的s3c2410、s3c6410等板级目录,代码量在数万行。
    社区必须改变这种局面,于是PowerPC等其他体系架构下已经使用的Flattened Device Tree(FDT)进入ARM社区的视野。Device Tree是一种描述硬件的数据结构,它起源于 OpenFirmware (OF)。在Linux 2.6中,ARM架构的板极硬件细节过多地被硬编码在arch/arm/plat-xxx和arch/arm/mach-xxx,采用Device Tree后,许多硬件的细节可以直接透过它传递给Linux,而不再需要在kernel中进行大量的冗余编码。
    Device Tree由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子结点。所谓属性,其实就是成对出现的name和value。在Device Tree中,可描述的信息包括(原先这些信息大多被hard code到kernel中):
    CPU的数量和类别
    内存基地址和大小
    总线和桥
    外设连接
    中断控制器和中断使用情况
    GPIO控制器和GPIO使用情况
    Clock控制器和Clock使用情况
    它基本上就是画一棵电路板上CPU、总线、设备组成的树,Bootloader会将这棵树传递给内核,然后内核可以识别这棵树,并根据它展开出Linux内核中的platform_device、i2c_client、spi_device等设备,而这些设备用到的内存、IRQ等资源,也被传递给了内核,内核会将这些资源绑定给展开的相应的设备。

  7. 就是因为上面那个因素,所以要把Legacy uImage 改进一下,变成 fit img (Flattened uImage Tree)。

四、Legacy uImage 是怎么把信息弄进镜像里的

直接上段代码吧。

mkimage -A arm -O linux -C none -T kernel -a 0x20008000 -e 0x20008040 -n Linux_Image -d zImage uImage

各个参数意义如下
Usage: mkimage -l image
          -l ==> list image header information
       mkimage [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image
          -A ==> set architecture to 'arch'  // 体系
          -O ==> set operating system to 'os' // 操作系统
          -T ==> set image type to 'type' // 镜像类型
          -C ==> set compression type 'comp' // 压缩类型
          -a ==> set load address to 'addr' (hex) // 加载地址
          -e ==> set entry point to 'ep' (hex) // 入口地址
          -n ==> set image name to 'name' // 镜像名称,注意不能超过32B
          -d ==> use image data from 'datafile' // 输入文件
          -x ==> set XIP (execute in place)
  1. 从上面命令可以基本看到,参数是通过制作镜像的工具 mkimage 传入Legacy uImage的。

  2. mkimage 的可选参数基本描述了,有哪些信息是需要和可以写入到 Legacy uImage的。

五、fit img (Flattened uImage Tree) 的原理和生成

  1. 上面说了,fit img的出现,是为了跟上Linux Flattened Device Tree(FDT)的步伐而进行的一种改进。

  2. its文件( image source file)。
    有点类似于平时我们用的ubuntu 和centos上面的 grub.cfg配置文件,主要是配置一些启动参数的。(在制作Legacy uImage的时候,我们是直接传参数给mkimage,现在是把参数先写入 its文件而已)

  3. image data file(也就是不包含启动参数的内核镜像了)

  4. itb文件。
    这个就是最后生成的镜像文件了,是通过打包工具,把mkimage 把 its文件和linux kernel 镜像打包而成的。也就是uboot可以直接对其进行识别和解析的FIT uImage。

  5. 贴一个 its的例子吧。

{
    description = "U-Boot uImage source file for X project";
    #address-cells = <1>;

    images {
        kernel@tiny210 {
            description = "Unify(TODO) Linux kernel for project-x";
            data = /incbin/("/home/hlos/code/xys/temp/project-x/build/out/linux/arch/arm/boot/zImage");
            type = "kernel";
            arch = "arm";
            os = "linux";
            compression = "none";
            load = <0x20008000>;
            entry = <0x20008000>;
        };
        fdt@tiny210 {
            description = "Flattened Device Tree blob for project-x";
            data = /incbin/("/home/hlos/code/xys/temp/project-x/build/out/linux/arch/arm/boot/dts/s5pv210-tiny210.dtb");
            type = "flat_dt";
            arch = "arm";
            compression = "none";
        };
        ramdisk@tiny210 {
            description = "Ramdisk for project-x";
            data = /incbin/("/home/hlos/code/xys/temp/project-x/build/out/rootfs/initramfs.gz");
            type = "ramdisk";
            arch = "arm";
            os = "linux";
            compression = "gzip";
        };
    };

    configurations {
        default = "conf@tiny210";
        conf@tiny210 {
            description = "Boot Linux kernel with FDT blob";
            kernel = "kernel@tiny210";
            fdt = "fdt@tiny210";
            ramdisk = "ramdisk@tiny210";
        };
    };
};
  1. 最后讲一下怎么用mkimage生成 itb镜像
    需要注意的是,kernel 镜像的路径和其它信息是写在 its文件里的,不需要像Legacy uImage那样子,给 mkimage 加很多参数了。
mkimage -f kernel_fdt.its kernel_fdt.itb



http://xzh.i3geek.com

爱唠叨的老鱼

爱唠叨的老鱼

技术经理,个人站长,创业者

0 条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据