secure boot (一)fit image

鼠扑  金牌会员 | 2022-9-21 22:36:05 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 919|帖子 919|积分 2757

前言

secure boot 和FIT Image是前段时间接触到的,其实早就该总结下了,奈何懒癌犯了,拖了好久才写出来。
之前也有人问我,工作后最大的感受是什么?我的回答是:“快速学习”。
就嵌入式来讲,大多数应届生在校期间可能都没做过完整的项目,仅凭在校期间学习的内容很难胜任公司的要求。
就底层驱动来讲,虽然我之前也学习过韦东山老师的上s3c2440的课程,但是到了公司才发现,这些内容其实都已经过时了。
但并不是说这些内容都没有必要去学习了。在学习的过程中,认为最重要的是培养我们的自学能力。
很多初学者在刚开始学习时,可能就败在了搭建环境上。搭建环境时遇到问题不知道怎么办?
我们日常开发中遇到的90%的问题,在网上都有人遇到过,也有相应的解决办法。学会利用bing,google,stackoverflow等搜索工具是一项很重要的技能。
如果遇到了网上没有的问题怎么办?软件问题要先搞清楚原理,再去看代码逻辑。硬件问题看官方手册。像Linux kernel,ARM等都提供了完善的手册,大部分问题在手册中都有相应说明。
好了,扯远了。下面回归正题。
本文主要介绍了FIT Image起源,制作方法,its的语法结构,bootm 启动FIT Image的方式。
本文这篇文章是对后面介绍的secure boot做铺垫。ARMv8 secure boot一种实现的方式就是利用了FIT Image的特性。
zImage,uImage, Legacy uImage 和 FIT uImage

内核经过编译后,会生成一个elf的可执行程序,叫vmlinux,这个就是原始的未经任何处理加工的原版内核elf文件。不过,最终烧写在嵌入式设备上的并不是这个文件。而是经过objcopy工具加工后的专门用于烧录的镜像格式Image。
原则上Image就可以直接被烧录到Flash上进行启动执行,但linux的内核开发者觉得Image还是太大了,因此对Image进行了压缩,并且在Image压缩后的文件的前端附加了一部分解压缩代码,构成了一个压缩格式的镜像文件就叫zImage
解压的时候,通过zImage镜像头部的解压缩代码进行自解压,然后执行解压出来的内核镜像。
Uboot要正确启动Linux内核,就需要知道内核的一些信息,比如镜像的类型(kernel image,dtb,ramdisk image),镜像在内存的位置,镜像的链接地址,镜像文件是否有压缩等等。
Uboot为了拿到这些信息,发明了一种内核格式叫uImage,也叫Legacy uImage。uImage是由zImage加工得到的,uboot中有一个工具mkimage,该工具会给zImage加一个64字节的header,将启动内核所需的信息存储在header中。uboot启动后,从header中读取所需的信息,按照指示,进行相应的动作即可。
header格式可以参考:include/image.h。mkimage源码在tools/mkimage
FIT image的来源

有了Legacy uImage后,为什么又搞出来一个FIT uImage呢?
在Linus Torvalds 看来,内核中arch/arm/mach-xxx充斥着大量的垃圾代码。因为内核并不关心板级细节,比如板上的platform设备、resource、i2c_board_info、spi_board_info等等。大家有兴趣可以看下s3c2410的板级目录,代码量在数万行。
因此,ARM社区引入了Device Tree,使用Device Tree后,许多硬件的细节可以直接透过它传递给Linux,而不再需要在kernel中进行大量的冗余编码。
为了更好的支持单个固件的通用性,Uboot也需要对这种uImage固件进行支持。FIT uImage中加入多个dtb文件 和ramdisk文件,当然如果需要的话,同样可以支持多个kernel文件。
内核中的FDT全程为flattened device tree,FIT全称叫flattened image tree。FIT利用了Device Tree Source files(DTS)的语法,生成的Image文件也和dtb文件类似(称作itb)。
这样的目的就是能够使同一个uImage能够在Uboot中选择特定的kernel/dtb和ramdisk进行启动了,达成一个uImage可以通用多个板型的目的。
制作FIT Image

制作FIT Image需要用到两个工具,mkimage和的dtc。dtc要导入到环境变量$PATH中,mkimage会调用dtc。
mkimage的输入为 image source file,它定义了启动过程中image的各种属性,扩展名为.its。its只是描述了Image的属性,实际的Image data 是在uImage中,具体路径由its指定。

