《電子技術(shù)應(yīng)用》
您所在的位置:首頁 > 可編程邏輯 > 其他 > 教學(xué):secure boot (一)FIT Image

教學(xué):secure boot (一)FIT Image

2022-09-05
來源:電子技術(shù)應(yīng)用專欄作家 嵌入式與Linux那些事
關(guān)鍵詞: secureboot FITImage

  前言

  secure boot 和FIT Image是前段時(shí)間接觸到的,其實(shí)早就該總結(jié)下了,奈何懶癌犯了,,拖了好久才寫出來。

  之前也有人問我,,工作后最大的感受是什么?我的回答是:“快速學(xué)習(xí)”,。

  就嵌入式來講,,大多數(shù)應(yīng)屆生在校期間可能都沒做過完整的項(xiàng)目,僅憑在校期間學(xué)習(xí)的內(nèi)容很難勝任公司的要求,。

  就底層驅(qū)動來講,,雖然我之前也學(xué)習(xí)過韋東山老師的上s3c2440的課程,但是到了公司才發(fā)現(xiàn),,這些內(nèi)容其實(shí)都已經(jīng)過時(shí)了,。

  但并不是說這些內(nèi)容都沒有必要去學(xué)習(xí)了,。在學(xué)習(xí)的過程中,認(rèn)為最重要的是培養(yǎng)我們的自學(xué)能力,。

  很多初學(xué)者在剛開始學(xué)習(xí)時(shí),,可能就敗在了搭建環(huán)境上。搭建環(huán)境時(shí)遇到問題不知道怎么辦,?

  我們?nèi)粘i_發(fā)中遇到的90%的問題,,在網(wǎng)上都有人遇到過,也有相應(yīng)的解決辦法,。學(xué)會利用bing,,google,stackoverflow等搜索工具是一項(xiàng)很重要的技能,。

  如果遇到了網(wǎng)上沒有的問題怎么辦,?軟件問題要先搞清楚原理,再去看代碼邏輯,。硬件問題看官方手冊,。像Linux kernel,ARM等都提供了完善的手冊,,大部分問題在手冊中都有相應(yīng)說明,。

  好了,扯遠(yuǎn)了,。下面回歸正題,。

  本文主要介紹了FIT Image起源,制作方法,,its的語法結(jié)構(gòu),,bootm 啟動FIT Image的方式。

  本文這篇文章是對后面介紹的secure boot做鋪墊,。ARMv8 secure boot一種實(shí)現(xiàn)的方式就是利用了FIT Image的特性,。

  zImage,uImage,, Legacy uImage 和 FIT uImage

  內(nèi)核經(jīng)過編譯后,會生成一個(gè)elf的可執(zhí)行程序,,叫vmlinux,,這個(gè)就是原始的未經(jīng)任何處理加工的原版內(nèi)核elf文件。不過,,最終燒寫在嵌入式設(shè)備上的并不是這個(gè)文件,。而是經(jīng)過objcopy工具加工后的專門用于燒錄的鏡像格式Image。

  原則上Image就可以直接被燒錄到Flash上進(jìn)行啟動執(zhí)行,,但linux的內(nèi)核開發(fā)者覺得Image還是太大了,,因此對Image進(jìn)行了壓縮,并且在Image壓縮后的文件的前端附加了一部分解壓縮代碼,構(gòu)成了一個(gè)壓縮格式的鏡像文件就叫zImage,。

  解壓的時(shí)候,,通過zImage鏡像頭部的解壓縮代碼進(jìn)行自解壓,然后執(zhí)行解壓出來的內(nèi)核鏡像,。

  Uboot要正確啟動Linux內(nèi)核,,就需要知道內(nèi)核的一些信息,比如鏡像的類型(kernel image,,dtb,,ramdisk image),鏡像在內(nèi)存的位置,,鏡像的鏈接地址,,鏡像文件是否有壓縮等等。

  Uboot為了拿到這些信息,,發(fā)明了一種內(nèi)核格式叫uImage,,也叫Legacy uImage。uImage是由zImage加工得到的,,uboot中有一個(gè)工具mkimage,,該工具會給zImage加一個(gè)64字節(jié)的header,將啟動內(nèi)核所需的信息存儲在header中,。uboot啟動后,,從header中讀取所需的信息,按照指示,,進(jìn)行相應(yīng)的動作即可,。

  header格式可以參考:include/image.h。mkimage源碼在tools/mkimage

  FIT image的來源

  有了Legacy uImage后,,為什么又搞出來一個(gè)FIT uImage呢,?

  在Linus Torvalds 看來,內(nèi)核中arch/arm/mach-xxx充斥著大量的垃圾代碼,。因?yàn)閮?nèi)核并不關(guān)心板級細(xì)節(jié),,比如板上的platform設(shè)備、resource,、i2c_board_info,、spi_board_info等等。大家有興趣可以看下s3c2410的板級目錄,,代碼量在數(shù)萬行,。

  因此,ARM社區(qū)引入了Device Tree,,使用Device Tree后,,許多硬件的細(xì)節(jié)可以直接透過它傳遞給Linux,,而不再需要在kernel中進(jìn)行大量的冗余編碼。

  為了更好的支持單個(gè)固件的通用性,,Uboot也需要對這種uImage固件進(jìn)行支持,。FIT uImage中加入多個(gè)dtb文件 和ramdisk文件,當(dāng)然如果需要的話,,同樣可以支持多個(gè)kernel文件,。

  內(nèi)核中的FDT全程為flattened device tree,F(xiàn)IT全稱叫flattened image tree,。FIT利用了Device Tree Source files(DTS)的語法,,生成的Image文件也和dtb文件類似(稱作itb)。

  這樣的目的就是能夠使同一個(gè)uImage能夠在Uboot中選擇特定的kernel/dtb和ramdisk進(jìn)行啟動了,,達(dá)成一個(gè)uImage可以通用多個(gè)板型的目的,。

  制作FIT Image

  制作FIT Image需要用到兩個(gè)工具,mkimage和的dtc,。dtc要導(dǎo)入到環(huán)境變量$PATH中,,mkimage會調(diào)用dtc。

  mkimage的輸入為 image source file,它定義了啟動過程中image的各種屬性,,擴(kuò)展名為.its,。its只是描述了Image的屬性,實(shí)際的Image data 是在uImage中,,具體路徑由its指定,。

  微信圖片_20220905173802.png

  如下是kernel 的its文件,后面會介紹各項(xiàng)內(nèi)容的含義。

  /*

  * Simple U-Boot uImage source file containing a single kernel

  */

  /dts-v1/;

  / {

  description = "Simple image with single Linux kernel";

  #address-cells = <1>;

  images {

  kernel@1 {

  description = "Vanilla Linux kernel";

  data = /incbin/("./vmlinux.bin.gz"); # Image data 具體路徑

  type = "kernel";

  arch = "ppc";

  os = "linux";

  compression = "gzip";

  load = <00000000>;

  entry = <00000000>;

  hash@1 {

  algo = "crc32";

  };

  hash@2 {

  algo = "sha1";

  };

  };

  };

  configurations {

  default = "config@1";

  config@1 {

  description = "Boot Linux kernel";

  kernel = "kernel@1";

  };

  };

  };

  mkimage的輸出是一個(gè)后綴為.itb的二進(jìn)制文件,,包含了所有需要的數(shù)據(jù)(kernel,,dtb,ramdisk),。itb文件制作好之后,,就可以直接加載到嵌入式設(shè)備上,通過bootm命令啟動,。

  總結(jié)下制作FIT Image的4個(gè)必要文件:

  mkimage,,

  dtc

  its(image source file (*.its))

  image data file(s)。

  its語法結(jié)構(gòu)

  uImage Tree 的根節(jié)點(diǎn)結(jié)構(gòu)

  / o image-tree

  |- description = "image description"

  |- timestamp = <12399321>

  |- #address-cells = <1>

  |

  o images

  | |

  | o image@1 {...}

  | o image@2 {...}

  | ...

  |

  o configurations

  |- default = "conf@1"

  |

  o conf@1 {...}

  o conf@2 {...}

  ...

  description:描述uImage的文本,。

  timestamp:修改Image鏡像的時(shí)間,,由mkimage工具自動生成。在security boot中,,timestamp不同也會被認(rèn)為是不同的Image。

  images:子鏡像,,如kernel Image,,ramdisk Image,。

  configurations:配置項(xiàng)節(jié)點(diǎn),可以將不同類型的二進(jìn)制文件,,根據(jù)不同的場景,,組合起來,形成一個(gè)個(gè)的配置項(xiàng),。u-boot在boot的時(shí)候,,以配置項(xiàng)為單位加載、執(zhí)行,,這樣就可以根據(jù)不同的場景,,方便的選擇不同的配置。

  '/images' node

  該節(jié)點(diǎn)中描述了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 = <00000000>

  |- entry = <00000000>

  |

  o hash@1 {...}

  o hash@2 {...}

  ...

  description:子鏡像的文本描述,,可以隨便寫,。

  type:子鏡像的類型,比如standalone,,kernel,,ramdisk,firmware等等,。

  data:包含該節(jié)點(diǎn)二進(jìn)制文件的路徑,。

  compression:壓縮方式,比如none,,gzip,,bzip2。

  os:操作系統(tǒng)的名稱,,如solaris,,uboot,qnx等,。

  arch:平臺架構(gòu),,如arm,mips,,i386等,。

  entry:二進(jìn)制文件入口地址,即鏈接地址,。

  load:二進(jìn)制文件的加載位置,。

  hash@1:鏡像使用的校驗(yàn)算法,如sha256,,crc32等,。

  Hash nodes

  o hash@1

  |- algo = "hash or checksum algorithm name"

  |- value = [hash or checksum value]

  algo:算法名稱,如crc32,,md5,,sha256等,。

  value:算法校驗(yàn)值,即algo計(jì)算后的數(shù)值,。

  '/configurations' node

  o configurations

  |- default = "default configuration sub-node unit name"

  |

  o config@1 {...}

  o config@2 {...}

  ...

  default:默認(rèn)的子節(jié)點(diǎn)的配置

  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:額外的可加載的二進(jìn)制文件的列表,,U-Boot將在給定的起始地址加載每個(gè)二進(jìn)制文件。

  舉例

  如下是一個(gè)有多種kernels, ramdisks and FDT blobs鏡像多套配置的its文件,。它包含了3種配置,,每種配置使用了不同的kernel、ramdisk和fdt,,默認(rèn)配置項(xiàng)由“default”指定,,當(dāng)然也可以在運(yùn)行時(shí)指定。

  /*

  * U-Boot uImage source file with multiple kernels, ramdisks and FDT blobs

  */

  /dts-v1/;

  / {

  description = "Various kernels, ramdisks and FDT blobs";

  #address-cells = <1>;

  images {

  kernel@1 {

  description = "vanilla-2.6.23";

  data = /incbin/("./vmlinux.bin.gz");

  type = "kernel";

  arch = "ppc";

  os = "linux";

  compression = "gzip";

  load = <00000000>;

  entry = <00000000>;

  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 = <00000000>;

  entry = <00000000>;

  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 = <00000000>;

  entry = <00000000>;

  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 = <00000000>;

  entry = <00000000>;

  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 = <00000000>;

  entry = <00000000>;

  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 = <00700000>;

  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的編譯和啟動

  在服務(wù)器上,,可以使用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 = <1>;

  images {

  kernel@1 {

  description = "Vanilla Linux kernel";

  data = /incbin/("./vmlinux.bin.gz");

  type = "kernel";

  arch = "ppc";

  os = "linux";

  compression = "gzip";

  load = <00000000>;

  entry = <00000000>;

  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.itb

  DTC: dts->dtb  on file "kernel_fdt.its"

  $

  $ mkimage -l kernel_fdt.itb

  FIT description: Simple image with single Linux kernel and FDT blob

  Created:  Tue Mar 11 16:29:22 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

  在當(dāng)前目錄下就可以找到kernel_fdt.itb,,itb文件就可以加載到設(shè)備上啟動。

  > tftp 900000 /path/to/tftp/location/kernel_fdt.itb

  Using FEC device

  TFTP from server 192.168.1.1; our IP address is 192.168.160.5

  Filename '/path/to/tftp/location/kernel_fdt.itb'.

  Load address: 0x900000

  Loading: #################################################################

  ###########

  done

  Bytes 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 15:29:22 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 15:38:48 CET 2008

  bootm啟動不同的配置

  對于FIT Image,,bootm有多種啟動方式,。

  1. bootm <addr1>

  2. bootm [<addr1>]:<subimg1>

  3. bootm [<addr1>]#<conf>[#<extra-conf[#...]]

  4. bootm [<addr1>]:<subimg1> [<addr2>]:<subimg2>

  5. bootm [<addr1>]:<subimg1> [<addr2>]:<subimg2> [<addr3>]:<subimg3>

  6. bootm [<addr1>]:<subimg1> [<addr2>]:<subimg2> <addr3>

  7. bootm [<addr1>]:<subimg1> -     [<addr3>]:<subimg3>

  8. bootm [<addr1>]:<subimg1> -     <addr3>

  對于有多種鏡像,多套配置的itb,,都是以configurations 中default 指定的配置啟動,。

  bootm 200000

  也可以手動指定使用那套配置

  bootm 200000#cfg@1

  也可以手動搭配不同的鏡像節(jié)點(diǎn)啟動

  bootm 200000:kernel@1 800000:ramdisk@2

  bootm 200000:kernel@1 800000:ramdisk@1 800000:fdt@1

  bootm 200000:kernel@2 200000:ramdisk@2 600000

  bootm 200000:kernel@2 - 200000:fdt@1

  如果bootm的時(shí)候不指定地址,則會使用CONFIG_SYS_LOAD_ADDR配置的地址,。

  總結(jié)

  本文對FIT Image作了簡單的介紹,,更詳細(xì)的內(nèi)容可以參考官方文檔。后面有時(shí)間會動手制作一個(gè)FIT Image在板子上跑下,。

  FIT Image可以兼容于多種板子,,而無需重新進(jìn)行編譯燒寫。對于有多個(gè)kernel節(jié)點(diǎn)或者fdt節(jié)點(diǎn)等等,,兼容性更強(qiáng),。同時(shí),可以有多種configurations,來對kernel,、fdt,、ramdisk來進(jìn)行組合。


 更多信息可以來這里獲取==>>電子技術(shù)應(yīng)用-AET<<

微信圖片_20210517164139.jpg

微信圖片_20220708145705.jpg

電子技術(shù)應(yīng)用專欄作家  嵌入式與Linux那些事

原文鏈接:https://mp.weixin.qq.com/s/MtfGhhP_6PSa_mTeLn_XFQ

本站內(nèi)容除特別聲明的原創(chuàng)文章之外,,轉(zhuǎn)載內(nèi)容只為傳遞更多信息,并不代表本網(wǎng)站贊同其觀點(diǎn),。轉(zhuǎn)載的所有的文章,、圖片、音/視頻文件等資料的版權(quán)歸版權(quán)所有權(quán)人所有,。本站采用的非本站原創(chuàng)文章及圖片等內(nèi)容無法一一聯(lián)系確認(rèn)版權(quán)者,。如涉及作品內(nèi)容、版權(quán)和其它問題,,請及時(shí)通過電子郵件或電話通知我們,,以便迅速采取適當(dāng)措施,避免給雙方造成不必要的經(jīng)濟(jì)損失,。聯(lián)系電話:010-82306118,;郵箱:[email protected]