compress/head.S解析

  1. 清除BBS
	xorl %eax,%eax //eax=0
	movl $_edata,%edi //edi=0x262a2d
	movl $_end,%ecx  //ecx=26eea4
	subl %edi,%ecx
	cld
	rep
	stosb

说明:

arch/i386/kernel/vmlinux.lds.S
_edata和_end的定义是:

        *(.bss)
  }
  . = ALIGN(4);
  __bss_stop = .;

  _end = . ;

在System.map中:
c03fe0fc A __bss_stop
c03fe0fc A _end
问题1:
_end=0x26eea4和System.map中的_end的数值0xc03fe0fc不相等,那么这里的_end是在哪里定义的?
arch/i386/kernel/vmlinux.lds.S是针对于生成主目录下的vmlinux的连接脚本.

现在执行的是compress/vmlinux,生成的命令如下:

cmd_arch/i386/boot/compressed/vmlinux := ld -m elf_i386  -Ttext 0x100000 -e startup_32 arch/i386/boot/compressed/head.o arch/i386/boot/compressed/misc.o arch/i386/boot/compressed/piggy.o -o arch/i386/boot/compressed/vmlinux

可以看出是直接的ld命令,使用的是内部的连接脚本,所以会根据内部链接脚本的定义生成:ld --verbose

  .data1          : { *(.data1) }
  _edata = .; PROVIDE (edata = .);
  __bss_start = .;
  .bss            :
  {
   *(.dynbss)
   *(.bss .bss.* .gnu.linkonce.b.*)
   *(COMMON)
   /* Align here to ensure that the .bss section occupies space up to
      _end.  Align after .bss to ensure correct alignment even if the
      .bss section disappears because there are no input sections.
      FIXME: Why do we need it? When there is no .bss section, we don't
      pad the .data section.  */
   . = ALIGN(. != 0 ? 32 / 8 : 1);
  }
  . = ALIGN(32 / 8);
  . = ALIGN(32 / 8);
  _end = .; PROVIDE (end = .);

从这个脚本可以看出,_edata 和__bss_start的值相等。就是清空bbs的数值。

  1. 解压缩内核,就是从压缩的vmlinux,解压出vmlinux.bin。解压函数是
    decompress_kernel。
/*
 * 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      
	//esi=0x9000  传递给decompress_kernel的第2个参数
	pushl %eax	# address of structure as first arg         
	 //eax=1  传递给decompress_kernel的第1个参数
	call decompress_kernel
	
	// eax=1 ecx=0x266a30 edx=0x2e2086 
	// esp=0x266a28
    	
    	orl  %eax,%eax //eax=1
	jnz  3f  //跳转到标签3
	popl %esi	# discard address
	popl %esi	# real mode pointer
	xorl %ebx,%ebx
	ljmp $(__BOOT_CS), $0x100000

调用decompress_kernel后,内核解压后的buffer,地址放在堆栈中。
因为是bzImage,会解压到两个地址,一个是0x2000-0x90000;另外一个地址是在0x100000的0x3000之后,且离0x100000不小于低端长度的最大长度。

为什么低端内存不联系放?
因为刚开始镜像在0x10 0000,在0x2000-0x90000放不下这么大的镜像,如果接着放,会冲掉放在0x10 0000地址的内容。

为什么不一起高端内存?
猜测
1)高端的内存没有初始化好。
2) 汇编中的跳转命令,跳转距离没有这么远。

  1. 把move_routine_start搬移到0x1000处。
3:
	movl $move_routine_start,%esi   //esi=0x100082
	movl $0x1000,%edi              // edi=0x1000
	movl $move_routine_end,%ecx   // ecx=0x1000a7
	subl %esi,%ecx  //ecx=0x25 搬移的长度
	addl $3,%ecx   //ecx=0x28
	shrl $2,%ecx   //ecx=0xa
	cld
	rep
	movsl
	popl %esi	# discard the address
	popl %ebx	# real mode pointer
	popl %esi	# low_buffer_start   //解压的vmlinux的开始地址  0x2000
	popl %ecx	# lcount             //0x8e00
	popl %edx	# high_buffer_start  //0x271ea4
	popl %eax	# hcount             //0x254086
	movl $0x100000,%edi    //edi=0x10 0000
	cli		# make sure we don't get interrupted
	ljmp $(__BOOT_CS), $0x1000 # and jump to the move routine

把move_routine_start例程搬运到0x1000处,然后把vmlinux解压到低端内存(0x2000)的启始地址放到esi寄存器中,长度(lcount)存放到ecx中;高端内存地址(0x271ea4)放到edx中,长度放到eax中。这四个值是由decompress_kernel返回得到的。

然后跳转到0x1000处,执行例程move_routine_start。

  1. 把解压到0x2000的低端内容和0x1000a7的高端内容搬运到0x10 0000处。
    具体操作就是0x2000的内容搬运到0x10 0000处,后面紧接着存放0x1000a7的内容,这样完成了vmlinux.bin的合并,并且存放在0x10 0000(也就是一起在 1M处的内容)。
move_routine_start:
	movl %ecx,%ebp     //ebp=ecx=0x8e00
	shrl $2,%ecx       //ecx=0x23800
	rep
	movsl             //把地址0x2000的地址搬移到0x100000地址
	movl %ebp,%ecx   //
	andl $3,%ecx  //ecx=0x254089
	rep //
	movsb  //
	movl %edx,%esi  //esi=0x271ea4
	movl %eax,%ecx	//ecx= 0x254086  # NOTE: rep movsb won't move if %ecx == 0
	addl $3,%ecx   //ecx=0x254089
	shrl $2,%ecx  //ecx=0x95022
	//SI=0x271ea4 DI=0x18e000
	rep
	movsl
	movl %ebx,%esi	# Restore setup pointer
	xorl %ebx,%ebx
	ljmp $(__BOOT_CS), $0x100000
move_routine_end:
  1. 最后执行0x10 0000内容,也就是arch/i386/kernel/head.S处执行。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值