如下是kernel 的its文件,后面会介绍各项内容的含义。
  1. /*
  2. * Simple U-Boot uImage source file containing a single kernel
  3. */
  4. /dts-v1/;
  5. / {
  6.         description = "Simple image with single Linux kernel";
  7.         #address-cells = <1>;
  8.         images {
  9.                 kernel@1 {
  10.                         description = "Vanilla Linux kernel";
  11.                         data = /incbin/("./vmlinux.bin.gz");        # Image data 具体路径
  12.                         type = "kernel";
  13.                         arch = "ppc";
  14.                         os = "linux";
  15.                         compression = "gzip";
  16.                         load = <00000000>;
  17.                         entry = <00000000>;
  18.                         hash@1 {
  19.                                 algo = "crc32";
  20.                         };
  21.                         hash@2 {
  22.                                 algo = "sha1";
  23.                         };
  24.                 };
  25.         };
  26.         configurations {
  27.                 default = "config@1";
  28.                 config@1 {
  29.                         description = "Boot Linux kernel";
  30.                         kernel = "kernel@1";
  31.                 };
  32.         };
  33. };
复制代码
mkimage的输出是一个后缀为.itb的二进制文件,包含了所有需要的数据(kernel,dtb,ramdisk)。itb文件制作好之后,就可以直接加载到嵌入式设备上,通过bootm命令启动。
总结下制作FIT Image的4个必要文件:

  • mkimage,
  • dtc
  • its(image source file (*.its))
  • image data file(s)。
its语法结构

uImage Tree 的根节点结构
  1. / o image-tree
  2.     |- description = "image description"
  3.     |- timestamp = <12399321>
  4.     |- #address-cells = <1>
  5.     |
  6.     o images
  7.     | |
  8.     | o image@1 {...}
  9.     | o image@2 {...}
  10.     | ...
  11.     |
  12.     o configurations
  13.       |- default = "conf@1"
  14.       |
  15.       o conf@1 {...}
  16.       o conf@2 {...}
  17.       ...
复制代码

  • description:描述uImage的文本。
  • timestamp:修改Image镜像的时间,由mkimage工具自动生成。在security boot中,timestamp不同也会被认为是不同的Image。
  • images:子镜像,如kernel Image,ramdisk Image。
  • configurations:配置项节点,可以将不同类型的二进制文件,根据不同的场景,组合起来,形成一个个的配置项。u-boot在boot的时候,以配置项为单位加载、执行,这样就可以根据不同的场景,方便的选择不同的配置。
'/images' node

该节点中描述了Image镜像必要的信息.
  1. o image@1
  2.    |- description = "component sub-image description"
  3.    |- data = /incbin/("path/to/data/file.bin")
  4.    |- type = "sub-image type name"
  5.    |- arch = "ARCH name"
  6.    |- os = "OS name"
  7.    |- compression = "compression name"
  8.    |- load = <00000000>
  9.    |- entry = <00000000>
  10.    |
  11.    o hash@1 {...}
  12.    o hash@2 {...}
  13.    ...
复制代码

  • description:子镜像的文本描述,可以随便写。
  • type:子镜像的类型,比如standalone,kernel,ramdisk,firmware等等。
  • data:包含该节点二进制文件的路径。
  • compression:压缩方式,比如none,gzip,bzip2。
  • os:操作系统的名称,如solaris,uboot,qnx等。
  • arch:平台架构,如arm,mips,i386等。
  • entry:二进制文件入口地址,即链接地址。
  • load:二进制文件的加载位置。
  • hash@1:镜像使用的校验算法,如sha256,crc32等。
Hash nodes
  1. o hash@1
  2.   |- algo = "hash or checksum algorithm name"
  3.   |- value = [hash or checksum value]
复制代码

  • algo:算法名称,如crc32,md5,sha256等。
  • value:算法校验值,即algo计算后的数值。
'/configurations' node
  1. o configurations
  2.   |- default = "default configuration sub-node unit name"
  3.   |
  4.   o config@1 {...}
  5.   o config@2 {...}
  6.   ...
复制代码

  • default:默认的子节点的配置
  • config@1: 该配置具体使用那些kernel Image,ramdisk Image等。
