Android培训班(98)内核解压过程11
从前面那段代码,就可以看到调用decompress_kernel函数来把内核压缩的代码解压出来,那么你也许问传给解压函数decompress_kernel的四个参数是什么呢?由于ARM里编译时就决定这四个参数是使用四个寄存器来传送,分别为r0,r1,r2,r3等四个寄存器。因此,只需要搞清楚这四个寄存器是什么样的内容,就知道传送给函数什么值了。从代码上看到r0的值与r2、r5的值一样,都是指向栈后面64K的位置。r1是指向栈的开始位置。r3是等于r7的值,由于r7里保存着内核的架构ID,因此r3就是CPU的架构ID。这样这四个参数就传送给下面的函数调用:
ulg
decompress_kernel(ulgoutput_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p,
int arch_id)
{
output_data =(uch *)output_start; /* Points to kernel 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();
makecrc();
putstr("UncompressingLinux...");
gunzip();
putstr("done, booting the kernel.\n");
returnoutput_ptr;
}
在函数decompress_kernel里,就获取得解压后数据输出位置,以及临时的内存开始位置和结束位置,同时得到CPU的架构ID。再把输出位置给全局变量output_data,以便解压函数把数据写到里面。
arch_decomp_setup函数在这里没有任何需要初始化的代码。
makecrc函数是计算内核压缩代码的CRC码表,达到检验代码是否正确的目的。
gunzip函数是进行所有数据解压的操作。
最后在函数返回解压后代码数据结束位置,以便后面的代码进行重定位的操作。
在整个函数没有看到压缩的代码数据从那里输入,以及需要解压数据的长度,到底在那里呢?其实这需要从编译内核时就需要了解,如果还不懂赶紧看看前面的文章了。会在下面函数fill_inbuf里获取解压的数据:
intfill_inbuf(void)
{
if(insize != 0)
error("ranout of input data");
inbuf= input_data;
insize= &input_data_end[0] - &input_data[0];
inptr= 1;
returninbuf[0];
}
看到函数里的input_data和input_data_end,应很眼熟吧,其实它们就是编译时在文件piggy.S汇编文件里,通过这两个指针,就可以得到数据的开始位置和结束位置,从而计算出来要压缩后的数据长度。
通过在gunzip函数解压代码,就可以把压缩的内核变换为可执行的代码,这时代码就全部解压到内存里,能否立即跳到那里执行吗?这个要看输入的解压的地址,如果是内核实际执行位置,就可以直接运行,如果不是,又需要重定位了。