android13 boot类镜像解析

android 包含的boot类镜像有哪些:
boot.img
recovery.img
vendor_boot.img
init_boot.img
vendor_kernel_boot.img
等

boot类镜像的结构:

system/tools/mkbootimg/include/bootimg/bootimg.h:
#pragma once

#include <stdint.h>

#define BOOT_MAGIC "ANDROID!"
#define BOOT_MAGIC_SIZE 8
#define BOOT_NAME_SIZE 16
#define BOOT_ARGS_SIZE 512
#define BOOT_EXTRA_ARGS_SIZE 1024

#define VENDOR_BOOT_MAGIC "VNDRBOOT"
#define VENDOR_BOOT_MAGIC_SIZE 8
#define VENDOR_BOOT_ARGS_SIZE 2048
#define VENDOR_BOOT_NAME_SIZE 16

#define VENDOR_RAMDISK_TYPE_NONE 0
#define VENDOR_RAMDISK_TYPE_PLATFORM 1
#define VENDOR_RAMDISK_TYPE_RECOVERY 2
#define VENDOR_RAMDISK_TYPE_DLKM 3
#define VENDOR_RAMDISK_NAME_SIZE 32
#define VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE 16
/* When a boot header is of version 0, the structure of boot image is as
 * follows:
 *
 * +-----------------+
 * | boot header     | 1 page
 * +-----------------+
 * | kernel          | n pages
 * +-----------------+
 * | ramdisk         | m pages
 * +-----------------+
 * | second stage    | o pages
 * +-----------------+
 *
 * n = (kernel_size + page_size - 1) / page_size
 * m = (ramdisk_size + page_size - 1) / page_size
 * o = (second_size + page_size - 1) / page_size
 *
 * 0. all entities are page_size aligned in flash =>所有flash中的条目都是pase_size对齐
 * 1. kernel and ramdisk are required (size != 0) => kernel和ramdisk被需要(并且大小!=0)
 * 2. second is optional (second_size == 0 -> no second) => second 是可选的(second_size == 0 -> 没有 second)
 * 3. load each element (kernel, ramdisk, second) at the specified physical address (kernel_addr, etc) 
 * => 在指定的物理地址(kernel_addr 等)加载每个元素(kernel、ramdisk、second)
 * 4. prepare tags at tag_addr.  kernel_args[] is appended to the kernel commandline in the tags.
 * => 在 tag_addr 准备标签。 kernel_args[] 附加到标签中的内核命令行。
 * 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
 * 6. if second_size != 0: jump to second_addr
 *    else: jump to kernel_addr
 */
struct boot_img_hdr_v0 {
    // Must be BOOT_MAGIC.
    uint8_t magic[BOOT_MAGIC_SIZE]; // "ANDROID!"占8字节

    uint32_t kernel_size; /* size in bytes */
    uint32_t kernel_addr; /* physical load addr */

    uint32_t ramdisk_size; /* size in bytes */
    uint32_t ramdisk_addr; /* physical load addr */

    uint32_t second_size; /* size in bytes */
    uint32_t second_addr; /* physical load addr */

    uint32_t tags_addr; /* physical addr for kernel tags (if required) */
    uint32_t page_size; /* flash page size we assume */

    // Version of the boot image header.  => boot镜像头的版本,偏移量为40(0x28)个字节
    uint32_t header_version;

    // Operating system version and security patch level.
    // For version "A.B.C" and patch level "Y-M-D":
    //   (7 bits for each of A, B, C; 7 bits for (Y-2000), 4 bits for M)
    //   os_version = A[31:25] B[24:18] C[17:11] (Y-2000)[10:4] M[3:0]
    uint32_t os_version;

#if __cplusplus
    void SetOsVersion(unsigned major, unsigned minor, unsigned patch) {
        os_version &= ((1 << 11) - 1);
        os_version |= (((major & 0x7f) << 25) | ((minor & 0x7f) << 18) | ((patch & 0x7f) << 11));
    }

    void SetOsPatchLevel(unsigned year, unsigned month) {
        os_version &= ~((1 << 11) - 1);
        os_version |= (((year - 2000) & 0x7f) << 4) | ((month & 0xf) << 0);
    }
#endif

    uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */ // 16字节的产品名大小,

    uint8_t cmdline[BOOT_ARGS_SIZE]; /* asciiz kernel commandline */ // 512字节的kernel命令行

    uint32_t id[8]; /* timestamp / checksum / sha1 / etc */

