Android源码分析之boot.img的生成与结构

一、引言

前面给大家介绍过,boot.img不是普通意义上的文件镜像,而是一种特殊的Android定制格式,由文件头信息boot header,压缩的内核,文件系统数据ramdisk以及second stage loader(可选)组成,它们之间非页面对齐部分用0填充。今天来好好分析一下。

二、boot.img的生成与结构

boot.img的生成、配置

在build目录下查找boot.img,即可知道其编译规则在build/core/Makefile中,如下

# -----------------------------------------------------------------
# the boot image, which is a collection of other images.
INTERNAL_BOOTIMAGE_ARGS := \
        $(addprefix --second ,$(INSTALLED_2NDBOOTLOADER_TARGET)) \
        --kernel $(INSTALLED_KERNEL_TARGET) \
        --ramdisk $(INSTALLED_RAMDISK_TARGET)

INTERNAL_BOOTIMAGE_FILES := $(filter-out --%,$(INTERNAL_BOOTIMAGE_ARGS))

BOARD_KERNEL_CMDLINE := $(strip $(BOARD_KERNEL_CMDLINE))
ifdef BOARD_KERNEL_CMDLINE
  INTERNAL_BOOTIMAGE_ARGS += --cmdline "$(BOARD_KERNEL_CMDLINE)"
endif

BOARD_KERNEL_BASE := $(strip $(BOARD_KERNEL_BASE))
ifdef BOARD_KERNEL_BASE
  INTERNAL_BOOTIMAGE_ARGS += --base $(BOARD_KERNEL_BASE)
endif

BOARD_KERNEL_PAGESIZE := $(strip $(BOARD_KERNEL_PAGESIZE))
ifdef BOARD_KERNEL_PAGESIZE
  INTERNAL_BOOTIMAGE_ARGS += --pagesize $(BOARD_KERNEL_PAGESIZE)
endif

INSTALLED_BOOTIMAGE_TARGET := $(PRODUCT_OUT)/boot.img

ifeq ($(TARGET_BOOTIMAGE_USE_EXT2),true)
tmp_dir_for_image := $(call intermediates-dir-for,EXECUTABLES,boot_img)/bootimg
INTERNAL_BOOTIMAGE_ARGS += --tmpdir $(tmp_dir_for_image)
INTERNAL_BOOTIMAGE_ARGS += --genext2fs $(MKEXT2IMG)
$(INSTALLED_BOOTIMAGE_TARGET): $(MKEXT2IMG) $(INTERNAL_BOOTIMAGE_FILES)
        $(call pretty,"Target boot image: $@")
        $(hide) $(MKEXT2BOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) --output $@

根据

INTERNAL_BOOTIMAGE_ARGS := \
        $(addprefix --second ,$(INSTALLED_2NDBOOTLOADER_TARGET)) \
        --kernel $(INSTALLED_KERNEL_TARGET) \
        --ramdisk $(INSTALLED_RAMDISK_TARGET)

可知道,boot.img中包含了Image和ramdisk.img文件。
往下看

BOARD_KERNEL_CMDLINE := $(strip $(BOARD_KERNEL_CMDLINE))
ifdef BOARD_KERNEL_CMDLINE
  INTERNAL_BOOTIMAGE_ARGS += --cmdline "$(BOARD_KERNEL_CMDLINE)"
endif

可知道,在这里设置内核命令行(cmdline):BOARD_KERNEL_CMDLINE
在根目录下查找此变量

build/target/board/vbox_x86/BoardConfig.mk:20:BOARD_KERNEL_CMDLINE := init=/init qemu=1 console=tty0 vga=788 verbose androidboot.hardware=vbox_x86 androidboot.console=tty0 android.qemud=tty0
build/core/Makefile:404:BOARD_KERNEL_CMDLINE := $(strip $(BOARD_KERNEL_CMDLINE))
build/core/Makefile:405:ifdef BOARD_KERNEL_CMDLINE
build/core/Makefile:406:  INTERNAL_BOOTIMAGE_ARGS += --cmdline "$(BOARD_KERNEL_CMDLINE)"
build/core/Makefile:709:ifdef BOARD_KERNEL_CMDLINE
build/core/Makefile:710:  INTERNAL_RECOVERYIMAGE_ARGS += --cmdline "$(BOARD_KERNEL_CMDLINE)"
build/core/Makefile:987:    $(hide) echo $(BOARD_KERNEL_CMDLINE) > $(PRODUCT_OUT)/boot/cmdline
build/core/Makefile:1255:ifdef BOARD_KERNEL_CMDLINE
build/core/Makefile:1256:	$(hide) echo "$(BOARD_KERNEL_CMDLINE)" > $(zip_root)/RECOVERY/cmdline
build/core/Makefile:1275:ifdef BOARD_KERNEL_CMDLINE
build/core/Makefile:1276:	$(hide) echo "$(BOARD_KERNEL_CMDLINE)" > $(zip_root)/BOOT/cmdline
build/core/tasks/factory_ramdisk.mk:82:ifneq (,$(BOARD_KERNEL_CMDLINE_FACTORY_BOOT))
build/core/tasks/factory_ramdisk.mk:83:  RAMDISK_CMDLINE := --cmdline "$(BOARD_KERNEL_CMDLINE_FACTORY_BOOT)"
build/core/product.mk:238:	BOARD_KERNEL_CMDLINE \

