bootloader阶段会从boot/recovery分区中读取kernel/ramdisk到ram上,然后引导kernel,
加载虚拟文件系统ramdisk,启动init,然后读取rom中的文件系统的内容。
组成
分析其header可以知道boot.img的组织结构如下:
struct boot_img_hdr_v0 {
uint8_t magic[BOOT_MAGIC_SIZE];
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 */
uint32_t page_size; /* flash page size we assume */
/*
* version for the boot image header.
*/
uint32_t header_version;
/* operating system version and security patch level; for
* version "A.B.C" and patch level "Y-M-D":
* ver = A << 14 | B << 7 | C (7 bits for each of A, B, C)
* lvl = ((Y - 2000) & 127) << 4 | M (7 bits for Y, 4 bits for M)
* os_version = ver << 11 | lvl */
uint32_t os_version;
uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */
uint8_t cmdline[BOOT_ARGS_SIZE];
uint32_t id[8]; /* timestamp / checksum / sha1 / etc */
/* Supplemental command line data; kept here to maintain
* binary compatibility with older versions of mkbootimg */
uint8_t extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
} __attribute__((packed));
看下各个部分大小计算方式:
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
* 1. kernel and ramdisk are required (size != 0)
* 2. second is optional (second_size == 0 -> no second)
* 3. load each element (kernel, ramdisk, second) at
* the specified physical address (kernel_addr, etc)
* 4. prepare tags at tag_addr. kernel_args[] is
* appended to the kernel commandline in the tags.
* 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
* 6. if second_size != 0: jump to second_addr
* else: jump to kernel_addr
*/
当然了还有一个叫boot_img_hdr_v1,是在v0后追加了一个recovery dtbo 的section,这个东东是给没有A/B slot的设备上recovery时需要用的。
struct boot_img_hdr_v1 : public boot_img_hdr_v0 {
uint32_t recovery_dtbo_size; /* size in bytes for recovery DTBO image */
uint64_t recovery_dtbo_offset; /* offset to recovery dtbo in boot image */
uint32_t header_size;
} __attribute__((packed));
bootloader会从boot header得到kernel/ramdisk/second/device的大小和要加载到ram上的地址,读取aboot/recovery分区的内容到ram。当我们使用fastboot刷分区时候会执行,以高通为例。
(注:下面为例方便贴至一处,不以实际为准),
static unsigned page_size = 2048;
static unsigned base_addr = 0x10000000;
static unsigned kernel_offset = 0x00008000;
static unsigned ramdisk_offset = 0x01000000;
static unsigned second_offset = 0x00f00000;
static unsigned tags_offset = 0x00000100;
boot_img_hdr_v1* mkbootimg(void* kernel, int64_t kernel_size, off_t kernel_offset, void* ramdisk,
int64_t ramdisk_size, off_t ramdisk_offset, void* second,
int64_t second_size, off_t second_offset, size_t page_size, size_t base,
off_t tags_offset, uint32_t header_version, int64_t* bootimg_size) {
size_t page_mask = page_size - 1;
int64_t header_actual = (sizeof(boot_img_hdr_v1) + page_mask) & (~page_mask);
int64_t kernel_actual = (kernel_size + page_mask) & (~page_mask);
int64_t ramdisk_actual = (ramdisk_size + page_mask) & (~page_mask);
int64_t second_actual = (second_size + page_mask) & (~page_mask);
*bootimg_size = header_actual + kernel_actual + ramdisk_actual + second_actual;
boot_img_hdr_v1* hdr = reinterpret_cast<boot_img_hdr_v1*>(calloc(*bootimg_size, 1));
if (hdr == nullptr) {
return hdr;
}
memcpy(hdr->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
hdr->kernel_size = kernel_size;
hdr->ramdisk_size = ramdisk_size;
hdr->second_size = second_size;
hdr->kernel_addr = base + kernel_offset;
hdr->ramdisk_addr = base + ramdisk_offset;
hdr->second_addr = base + second_offset;
hdr->tags_addr = base + tags_offset;
hdr->page_size = page_size;
if (header_version) {
hdr->header_version = header_version;
hdr->header_size = sizeof(boot_img_hdr_v1);
}
memcpy(hdr->magic + page_size, kernel, kernel_size);
memcpy(hdr->magic + page_size + kernel_actual, ramdisk, ramdisk_size);
memcpy(hdr->magic + page_size + kernel_actual + ramdisk_actual, second, second_size);
return hdr;
}