前置:這里使用的linux版本是4.8,x86體系。
這篇是 http://home.ustc.edu.cn/~boj/courses/linux_kernel/1_boot.html 的學習筆記。
linux的啟動過程有點像是小魚吃大魚,最后吃成一個胖子。

計算機中的PC寄存器是用來指示下個執行程序。最開始的時候,pc寄存器都是指向0xfffffff0。這個程序是指向BIOS的POST程序的。POST全稱是Power On Self Test,意思是加點自檢。過程包括內存檢查,系統總線檢查等。
POST過程結束,就進入到了自舉過程,自舉過程把MBR(主引導扇區)加載到內存中,並且執行它。這個主引導扇區是第一個扇區的前512字節。
Master Boot Record過程是為了后面一個過程准備的。它主要做的是讀入GRUB stage2所在的扇區。並且執行它。
GRUB stage2 將系統切換到保護模式。設置C運行環境。
然后進入到x86/boot/header.S中執行。在這里面,你能找到main的函數入口。這個對應到x86/boot/main.c的main函數。
這個main函數執行到最后會進入go_to_protected_mode(); 進入到pm.c的這個函數的定義,除了初始化一些邏輯以外,主要是protected_mode_jump
下面就進入到boot/pmjump.S的protected_mode_jump
29 protected_mode_jump:
30 movl %edx, %esi # Pointer to boot_params table
31
32 xorl %ebx, %ebx
33 movw %cs, %bx # 將實模式的代碼段放入 bx
34 shll $4, %ebx # 轉換為線性地址
35 addl %ebx, 2f # 將 in_pm32 的實模式地址轉換為線性地址
36
37 movw $__BOOT_DS, %cx # ds 段選擇子
38 movw $__BOOT_TSS, %di # tss 段選擇子
39
40 movl %cr0, %edx
41 orb $X86_CR0_PE, %dl # Protected mode
42 movl %edx, %cr0 # 將 cr0 的0位置0是進入保護模式的標志
43 jmp 1f # Short jump to serialize on 386/486
44 1:
45 # 下面這段作用是跳轉到 in_pm32,由於已經在保護模式,所以需要考慮段的問題
46 # Transition to 32-bit mode
47 .byte 0x66, 0xea # ljmpl opcode
48 2: .long in_pm32 # offset
49 .word __BOOT_CS # segment
50
51 .size protected_mode_jump, .-protected_mode_jump
52
53 .code32
54 .type in_pm32, @function
55 in_pm32: # 下面的注釋挺清楚,就不翻譯了
56 # Set up data segments for flat 32-bit mode
57 movl %ecx, %ds
58 movl %ecx, %es
59 movl %ecx, %fs
60 movl %ecx, %gs
61 movl %ecx, %ss
62 # The 32-bit code sets up its own stack, but this way we do have
63 # a valid stack if some debugging hack wants to use it.
64 addl %ebx, %esp
65
66 # Set up TR to make Intel VT happy
67 ltr %di # 這個比較有意思
68
69 # Clear registers to allow for future extensions to the
70 # 32-bit boot protocol
71 xorl %ecx, %ecx
72 xorl %edx, %edx
73 xorl %ebx, %ebx
74 xorl %ebp, %ebp
75 xorl %edi, %edi
76
77 # Set up LDTR to make Intel VT happy
78 lldt %cx # 又是一個騙 CPU 的東西
79 # eax 是 protected_mode_jump 的第一個參數,即 header.S 中定義的 boot_params.hdr.code32_start,即 vmlinux 的入口地址
80 jmpl *%eax # Jump to the 32-bit entrypoint
81
82 .size in_pm32, .-in_pm32
最后的jmpl就跳轉到
arch/x86/kernel/head_32.S的startup_32
ENTRY(initial_code)
.long i386_start_kernel
進入到arch/x86/kernel/head32.c
asmlinkage __visible void __init i386_start_kernel(void)
{
cr4_init_shadow();
sanitize_boot_params(&boot_params);
x86_early_init_platform_quirks();
/* Call the subarch specific early setup function */
switch (boot_params.hdr.hardware_subarch) {
case X86_SUBARCH_INTEL_MID:
x86_intel_mid_early_setup();
break;
case X86_SUBARCH_CE4100:
x86_ce4100_early_setup();
break;
default:
i386_default_early_setup();
break;
}
start_kernel();
}
這里最后是調用了start_kernel,這里的start_kernel是與操作系統無關的init/main.c里面了。
參考
http://home.ustc.edu.cn/~boj/courses/linux_kernel/1_boot.html
http://blog.csdn.net/alais/article/details/5129005