    // Supplemental command line data; kept here to maintain
    // binary compatibility with older versions of mkbootimg.
    // Asciiz.
    uint8_t extra_cmdline[BOOT_EXTRA_ARGS_SIZE];   // 1024字节的额外命令行,主要与旧版本的mkbootimg兼容
} __attribute__((packed));

/*
 * It is expected that callers would explicitly specify which version of the
 * boot image header they need to use.
 * 预期调用者将明确指定他们需要使用哪个版本的引导映像标头。
 */
typedef struct boot_img_hdr_v0 boot_img_hdr; //1632(0x660)个字节
/* When a boot header is of version 1, the structure of boot image is as
 * follows:
 *
 * +---------------------+
 * | boot header         | 1 page
 * +---------------------+
 * | kernel              | n pages
 * +---------------------+
 * | ramdisk             | m pages
 * +---------------------+
 * | second stage        | o pages
 * +---------------------+
 * | recovery dtbo/acpio | p pages
 * +---------------------+
 *
 * n = (kernel_size + page_size - 1) / page_size
 * m = (ramdisk_size + page_size - 1) / page_size
 * o = (second_size + page_size - 1) / page_size
 * p = (recovery_dtbo_size + page_size - 1) / page_size
 *
 * 0. all entities are page_size aligned in flash
 * 1. kernel and ramdisk are required (size != 0)
 * 2. recovery_dtbo/recovery_acpio is required for recovery.img in non-A/B
 *    devices(recovery_dtbo_size != 0) 
 *   非 A/B 设备中的 recovery.img 需要 recovery_dtbo/recovery_acpio (recovery_dtbo_size != 0)
 * 3. second is optional (second_size == 0 -> no second)
 * 4. load each element (kernel, ramdisk, second) at
 *    the specified physical address (kernel_addr, etc)
 * 5. If booting to recovery mode in a non-A/B device, extract recovery
 *    dtbo/acpio and apply the correct set of overlays on the base device tree
 *    depending on the hardware/product revision.
 *  如果在非 A/B 设备中启动到recovery模式,请提取recovery dtbo/acpio 并根据硬件/产品版本
 *  在基本设备树上应用正确的overlays集。
 * 6. set up registers for kernel entry as required by your architecture 
 *    根据您的体系结构的要求为内核入口设置寄存器
 * 7. if second_size != 0: jump to second_addr
 *    else: jump to kernel_addr
 */
struct boot_img_hdr_v1 : public boot_img_hdr_v0 {
    uint32_t recovery_dtbo_size;   /* size in bytes for recovery DTBO/ACPIO image */
    uint64_t recovery_dtbo_offset; /* offset to recovery dtbo/acpio in boot image */
    uint32_t header_size;
} __attribute__((packed));  //1648(0x670)个字节
/* When the boot image header has a version of 2, the structure of the boot
 * image is as follows:
 *
 * +---------------------+
 * | boot header         | 1 page
 * +---------------------+
 * | kernel              | n pages
 * +---------------------+
 * | ramdisk             | m pages
 * +---------------------+
 * | second stage        | o pages
 * +---------------------+
 * | recovery dtbo/acpio | p pages
 * +---------------------+
 * | dtb                 | q pages
 * +---------------------+

 * n = (kernel_size + page_size - 1) / page_size
 * m = (ramdisk_size + page_size - 1) / page_size
 * o = (second_size + page_size - 1) / page_size
 * p = (recovery_dtbo_size + page_size - 1) / page_size
 * q = (dtb_size + page_size - 1) / page_size
 *
 * 0. all entities are page_size aligned in flash
 * 1. kernel, ramdisk and DTB are required (size != 0)
 * 2. recovery_dtbo/recovery_acpio is required for recovery.img in non-A/B
 *    devices(recovery_dtbo_size != 0)
 * 3. second is optional (second_size == 0 -> no second)
 * 4. load each element (kernel, ramdisk, second, dtb) at
 *    the specified physical address (kernel_addr, etc)
 * 5. If booting to recovery mode in a non-A/B device, extract recovery
 *    dtbo/acpio and apply the correct set of overlays on the base device tree
 *    depending on the hardware/product revision.
 * 6. set up registers for kernel entry as required by your architecture
 * 7. if second_size != 0: jump to second_addr
 *    else: jump to kernel_addr
 */
