- 从
arch/x86/boot/main.c开始执行代码,当前工作在实模式下.
copy_boot_params函数把把头部各参数复制到boot_params变量中.初始化
early-boot console和heap 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().
- 跳转到保护模式的
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.
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位入口执行.