The generation and structure of boot.img in Android source code analysis

I. Introduction

As I mentioned earlier, boot.img is not a common file image, but a special Android custom format. It consists of the file header information boot header, compressed kernel, file system data ramdisk and second stage loader (optional). The non page alignment part between them is filled with 0. Let's have a good analysis today.

2, The generation and structure of boot.img

Generation and configuration of boot.img

Find boot.img in the build directory, and you will know that its compilation rules are in build/core/Makefile, as follows

# -----------------------------------------------------------------
# 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 $@

according to

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

As you can see, boot.img contains Image and ramdisk.img files.
Look down

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

As you can see, set the kernel command line here: board? Kernel? CmdLine
Find this variable in the root directory

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 \

Obviously, this variable is set in "build/target/board/vbox_x86/BoardConfig.mk"
Change the console variable in this file to the serial port and baud rate we use. After compiling, the console will start successfully.

down

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

Here, set the base address of kernel loading, board? Kernel? Base
As above, you can find and modify the base address of kernel loading by searching this variable in the source code

down

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

Set the page size of the image here: board? Kernel? PageSize

At this point, the rest of the code is to generate the boot.img statement:

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 $@

At this point, we can know that the contents of the internal image arts are:

– kernel out / target / product / xxx (product name directory) / kernel
– ramdisk out / target / product / xxx (product name directory) / ramdisk.img
– CmdLine console = ttyx, 115200n8 (actual set serial port, baud rate)
– base 0x40000000 --pagesize 8192 (set page size)

The structure of boot.img

To understand the format of boot.img, you must check mkbootimg, which is actually the mkbootimg program in out/host/linux-x86/bin/mkbootimg.
The mkbootimg program is generated by the system/core/mkbootimg project, so let's look at the mkbootimg.c file:

    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;
        }

We can see that boot.img combines the options of header, kernel, ramdisk and second stage loader. We can also modify the above code to change the mechanism of boot.img.

Published 13 original articles, won praise 8, visited 5626
Private letter follow

Tags: Makefile Android REST Linux

Posted on Wed, 15 Jan 2020 03:11:11 -0500 by John Rowe