struct boot_img_hdr_v2 : public boot_img_hdr_v1 {
    uint32_t dtb_size; /* size in bytes for DTB image */
    uint64_t dtb_addr; /* physical load address for DTB image */
} __attribute__((packed));  //1660(0x67C)个字节
上面的版本0,1,2差异不大
==============================================
下面的版本3,4重构了,差异较大
/* When the boot image header has a version of 3, the structure of the boot
 * image is as follows:
 *
 * +---------------------+
 * | boot header         | 4096 bytes
 * +---------------------+
 * | kernel              | m pages
 * +---------------------+
 * | ramdisk             | n pages
 * +---------------------+
 *
 * m = (kernel_size + 4096 - 1) / 4096
 * n = (ramdisk_size + 4096 - 1) / 4096
 *
 * Note that in version 3 of the boot image header, page size is fixed at 4096 bytes.
 * 请注意,在版本 3 的引导映像标头中,页面大小固定为 4096 字节。
 * The structure of the vendor boot image (introduced with version 3 and
 * required to be present when a v3 boot image is used) is as follows:
 * vendor_boot.img的结构(在版本 3 中引入,并且在使用 v3 引导映像时需要存在)如下所示:
 * +---------------------+
 * | vendor boot header  | o pages
 * +---------------------+
 * | vendor ramdisk      | p pages
 * +---------------------+
 * | dtb                 | q pages
 * +---------------------+

 * o = (2112 + page_size - 1) / page_size
 * p = (vendor_ramdisk_size + page_size - 1) / page_size
 * q = (dtb_size + page_size - 1) / page_size
 *
 * 0. all entities in the boot image are 4096-byte aligned in flash, all
 *    entities in the vendor boot image are page_size (determined by the vendor
 *    and specified in the vendor boot image header) aligned in flash
 * 引导映像中的所有条目在闪存flash中都是 4096 字节对齐的,
 * 供应商引导映像中的所有实体都是 page_size(由供应商确定并在供应商引导映像标头中指定)在闪存flash中对齐
 * 1. kernel, ramdisk, vendor ramdisk, and DTB are required (size != 0) 
 *   // 需要kernel、ramdisk、vendor ramdisk 和 DTB(大小!= 0)
 * 2. load the kernel and DTB at the specified physical address (kernel_addr,
 *    dtb_addr) // 在指定的物理地址(kernel_addr,dtb_addr)加载内核和DTB
 * 3. load the vendor ramdisk at ramdisk_addr  //在 ramdisk_addr 加载供应商 ramdisk
 * 4. load the generic ramdisk immediately following the vendor ramdisk in
 *    memory //在内存中的供应商 ramdisk 之后立即加载通用 ramdisk
 * 5. set up registers for kernel entry as required by your architecture 
 * // 根据您的体系结构的要求为内核入口设置寄存器
 * 6. if the platform has a second stage bootloader jump to it (must be
 *    contained outside boot and vendor boot partitions), otherwise
 *    jump to kernel_addr
 * 如果平台有第二阶段引导加载程序跳转到它(必须包含在引导和供应商引导分区之外),
 * 否则跳转到 kernel_addr
 */
struct boot_img_hdr_v3 {
    // Must be BOOT_MAGIC.
    uint8_t magic[BOOT_MAGIC_SIZE];

    uint32_t kernel_size; /* size in bytes */
    uint32_t ramdisk_size; /* size in bytes */

    // Operating system version and security patch level.
    // For version "A.B.C" and patch level "Y-M-D":
    //   (7 bits for each of A, B, C; 7 bits for (Y-2000), 4 bits for M)
    //   os_version = A[31:25] B[24:18] C[17:11] (Y-2000)[10:4] M[3:0]
    uint32_t os_version;

#if __cplusplus
    void SetOsVersion(unsigned major, unsigned minor, unsigned patch) {
        os_version &= ((1 << 11) - 1);
        os_version |= (((major & 0x7f) << 25) | ((minor & 0x7f) << 18) | ((patch & 0x7f) << 11));
    }

    void SetOsPatchLevel(unsigned year, unsigned month) {
        os_version &= ~((1 << 11) - 1);
        os_version |= (((year - 2000) & 0x7f) << 4) | ((month & 0xf) << 0);
    }
#endif

    uint32_t header_size;

    uint32_t reserved[4]; //预留4字节为了解析下面的header_version版本号时与上面0,1,2版本兼容

    // Version of the boot image header.
    uint32_t header_version;

    // Asciiz kernel commandline.
    uint8_t cmdline[BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE];
} __attribute__((packed));

struct vendor_boot_img_hdr_v3 {
    // Must be VENDOR_BOOT_MAGIC.
    uint8_t magic[VENDOR_BOOT_MAGIC_SIZE]; //"VNDRBOOT"占8字节

    // Version of the vendor boot image header.
    uint32_t header_version;