Configuration nodes
  1. o config@1
  2.   |- description = "configuration description"
  3.   |- kernel = "kernel sub-node unit name"
  4.   |- ramdisk = "ramdisk sub-node unit name"
  5.   |- fdt = "fdt sub-node unit-name" [, "fdt overlay sub-node unit-name", ...]
  6.   |- fpga = "fpga sub-node unit-name"
  7.   |- loadables = "loadables sub-node unit-name"
复制代码

  • description:该配置的名称。
  • kernel:镜像类型为kernel的单元的名称。
  • ramdisk:镜像类型为ramdisk的单元的名称。
  • fdt:镜像类型为fdt的单元的名称。
  • loadables:额外的可加载的二进制文件的列表,U-Boot将在给定的起始地址加载每个二进制文件。
举例

如下是一个有多种kernels, ramdisks and FDT blobs镜像多套配置的its文件。它包含了3种配置,每种配置使用了不同的kernel、ramdisk和fdt,默认配置项由“default”指定,当然也可以在运行时指定。
  1. /*
  2. * U-Boot uImage source file with multiple kernels, ramdisks and FDT blobs
  3. */
  4. /dts-v1/;
  5. / {
  6.         description = "Various kernels, ramdisks and FDT blobs";
  7.         #address-cells = <1>;
  8.         images {
  9.                 kernel@1 {
  10.                         description = "vanilla-2.6.23";
  11.                         data = /incbin/("./vmlinux.bin.gz");
  12.                         type = "kernel";
  13.                         arch = "ppc";
  14.                         os = "linux";
  15.                         compression = "gzip";
  16.                         load = <00000000>;
  17.                         entry = <00000000>;
  18.                         hash@1 {
  19.                                 algo = "md5";
  20.                         };
  21.                         hash@2 {
  22.                                 algo = "sha1";
  23.                         };
  24.                 };
  25.                 kernel@2 {
  26.                         description = "2.6.23-denx";
  27.                         data = /incbin/("./2.6.23-denx.bin.gz");
  28.                         type = "kernel";
  29.                         arch = "ppc";
  30.                         os = "linux";
  31.                         compression = "gzip";
  32.                         load = <00000000>;
  33.                         entry = <00000000>;
  34.                         hash@1 {
  35.                                 algo = "sha1";
  36.                         };
  37.                 };
  38.                 kernel@3 {
  39.                         description = "2.4.25-denx";
  40.                         data = /incbin/("./2.4.25-denx.bin.gz");
  41.                         type = "kernel";
  42.                         arch = "ppc";
  43.                         os = "linux";
  44.                         compression = "gzip";
  45.                         load = <00000000>;
  46.                         entry = <00000000>;
  47.                         hash@1 {
  48.                                 algo = "md5";
  49.                         };
  50.                 };
  51.                 ramdisk@1 {
  52.                         description = "eldk-4.2-ramdisk";
  53.                         data = /incbin/("./eldk-4.2-ramdisk");
  54.                         type = "ramdisk";
  55.                         arch = "ppc";
  56.                         os = "linux";
  57.                         compression = "gzip";
  58.                         load = <00000000>;
  59.                         entry = <00000000>;
  60.                         hash@1 {
  61.                                 algo = "sha1";
  62.                         };
  63.                 };
  64.                 ramdisk@2 {
  65.                         description = "eldk-3.1-ramdisk";
  66.                         data = /incbin/("./eldk-3.1-ramdisk");
  67.                         type = "ramdisk";
  68.                         arch = "ppc";
  69.                         os = "linux";
  70.                         compression = "gzip";
  71.                         load = <00000000>;
  72.                         entry = <00000000>;
  73.                         hash@1 {
  74.                                 algo = "crc32";
  75.                         };
  76.                 };
  77.                 fdt@1 {
  78.                         description = "tqm5200-fdt";
  79.                         data = /incbin/("./tqm5200.dtb");
  80.                         type = "flat_dt";
  81.                         arch = "ppc";
  82.                         compression = "none";
  83.                         hash@1 {
  84.                                 algo = "crc32";
  85.                         };
  86.                 };
  87.                 fdt@2 {
  88.                         description = "tqm5200s-fdt";
  89.                         data = /incbin/("./tqm5200s.dtb");
  90.                         type = "flat_dt";
  91.                         arch = "ppc";
  92.                         compression = "none";
  93.                         load = <00700000>;
  94.                         hash@1 {
  95.                                 algo = "sha1";
  96.                         };
  97.                 };
  98.         };
  99.         configurations {
  100.                 default = "config@1";
  101.                 config@1 {
  102.                         description = "tqm5200 vanilla-2.6.23 configuration";
  103.                         kernel = "kernel@1";
  104.                         ramdisk = "ramdisk@1";
  105.                         fdt = "fdt@1";
  106.                 };
  107.                 config@2 {
  108.                         description = "tqm5200s denx-2.6.23 configuration";
  109.                         kernel = "kernel@2";
  110.                         ramdisk = "ramdisk@1";
  111.                         fdt = "fdt@2";
  112.                 };
  113.                 config@3 {
  114.                         description = "tqm5200s denx-2.4.25 configuration";
  115.                         kernel = "kernel@3";
  116.                         ramdisk = "ramdisk@2";
  117.                 };
  118.         };
  119. };
