我是靠谱客的博主 贪玩小懒虫,最近开发中收集的这篇文章主要介绍linux运行startup,Linux Kernel 2.6.37 启动过程:startup_32,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

#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所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(67)

评论列表共有 0 条评论

立即
投稿
返回
顶部