    uint32_t page_size; /* flash page size we assume */ 我们假设的flash页大小

    uint32_t kernel_addr; /* physical load addr */
    uint32_t ramdisk_addr; /* physical load addr */

    uint32_t vendor_ramdisk_size; /* size in bytes */

    uint8_t cmdline[VENDOR_BOOT_ARGS_SIZE]; /* asciiz kernel commandline */

    uint32_t tags_addr; /* physical addr for kernel tags (if required) */
    uint8_t name[VENDOR_BOOT_NAME_SIZE]; /* asciiz product name */

    uint32_t header_size;

    uint32_t dtb_size; /* size in bytes for DTB image */
    uint64_t dtb_addr; /* physical load address for DTB image */
} __attribute__((packed));
/* When the boot image header has a version of 4, the structure of the boot
 * image is as follows:
 * 当引导映像头文件的版本为 4 时,引导映像的结构如下:
 * +---------------------+
 * | boot header         | 4096 bytes
 * +---------------------+
 * | kernel              | m pages
 * +---------------------+
 * | ramdisk             | n pages
 * +---------------------+
 * | boot signature      | g pages
 * +---------------------+
 *
 * m = (kernel_size + 4096 - 1) / 4096
 * n = (ramdisk_size + 4096 - 1) / 4096
 * g = (signature_size + 4096 - 1) / 4096
 *
 * Note that in version 4 of the boot image header, page size is fixed at 4096
 * bytes.
 * 请注意,在版本 4 的引导映像标头中,页面大小固定为 4096 字节。
 * The structure of the vendor boot image version 4, which is required to be
 * present when a version 4 boot image is used, is as follows:
 * 供应商引导映像版本 4 的结构,在使用版本 4 引导映像时需要存在,如下所示:
 * +------------------------+
 * | vendor boot header     | o pages
 * +------------------------+
 * | vendor ramdisk section | p pages
 * +------------------------+
 * | dtb                    | q pages
 * +------------------------+
 * | vendor ramdisk table   | r pages
 * +------------------------+
 * | bootconfig             | s pages
 * +------------------------+
 *
 * o = (2128 + page_size - 1) / page_size
 * p = (vendor_ramdisk_size + page_size - 1) / page_size
 * q = (dtb_size + page_size - 1) / page_size
 * r = (vendor_ramdisk_table_size + page_size - 1) / page_size
 * s = (vendor_bootconfig_size + page_size - 1) / page_size
 *
 * Note that in version 4 of the vendor boot image, multiple vendor ramdisks can
 * be included in the vendor boot image. The bootloader can select a subset of
 * ramdisks to load at runtime. To help the bootloader select the ramdisks, each
 * ramdisk is tagged with a type tag and a set of hardware identifiers
 * describing the board, soc or platform that this ramdisk is intended for.
 *请注意,在供应商启动映像的版本 4 中,多个供应商 ramdisk 可以包含在供应商启动映像中。 
 *bootloader可以选择 ramdisks 的子集在运行时加载。 为了帮助bootloader选择 ramdisk,
 *每个 ramdisk 都标有类型标签和一组硬件标识符,用于描述该 ramdisk 适用的board、soc 或platform。
 *
 * The vendor ramdisk section is consist of multiple ramdisk images concatenated
 * one after another, and vendor_ramdisk_size is the size of the section, which
 * is the total size of all the ramdisks included in the vendor boot image.
 * ===vendor ramdisk section由多个ramdisk image依次拼接而成,vendor_ramdisk_size为该section的大小,
 * 即vendor boot image中包含的所有ramdisk的总大小。
 * 
 * The vendor ramdisk table holds the size, offset, type, name and hardware
 * identifiers of each ramdisk. The type field denotes the type of its content.
 * The vendor ramdisk names are unique. The hardware identifiers are specified
 * in the board_id field in each table entry. The board_id field is consist of a
 * vector of unsigned integer words, and the encoding scheme is defined by the
 * hardware vendor.
 * 供应商 ramdisk 表包含每个 ramdisk 的大小、偏移量、类型、名称和硬件标识符。 
 * 类型字段表示其内容的类型。供应商 ramdisk 名称是唯一的。 
 * 硬件标识符在每个表条目的 board_id 字段中指定。 
 * board_id 字段由无符号整数字向量组成,编码方案由硬件供应商定义。
 *
 * For the different type of ramdisks, there are: 对于不同类型的ramdisk,有:
 *    - VENDOR_RAMDISK_TYPE_NONE indicates the value is unspecified. 
 *    - VENDOR_RAMDISK_TYPE_NONE 表示该值未指定。
 *    - VENDOR_RAMDISK_TYPE_PLATFORM ramdisks contain platform specific bits, so
 *      the bootloader should always load these into memory.
 *  - VENDOR_RAMDISK_TYPE_PLATFORM ramdisks 包含特定于平台的位,因此引导加载程序应始终将这些位加载到内存中。
 *    - VENDOR_RAMDISK_TYPE_RECOVERY ramdisks contain recovery resources, so
 *      the bootloader should load these when booting into recovery.
 *  - VENDOR_RAMDISK_TYPE_RECOVERY ramdisks 包含recovery资源,因此引导加载程序应在引导进入recovery时加载这些资源。
 *    - VENDOR_RAMDISK_TYPE_DLKM ramdisks contain dynamic loadable kernel
 *      modules.
 *  - VENDOR_RAMDISK_TYPE_DLKM ramdisks 包含动态可加载内核模块。
 *
 * Version 4 of the vendor boot image also adds a bootconfig section to the end
 * of the image. This section contains Boot Configuration parameters known at
 * build time. The bootloader is responsible for placing this section directly
 * after the generic ramdisk, followed by the bootconfig trailer, before
 * entering the kernel.
 * 供应商引导映像的版本 4 还在映像末尾添加了一个 bootconfig 部分。
 *  此部分包含构建时已知的引导配置参数。 在进入内核之前,引导加载程序负责将此部分直接放在通用 ramdisk 之后,然后是 bootconfig trailer。
 *
 * 0. all entities in the boot image are 4096-byte aligned in flash, all
 *    entities in the vendor boot image are page_size (determined by the vendor
 *    and specified in the vendor boot image header) aligned in flash
 * 1. kernel, ramdisk, and DTB are required (size != 0)
 * 2. load the kernel and DTB at the specified physical address (kernel_addr,
 *    dtb_addr)
 * 3. load the vendor ramdisks at ramdisk_addr
 * 4. load the generic ramdisk immediately following the vendor ramdisk in
 *    memory
 * 5. load the bootconfig immediately following the generic ramdisk. Add
 *    additional bootconfig parameters followed by the bootconfig trailer.
 * 在通用 ramdisk 之后立即加载 bootconfig。 添加其他 bootconfig 参数,后跟 bootconfig 尾部。
 * 6. set up registers for kernel entry as required by your architecture
 * 7. if the platform has a second stage bootloader jump to it (must be
 *    contained outside boot and vendor boot partitions), otherwise
 *    jump to kernel_addr
 */
