日期:2014-05-16  浏览次数:20822 次

Linux 启动过程阅读
我阅读的代码是2.6.33.1的代码。

本文没有详细分析代码逻辑,主要是看函数执行流程。

启动过程从arch/x86/boot/header.S开始。按代码所在位置分为两部分,一部分是在boot目录下的,另一部分是在kernel目录下。
1. arch/x86/boot/header.S(Based on bootsect.S and setup.S)
   是在16-bit的实模式执行,因此访存是这样的:段地址:段内偏移
在header.S有一个jmp main的命令,跳转到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
    |
   \|/
/* called by boot processor to activate the rest */
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);
}
/* Any cleanup work */
printk(KERN_INFO "Brought up %ld CPUs\n", (long)num_online_cpus());
smp_cpu_done(setup_max_cpus);
--------------------------
cpu_up = native_cpu_up是一个回调函数。
注册地方是在:arch/x86/kernel/smp.c

struct smp_ops smp_ops = {
   ……
  .cpu_up = native_cpu_up,
   ……
}
arch/x86/kernel/smpboot.c:native_cpu_up(unsigned int cpu)
    |
   \|/
arch/x86/kernel/smpboot.c: do_boot_cpu(int apicid, int cpu)