Compressed 'head.S'
Why do we do this? Don’t ask me.. Incomprehensible are the ways of bootloaders.
— comments in arch/i386/boot/compressed/misc.c
There are two ‘head.S’ in linux source package. One is in $(Linux-2.6.15.3_dir/arch/i386/boot/compressed and the other one is in $(Linux-2.6.15.3_dir/arch/i386/kernel. The first one will be analyzed in this artical. Before we go ahead, let’s show a news of linux, that is ‘Army leans toward Linux for FCS(Future Combat System)’.
The first ‘head.S’ is also called ‘compressed head’, which used to decompress the kernel image. Different from those code before, we are now in 32-bit protected mode with paging disabled. The ‘compressed head’ starts from ‘startup_32′.
.text /* ! here just ‘.text’, without ‘.code16′ assembly directive */
.globl startup_32
startup_32:
/*
* ! clear direction flag
* ! and clear interrupt flag
*/
cld
cli
/*
* ! all other segment registers are
* ! reloaded after protected mode enabled
* ! __BOOT_DS = 0×18
*/
movl $(__BOOT_DS),%eax
movl %eax, %ds
movl %eax, %es
movl %eax, %fs
movl %eax, %gs
/*
* ! lss – load full pointer from memory
* ! to register
* ! and here ‘ss:esp = stack_start’
*/
lss stack_start,%esp
/*
* ! EAX = 0;
* ! do {
* ! DS:[0] = ++EAX;
* ! } while (DS:[0x100000] == EAX);
*/
xorl %eax, %eax
1: incl %eax # check that A20 really IS enabled
movl %eax, 0×000000 # loop forever if it isn’t
cmpl %eax, 0×100000
je 1b
After reload the segment registers, the ‘compressed head’ clears the ‘eflags’ register and fills the kernel bss(the area of uninitialized data of the kernel identified by the _edata and _end symbols) with zeros. Then the decompressed process begins.
/*
* ! %esi has been loaded in ‘setup.S’ with ‘INITSET << 4′
* ! ‘subl $16,%esp’ used to store the first arg, that is
* ! struct moveparams {
* ! uch *low_buffer_start;
* ! int lcount;
* ! uch *high_buffer_start;
* ! int hcount;
* ! } mv;
* ! the second arg is the %esi which indicates the position
* ! of the real-mode data
*/
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
/*
* ! if (!decompress_kernel(&mv, esi)) { // return value in AX
* ! restore esi from stack;
* ! ebx = 0;
* ! goto __BOOT_CS: $__PHYSICAL_START;
* ! // see linux/arch/i386/kernel/head.S:startup_32
* ! }
* ! ‘decompress_kernel’ is coded in
* ! $(linux-2.6.15.3_dir)/arch/i386/boot/compressed/misc.c
*/
call decompress_kernel
orl %eax,%eax
jnz 3f
popl %esi # discard address
popl %esi # real mode pointer
xorl %ebx,%ebx
ljmp $(__BOOT_CS), $__PHYSICAL_START
3:
/*
* ! move move_rountine_start..move_routine_end to 0×1000
* ! both the two functions are defined in the tail of
* ! this file
*/
movl $move_routine_start,%esi
movl $0×1000,%edi
movl $move_routine_end,%ecx
subl %esi,%ecx
addl $3,%ecx
shrl $2,%ecx
cld
rep
movsl
/*
* ! Do preparation for ‘move_routine_start’:
* ! set the parameters
* ! ebx = real mode pointer
* ! esi = mv.low_buffer_start
* ! ecx = mv.lcount
* ! edx = mv.high_buffer_start
* ! eax = mv.hcount
* ! edi = $__PHYSICAL_START
*/
popl %esi # discard the address
popl %ebx # real mode pointer
popl %esi # low_buffer_start
popl %ecx # lcount
popl %edx # high_buffer_start
popl %eax # hcount
movl $__PHYSICAL_START,%edi
cli # make sure we don’t get interrupted
/*
* ! jump to physical address: __BOOT_CS:0×1000
* ! where the move_routine_start function stays
*/
ljmp $(__BOOT_CS), $0×1000 # and jump to the move routine
/*
* ! the control has been transfered to ‘move_routine_start’
*/
move_routine_start:
movl %ecx,%ebp
shrl $2,%ecx
rep
movsl
movl %ebp,%ecx
andl $3,%ecx
rep
movsb
movl %edx,%esi
movl %eax,%ecx # NOTE: rep movsb won’t move if %ecx == 0
addl $3,%ecx
shrl $2,%ecx
rep
movsl
movl %ebx,%esi # Restore setup pointer
xorl %ebx,%ebx
ljmp $(__BOOT_CS), $__PHYSICAL_START
move_routine_end:
In ‘move_routine_start’, we perform the operations as follows:
(1) move mv.low_buffer_start to $__PHYSICAL_START, (mv.lcount >> 2) words;
(2) move/append (mv.lcount & 3) bytes;
(3) move/append mv.high_buffer_start, ((mv.hcount + 3) >> 2) words.
After move the decompressed kernel image to its right place, the control will be transfered to physical address:’$(__BOOT_CS):$__PHYSICAL_START’, where the second ‘head.S’ stays.
评论