struct boot_img_hdr_v4 : public boot_img_hdr_v3 {
    uint32_t signature_size; /* size in bytes */
} __attribute__((packed));

struct vendor_boot_img_hdr_v4 : public vendor_boot_img_hdr_v3 {
    uint32_t vendor_ramdisk_table_size; /* size in bytes for the vendor ramdisk table */
    uint32_t vendor_ramdisk_table_entry_num; /* number of entries in the vendor ramdisk table */
    uint32_t vendor_ramdisk_table_entry_size; /* size in bytes for a vendor ramdisk table entry */
    uint32_t bootconfig_size; /* size in bytes for the bootconfig section */
} __attribute__((packed));

struct vendor_ramdisk_table_entry_v4 { //VENDOR_RAMDISK_TABLE_ENTRY_V4_SIZE = 108字节
    uint32_t ramdisk_size; /* size in bytes for the ramdisk image */
    uint32_t ramdisk_offset; /* offset to the ramdisk image in vendor ramdisk section */
    uint32_t ramdisk_type; /* type of the ramdisk */
    uint8_t ramdisk_name[VENDOR_RAMDISK_NAME_SIZE]; /* asciiz ramdisk name */

    // Hardware identifiers describing the board, soc or platform which this
    // ramdisk is intended to be loaded on.=>硬件标识符描述了该 ramdisk 打算加载到的板、soc 或平台。
    uint32_t board_id[VENDOR_RAMDISK_TABLE_ENTRY_BOARD_ID_SIZE];
} __attribute__((packed));

boot镜像的制作:

system/tools/mkbootimg/mkbootimg.py
$ dd if=/dev/urandom of=./tmp/kernel bs=4096 count=1  # 创建一个4096字节的文件,内容随机
1+0 records in
1+0 records out
4096 bytes (4.1 kB, 4.0 KiB) copied, 0.000140272 s, 29.2 MB/s
$ dd if=/dev/urandom of=./tmp/ramdisk bs=4096 count=1  # 创建一个4096字节的文件,内容随机
1+0 records in
1+0 records out
4096 bytes (4.1 kB, 4.0 KiB) copied, 0.000145439 s, 28.2 MB/s

