关键词:Image,zImage,piggy,gzip,lzo,xz,lzma等等。
1. zImage的压缩
zImage是Image经过压缩后,加上解压缩头后生成的文件:Image -> piggy_data -> piggy.o ->vmlinux(compressed) -> zImage。
Image经过压缩生成piggy_data:
cmd_arch/arm/boot/compressed/piggy_data := { cat arch/arm/boot/compressed/../Image | lzop -9; printf \\070\\266\\126\\000; } > arch/arm/boot/compressed/piggy_data
piggy.o包含了piggy_data数据:
/* SPDX-License-Identifier: GPL-2.0 */ .section .piggydata,#alloc .globl input_data input_data: .incbin "arch/arm/boot/compressed/piggy_data" .globl input_data_end input_data_end:
cpmpressed/vmlinux包含了piggy.o:
cmd_arch/arm/boot/compressed/vmlinux := arm-none-linux-gnueabihf-ld -EL --defsym _kernel_bss_size=100900 --no-undefined -X
-T arch/arm/boot/compressed/vmlinux.lds
arch/arm/boot/compressed/head.o
arch/arm/boot/compressed/piggy.o
arch/arm/boot/compressed/misc.o
arch/arm/boot/compressed/decompress.o
arch/arm/boot/compressed/string.o
arch/arm/boot/compressed/hyp-stub.o
arch/arm/boot/compressed/lib1funcs.o
arch/arm/boot/compressed/ashldi3.o
arch/arm/boot/compressed/bswapsdi2.o
-o arch/arm/boot/compressed/vmlinux
从compressed/vmlinux.lds可以看出piggydata段放在rodata之后:
OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS { /DISCARD/ : { *(.ARM.exidx*) *(.ARM.extab*) *(.data) } . = 0; _text = .; .text : { _start = .; *(.start) *(.text) *(.text.*) *(.fixup) *(.gnu.warning) *(.glue_7t) *(.glue_7) } .table : ALIGN(4) { _table_start = .; LONG((2)) LONG((0x5a534c4b)) LONG((__piggy_size_addr - _start)) LONG((_kernel_bss_size)) LONG(0) _table_end = .; } .rodata : { *(.rodata) *(.rodata.*) *(.data.rel.ro) } .piggydata : { *(.piggydata) __piggy_size_addr = . - 4; } . = ALIGN(4); _etext = .; .got.plt : { *(.got.plt) } _got_start = .; .got : { *(.got) } _got_end = .; .pad : { BYTE(0); . = ALIGN(8); } _edata = .; .image_end (NOLOAD) : { _edata_real = .; } _magic_sig = (0x016f2818); _magic_start = (_start); _magic_end = (_edata); _magic_table = (_table_start - _start); . = ALIGN(8); __bss_start = .; .bss : { *(.bss) } _end = .; . = ALIGN(8); .stack : { *(.stack) } ... } ASSERT(_edata_real == _edata, "error: zImage file size is incorrect");
从compressed/vmlinux中拷贝zImage:
cmd_arch/arm/boot/zImage := arm-none-linux-gnueabihf-objcopy -O binary -R .comment -S arch/arm/boot/compressed/vmlinux arch/arm/boot/zImage
2. zImage的解压
由compressed/vmlinux.lds可知,zImage启动从arch/arm/boot/compressed/head.S中start开始:
start
->__hyp_stub_install
->not_angel
->restart ->wont_overwrite ->not_relocated--清空bss段,并配置好C执行环境。r0-kernel输出起始地址;r1/r2-分配内存的其实和结束地址;r3-架构类型ID。 ->decompress_kernel--对内核进行解压。 ->arch_decomp_setup ->do_decompress ->__decompress ->unlzo--调用对应的解压缩算法进行解压。 ->cache_clean_flush--刷新并清空cache。 ->cache_off--关闭cache。 ->__enter_kernel--准备好寄存器跳转到解压后的内核。
decompress_kernel是解压Image入口:
- output_start是指向zImage起始地址+TEXT_OFFSET的地址,对于0x80000000来说即为0x80008000。
- free_mem_ptr_p和free_mem_ptr_end_p指向分配的一段64KB空间起始和结束地址,给compressed中malloc/free使用。
- arch_id为架构ID,此为0x80004000。
void decompress_kernel(unsigned long output_start, unsigned long free_mem_ptr_p, unsigned long free_mem_ptr_end_p, int arch_id) { int ret; output_data = (unsigned char *)output_start; free_mem_ptr = free_mem_ptr_p; free_mem_end_ptr = free_mem_ptr_end_p; __machine_arch_type = arch_id; arch_decomp_setup(); putstr("Uncompressing Linux..."); ret = do_decompress(input_data, input_data_end - input_data, output_data, error);--input_data和input_data_end实在piggy.S中定义的piggy_data起始和结束地址。此处将piggy_data解压到TEXT_OFFSET之下那个的地方。 if (ret) error("decompressor returned an error"); else putstr(" done, booting the kernel.\n"); }
__enter_kernel未进入内核做准备,然后跳转到解压结果首地址。
r0为0,;r1架构编号;r2位atags指针。r4保存解压后内核跳转地址,最后跳转到解压后的内核。
__enter_kernel: mov r0, #0 @ must be 0 mov r1, r7 @ restore architecture number mov r2, r8 @ restore atags pointer ARM( mov pc, r4 ) @ call kernel M_CLASS( add r4, r4, #1 ) @ enter in Thumb mode for M class THUMB( bx r4 ) @ entry point is always ARM for A/R classes
3. 不同算法性能对比
在一FPGA环境下测试不同解压算法的耗时:
解压类型 | Gzip | LZMA | XZ | LZO | LZ4 |
镜像大小 | Image 17966904 zImage 7320936 |
Image 17966904 zImage 5037832 |
Image 17966904 zImage 4883408 |
Image 17966904 zImage 79859524 |
Image 17966904 zImage 8538088 |
耗时(秒) | 188 | 1812 | 1146 | 56 | 142 |