复制代码
FIT Image的编译和启动

在服务器上,可以使用mkimage工具制作 FIT Image。
如下是kernel_fdt.its,下面将使用该文件制作itb。
  1. /*
  2. * Simple U-Boot uImage source file containing a single kernel and FDT blob
  3. */
  4. /dts-v1/;
  5. / {
  6.         description = "Simple image with single Linux kernel and FDT blob";
  7.         #address-cells = <1>;
  8.         images {
  9.                 kernel@1 {
  10.                         description = "Vanilla Linux kernel";
  11.                         data = /incbin/("./vmlinux.bin.gz");
  12.                         type = "kernel";
  13.                         arch = "ppc";
  14.                         os = "linux";
  15.                         compression = "gzip";
  16.                         load = <00000000>;
  17.                         entry = <00000000>;
  18.                         hash@1 {
  19.                                 algo = "crc32";
  20.                         };
  21.                         hash@2 {
  22.                                 algo = "sha1";
  23.                         };
  24.                 };
  25.                 fdt@1 {
  26.                         description = "Flattened Device Tree blob";
  27.                         data = /incbin/("./target.dtb");
  28.                         type = "flat_dt";
  29.                         arch = "ppc";
  30.                         compression = "none";
  31.                         hash@1 {
  32.                                 algo = "crc32";
  33.                         };
  34.                         hash@2 {
  35.                                 algo = "sha1";
  36.                         };
  37.                 };
  38.         };
  39.         configurations {
  40.                 default = "conf@1";
  41.                 conf@1 {
  42.                         description = "Boot Linux kernel with FDT blob";
  43.                         kernel = "kernel@1";
  44.                         fdt = "fdt@1";
  45.                 };
  46.         };
  47. };
复制代码
  1. $ mkimage -f kernel_fdt.its kernel_fdt.itb
  2. DTC: dts->dtb  on file "kernel_fdt.its"
  3. $
  4. $ mkimage -l kernel_fdt.itb
  5. FIT description: Simple image with single Linux kernel and FDT blob
  6. Created:         Tue Mar 11 16:29:22 2008
  7. Image 0 (kernel@1)
  8.   Description:        Vanilla Linux kernel
  9.   Type:                Kernel Image
  10.   Compression:        gzip compressed
  11.   Data Size:        1092037 Bytes = 1066.44 kB = 1.04 MB
  12.   Architecture: PowerPC
  13.   OS:                Linux
  14.   Load Address: 0x00000000
  15.   Entry Point:        0x00000000
  16.   Hash algo:        crc32
  17.   Hash value:        2c0cc807
  18.   Hash algo:        sha1
  19.   Hash value:        264b59935470e42c418744f83935d44cdf59a3bb
  20. Image 1 (fdt@1)
  21.   Description:        Flattened Device Tree blob
  22.   Type:                Flat Device Tree
  23.   Compression:        uncompressed
  24.   Data Size:        16384 Bytes = 16.00 kB = 0.02 MB
  25.   Architecture: PowerPC
  26.   Hash algo:        crc32
  27.   Hash value:        0d655d71
  28.   Hash algo:        sha1
  29.   Hash value:        25ab4e15cd4b8a5144610394560d9c318ce52def
  30. Default Configuration: 'conf@1'
  31. Configuration 0 (conf@1)
  32.   Description:        Boot Linux kernel with FDT blob
  33.   Kernel:        kernel@1
  34.   FDT:                fdt@1