$ mkbootimg --header_version 4 \  #版本4的header的页大小为4096字节
 --kernel ./tmp/kernel \
 --ramdisk ./tmp/ramdisk \
 --cmdline 'printk.devkmsg=on firmware_class.path=/vendor/etc/ init=/init kfence.sample_interval=500 loop.max_part=7 bootconfig' \
 --os_version 11.0.0 \
 --os_patch_level 2021-01 \
 --gki_signing_algorithm SHA256_RSA2048 \  #以下三行是boot_signature的相关参数
 --gki_signing_key ./data/testkey_rsa2048.pem \  #签名工具路径
 --gki_signing_signature_args '--prop foo:bar --prop gki:nice' \
 --output ./tmp/boot.img \
 --gki_signing_avbtool_path avbtool #avbtool的签名工具路径

$ unpack_bootimg --boot_img ./tmp/boot.img --out ./tmp/out  #解压boot.img
boot magic: ANDROID!
kernel_size: 4096
ramdisk size: 4096
os version: 11.0.0
os patch level: 2021-01
boot image header version: 4
command line args: printk.devkmsg=on firmware_class.path=/vendor/etc/ init=/init kfence.sample_interval=500 loop.max_part=7 bootconfig
boot.img signature size: 4096

$ avbtool info_image --image ./tmp/out/boot_signature #查看boot_signature的信息
Minimum libavb version:   1.0
Header Block:             256 bytes
Authentication Block:     320 bytes
Auxiliary Block:          832 bytes
Public key (sha1):        cdbb77177f731920bbe0a0f94f84d9038ae0617d
Algorithm:                SHA256_RSA2048
Rollback Index:           0
Flags:                    0
Rollback Index Location:  0
Release String:           'avbtool 1.2.0'
Descriptors:
    Hash descriptor:
      Image Size:            12288 bytes
      Hash Algorithm:        sha256
      Partition Name:        boot
      Salt:                  d00df00d
      Digest:                cf3755630856f23ab70e501900050feef30b633b3e82a9085a578617e344f9c7
      Flags:                 0
    Prop: foo -> 'bar'
    Prop: gki -> 'nice'


$ mkbootimg --header_version 4 \ # signature为空时构建
--kernel ./tmp/kernel \
--ramdisk ./tmp/ramdisk \
--cmdline 'printk.devkmsg=on firmware_class.path=/vendor/etc/ init=/init kfence.sample_interval=500 loop.max_part=7 bootconfig' \
--os_version 11.0.0 \
--os_patch_level 2021-01 \
--output ./tmp/boot.img

$ unpack_bootimg --boot_img ./tmp/boot.img --out ./tmp/out
boot magic: ANDROID!
kernel_size: 4096
ramdisk size: 4096
os version: 11.0.0
os patch level: 2021-01
boot image header version: 4
command line args: printk.devkmsg=on firmware_class.path=/vendor/etc/ init=/init kfence.sample_interval=500 loop.max_part=7 bootconfig
boot.img signature size: 0

$ ls -l tmp/out  #解压只有没有boot_signature文件
total 8
-rw-r----- 1 wxy wxy 4096 Feb 18 18:55 kernel
-rw-r----- 1 wxy wxy 4096 Feb 18 18:55 ramdisk

vendor_boot镜像:

