要深入理解linux的启动过程,我们从开机开始追踪整个启动过程。这里以笔者所使用的archlinux为基础来讲解。
首先我们要理解如下两个概念:BIOS
Basic Input-output System,是开机第一个被执行的程序,又被称之为固件。当它被启动后,会顺序加载磁盘前512字节,也就是我们所说的主引导记录(MBR),前440字节包含某个启动引导器,比如GRUB、Syslinux之类的第一启动阶段代码。然后启动引导器通过链式引导或者直接加载内核,以加载一个操作系统。UEFI
UEFI 不仅能读取分区表,还能自动支持文件系统。所以不像 BIOS,没有440 字节可执行代码即 MBR 的限制了,它完全用不到 MBR。虽然UEFI 主流都支持 MBR 和 GPT 分区表。但不管第一块上有没有 MBR,UEFI 都不会执行它。相反,它依赖分区表上的一个特殊分区,叫 EFI 系统分区,里面有 UEFI 所要用到的一些文件。
从前,内核在init之前)处理一切硬件的检测和初始化。然而,但随着技术的演进,这种做法变得十分繁琐。
如今,根文件系统可能位于各种硬件上,如SCSI设备、SATA设备、U盘,而这些硬件受控于形形色色的厂家所提供的五花八门的驱动之下。另外,根系统可以加密、压缩,可存放在RAID阵列中,或者一个逻辑卷组上。为了简化这复杂的过程,可以把管理权转入一个用户空间:初始化内存盘。
在archlinux上,当内核被加载后,它会解压mkinitcpio(一个创建初始内存盘的bash脚本),把它当做成一个已经初始化的根文件系统。内核接着会执行/init作为第一条进程。
注:初始内存盘本质上是一个很小的运行环境(早期用户空间),用于加载一些核心模块,并在 init 接管启动过程之前做必要的准备。有了这个环境,才能支持加密根文件系统、RAID上的根文件系统等高级功能。
在「早期用户空间」的最终环节里,当真正的根文件系统被挂载好后,就会替换掉原来的伪根文件系统。接着 /sbin/init 被执行,同样也替换掉原来的 /init 进程。Arch 御用的init 就是 systemd
init为每一个虚拟终端调用getty,一般有6个,每个虚拟终端都会初始化tty并请求输入用户名和密码。当在某个虚拟终端中输入密码后,其getty会通过/etc/passwd检查是否正确,如果正确会启动login程序,该程序会为用户启动一个设置里环境变量的【会话】,然后再次通过查看/etc/passwd内容的配置为用户启动专用shell。
一旦当用户的专用shell启动后,它会在显示命令提示符前执行一个配置文件,比如.bashrc。当然,如果用户设置statx at login,配置文件会调用starx或者xinit.它同样也会调用配置文件,如xinitrc。