概述
#include
#include
#include
#include
#include
#include
__HEAD
ENTRY(startup_32)
cld
/*
* Test KEEP_SEGMENTS flag to see if the bootloader is asking
* us to not reload segments. BP_loadflags(%esi)即指向boot_params.loadflags.这一位应该是在设置了code32_start Hook的时候使用,因为在protected_mode_jump的最后已经将所有的段都置为_BOOT_DS了。如果bootloader hook了code32_start,返回kernel的时候显然kernel需要去恢复所有的段。
*/
testb$(1<<6), BP_loadflags(%esi)
jnz1f
cli
movl$__BOOT_DS, %eax
movl%eax, %ds
movl%eax, %es
movl%eax, %fs
movl%eax, %gs
movl%eax, %ss
1:
/*
* Calculate the delta between where we were compiled to run
* at and where we were actually loaded at. This can only be done
* with a short local call on x86. Nothing else will tell us what
* address we are running at. The reserved chunk of the real-mode
* data at 0x1e4 (defined as a scratch field) are used as the stack
* for this calculation. Only 4 bytes are needed.
*/
//仔细阅读了以上的这段英文,不能不说代码构思的巧妙。由于不知道代码是否被加载到0x100000的地址,通过以下的代码就能计算出实际加载的地址和预期地址的差异,也就是说是实际的startup_32的位置。
leal(BP_scratch+4)(%esi), %esp //boot_params.scratch的地址设置成为堆栈顶。
call1f //boot_params.scratch里面就是1:的实际地址
1:popl%ebp //ebp就是1:的实际地址
subl$1b, %ebp //ebp-1:就是实际与预期的差异, 也就是说是实际的startup_32的位置。
/*
* %ebp contains the address we are loaded at by the boot loader and %ebx
* contains the address where we should move the kernel image temporarily
* for safe in-place decompression.
*/
#ifdef CONFIG_RELOCATABLE
movl%ebp, %ebx
//kernel_alignment里面是kernel地址对齐所需要移动的位移量,这是有bootloader填入的,因为bootloader可能将startup_32装载在非对齐的地址。那么就需要增加移动的位移量来保证对齐而达到更好的性能。下面的代码就是要调整地址的位移而保证对齐。
movlBP_kernel_alignment(%esi), %eax
decl%eax
addl %eax, %ebx
notl%eax
andl %eax, %ebx
#else
movl$LOAD_PHYSICAL_ADDR, %ebx //LOAD_PHYSICAL_ADDR在 arch/x86/include/asm/boot.h里.实际上应该是0x100000
#endif
/* Target address to relocate to for decompression */
addl$z_extract_offset, %ebx//z_extract_offset由MKpiggy.c 在编译时产生的piggy.S里面定义。在我编译kernel时,z_extract_offset是0x4a0000,现在ebx的值在不考虑reloc的情况下是0x5a0000
/* Set up the stack */
lealboot_stack_end(%ebx), %esp //在0x5a0000+boot_stack_end的位置建立栈。
/* Zero EFLAGS */
pushl$0
popfl
/*
* Copy the compressed kernel to the end of our buffer
* where decompression in place becomes safe.
*/
pushl%esi
leal(_bss-4)(%ebp), %esi//esi指向源,即ebp+_bss-4的地址,是当前bootloader加载32位kernel的地址空间
leal(_bss-4)(%ebx), %edi //edi指向目的地址,即ebx+_bss-4的地址,如果kernel不要reloc,就是0x5a0000+_bss-4
movl$(_bss - startup_32), %ecx //从startup_32d到_bss有多少个字节?
shrl$2, %ecx //实际我们移动每次4个字节,所以ecx需要除4.
std
repmovsl //走咯,我们把自己移动上去
cld
popl%esi
/*
* Jump to the relocated address.
*/
lealrelocated(%ebx), %eax
jmp*%eax //跳转到relocated上去即ebx+relocated,即0x5a0000+relocated.
ENDPROC(startup_32)
.text
relocated:
/*
* Clear BSS (stack is currently empty)
*/
xorl%eax, %eax
leal_bss(%ebx), %edi
leal_ebss(%ebx), %ecx
subl%edi, %ecx
shrl$2, %ecx
repstosl
/*
* Adjust our own GOT GOT是什么?难道是Global Object Table?为什么GOT里面的每一个项都加上了ebx(0x5a0000)?难道里面是一堆指针需要调整所以加上ebx?
*/
leal_got(%ebx), %edx
leal_egot(%ebx), %ecx
1:
cmpl%ecx, %edx
jae2f
addl%ebx, (%edx)
addl$4, %edx
jmp1b
2:
/*
* Do the decompression, and jump to the new kernel..
*/
lealz_extract_offset_negative(%ebx), %ebp //ebp=ebx-0x4a0000=0x100000
/* push arguments for decompress_kernel: */
pushl%ebp /* output address */ //将Kernel解压缩到0x100000
pushl$z_input_len/* input_len */ //压缩过的kernel大小
lealinput_data(%ebx), %eax //压缩kernel开始地址
pushl%eax /* input_data */
lealboot_heap(%ebx), %eax//工作的堆
pushl%eax /* heap area */
pushl%esi /* real mode pointer *///esi是boot_params
calldecompress_kernel //我不准备去看怎么解压,只要知道它解压了好了
addl$20, %esp //看来不需要恢复寄存器
#if CONFIG_RELOCATABLE
/*
* Find the address of the relocations.
*/
lealz_output_len(%ebp), %edi
/*
* Calculate the delta between where vmlinux was compiled to run
* and where it was actually loaded.
*/
movl%ebp, %ebx
subl$LOAD_PHYSICAL_ADDR, %ebx
jz2f/* Nothing to be done if loaded at compiled addr. */ //如果ebx=0x100000,则不许要reloc
/*
* Process relocations. //这段没懂,但应该不影响理解
*/
1:subl$4, %edi
movl(%edi), %ecx
testl%ecx, %ecx
jz2f
addl%ebx, -__PAGE_OFFSET(%ebx, %ecx)
jmp1b
2:
#endif
/*
* Jump to the decompressed kernel.
*/
xorl%ebx, %ebx
jmp*%ebp //重新跳到0x100000开始。
/*
* Stack and heap for uncompression
*/
.bss
.balign 4
boot_heap:
.fill BOOT_HEAP_SIZE, 1, 0
boot_stack:
.fill BOOT_STACK_SIZE, 1, 0
boot_stack_end:
最后
以上就是贪玩小懒虫为你收集整理的linux运行startup,Linux Kernel 2.6.37 启动过程:startup_32的全部内容,希望文章能够帮你解决linux运行startup,Linux Kernel 2.6.37 启动过程:startup_32所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复