作者:opera 概述 ---- 1) Linux的初始内核映象以gzip压缩文件的格式存放在zImage或bzImage之中, 内核的自举 代码将它解压到1M内存开始处. 在内核初始化时, 如果加载了压缩的initrd映象, 内核会将解压到内存盘中, 这两处解压过程都使用了lib/inflate.c文件. 2) inflate.c是从gzip源程序中分离出来的, 包含了一些对全局数据的直接引用, 在使用时 需要直接嵌入到代码中. gzip压缩文件时总是在前32K字节的范围内寻找重复的字符串进行 编码, 在解压时需要一个至少为32K字节的解压缓冲区, 它定义为window[WSIZE]. inflate.c使用get_byte()读取输入文件, 它被定义成宏来提高效率. 输入缓冲区指针必须 定义为inptr, inflate.c中对之有减量操作. inflate.c调用flush_window()来输出window 缓冲区中的解压出的字节串, 每次输出长度用outcnt变量表示. 在flush_window()中, 还必 须对输出字节串计算CRC并且刷新crc变量. 在调用gunzip()开始解压之前, 调用makecrc() 初始化CRC计算表. 最后gunzip()返回0表示解压成功. 3) zImage或bzImage由16位引导代码和32位内核自解压映象两个部分组成. 对于zImage, 内 核自解压映象被加载到物理地址0x1000, 内核被解压到1M的部位. 对于bzImage, 内核自解 压映象被加载到1M开始的地方, 内核被解压为两个片段, 一个起始于物理地址0x2000-0x90000, 另一个起始于高端解压映象之后, 离1M开始处不小于低端片段最大长度的区域. 解压完成后, 这两个片段被合并到1M的起始位置. 解压根内存盘映象文件的代码 -------------------------- 代码: ; drivers/block/rd.c #ifdef BUILD_CRAMDISK /* * gzip declarations */ #define OF(args) args ; 用于函数原型声明的宏 #ifndef memzero #define memzero(s, n) memset ((s), 0, (n)) #endif typedef unsigned char UCh; 定义inflate.c所使用的3种数据类型 typedef unsigned short ush; typedef unsigned long ulg; #define INBUFSIZ 4096 用户输入缓冲区尺寸 #define WSIZE 0x8000 /* window size--must be a power of two, and */ /* at least 32K for zip's deflate method */ static uch *inbuf; 用户输入缓冲区,与inflate.c无关 static uch *window; 解压窗口 static unsigned insize; /* valid bytes in inbuf */ static unsigned inptr; /* index of next byte to be processed in inbuf */ static unsigned outcnt; /* bytes in output buffer */ static int exit_code; static long bytes_out; 总解压输出长度,与inflate.c无关 static struct file *crd_infp, *crd_outfp; #define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) 读取输入缓冲区中一个字节 /* Diagnostic functions (stubbed out) */ 一些调试宏 #define Assert(cond,msg) #define Trace(x) #define Tracev(x) #define Tracevv(x) #define Tracec(c,x) #define Tracecv(c,x) #define STATIC static static int fill_inbuf(void); static void flush_window(void); static void *malloc(int size); static void free(void *where); static void error(char *m); static void gzip_mark(void **); static void gzip_release(void **); #include "../../lib/inflate.c" static void __init *malloc(int size) { return kmalloc(size, GFP_KERNEL); } static void __init free(void *where) { kfree(where); } static void __init gzip_mark(void **ptr) { ; 读取用户一个标记 } static void __init gzip_release(void **ptr) { ; 归还用户标记 } /* =========================================================================== * Fill the input buffer. This is called only when the buffer is empty * and at least one byte is really needed. */ static int __init fill_inbuf(void) 填充输入缓冲区 { if (exit_code) return -1; insize = crd_infp->f_op->read(crd_infp, inbuf, INBUFSIZ, &crd_infp->f_pos); if (insize == 0) return -1; inptr = 1; return inbuf[0]; } /* =========================================================================== * Write the output window window[0..outcnt-1] and update crc and bytes_out. * (Used for the decompressed data only.) */ static void __init flush_window(void) 输出window缓冲区中outcnt个字节串 { ulg c = crc; /* temporary variable */ unsigned n; uch *in, ch; crd_outfp->f_op->write(crd_outfp, window, outcnt, &crd_outfp->f_pos); in = window; for (n = 0; n < outcnt; n++) { ch = *in++; c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); 计算输出串的CRC } crc = c; bytes_out += (ulg)outcnt; 刷新总字节数 outcnt = 0; } static void __init error(char *x) 解压出错调用的函数 { printk(KERN_ERR "%s", x); exit_code = 1; } static int __init crd_load(struct file * fp, struct file *outfp) { int result; insize = 0; /* valid bytes in inbuf */ inptr = 0; /* index of next byte to be processed in inbuf */ outcnt = 0; /* bytes in output buffer */ exit_code = 0; bytes_out = 0; crc = (ulg)0xffffffffL; /* shift register contents */ crd_infp = fp; crd_outfp = outfp; inbuf = kmalloc(INBUFSIZ, GFP_KERNEL); if (inbuf == 0) { printk(KERN_ERR "RAMDISK: Couldn't allocate gzip buffer\n"); return -1; } window = kmalloc(WSIZE, GFP_KERNEL); if (window == 0) { printk(KERN_ERR "RAMDISK: Couldn't allocate gzip window\n"); kfree(inbuf); return -1; } makecrc(); result = gunzip(); kfree(inbuf); kfree(window); return result; } #endif /* BUILD_CRAMDISK */ 32位内核自解压代码 ------------------ ; arch/i386/boot/compressed/head.S .text #include #include .globl startup_32 对于zImage该入口地址为0x1000; 对于bzImage为0x101000 startup_32: cld cli movl $(__KERNEL_DS),%eax movl %eax,%ds movl %eax,%es movl %eax,%fs movl %eax,%gs lss SYMBOL_NAME(stack_start),%esp # 自解压代码的堆栈为misc.c中定义的16K字节的数组 xorl %eax,%eax 1: incl %eax # check that A20 really IS enabled movl %eax,0x000000 # loop forever if it isn't cmpl %eax,0x100000 je 1b /* * Initialize eflags. Some BIOS's leave bits like NT set. This would * confuse the debugger if this code is traced. * XXX - best to initialize before switching to protected mode. */ pushl $0 popfl /* * Clear BSS 清除解压程序的BSS段 */ xorl %eax,%eax movl $ SYMBOL_NAME(_edata),%edi movl $ SYMBOL_NAME(_end),%ecx subl %edi,%ecx cld rep stosb /* * Do the decompression, and jump to the new kernel.. */ subl $16,%esp # place for structure on the stack movl %esp,%eax pushl %esi # real mode pointer as second arg pushl %eax # address of structure as first arg call SYMBOL_NAME(decompress_kernel) orl %eax,%eax # 如果返回非零,则表示为内核解压为低端和高端的两个片断 jnz 3f popl %esi # discard address popl %esi # real mode pointer xorl %ebx,%ebx ljmp $(__KERNEL_CS), $0x100000 # 运行start_kernel /* * We come here, if we were loaded high.
[1] [2] 下一页
(出处:http://www.sheup.com)
上一页 [1] [2]