复制代码
在当前目录下就可以找到kernel_fdt.itb,itb文件就可以加载到设备上启动。
  1. > tftp 900000 /path/to/tftp/location/kernel_fdt.itb
  2. Using FEC device
  3. TFTP from server 192.168.1.1; our IP address is 192.168.160.5
  4. Filename '/path/to/tftp/location/kernel_fdt.itb'.
  5. Load address: 0x900000
  6. Loading: #################################################################
  7.          ###########
  8. done
  9. Bytes transferred = 1109776 (10ef10 hex)
  10. => iminfo
  11. ## Checking Image at 00900000 ...
  12.    FIT image found
  13.    FIT description: Simple image with single Linux kernel and FDT blob
  14.    Created:            2008-03-11        15:29:22 UTC
  15.     Image 0 (kernel@1)
  16.      Description:  Vanilla Linux kernel
  17.      Type:           Kernel Image
  18.      Compression:  gzip compressed
  19.      Data Start:   0x009000ec
  20.      Data Size:    1092037 Bytes =  1 MB
  21.      Architecture: PowerPC
  22.      OS:           Linux
  23.      Load Address: 0x00000000
  24.      Entry Point:  0x00000000
  25.      Hash algo:    crc32
  26.      Hash value:   2c0cc807
  27.      Hash algo:    sha1
  28.      Hash value:   264b59935470e42c418744f83935d44cdf59a3bb
  29.     Image 1 (fdt@1)
  30.      Description:  Flattened Device Tree blob
  31.      Type:           Flat Device Tree
  32.      Compression:  uncompressed
  33.      Data Start:   0x00a0abdc
  34.      Data Size:    16384 Bytes = 16 kB
  35.      Architecture: PowerPC
  36.      Hash algo:    crc32
  37.      Hash value:   0d655d71
  38.      Hash algo:    sha1
  39.      Hash value:   25ab4e15cd4b8a5144610394560d9c318ce52def
  40.     Default Configuration: 'conf@1'
  41.     Configuration 0 (conf@1)
  42.      Description:  Boot Linux kernel with FDT blob
  43.      Kernel:           kernel@1
  44.      FDT:           fdt@1
  45. => bootm
  46. ## Booting kernel from FIT Image at 00900000 ...
  47.    Using 'conf@1' configuration
  48.    Trying 'kernel@1' kernel subimage
  49.      Description:  Vanilla Linux kernel
  50.      Type:           Kernel Image
  51.      Compression:  gzip compressed
  52.      Data Start:   0x009000ec
  53.      Data Size:    1092037 Bytes =  1 MB
  54.      Architecture: PowerPC
  55.      OS:           Linux
  56.      Load Address: 0x00000000
  57.      Entry Point:  0x00000000
  58.      Hash algo:    crc32
  59.      Hash value:   2c0cc807
  60.      Hash algo:    sha1
  61.      Hash value:   264b59935470e42c418744f83935d44cdf59a3bb
  62.    Verifying Hash Integrity ... crc32+ sha1+ OK
  63.    Uncompressing Kernel Image ... OK
  64. ## Flattened Device Tree from FIT Image at 00900000
  65.    Using 'conf@1' configuration
  66.    Trying 'fdt@1' FDT blob subimage
  67.      Description:  Flattened Device Tree blob
  68.      Type:           Flat Device Tree
  69.      Compression:  uncompressed
  70.      Data Start:   0x00a0abdc
  71.      Data Size:    16384 Bytes = 16 kB
  72.      Architecture: PowerPC
  73.      Hash algo:    crc32
  74.      Hash value:   0d655d71
  75.      Hash algo:    sha1
  76.      Hash value:   25ab4e15cd4b8a5144610394560d9c318ce52def
  77.    Verifying Hash Integrity ... crc32+ sha1+ OK
  78.    Booting using the fdt blob at 0xa0abdc
  79.    Loading Device Tree to 007fc000, end 007fffff ... OK
  80. [    0.000000] Using lite5200 machine description
  81. [    0.000000] Linux version 2.6.24-rc6-gaebecdfc (m8@hekate) (gcc version 4.0.0 (DENX ELDK 4.1 4.0.0)) #1 Sat Jan 12 15:38:48 CET 2008
复制代码
bootm启动不同的配置

对于FIT Image,bootm有多种启动方式。
[code]1. bootm 2. bootm []:3. bootm []#[#

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

鼠扑

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表