Penguin, Boot
启动过程概述
Linux的启动过程可以简单分为如下四步:
- BIOS POST
- Boot loader
- Kernel initialization
- Start systemd, the parent of all processes.
BIOS POST (Basic IO system Power On Self Test)
BIOS是和启动相关的一段重要的程序,为了研究BIOS的功能,我们首先对计算机体系结构进行一个概述
计算机体系结构概述
在计算机中,CPU通过总线与IO设备(硬盘、键盘、鼠标等)和内存相连。当计算机上电后,CPU执行的第一条指令在哪里呢?首先,CPU加电后会对寄存器进行初始化,然后开始执行第一条指令。第一条指令存放在ROM中,ROM是掉电非易失的,所以可以将我们的第一条代码保存在这里。
启动时计算机的内存布局
在计算机启动时,内存布局如下所示:
1 | +------------------+ <- 0xFFFFFFFF (4GB) |
其中,640KB到1MB这一段是系统硬件部分,BIOS写死在960KB开始的地方。CPU启动后处于实模式,第一条指令位于CS:IP=0xf000:fff0的位置,即BIOS ROM的区域。此时只有20位地址(1MB)可用。
BIOS提供的服务
- 基本输入输出(从硬盘、键盘输入输出等)
- 系统设置信息
- 开机自检程序
- 系统自启动程序
进入BIOS程序后,将BootLoader从磁盘加载至0x7c00,并跳转。载入Boot Loader后的内存如下
1 | +------------------+ <- 0x00100000 (1MB) |
BIOS 基本IO功能
以下功能只能在实模式下使用
- INT 10h:字符显示
- INT 13h:磁盘扇区读写
- INT 15h:内存大小检测
- INT 16h:键盘输入
BIOS 过程
为什么不让BIOS直接加载?
因为各种文件系统是不同的,不可能让一个BIOS包含所有的文件系统的读取,因此只让BIOS从硬盘固定区域进行读写
UEFI
UEFI的目标是在所有平台上一致的操作系统启动服务,实际是一个接口标准。
Boot Loader
Boot Loader 负责将操作系统代码数据加载至内存,然后跳转至起始地址
Linux Boot Loader 过程
GRUB2
GRUB2全称为GRand Unified Bootloader, version 2,是现今主流Linux普遍采用的Boot Loader。其基本功能是找到linux内核,然后载入到内存中并运行。
第一阶段
在POST结束时,BIOS会寻找到第一个Boot分区,加载bootstrap code,即GRUB2 Stage 1,这段代码非常小,因为必须适配前512字节的扇区(统一规定)。因为这个代码太小了,做不到太多有意义的工作,唯一的目的是定位下一个阶段并进行跳转
第1.5阶段
GRUB2 的1.5阶段位于boot record和第一块硬盘分区之间,这一段空间因为一些原因没有被使用。这一段有62 512-byte的空间存放core.img文件,这个文件的大小是25,389 Bytes,足够放下一些文件系统的驱动,例如标准EXT、FAT及NTFS等。这意味着GRUB第二阶段可以位于标准的EXT文件系统内。第二阶段实际位于/boot下,即/boot/grub2。
第2阶段
第二阶段位于/boot/grub2和其子文件夹下,它将运行期内核模块放置在了/boot/grub2/i386-pc文件夹下。第2阶段的作用是定位并载入所选择的Linux内核,内核和相关文件在/boot文件夹下。
Kernel
所有的kernel都经过了压缩并可自解压,从而节省空间,kernel和初始的RAM镜像以及设备映射位于/boot文件夹下。当内核被载入后,它会进行自解压,并载入systemd,并将控制权移交。至此,Boot阶段结束。
启动阶段
systemd
systemd是所有进程的父进程,它将会使linux正式进入可工作状态。systemd将会完成如下工作:
- 挂载由/etc/fstab定义的文件系统,从而可以获取/etc下的配置文件
实模式VS保护模式
实模式
地址表示
在实模式下,CPU通过直接访问实际的物理地址对内存进行访问,此时地址格式为[CS:IP],物理地址为:
保护模式
在保护模式下,segment_part由一个16位的选择器代替,高13位为描述表的入口;而第2位表示使用GDT或LDT,最低两位表示优先级,0-3分别代表最高优先级和最低优先级