Linux 启动过程(一)

CMOS 与 BIOS

CMOS 是主板上一块可读写的 RAM,用来保存 BIOS 设置硬件参数后的数据(系统时间,CPU 核心电压,磁盘启动顺序等),它在关机断电状态下可转为由主板上的电池供电,即使系统掉电信息也不会丢失。所以 CMOS 本身只是一块存储器,只具有数据存储功能。

BIOS 是主板上的一块固件芯片(现在一般是用可读写的 EEPROM 或闪存,在掉电情况下也能保存数据)。在计算机主板通电后,发出一个电信号将 CPU 内的所有寄存器遗留数据清除,同时将程序计算器置成一个特定的值,这个值就是固化的计算机启动程序的起始地址。CPU 根据程序计数器记录的地址定位到 BIOS 的启动代码处,加载 CMOS 内的配置值取得主机的各项硬件配置,进行 POSTPower-on Self Test 加电自检),POST 结果与 CMOS 中存储的参数比较整合成一个表格写到内存中,我们开机进入 BIOS 设置界面所看到的所有内容都来自这个表格。

系统在完成加电自检后,BIOS 自举程序按照 CMOS 设置中保存的启动顺序搜索第一个有效的磁盘或网络服务器等启动驱动器,通过 INT 13 中断 (Direct Disk Service) 来读取首个扇区前466字节的 MBRMaster Boot Record 主引导记录),将 MBR 中的 boot loader 复制到内存中,系统的控制权交给 boot loader

  • 将主板上电池取出,通过对 CMOS 的放电操作可以达到还原 BIOS 设置的目的。
  • 程序计数器 (PC) 是存放下一条指令地址的地方。 当执行一条指令时,先根据PC中存放的指令地址将指令由内存取到指令寄存器中,与此同时,PC 中的地址或自动加1或由转移指针给出下一条指令的地址。


Boot Loader

Boot loader 是操作系统内核运行之前运行的一段小程序。Boot loader 有若干种,其中 GRUB (GRand Unified Bootloader) 是常见的 loader。它是一个多重操作系统启动管理器,用来引导不同系统,装载内核并将控制权转交。内核再初始化操作系统的其它部分。GRUB 的主要功能有:

  1. 提供开机系统选单:
    开机选单功能可以提供选择不同的内核进行加载,比如同个操作系统不同的 DIY 内核。
  2. 载入操作系统内核:
    Boot loader 的主要功能就是识别操作系统内核并进行装载。
  3. 转交开机管理权限给其他 boot loader
    不同操作系统支持的文件格式往往不同,所以每种操作系统一般要用自己特定的 boot loader 才能载入内核。但是一块磁盘只有一个 MBR,不能同时在一个 MBR 上安装多个 boot loader,所以每个分区都会保留一块 boot sector 来提供操作系统安装 boot loader。通常操作系统都会在根目录所在分区的 boot sector 安装自己的 boot loader,通过 GRUB 将控制权转交给指定分区的 Boot Loader,实现了多系统的选择启动。所以 GRUB 实质上可以被认为是一个 mini OS,通过链式启动方式它可以启动所有主流操作系统。

    需要注意的是 Windows 的 loader 会主动覆盖 BMR 中的其它 loader(GRUB 可选择不写入 MBR),且没有控制权转交功能。所以如果先安装 Linux 再安装 Windows,则 MBR 中是 Windows 的 loader,无法启动 Linux。

GRUB 载入操作系统内核过程中,它寻找自己的配置文件。GRUB 配置文件的文件名和位置随系统不同而不同,在当前 Ubuntu 版本 (14.04.2) 中这个文件为 /boot/grub/grub.cfg。当找到配置文件后,使用这个配置文件建立一个要载入的操作系统的菜单列表,显示引导菜单接口。如果找不到配置文件或配置文件不能被读取,GRUB 将载入命令行接口。

grub.cfg### BEGIN /etc/grub.d/10_lupin ### 后面的部分记录着启动选项的信息。将一条启动选项的主要信息提取后大致如下:

menuentry 'Ubuntu' {  
    insmod gzio
    insmod part_msdos
    insmod ext2
    set root='hd0,msdos1'
    if [ x$feature_platform_search_hint = xy ]; then
      search --no-floppy --fs-uuid --set=root --hint-bios=hd0,msdos1 --hint-efi=hd0,msdos1 --hint-baremetal=ahci0,msdos1  517191ec-911b-4cce-8207-6a5fae6c241d
    else
      search --no-floppy --fs-uuid --set=root 517191ec-911b-4cce-8207-6a5fae6c241d
    fi
    linux    /boot/vmlinuz-3.16.0-31-generic root=UUID=517191ec-911b-4cce-8207-6a5fae6c241d ro  quiet splash
    initrd    /boot/initrd.img-3.16.0-31-generic
}
  • menuentry "title" {entry options} 设置一个名为 title 的启动项。
  • insmod ext2 表示载入动态 GRUB 模块 /boot/grub/i386-pc/ext2.mod,ext2.mod 中包括了 ext2, ext3 和 ext4 文件格式的支持驱动。insmod gzip 载入压缩解压模块,insmod part_msdos 添加对 MSDOS 分区表类型的支持,另一种流行的磁盘分区格式 GPT 支持模块载入命令是 insmod part_gpt
  • 'hd0,msdos1' 表示第1个磁盘的第1个分区,磁盘从0开始计数,分区从1开始计数。set root='hd0,msdos1' 设定内核和 GRUB 模块所在的启动分区,即 /boot 所在分区,有可能与根目录不在同一分区。
  • set root='dh0,msdos1' 只是对 root 赋初值,下面 search 命令会对 root 再次赋值,这是真正使用的root 值。对 root 赋初值是为了防止 search 命令找不到分区导致出错。
  • ro 表示以只读方式读入。quiet 表示内核启动时候简化提示信息,不滚动log。 splash 意思是启动的时候使用图形化的进度条。
  • /boot/vmlinuz-3.16.0-31-generic 即内核。
  • /boot/initrd.img-3.16.0-31-generic 即 initial RAM disk,是在系统引导过程中的一个临时根文件系统,后面将详细介绍。
  • 不推荐直接编辑 grub.cfg,这个文件由 grub-mkconfig 生成,最好编辑 /etc/default/grub 和 /etc/grub.d 文件夹下的脚本以实现修改。如果直接修改了 grub.cfg,以后升级了系统内核,grub.cfg 将会被重写导致更改丢失,同样运行 grub-mkconfig 命令也会重新生成 grub.cfg 导致更改丢失。
  • 更多关于 GRUB 的配置可以参考 GNU GRUB Manual 2.00


下一篇:Linux 启动过程(二)