Chinaunix首页 | 论坛 | 博客
  • 博客访问: 128817
  • 博文数量: 15
  • 博客积分: 209
  • 博客等级: 入伍新兵
  • 技术积分: 205
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-07 13:20
文章分类
文章存档

2014年(4)

2013年(1)

2012年(2)

2011年(8)

分类: LINUX

2011-09-08 10:55:04

引子:我试图去简要的描述一下开机启动流程,下述的内容可能会有所偏差,但力求完整、准确。最想说的是,在reference中的文章都是比较经典的描述,如果有时间还是多看一看为宜。

以IA-32架构为例,从PC加电到出现登录提示符,会经历下述的五个主要阶段。
  1. 系统加电 power on
  2. bios
  3. boot loader
  4. kernel
  5. init

BIOS会根据约定,加载可引导盘上面的第一个512字节,像grub一般在硬盘mbr内。MBR中含有446字节的grub第一阶段代码,64字节的GPT(global partition table)及8字节的magic number以表示这是一个或引导分区。


grub被bios加载后,会执行第二阶段的操作,读取/boot/grub/menu.lst中的配置内容来加载操作系统。

  1. # (0) Arch Linux
  2. title Arch Linux
  3. root (hd0,0)
  4. kernel /vmlinuz26 root=/dev/sda5 ro vga=789
  5. initrd /kernel26.img
vmlinuz26是被grub首先加载入内存的部分,其中包含head.S、压缩过的vmlinuz及解压缩程序gzip,grub加载其之后将控制权交与head.S后,grub的使命就已完成。其后的时间就一直由kernel自己来处理了。

head.S被加载后,会执行下述工作
  1. 从real mode转换到protected mode
  2. 解压缩内核
  3. setup_32
  4. 硬盘,内存及其它相关内容的初始化
  5. 创建进程0
  6. 由进程0创建进程1(即后文提到的init)

下图是vmlinuz具体生成过程的详细描述。




在Ref 5中是关于内核编译的详细描述。这一过程中有一点需要引起注意,即使用objcopy将elf格式转换成raw binary file,为什么需要这么做。因为一开始的时候,没有elf intepreter所以必须将其做转换,一切都需要手工指定,否则陷入鸡生蛋还是蛋生鸡的死循环了。

当理解了vmlinuz26的功能之后,紧随而来的问题是kernel26.img干什么用的。initrd是initial ram disk的缩写具体解释如下所述进一步的解释请参阅ref 6

  1. The initrd contains various executables and drivers that permit the real root file system to be mounted, after which the initrd RAM disk is unmounted and its memory freed. In many embedded Linux systems, the initrd is the final root file system. This article explores the initial RAM disk for Linux 2.6, including its creation and use in the Linux kernel.

一般来说,/sbin/init是被内核执行的第一个application,其pid为1。以下是具体调用代码,见内核init/main.c。注意其中的run_init_process

  1. static noinline int init_post(void)
  2. {
  3.     /* need to finish all async __init code before freeing the memory */
  4.     async_synchronize_full();
  5.     free_initmem();
  6.     mark_rodata_ro();
  7.     system_state = SYSTEM_RUNNING;
  8.     numa_default_policy();


  9.     current->signal->flags |= SIGNAL_UNKILLABLE;

  10.     if (ramdisk_execute_command) {
  11.         run_init_process(ramdisk_execute_command);
  12.         printk(KERN_WARNING "Failed to execute %s\n",
  13.                 ramdisk_execute_command);
  14.     }

  15.     /*
  16.      * We try each of these until one succeeds.
  17.      *
  18.      * The Bourne shell can be used instead of init if we are
  19.      * trying to recover a really broken machine.
  20.      */
  21.     if (execute_command) {
  22.         run_init_process(execute_command);
  23.         printk(KERN_WARNING "Failed to execute %s. Attempting "
  24.                     "defaults...\n", execute_command);
  25.     }
  26.     run_init_process("/sbin/init");
  27.     run_init_process("/etc/init");
  28.     run_init_process("/bin/init");
  29.     run_init_process("/bin/sh");

  30.     panic("No init found. Try passing init= option to kernel. "
  31.      "See Linux Documentation/init.txt for guidance.");
  32. }

