Linux 启动过程阅读
我阅读的代码是2.6.33.1的代码。
本文没有详细分析代码逻辑,主要是看函数执行流程。
启动过程从arch/x86/boot/header.S开始。按代码所在位置分为两部分,一部分是在boot目录下的,另一部分是在kernel目录下。
1.arch/x86/boot/header.S(Basedonbootsect.Sandsetup.S)
是在16-bit的实模式执行,因此访存是这样的:段地址:段内偏移
在header.S有一个jmpmain的命令,跳转到arch/x86/boot/main.c。
在这个main函数中,初始化许多设定,例如init_heap(),set_video()……
最后进入保护模式go_to_protected_mode(),注意,在这个函数里面有set_idt()与setup_gdt()两个操作。
看了go_to_protected_mode(),它最后一个跳转操作,现在不确定跳转到哪里。
个人感觉是跳转到arch/x86/boot/compressed/head_32.S:startup_32,这段汇编文件代码会调用decompress_kernel,在它将kernel解压后跳转到kernel代码开始执行kernel代码,kernel的入口代码是在arch/x86/kernel/head_32.S
2.在arch/x86/kernel/head_32.S在做许多初始化工作(建立gdt,idt表,开启Page机制等)之后,执行jmp*(initial_code),就跳转到了i386_start_kernel。
而在i386_start_kernel的最后调用了start_kernel,在这个函数中kernel完成了自己的许多初始化工作,包括创建init内核线程,然后最后在reset_init函数中启动了cpu_idle.
启动多个CPU的代码流程:
init/main.c:start_kernel()
|
\|/
init/main.c:rest_init
|
\|/
kernel_thread(kernel_init,NULL,CLONES_FS|CLONE_SIGHAND)
-----------------------------------------------------------------
kernel_init会被当成kernel_thread_function
kernel_thread创建地方是在init/main.c:rest_init
init/main.c:smp_init():kernel_init
|
\|/
/*calledbybootprocessortoactivatetherest*/
init/main.c:smp_init()
|
\|/
for_each_present_cpu(cpu){
if(num_onlien_cpus()>=setup_max_cpus)
break;
if(!cpu_online(cpu))
cpu_up(cpu);
}
/*Anycleanupwork*/
printk(KERN_INFO"Broughtup%ldCPUs\n",(long)num_online_cpus());
smp_cpu_done(setup_max_cpus);
--------------------------------------------------------------
cpu_up=native_cpu_up是一个回调函数。
注册地方是在:arch/x86/kernel/smp.c
structsmp_opssmp_ops={
……
.cpu_up=native_cpu_up,
……
}
arch/x86/kernel/smpboot.c:native_cpu_up(unsignedintcpu)
|
\|/
arch/x86/kernel/smpboot.c:do_boot_cpu(intapicid,intcpu)