很明显,此变量在"build/target/board/vbox_x86/BoardConfig.mk"中设置
将此文件中的此变量console修改为我们用的串口、波特率,修改完编译后,console即可成功启动。

往下

BOARD_KERNEL_BASE := $(strip $(BOARD_KERNEL_BASE))
ifdef BOARD_KERNEL_BASE
  INTERNAL_BOOTIMAGE_ARGS += --base $(BOARD_KERNEL_BASE)
endif

此处设置内核加载的基地址,BOARD_KERNEL_BASE
同上,在源码中查找此变量即可找到并修改kernel加载的基地址

往下

BOARD_KERNEL_PAGESIZE := $(strip $(BOARD_KERNEL_PAGESIZE))
ifdef BOARD_KERNEL_PAGESIZE
  INTERNAL_BOOTIMAGE_ARGS += --pagesize $(BOARD_KERNEL_PAGESIZE)
endif

此处设置映像的页面大小:BOARD_KERNEL_PAGESIZE

此时,剩下的代码就是生成boot.img的语句:

INSTALLED_BOOTIMAGE_TARGET := $(PRODUCT_OUT)/boot.img

ifeq ($(TARGET_BOOTIMAGE_USE_EXT2),true)
tmp_dir_for_image := $(call intermediates-dir-for,EXECUTABLES,boot_img)/bootimg
INTERNAL_BOOTIMAGE_ARGS += --tmpdir $(tmp_dir_for_image)
INTERNAL_BOOTIMAGE_ARGS += --genext2fs $(MKEXT2IMG)
$(INSTALLED_BOOTIMAGE_TARGET): $(MKEXT2IMG) $(INTERNAL_BOOTIMAGE_FILES)
        $(call pretty,"Target boot image: $@")
        $(hide) $(MKEXT2BOOTIMG) $(INTERNAL_BOOTIMAGE_ARGS) --output $@

到此,我们可以知道 INTERNAL_BOOTIMAGE_ARGS的内容是:

–kernel out/target/product/xxx(产品名称目录)/kernel
–ramdisk out/target/product/xxx(产品名称目录)/ramdisk.img
–cmdline console=ttyx,115200n8(实际设置的串口、波特率)
–base 0x40000000 --pagesize 8192(设置的页大小)

boot.img的结构

了解boot.img的格式,必须查看MKBOOTIMG这个程序,其实就是out/host/linux-x86/bin/mkbootimg中的mkbootimg程序。
mkbootimg程序由system/core/mkbootimg工程生成得到,为此我们来看看其中的mkbootimg.c文件:

    if(write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto fail;
    if(write_padding(fd, pagesize, sizeof(hdr))) goto fail;

    if(write(fd, kernel_data, hdr.kernel_size) != hdr.kernel_size) goto fail;
    if(write_padding(fd, pagesize, hdr.kernel_size)) goto fail;

    if(write(fd, ramdisk_data, hdr.ramdisk_size) != hdr.ramdisk_size) goto fail;
    if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail;

    if(second_data) {
        if(write(fd, second_data, hdr.second_size) != hdr.second_size) goto fail;
        if(write_padding(fd, pagesize, hdr.second_size)) goto fail;
        }

可知boot.img将信息头、内核、ramdisk以及second stage loader的可选选项组合到了一起,我们也可以修改上述代码来改变boot.img的机构。

发布了13 篇原创文章 · 获赞 8 · 访问量 5668

猜你喜欢

转载自blog.csdn.net/weixin_38019025/article/details/103989141