init会根据/etc/inittab文件中的配置来执行相应的程序。有关/etc/inittab的详细说明,请执行以下命令。

  1. #man inittab
这里想说明的是从init到login prompt的过程。
init调用gettty或者相关变种如agetty, getty调用/bin/login

getty会根据/etc/issue中的配置来在屏幕中显示相应的信息。如arch中的/etc/issue具体配置如下。

  1. Arch Linux \r (\n) (\l)
等待输入用户名的那一行提示信息应该是login程序打印出来的。这样子就完全解释了为什么在登录的时候会显示两行信息。头一行由/etc/issue控制,第二行由login控制。有关具体解释请参考ref 4

login根据/etc/passwd中的内容来对输入内容进行验证。一旦用户通过验证,则执行/etc/passwd中指定的shell,一般来说是bash.

/etc/passwd内容示例
  1. root:x:0:0:root:/root:/bin/bash
最后粘上2.6.x内核从grub引导后执行的backtrace
  1. arch/x86/boot/header.S::start_of_setup
  2. arch/x86/boot/main.c::main()
  3.  arch/x86/boot/memory.c::detect_memory()
  4.  arch/x86/boot/memory.c::detect_memory_e820() = boot_params.e820_entries
  5.  ...
  6.  arch/x86/boot/pm.c::go_to_protected_mode()

  7. arch/x86/boot/pmjump.S::protected_mode_jump
  8. arch/x86/kernel/compressed/head_64.S::startup_32
  9. arch/x86/kernel/compressed/head_64.S::startup_64
  10. arch/x86/kernel/head_64.S::startup_64
  11. kernel/main.c::start_kernel()
  12.  ...
  13.  arch/x86/kernel/setup_64.c::setup_arch()
  14.   ...
  15.   arch/x86/kernel/setup_64.c::memory_setup()
  16.    arch/x86/kernel/e820_64.c::machine_specific_memory_setup()
  17.     arch/x86/kernel/e820_64.c::sanitize_e820_map(boot_params.e820_map, &boot_params.e820_entries)
  18.   ...
  19.   arch/x86/kernel/e820_64.c::finish_e820_parsing()
  20.   ...
  21.   arch/x86/kernel/e820_64.c::e820_register_active_regions()
  22.   ...
  23.   arch/x86/kernel/acpi/boot.c::acpi_boot_table_init()
  24.   arch/x86/kernel/pci-dma.c::dma32_reserve_bootmem()
  25.   arch/x86/kernel/acpi/sleep.c::acpi_reserve_bootmem()
  26.   arch/x86/kernel/efi_64.c::efi_reserve_bootmem()
  27.   ...
  28.   arch/x86/kernel/acpi/boot.c::acpi_boot_init()
  29.   ...
  30.   arch/x86/kernel/e820_64.c::e820_reserve_resources()
  31.   arch/x86/kernel/e820_64.c::e820_mark_nosave_regions()
  32.   arch/x86/kernel/e820_64.c::e820_setup_gap()
  33.   ...
  34.  }
  35.  drivers/acpi/bus.c::acpi_early_init()
  36.  kernel/main.c::rest_init()
  37.   arch/x86/kernel/process_32.c::kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
  38. }
  39. kernel/main.c::kernel_init()
  40.  ...
  41.  do_basic_setup()
  42.   ...
  43.   drivers/base/init.c::driver_init()
  44.   ...
  45.   init/main.c::do_initcalls()
  46.  }
  47.  ...
  48.  init/main.c::init_post()
  49. }



Reference
  1. Inside the linux boot process
  2. Linux Initial RAM Disk (initrd) Overview
阅读(3178) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:从哪个角度入手阅读Linux内核源代码

给主人留下些什么吧!~~