!!!!!!版权所有,如需要转载,请注明出处,作者:乔迁!!!!!!
内核版本号:
2.6.23
当PC按下电源,CPU加电后,自动从0xFFFF0处开始执行代码,这个地址位于BIOS中。接着BIOS开始一系列系统检测,并在内存物理地址0处初
始化中断向量,供Linux内核启动过程中进行调用。此后,它将启动设备的第一个扇区(磁盘引导扇区,512Bytes)读入内存绝对地址0x7C00
处,并跳到这个地方开始执行(arch/i386/boot/header.s)。
注意,现在程序现在运行在16位实模式下,使用64k的段。 segment(段地址) : offset(偏移)构成了
逻辑地址,段地址乘以 16 再加上 偏移 ,就得到 linear
address(线性地址)。header.s(arch/i386/boot/header.s)中包含了大量的.h(头文件)。
18 #include
19 #include
20 #include
21 #include
22 #include
23 #include
24 #include "boot.h"
这些头文件包含了许多重要的宏和声明,在Linux 内核的其他程序中,都会用到。
.section ".header", "a"
.globl hdr
hdr:
上面开始了header.s的最重要的部分,hdr数据段存储了Linux kernel启动过程所需的信息数据,它的结构struct
boot_params定义在 include/asm-i386/bootparam.h中。struct
boot_params非常重要,它包含了其他的一些struct,并不是很复杂。下面开始了header.s程序,开始了header.s的真正的执行。
.section ".inittext", "ax"
start_of_setup:
它首先初始化 Disk Controller(磁盘控制器),是通过 int 0x13进行的。然后设置寄存器,Zero the
bss(初始化数据段),接着 call main(调用
main)跳转到:arch/i386/boot/main.c的main()函数开始执行。(终于见到我们的可亲可爱的C了,不过别高兴太早喔:~)
下面我们看看main()都做了什么(注:linux kernel 中有太多main函数,程序并不是总是从main开始执行)
copy_boot_params();
复制 boot header 到 "zeropage"
validate_cpu();
确保支持当前运行的CPU
set_bios_mode();
告诉BIOS什么CPU我们将要去运行
detect_memory();
检测Memory
keyboard_set_repeat();
设置键盘 repeat rate (Why ?)
set_video();
设置 Video mode
query_mca();
获得 MCA 信息
query_voyager();
Voyager ?
query_ist();
获得 Query
Intel SpeedStep (IST) 信息
query_apm_bios();
获得APM 信息
query_edd();
获得EDD信息
go_to_protected_mode();
最后一件事,也是最重要的一件事,进入保护模式
上面只是函数调用的大致顺序,并不是真正的程序,通过这些函数我们可以一目了然地看到内核的执行过程(还是C好啊,不像汇编,得一行一行地看),当然你要了解更多的细节,可以追踪到每一个函数中去。它通过上方面的检测,不断地填充struct
boot_params结构,记住,struct boot_params 是很重要的喔
。其他函数我们就不研究了,单看最后一个,go_to_protected_mode(),究竟在哪儿?
arch/i386/boot/pm.c
void go_to_protected_mode(void)
依次调用了如下函数:
realmode_switch_hook();
Hook before leaving realmode
move_kernel_around();
把
Kernel/setup 移到 它们最终的地方
enable_a20()