$ dd if=/dev/urandom of=./tmp/dtb bs=4096 count=1
1+0 records in
1+0 records out
4096 bytes (4.1 kB, 4.0 KiB) copied, 0.00010651 s, 38.5 MB/s
$ dd if=/dev/urandom of=./tmp/ramdisk1 bs=4096 count=1
1+0 records in
1+0 records out
4096 bytes (4.1 kB, 4.0 KiB) copied, 0.000115653 s, 35.4 MB/s
$ dd if=/dev/urandom of=./tmp/ramdisk2 bs=8192 count=1
1+0 records in
1+0 records out
8192 bytes (8.2 kB, 8.0 KiB) copied, 0.000138211 s, 59.3 MB/s
$ dd if=/dev/urandom of=./tmp/bootconfig bs=4096 count=1
1+0 records in
1+0 records out
4096 bytes (4.1 kB, 4.0 KiB) copied, 0.000110595 s, 37.0 MB/s
$ ls -l tmp/*
-rw-r----- 1 wxy wxy 4096 Feb 18 20:26 tmp/bootconfig
-rw-r----- 1 wxy wxy 4096 Feb 18 20:24 tmp/dtb
-rw-r----- 1 wxy wxy 4096 Feb 18 20:25 tmp/ramdisk1
-rw-r----- 1 wxy wxy 8192 Feb 18 20:25 tmp/ramdisk2
$ mkbootimg --header_version 4 \
> --vendor_boot ./tmp/vendor_boot.img \
> --dtb ./tmp/dtb \
> --vendor_ramdisk ./tmp/ramdisk1 \
> --ramdisk_type 'PLATFORM' \
> --ramdisk_name 'RAMDISK1' \
> --vendor_ramdisk_fragment ./tmp/ramdisk1 \
> --ramdisk_type 'DLKM' \
> --ramdisk_name 'RAMDISK2' \
> --board_id0 '0xC0FFEE' \
> --board_id15 '0x15151515' \
> --vendor_ramdisk_fragment ./tmp/ramdisk2 \
> --vendor_cmdline 'printk.devkmsg=on firmware_class.path=/vendor/etc/ init=/init kfence.sample_interval=500 loop.max_part=7 bootconfig' \
> --vendor_bootconfig ./tmp/bootconfig
或者
$ mkbootimg --header_version 4 --vendor_boot ./tmp/vendor_boot.img --dtb ./tmp/dtb --vendor_ramdisk ./tmp/ramdisk1 --ramdisk_type 'PLATFORM' --ramdisk_name 'RAMDISK1' --vendor_ramdisk_fragment ./tmp/ramdisk1 --ramdisk_type 'DLKM' --ramdisk_name 'RAMDISK2' --board_id0 '0xC0FFEE' --board_id15 '0x15151515' --vendor_ramdisk_fragment ./tmp/ramdisk2 --vendor_cmdline 'printk.devkmsg=on firmware_class.path=/vendor/etc/ init=/init kfence.sample_interval=500 loop.max_part=7 bootconfig' --vendor_bootconfig ./tmp/bootconfig
$ ls -l tmp/*
-rw-r----- 1 wxy wxy  4096 Feb 18 20:26 tmp/bootconfig
-rw-r----- 1 wxy wxy  4096 Feb 18 20:24 tmp/dtb
-rw-r----- 1 wxy wxy  4096 Feb 18 20:25 tmp/ramdisk1
-rw-r----- 1 wxy wxy  8192 Feb 18 20:25 tmp/ramdisk2
-rw-r----- 1 wxy wxy 30720 Feb 18 20:32 tmp/vendor_boot.img #生成的vendor_boot.img镜像

$ unpack_bootimg --boot_img ./tmp/vendor_boot.img --out ./tmp/out
boot magic: VNDRBOOT
vendor boot image header version: 4
page size: 0x00000800
kernel load address: 0x10008000
ramdisk load address: 0x11000000
vendor ramdisk total size: 16384
vendor command line args: printk.devkmsg=on firmware_class.path=/vendor/etc/ init=/init kfence.sample_interval=500 loop.max_part=7 bootconfig
kernel tags load address: 0x10000100
product name:
vendor boot image header size: 2128
dtb size: 4096
dtb address: 0x0000000011f00000
vendor ramdisk table size: 324
vendor ramdisk table: [
    vendor_ramdisk00: { #--vendor_ramdisk ./tmp/ramdisk1对应的默认的第一组
        size: 4096
        offset: 0
        type: 0x1  #第一组默认为VENDOR_RAMDISK_TYPE_PLATFORM
        name: #第一组默认为''
        board_id: [ #第一组默认为None,即全零
            0x00000000, 0x00000000, 0x00000000, 0x00000000,
            0x00000000, 0x00000000, 0x00000000, 0x00000000,
            0x00000000, 0x00000000, 0x00000000, 0x00000000,
            0x00000000, 0x00000000, 0x00000000, 0x00000000,
        ]
    }
    vendor_ramdisk01: { #--ramdisk_type 'PLATFORM' --ramdisk_name 'RAMDISK1'  --vendor_ramdisk_fragment ./tmp/ramdisk1 指定的第二组

        size: 4096
        offset: 4096
        type: 0x1
        name: RAMDISK1
        board_id: [
            0x00000000, 0x00000000, 0x00000000, 0x00000000,
            0x00000000, 0x00000000, 0x00000000, 0x00000000,
            0x00000000, 0x00000000, 0x00000000, 0x00000000,
            0x00000000, 0x00000000, 0x00000000, 0x00000000,
        ]
    }
    vendor_ramdisk02: { #--ramdisk_type 'DLKM'  --ramdisk_name 'RAMDISK2'  --board_id0 '0xC0FFEE' --board_id15 '0x15151515' --vendor_ramdisk_fragment ./tmp/ramdisk2 指定的第三组

        size: 8192
        offset: 8192
        type: 0x3
        name: RAMDISK2
        board_id: [
            0x00c0ffee, 0x00000000, 0x00000000, 0x00000000,
            0x00000000, 0x00000000, 0x00000000, 0x00000000,
            0x00000000, 0x00000000, 0x00000000, 0x00000000,
            0x00000000, 0x00000000, 0x00000000, 0x15151515,
        ]
    }
]
vendor bootconfig size: 4096

$ ls -l ./tmp/out/  #解压之后的东西
total 44
-rw-r----- 1 wxy wxy  4096 Feb 18 20:35 bootconfig
-rw-r----- 1 wxy wxy  4096 Feb 18 20:35 dtb
-rw-r----- 1 wxy wxy 16384 Feb 18 20:35 vendor_ramdisk
-rw-r----- 1 wxy wxy  4096 Feb 18 20:35 vendor_ramdisk00
-rw-r----- 1 wxy wxy  4096 Feb 18 20:35 vendor_ramdisk01
-rw-r----- 1 wxy wxy  8192 Feb 18 20:35 vendor_ramdisk02
drwxr-x--- 2 wxy wxy  4096 Feb 18 20:35 vendor-ramdisk-by-name
$ tree ./tmp/out/
./tmp/out/
├── bootconfig
├── dtb
├── vendor_ramdisk
├── vendor_ramdisk00
├── vendor_ramdisk01
├── vendor_ramdisk02
└── vendor-ramdisk-by-name
    ├── ramdisk_ -> ../vendor_ramdisk00
    ├── ramdisk_RAMDISK1 -> ../vendor_ramdisk01
    └── ramdisk_RAMDISK2 -> ../vendor_ramdisk02

1 directory, 9 files

$ unpack_bootimg --boot_img ./tmp/vendor_boot.img \
> --out  ./tmp/out \
> --format=mkbootimg
--header_version 4 --pagesize 0x00000800 --base 0x00000000 --kernel_offset 0x10008000 --ramdisk_offset 0x11000000 --tags_offset 0x10000100 --dtb_offset 0x0000000011f00000 --vendor_cmdline 'printk.devkmsg=on firmware_class.path=/vendor/etc/ init=/init kfence.sample_interval=500 loop.max_part=7 bootconfig' --board '' --dtb ./tmp/out/dtb --vendor_bootconfig ./tmp/out/bootconfig --ramdisk_type 1 --ramdisk_name '' --vendor_ramdisk_fragment ./tmp/out/vendor_ramdisk00 --ramdisk_type 1 --ramdisk_name RAMDISK1 --vendor_ramdisk_fragment ./tmp/out/vendor_ramdisk01 --ramdisk_type 3 --ramdisk_name RAMDISK2 --board_id0 0x00c0ffee --board_id15 0x15151515 --vendor_ramdisk_fragment ./tmp/out/vendor_ramdisk02
wxy@siashcsitd04211:~/jieya/system-tools-mkbootimg/tests$ ls -l ./tmp/out/*
-rw-r----- 1 wxy wxy  4096 Feb 18 21:42 ./tmp/out/bootconfig
-rw-r----- 1 wxy wxy  4096 Feb 18 21:42 ./tmp/out/dtb
-rw-r----- 1 wxy wxy 16384 Feb 18 21:42 ./tmp/out/vendor_ramdisk
-rw-r----- 1 wxy wxy  4096 Feb 18 21:42 ./tmp/out/vendor_ramdisk00
-rw-r----- 1 wxy wxy  4096 Feb 18 21:42 ./tmp/out/vendor_ramdisk01
-rw-r----- 1 wxy wxy  8192 Feb 18 21:42 ./tmp/out/vendor_ramdisk02

./tmp/out/vendor-ramdisk-by-name:
total 0
lrwxrwxrwx 1 wxy wxy 19 Feb 18 21:42 ramdisk_ -> ../vendor_ramdisk00
lrwxrwxrwx 1 wxy wxy 19 Feb 18 21:42 ramdisk_RAMDISK1 -> ../vendor_ramdisk01
lrwxrwxrwx 1 wxy wxy 19 Feb 18 21:42 ramdisk_RAMDISK2 -> ../vendor_ramdisk02

boot镜像重新打包:

system/tools/mkbootimg/repack_bootimg.py

boot镜像解压:

system/tools/mkbootimg/unpack_bootimg.py