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文件,后面会介绍各项内容的含义。
/* * simple u-boot uimage source file containing a single kernel *//dts-v1/;/ { description = simple image with single linux kernel; #address-cells = ; images { kernel@1 { description = vanilla linux kernel; data = /incbin/(./vmlinux.bin.gz); # image data 具体路径 type = kernel; arch = ppc; os = linux; compression = gzip; load = ; entry = ; hash@1 { algo = crc32; }; hash@2 { algo = sha1; }; }; }; configurations { default = config@1; config@1 { description = boot linux kernel; kernel = kernel@1; }; };};
mkimage的输出是一个后缀为.itb的二进制文件,包含了所有需要的数据(kernel,dtb,ramdisk)。itb文件制作好之后,就可以直接加载到嵌入式设备上,通过bootm命令启动。
总结下制作fit image的4个必要文件:
mkimage,
dtc
its(image source file (*.its))
image data file(s)。
its语法结构
uimage tree 的根节点结构
/ o image-tree |- description = image description |- timestamp = |- #address-cells = | o images | | | o image@1 {...} | o image@2 {...} | ... | o configurations |- default = conf@1 | o conf@1 {...} o conf@2 {...} ...
description:描述uimage的文本。
timestamp:修改image镜像的时间,由mkimage工具自动生成。在security boot中,timestamp不同也会被认为是不同的image。
images:子镜像,如kernel image,ramdisk image。
configurations:配置项节点,可以将不同类型的二进制文件,根据不同的场景,组合起来,形成一个个的配置项。u-boot在boot的时候,以配置项为单位加载、执行,这样就可以根据不同的场景,方便的选择不同的配置。
'/images' node
该节点中描述了image镜像必要的信息.
o image@1 |- description = component sub-image description |- data = /incbin/(path/to/data/file.bin) |- type = sub-image type name |- arch = arch name |- os = os name |- compression = compression name |- load = |- entry = | o hash@1 {...} o hash@2 {...} ...
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
o hash@1 |- algo = hash or checksum algorithm name |- value = [hash or checksum value]
algo:算法名称,如crc32,md5,sha256等。
value:算法校验值,即algo计算后的数值。
'/configurations' node
o configurations |- default = default configuration sub-node unit name | o config@1 {...} o config@2 {...} ...
default:默认的子节点的配置
config@1: 该配置具体使用那些kernel image,ramdisk image等。
configuration nodes
o config@1 |- description = configuration description |- kernel = kernel sub-node unit name |- ramdisk = ramdisk sub-node unit name |- fdt = fdt sub-node unit-name [, fdt overlay sub-node unit-name, ...] |- fpga = fpga sub-node unit-name |- 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”指定,当然也可以在运行时指定。
/* * u-boot uimage source file with multiple kernels, ramdisks and fdt blobs *//dts-v1/;/ { description = various kernels, ramdisks and fdt blobs; #address-cells = ; images { kernel@1 { description = vanilla-2.6.23; data = /incbin/(./vmlinux.bin.gz); type = kernel; arch = ppc; os = linux; compression = gzip; load = ; entry = ; hash@1 { algo = md5; }; hash@2 { algo = sha1; }; }; kernel@2 { description = 2.6.23-denx; data = /incbin/(./2.6.23-denx.bin.gz); type = kernel; arch = ppc; os = linux; compression = gzip; load = ; entry = ; hash@1 { algo = sha1; }; }; kernel@3 { description = 2.4.25-denx; data = /incbin/(./2.4.25-denx.bin.gz); type = kernel; arch = ppc; os = linux; compression = gzip; load = ; entry = ; hash@1 { algo = md5; }; }; ramdisk@1 { description = eldk-4.2-ramdisk; data = /incbin/(./eldk-4.2-ramdisk); type = ramdisk; arch = ppc; os = linux; compression = gzip; load = ; entry = ; hash@1 { algo = sha1; }; }; ramdisk@2 { description = eldk-3.1-ramdisk; data = /incbin/(./eldk-3.1-ramdisk); type = ramdisk; arch = ppc; os = linux; compression = gzip; load = ; entry = ; hash@1 { algo = crc32; }; }; fdt@1 { description = tqm5200-fdt; data = /incbin/(./tqm5200.dtb); type = flat_dt; arch = ppc; compression = none; hash@1 { algo = crc32; }; }; fdt@2 { description = tqm5200s-fdt; data = /incbin/(./tqm5200s.dtb); type = flat_dt; arch = ppc; compression = none; load = ; hash@1 { algo = sha1; }; }; }; configurations { default = config@1; config@1 { description = tqm5200 vanilla-2.6.23 configuration; kernel = kernel@1; ramdisk = ramdisk@1; fdt = fdt@1; }; config@2 { description = tqm5200s denx-2.6.23 configuration; kernel = kernel@2; ramdisk = ramdisk@1; fdt = fdt@2; }; config@3 { description = tqm5200s denx-2.4.25 configuration; kernel = kernel@3; ramdisk = ramdisk@2; }; };};
fit image的编译和启动
在服务器上,可以使用mkimage工具制作 fit image。
如下是kernel_fdt.its,下面将使用该文件制作itb。
/* * simple u-boot uimage source file containing a single kernel and fdt blob *//dts-v1/;/ { description = simple image with single linux kernel and fdt blob; #address-cells = ; images { kernel@1 { description = vanilla linux kernel; data = /incbin/(./vmlinux.bin.gz); type = kernel; arch = ppc; os = linux; compression = gzip; load = ; entry = ; hash@1 { algo = crc32; }; hash@2 { algo = sha1; }; }; fdt@1 { description = flattened device tree blob; data = /incbin/(./target.dtb); type = flat_dt; arch = ppc; compression = none; hash@1 { algo = crc32; }; hash@2 { algo = sha1; }; }; }; configurations { default = conf@1; conf@1 { description = boot linux kernel with fdt blob; kernel = kernel@1; fdt = fdt@1; }; };};$ mkimage -f kernel_fdt.its kernel_fdt.itbdtc: dts->dtb on file kernel_fdt.its$$ mkimage -l kernel_fdt.itbfit description: simple image with single linux kernel and fdt blobcreated: tue mar 11 1622 2008 image 0 (kernel@1) description: vanilla linux kernel type: kernel image compression: gzip compressed data size: 1092037 bytes = 1066.44 kb = 1.04 mb architecture: powerpc os: linux load address: 0x00000000 entry point: 0x00000000 hash algo: crc32 hash value: 2c0cc807 hash algo: sha1 hash value: 264b59935470e42c418744f83935d44cdf59a3bb image 1 (fdt@1) description: flattened device tree blob type: flat device tree compression: uncompressed data size: 16384 bytes = 16.00 kb = 0.02 mb architecture: powerpc hash algo: crc32 hash value: 0d655d71 hash algo: sha1 hash value: 25ab4e15cd4b8a5144610394560d9c318ce52def default configuration: 'conf@1' configuration 0 (conf@1) description: boot linux kernel with fdt blob kernel: kernel@1 fdt: fdt@1
在当前目录下就可以找到kernel_fdt.itb,itb文件就可以加载到设备上启动。
> tftp 900000 /path/to/tftp/location/kernel_fdt.itbusing fec devicetftp from server 192.168.1.1; our ip address is 192.168.160.5filename '/path/to/tftp/location/kernel_fdt.itb'.load address: 0x900000loading: ################################################################# ###########donebytes transferred = 1109776 (10ef10 hex)=> iminfo## checking image at 00900000 ... fit image found fit description: simple image with single linux kernel and fdt blob created: 2008-03-11 1522 utc image 0 (kernel@1) description: vanilla linux kernel type: kernel image compression: gzip compressed data start: 0x009000ec data size: 1092037 bytes = 1 mb architecture: powerpc os: linux load address: 0x00000000 entry point: 0x00000000 hash algo: crc32 hash value: 2c0cc807 hash algo: sha1 hash value: 264b59935470e42c418744f83935d44cdf59a3bb image 1 (fdt@1) description: flattened device tree blob type: flat device tree compression: uncompressed data start: 0x00a0abdc data size: 16384 bytes = 16 kb architecture: powerpc hash algo: crc32 hash value: 0d655d71 hash algo: sha1 hash value: 25ab4e15cd4b8a5144610394560d9c318ce52def default configuration: 'conf@1' configuration 0 (conf@1) description: boot linux kernel with fdt blob kernel: kernel@1 fdt: fdt@1=> bootm## booting kernel from fit image at 00900000 ... using 'conf@1' configuration trying 'kernel@1' kernel subimage description: vanilla linux kernel type: kernel image compression: gzip compressed data start: 0x009000ec data size: 1092037 bytes = 1 mb architecture: powerpc os: linux load address: 0x00000000 entry point: 0x00000000 hash algo: crc32 hash value: 2c0cc807 hash algo: sha1 hash value: 264b59935470e42c418744f83935d44cdf59a3bb verifying hash integrity ... crc32+ sha1+ ok uncompressing kernel image ... ok## flattened device tree from fit image at 00900000 using 'conf@1' configuration trying 'fdt@1' fdt blob subimage description: flattened device tree blob type: flat device tree compression: uncompressed data start: 0x00a0abdc data size: 16384 bytes = 16 kb architecture: powerpc hash algo: crc32 hash value: 0d655d71 hash algo: sha1 hash value: 25ab4e15cd4b8a5144610394560d9c318ce52def verifying hash integrity ... crc32+ sha1+ ok booting using the fdt blob at 0xa0abdc loading device tree to 007fc000, end 007fffff ... ok[ 0.000000] using lite5200 machine description[ 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 1548 cet 2008
bootm启动不同的配置
对于fit image,bootm有多种启动方式。
1. bootm 2. bootm []:3. bootm []#[#
对于有多种镜像,多套配置的itb,都是以configurations 中default 指定的配置启动。
bootm 200000
也可以手动指定使用那套配置
bootm 200000#cfg@1
也可以手动搭配不同的镜像节点启动
bootm 200000:kernel@1 800000:ramdisk@2bootm 200000:kernel@1 800000:ramdisk@1 800000:fdt@1bootm 200000:kernel@2 200000:ramdisk@2 600000bootm 200000:kernel@2 - 200000:fdt@1
如果bootm的时候不指定地址,则会使用config_sys_load_addr配置的地址。
总结
本文对fit image作了简单的介绍,更详细的内容可以参考官方文档。后面有时间会动手制作一个fit image在板子上跑下。
fit image可以兼容于多种板子,而无需重新进行编译烧写。对于有多个kernel节点或者fdt节点等等,兼容性更强。同时,可以有多种configurations,来对kernel、fdt、ramdisk来进行组合。
全方面解读标致2008底盘
IBM致力帮助企业及其员工在AI和智能自动化时代释放更大潜能
福建耗费六年终建成智慧博物馆,运用RFID和大数据技术
泰克智能座舱测试白皮书发布
多个半导体产业相关项目列入浙江省2020年重点建设项目名单
FIT Image起源及制作方法
智能变电站实现变电站数字二次回路的设计方案
谷歌CEO等硅谷大佬纷纷反对特朗普的移民新政
居家必备灭蚊神器,灭蚊灯哪个牌子好
双频双路WiFi让你拥有顺畅的上网体验
Orbital 淋浴系统采用PCR雷达传感器实现节水节能
关于捷变频雷达频踪测试方法的介绍和分享
深圳晟源达五金的CNC加工
硬开关与软开关功率因数校正电路的研究
高智能型的土壤养分快速测试仪,它的作用是什么
医用检验仪器的维修经验及技巧
以太网:速率多样化和数据安全同样重要
英特尔以数据为中心产品组合 加速HPC和AI工作负载不断融合
哈罗出行利用AI技术开创了中国自行车共享产业的3.0时代
复盘2020年中国科技的关键词