4.1.2 解压缩内核
解压缩内核使用的是decompress_kernel函数,来自arch/x86/boot/compressed/misc.c:
301asmlinkage void decompress_kernel(void *rmode, memptr heap, 302 unsigned char *input_data, 303 unsigned long input_len, 304 unsigned char *output) 305{ 306 real_mode = rmode; 307 308 if (real_mode->hdr.loadflags & QUIET_FLAG) 309 quiet = 1; 310 311 if (real_mode->screen_info.orig_video_mode == 7) { 312 vidmem = (char *) 0xb0000; 313 vidport = 0x3b4; 314 } else { 315 vidmem = (char *) 0xb8000; 316 vidport = 0x3d4; 317 } 318 319 lines = real_mode->screen_info.orig_video_lines; 320 cols = real_mode->screen_info.orig_video_cols; 321 322 free_mem_ptr = heap; /* Heap */ 323 free_mem_end_ptr = heap + BOOT_HEAP_SIZE; 324 325 if ((unsigned long)output & (MIN_KERNEL_ALIGN - 1)) 326 error("Destination address inappropriately aligned"); 327#ifdef CONFIG_X86_64 328 if (heap > 0x3fffffffffffUL) 329 error("Destination address too large"); 330#else 331 if (heap > ((-__PAGE_OFFSET-(512<<20)-1) & 0x7fffffff)) 332 error("Destination address too large"); 333#endif 334#ifndef CONFIG_RELOCATABLE 335 if ((unsigned long)output != LOAD_PHYSICAL_ADDR) 336 error("Wrong destination address"); 337#endif 338 339 if (!quiet) 340 putstr("/nDecompressing Linux... "); 341 decompress(input_data, input_len, NULL, NULL, output, NULL, error); 342 parse_elf(output); 343 if (!quiet) 344 putstr("done./nBooting the kernel./n"); 345 return; 346} |
看到他的参数,共有5个,是刚才依次压栈而得到的。第一个是压入的output(还记得吧,倒着来的),在刚才的131行看到的,来自z_extract_offset_negative,用于作为解压缩的缓存首地址;第二个,input_len,其值等于z_input_len,表示待压缩内核大小;第三个,input_data,来自input_data,表示待压缩内核地址;第四个参数,heap,32位下是32位,来自boot_heap,表示解压缩阶段的堆;最后一个参数,rmode,来自我们刚才用到的esi寄存器,表示刚才拷贝之前内核映像地址。
假设我配置的是CONFIG_KERNEL_BZIP2,那么会调用顶层lib/decompress_bunzip2.c中的decompress函数,最终会调用位于同一文件的bunzip2函数(注意,在我们制作bzImage的时候使用的压缩程序只有一个,如果指定的bunzip2,那么都在decompress_bunzip2.c里):
674/* Example usage: decompress src_fd to dst_fd. (Stops at end of bzip2 data, 675 not end of file.) */ 676STATIC int INIT bunzip2(unsigned char *buf, int len, 677 int(*fill)(void*, unsigned int), 678 int(*flush)(void*, unsigned int), 679 unsigned char *outbuf, 680 int *pos, 681 void(*error_fn)(char *x)) 682{ 683 struct bunzip_data *bd; 684 int i = -1; 685 unsigned char *inbuf; 686 687 set_error_fn(error_fn); 688 if (flush) 689 outbuf = malloc(BZIP2_IOBUF_SIZE); 690 691 if (!outbuf) { 692 error("Could not allocate output bufer"); 693 return RETVAL_OUT_OF_MEMORY; 694 } 695 if (buf) 696 inbuf = buf; 697 else 698 inbuf = malloc(BZIP2_IOBUF_SIZE); 699 if (!inbuf) { 700 error("Could not allocate input bufer"); 701 i = RETVAL_OUT_OF_MEMORY; 702 goto exit_0; 703 } 704 i = start_bunzip(&bd, inbuf, len, fill); 705 if (!i) { 706 for (;;) { 707 i = read_bunzip(bd, outbuf, BZIP2_IOBUF_SIZE); 70 |