稻花香

软件开发,喜欢读书,编程,禅修

linux内核启动分析-实模式跳转

01 Mar 2020 » Linux
  1. arch/x86/boot/main.c开始执行代码,当前工作在实模式下.
  • copy_boot_params函数把把头部各参数复制到boot_params变量中.

  • 初始化early-boot consoleheap check

  • set_bios_mode() function that Tell the BIOS what CPU mode we intend to run in.

  • Detect memory layout: detect_memory()

  • Set keyboard repeat rate (why?) and query the lock flags, keyboard_init().

  • Query Intel SpeedStep (IST) information, query_ist().

  • Set the video mode, set_video().

  • 最后一步从保护模式跳转到实模式 go_to_protected_mode()

  1. 跳转到保护模式的go_to_protected_mode()函数在pm.c文件中,包含如下操作:
  • 关中断realmode_switch_hook

  • 开启A20.

  • Reset 协处理器.

  • 关闭所有中断.

  • 设置idt和gdt.

  • 执行protected_mode_jump(boot_params.hdr.code32_start, (u32)&boot_params + (ds() << 4))函数.
  • 注意在内核中调用都是fastcall的,所以两个参数对应为:EAX:参数1=boot_params.hdr.code32_start以及EDX=(u32)&boot_params + (ds() << 4)

  • 根据前文,EAX中的值是压缩内核入口(未hook的情况下),EDX的值是boot_params的地址.

  • pm.c中ds值是loader加载内核载地址X所在的段,在document/x86/boot.txt中对X有描述。其它段自header.S进入boot/main.c后,也没变过都等于X.
  1. protected_mode_jump函数在pmjump.S文件,这个文件是汇编文件:
/*
 * void protected_mode_jump(u32 entrypoint, u32 bootparams);
 */
SYM_FUNC_START_NOALIGN(protected_mode_jump)
	movl	%edx, %esi		# Pointer to boot_params table

	xorl	%ebx, %ebx
	movw	%cs, %bx
	shll	$4, %ebx
	addl	%ebx, 2f
	jmp	1f			# Short jump to serialize on 386/486
1:

	movw	$__BOOT_DS, %cx
	movw	$__BOOT_TSS, %di

	movl	%cr0, %edx
	orb	$X86_CR0_PE, %dl	# Protected mode
	movl	%edx, %cr0

	# Transition to 32-bit mode
	.byte	0x66, 0xea		# ljmpl opcode
2:	.long	.Lin_pm32		# offset
	.word	__BOOT_CS		# segment
SYM_FUNC_END(protected_mode_jump)

	.code32
	.section ".text32","ax"
SYM_FUNC_START_LOCAL_NOALIGN(.Lin_pm32)
	# Set up data segments for flat 32-bit mode
	movl	%ecx, %ds
	movl	%ecx, %es
	movl	%ecx, %fs
	movl	%ecx, %gs
	movl	%ecx, %ss
	# The 32-bit code sets up its own stack, but this way we do have
	# a valid stack if some debugging hack wants to use it.
	addl	%ebx, %esp

	# Set up TR to make Intel VT happy
	ltr	%di

	# Clear registers to allow for future extensions to the
	# 32-bit boot protocol
	xorl	%ecx, %ecx
	xorl	%edx, %edx
	xorl	%ebx, %ebx
	xorl	%ebp, %ebp
	xorl	%edi, %edi

	# Set up LDTR to make Intel VT happy
	lldt	%cx

	jmpl	*%eax			# Jump to the 32-bit entrypoint
SYM_FUNC_END(.Lin_pm32)
  • protected_mode_jump函数段开始执行,jmp 1f 跳转到1标签处.

  • byte 0x66, 0xea长跳转到 .long .Lin_pm32偏移处,即Lin_pm32代码段.

  • 执行Lin_pm32代码段清空寄存器的值,设置ldtr寄存器.

  • jmpl *%eax 跳转到32位入口执行.