从加电到出现登录界面,整个流程大致如下(基于 CentOS Linux release 8.2.2004 (Core)):
BIOS/UEFI ==> bootloader ==> kernel ==> initramfs ==> systemd(initramfs) ==> switch-root ==> systemd(real rootfs)
可以将上述过程粗略的划分为四个阶段:
该阶段有两种引导方式:传统的 BIOS 模式(功能有限)以及UEFI 模式(功能丰富),核心功能大致是一些硬件启动前的检测,提供交互式界面来配置启动参数,加载 bootloader 到内存,并且将控制权交给 bootloader。
vmware 虚拟机可以设置启动方式,虚拟机设置 > 选项 > 高级 > 固件类型,virtual box 也有类似设置:
该阶段核心功能是加载内核镜像 vmlinuz 以及 initramfs 到内存,并将控制权交给内核。
根据安装系统时启动方式的不同,系统启动盘分区格式会有所不同,默认是 BIOS/MS-DOS 和 UEFI/GPT 组合。如果采用 BIOS 启动方式安装 OS,启动盘将采用 MS-DOS 分区格式,可以通过在安装参数里添加 inst.gpt 来使用 GPT 分区,该种方式下,必须存在 biosboot 分区;如果采用 UEFI 方式安装,启动盘将采用 GPT 分区格式,UEFI 启动方式下,必须存在 efi 分区。
MS-DOS 分区
MBR(Master Boot Record, 主引导记录)。早期的 Linux 系统为了相容于 Windows 的磁盘,以支持 Windows 的 MBR 的方式来处理 bootloader 与 partion table。bootloader 与 partion table 都放在磁盘的第一个扇区,具体分布如下:
第一部分记录部分 bootloader,共446B
第二部分记录分区表,共 64B,最多记录 4 个分区信息
第三部分记录 MBR 标记,内容是 55AA,共 2 B
# hexdump 可以查看磁盘上指定地址的内容,下面是 BIOS 方式下启动盘前 512 字节的内容
[root@localhost rootfs]# hexdump -C -n 512 /dev/sda
00000000 eb 63 90 10 8e d0 bc 00 b0 b8 00 00 8e d8 8e c0 |.c..............|
00000010 fb be 00 7c bf 00 06 b9 00 02 f3 a4 ea 21 06 00 |...|.........!..|
00000020 00 be be 07 38 04 75 0b 83 c6 10 81 fe fe 07 75 |....8.u........u|
00000030 f3 eb 16 b4 02 b0 01 bb 00 7c b2 80 8a 74 01 8b |.........|...t..|
00000040 4c 02 cd 13 ea 00 7c 00 00 eb fe 00 00 00 00 00 |L.....|.........|
00000050 00 00 00 00 00 00 00 00 00 00 00 80 01 00 00 00 |................|
00000060 00 00 00 00 ff fa 90 90 f6 c2 80 74 05 f6 c2 70 |...........t...p|
00000070 74 02 b2 80 ea 79 7c 00 00 31 c0 8e d8 8e d0 bc |t....y|..1......|
00000080 00 20 fb a0 64 7c 3c ff 74 02 88 c2 52 be 05 7c |. ..d|<.t...R..||
00000090 b4 41 bb aa 55 cd 13 5a 52 72 3d 81 fb 55 aa 75 |.A..U..ZRr=..U.u|
000000a0 37 83 e1 01 74 32 31 c0 89 44 04 40 88 44 ff 89 |7...t21..[email protected]..|
000000b0 44 02 c7 04 10 00 66 8b 1e 5c 7c 66 89 5c 08 66 |D.....f..\|f.\.f|
000000c0 8b 1e 60 7c 66 89 5c 0c c7 44 06 00 70 b4 42 cd |..`|f.\..D..p.B.|
000000d0 13 72 05 bb 00 70 eb 76 b4 08 cd 13 73 0d 5a 84 |.r...p.v....s.Z.|
000000e0 d2 0f 83 de 00 be 85 7d e9 82 00 66 0f b6 c6 88 |.......}...f....|
000000f0 64 ff 40 66 89 44 04 0f b6 d1 c1 e2 02 88 e8 88 |[email protected]..........|
00000100 f4 40 89 44 08 0f b6 c2 c0 e8 02 66 89 04 66 a1 |[email protected].......f..f.|
00000110 60 7c 66 09 c0 75 4e 66 a1 5c 7c 66 31 d2 66 f7 |`|f..uNf.\|f1.f.|
00000120 34 88 d1 31 d2 66 f7 74 04 3b 44 08 7d 37 fe c1 |4..1.f.t.;D.}7..|
00000130 88 c5 30 c0 c1 e8 02 08 c1 88 d0 5a 88 c6 bb 00 |..0........Z....|
00000140 70 8e c3 31 db b8 01 02 cd 13 72 1e 8c c3 60 1e |p..1......r...`.|
00000150 b9 00 01 8e db 31 f6 bf 00 80 8e c6 fc f3 a5 1f |.....1..........|
00000160 61 ff 26 5a 7c be 80 7d eb 03 be 8f 7d e8 34 00 |a.&Z|..}....}.4.|
00000170 be 94 7d e8 2e 00 cd 18 eb fe 47 52 55 42 20 00 |..}.......GRUB .|
00000180 47 65 6f 6d 00 48 61 72 64 20 44 69 73 6b 00 52 |Geom.Hard Disk.R|
00000190 65 61 64 00 20 45 72 72 6f 72 0d 0a 00 bb 01 00 |ead. Error......|
000001a0 b4 0e cd 10 ac 3c 00 75 f4 c3 00 00 00 00 00 00 |.....<.u........|
000001b0 00 00 00 00 00 00 00 00 f3 bb 74 a1 00 00 80 04 |..........t.....|
000001c0 01 04 83 fe c2 ff 00 08 00 00 00 a0 0f 00 00 fe |................|
000001d0 c2 ff 83 fe c2 ff 00 a8 0f 00 00 58 30 06 00 00 |...........X0...|
000001e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.|
MS-DOS 分区表有主分区、扩展分区和逻辑分区的概念:
MS-DOS 分区的缺陷:
由于分区表位数的限制,OS 无法获取 2.2T 以上的磁盘容量
MBR只有一个扇区,且只有一份,破坏后,很难恢复
bootloader 只有 446 字节,无法容纳较多的程序代码
GPT 分区
GPT 为了处理大硬盘,使用 LBA 编址,每个 LBA 512B。原来 MBR 占用的第一个 sector 现在是 LBA0。GPT 使用了 34 个 LBA 区块来纪录分区信息!与 MBR 仅有一的区块, GPT 除了前面 34 个 LBA 之外,整个磁盘的最后 33 个 LBA 也拿来作为另一个备份。具体结构如下:
引导过程如下:
boot.img(mbr 446B) ==> diskboot.img ==> kernel.img,通过 /boot/grub2/grub.cfg 找到 vmlinuz 和 initramfs
上述 boot.img、diskboot.img 和 kernel.img 都是 bootloader的一部分,他们被硬编码到启动盘上,不是以文件的形式存在于文件系统中。
boot.img
在 BIOS 平台下,boot.img 是 grub 启动的第一个 img 文件,它被写入到MBR中或分区的boot sector中,因为 boot sector 的大小是512字节,所以该 img 文件的大小也是 512 字节。
boot.img 唯一的作用是读取属于 core.img 的第一个扇区并跳转到它身上,将控制权交给该扇区的 img。由于体积大小的限制,boot.img 无法理解文件系统的结构,因此 grub2-install 将会把 core.img 的位置硬编码到 boot.img 中,这样就一定能找到 core.img 的位置。
core.img
core.img 根据 diskboot.img、kernel.img 和一系列的模块被 grub2-mkimage 程序动态创建。core.img 中嵌入了足够多的功能模块以保证 grub 能访问 /boot/grub2,并且可以加载相关的模块实现相关的功能,例如加载启动菜单、加载目标操作系统的信息等,由于 grub2 大量使用了动态功能模块,使得 core.img 体积变得足够小。
core.img 中包含了多个 img 文件的内容,包括 diskboot.img/kernel.img 等。
diskboot.img
如果启动设备是硬盘,即从硬盘启动时,core.img 中的第一个扇区的内容就是 diskboot.img。diskboot.img 的作用是读取 core.img 中剩余的部分到内存中,并将控制权交给 kernel.img,由于此时还不识别文件系统,所以将 core.img 的全部位置以 block 列表的方式编码,使得 diskboot.img 能够找到剩余的内容。
该img文件因为占用一个扇区,所以体积为512字节。
kernel.img
kernel.img 文件包含了 grub 的基本运行时环境:设备框架、文件句柄、环境变量、救援模式下的命令行解析器等等。很少直接使用它,因为它们已经整个嵌入到了 core.img 中了。注意,kernel.img 是 grub 的 kernel,和操作系统的内核无关。
如果细心的话,会发现 kernel.img 本身就占用 28KB 空间,但嵌入到了 core.img 中后,core.img 文件才只有 26KB 大小。这是因为 core.img 中的 kernel.img 是被压缩过的。
*.mod
各种功能模块,部分模块已经嵌入到 core.img 中,或者会被 grub 自动加载,但有时也需要使用 insmod 命令手动加载。
引导方式如下:
x86_64: uefi ==> shimx64.efi ==> grubx64.efi ==> /boot/efi/EFI/centos/grub.cfg ==> vmlinuz & initramfs
aarch64: uefi ==> shimaa64.efi ==> grubaa64.efi ==> /boot/efi/EFI/centos/grub.cfg ==> vmlinuz & initramfs
x86 架构系统中,shimx64.efi 和 grubx64.efi 是 UEFI 启动方式下的 bootloader,他们以文件的形式存在于磁盘的 /boot/efi/EFI/centos 目录下,UEFI 可以直接识别文件系统,并获取 shimx64.efi 加载到内存运行,然后 shimx64.efi 获取 grubx64.efi,grubx64.efi 则通过 grub.cfg 寻找 vmlinuz 和 initfamfs,并将其加载到内存中。arm 架构系统过程类似。
内核启动过程比较复杂,未深入研究,以后有时间研究再整理。为了启动用户态服务,内核需要做的一些工作如下:
上述过程内核代码流程如下(基于 4.19.112 内核):
start_kernel() // init/main.c
|── vfs_caches_init()
| └── mnt_init()
| |── init_rootfs()
| | |── register_filesystem(&rootfs_fs_type)
| | └── init_ramfs_fs()
| | └── register_filesystem(&ramfs_fs_type)
| └── init_mount_tree()
| |── init_task.nsproxy->mnt_ns = ns
| |── set_fs_pwd(current->fs, &root)
| └── set_fs_root(current->fs, &root)
└── rest_init()
└── kernel_thread(kernel_init, NULL, CLONE_FS)
└── kernel_init()
|── kernel_init_freeable()
| |── do_basic_setup()
| | └── do_initcalls()
| | └── populate_rootfs()
| | └── unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start)
| └── ramdisk_execute_command = "/init"
└── run_init_process(ramdisk_execute_command)
initramfs 中的内容如下:
# initramfs 可以通过如下命令解压
[root@localhost rootfs]# /usr/lib/dracut/skipcpio /boot/initramfs-4.18.0-193.el8.x86_64.img | zcat | cpio -divm
[root@localhost rootfs]# ll
total 44
lrwxrwxrwx. 1 root root 7 Jul 3 19:13 bin -> usr/bin
drwxr-xr-x. 2 root root 4096 Jul 3 19:13 dev
drwxr-xr-x. 11 root root 4096 Jul 3 19:13 etc
lrwxrwxrwx. 1 root root 23 Jul 3 19:13 init -> usr/lib/systemd/systemd
lrwxrwxrwx. 1 root root 7 Jul 3 19:13 lib -> usr/lib
lrwxrwxrwx. 1 root root 9 Jul 3 19:13 lib64 -> usr/lib64
drwxr-xr-x. 2 root root 4096 Apr 24 11:24 proc
drwxr-xr-x. 2 root root 4096 Apr 24 11:24 root
drwxr-xr-x. 2 root root 4096 Apr 24 11:24 run
lrwxrwxrwx. 1 root root 8 Jul 3 19:13 sbin -> usr/sbin
-rwxr-xr-x. 1 root root 3126 Oct 8 2018 shutdown
drwxr-xr-x. 2 root root 4096 Apr 24 11:24 sys
drwxr-xr-x. 2 root root 4096 Apr 24 11:24 sysroot
drwxr-xr-x. 2 root root 4096 Apr 24 11:24 tmp
drwxr-xr-x. 7 root root 4096 Jul 3 19:13 usr
从 initramfs 解压的内容中可以看出,这就是一个小型的根文件系统,其中,init 是指向 usr/lib/systemd/systemd 的软连接。
该阶段主要启动一些用户态服务。
由于大部分用户态服务涉及的可执行文件以及配置文件都在根文件系统中,需要挂载根文件系统;若要识别根文件系统,又需要加载磁盘驱动,而磁盘驱动也位于根文件系统中,形成死锁。
对于上述问题,主流 OS 发行版的做法都是通过 initramfs 方式,就是将一些必要的驱动和用户态工具打包到 initramfs 中,然后通过 initramfs 启动,必要的初始化后,再切换到真实的根文件系统,过程如下:
systemd 是通过 target 的方式来完成各种服务的启动,具体流程如下:
sysinit.target ==> basic.target ==> initrd.target ==> switch-root ==> multi-user.target
上述流程中可以看到关键的步骤 switch-root,switch-root 之前运行的服务都来自 initramfs,switch-root 之后运行的服务都来自真实根文件系统。
sysinit.target、basic.target 和 initrd.target 中涉及的一些 dracut 服务是启动过程中一些关键的启动点,可以通过在启动参数里添加 rd.break 启动参数,在这些点停下来,部分可以进入shell,具体可以查看 10. dracut.cmdline(7) — Linux manual page 。
switch-root 之前的初始启动日志会打印 Welcome to CentOS Linux 8 (Core) dracut-049-70.git20200228.el8 (Initramfs)!,该内容来自 initramfs 中的 /etc/initrd-release,systemd 也正是通过这个文件判断是否运行在 initramfs 中。
switch-root 之后启动日志中会打印 Welcome to CentOS Linux 8 (Core)!(过程太快,这里没有截到图,想从串口查看日志,vmware 设置串口没有成功)。
# /usr/lib/systemd/system/../../dracut/modules.d/98dracut-systemd/dracut-cmdline.service
# This file is part of dracut.
#
# See dracut.bootup(7) for details
[Unit]
Description=dracut cmdline hook
Documentation=man:dracut-cmdline.service(8)
DefaultDependencies=no
Before=dracut-pre-udev.service
After=systemd-journald.socket
Wants=systemd-journald.socket
ConditionPathExists=/usr/lib/initrd-release
ConditionPathExistsGlob=|/etc/cmdline.d/*.conf
ConditionDirectoryNotEmpty=|/lib/dracut/hooks/cmdline
ConditionKernelCommandLine=|rd.break=cmdline
ConditionKernelCommandLine=|resume
ConditionKernelCommandLine=|noresume
Conflicts=shutdown.target emergency.target
[Service]
Environment=DRACUT_SYSTEMD=1
Environment=NEWROOT=/sysroot
Type=oneshot
ExecStart=-/bin/dracut-cmdline
StandardInput=null
StandardOutput=syslog
StandardError=syslog+console
KillMode=process
RemainAfterExit=yes
# Bash ignores SIGTERM, so we send SIGHUP instead, to ensure that bash
# terminates cleanly.
KillSignal=SIGHUP
# /usr/lib/systemd/system/../../dracut/modules.d/98dracut-systemd/dracut-pre-udev.service
# This file is part of dracut.
#
# See dracut.bootup(7) for details
[Unit]
Description=dracut pre-udev hook
Documentation=man:dracut-pre-udev.service(8)
DefaultDependencies=no
Before=systemd-udevd.service dracut-pre-trigger.service
After=dracut-cmdline.service
Wants=dracut-cmdline.service
ConditionPathExists=/usr/lib/initrd-release
ConditionDirectoryNotEmpty=|/lib/dracut/hooks/pre-udev
ConditionKernelCommandLine=|rd.break=pre-udev
ConditionKernelCommandLine=|rd.driver.blacklist
ConditionKernelCommandLine=|rd.driver.pre
ConditionKernelCommandLine=|rd.driver.post
ConditionPathExistsGlob=|/etc/cmdline.d/*.conf
Conflicts=shutdown.target emergency.target
[Service]
Environment=DRACUT_SYSTEMD=1
Environment=NEWROOT=/sysroot
Type=oneshot
ExecStart=-/bin/dracut-pre-udev
StandardInput=null
StandardOutput=syslog
StandardError=syslog+console
KillMode=process
RemainAfterExit=yes
# Bash ignores SIGTERM, so we send SIGHUP instead, to ensure that bash
# terminates cleanly.
KillSignal=SIGHUP
# /usr/lib/systemd/system/../../dracut/modules.d/98dracut-systemd/dracut-pre-trigger.service
# This file is part of dracut.
#
# See dracut.bootup(7) for details
[Unit]
Description=dracut pre-trigger hook
Documentation=man:dracut-pre-trigger.service(8)
DefaultDependencies=no
Before=systemd-udev-trigger.service dracut-initqueue.service
After=dracut-pre-udev.service systemd-udevd.service systemd-tmpfiles-setup-dev.service
Wants=dracut-pre-udev.service systemd-udevd.service
ConditionPathExists=/usr/lib/initrd-release
ConditionDirectoryNotEmpty=|/lib/dracut/hooks/pre-trigger
ConditionKernelCommandLine=|rd.break=pre-trigger
Conflicts=shutdown.target emergency.target
[Service]
Environment=DRACUT_SYSTEMD=1
Environment=NEWROOT=/sysroot
Type=oneshot
ExecStart=-/bin/dracut-pre-trigger
StandardInput=null
StandardOutput=syslog
StandardError=syslog+console
KillMode=process
RemainAfterExit=yes
# Bash ignores SIGTERM, so we send SIGHUP instead, to ensure that bash
# terminates cleanly.
KillSignal=SIGHUP
# /usr/lib/systemd/system/../../dracut/modules.d/98dracut-systemd/dracut-initqueue.service
# This file is part of dracut.
#
# See dracut.bootup(7) for details
[Unit]
Description=dracut initqueue hook
Documentation=man:dracut-initqueue.service(8)
DefaultDependencies=no
Before=remote-fs-pre.target
Wants=remote-fs-pre.target
After=systemd-udev-trigger.service
Wants=systemd-udev-trigger.service
ConditionPathExists=/usr/lib/initrd-release
ConditionPathExists=|/lib/dracut/need-initqueue
ConditionKernelCommandLine=|rd.break=initqueue
Conflicts=shutdown.target emergency.target
[Service]
Environment=DRACUT_SYSTEMD=1
Environment=NEWROOT=/sysroot
Type=oneshot
ExecStart=-/bin/dracut-initqueue
StandardInput=null
StandardOutput=syslog
StandardError=syslog+console
KillMode=process
RemainAfterExit=yes
# Bash ignores SIGTERM, so we send SIGHUP instead, to ensure that bash
# terminates cleanly.
KillSignal=SIGHUP
# /usr/lib/systemd/system/../../dracut/modules.d/98dracut-systemd/dracut-pre-mount.service
# This file is part of dracut.
#
# See dracut.bootup(7) for details
[Unit]
Description=dracut pre-mount hook
Documentation=man:dracut-pre-mount.service(8)
DefaultDependencies=no
Before=initrd-root-fs.target sysroot.mount systemd-fsck-root.service
After=dracut-initqueue.service cryptsetup.target
ConditionPathExists=/usr/lib/initrd-release
ConditionDirectoryNotEmpty=|/lib/dracut/hooks/pre-mount
ConditionKernelCommandLine=|rd.break=pre-mount
Conflicts=shutdown.target emergency.target
[Service]
Environment=DRACUT_SYSTEMD=1
Environment=NEWROOT=/sysroot
Type=oneshot
ExecStart=-/bin/dracut-pre-mount
StandardInput=null
StandardOutput=syslog
StandardError=syslog+console
KillMode=process
RemainAfterExit=yes
# Bash ignores SIGTERM, so we send SIGHUP instead, to ensure that bash
# terminates cleanly.
KillSignal=SIGHUP
# /usr/lib/systemd/system/../../dracut/modules.d/98dracut-systemd/dracut-mount.service
# This file is part of dracut.
#
# See dracut.bootup(7) for details
[Unit]
Description=dracut mount hook
Documentation=man:dracut-mount.service(8)
After=initrd-root-fs.target initrd-parse-etc.service
After=dracut-initqueue.service dracut-pre-mount.service
ConditionPathExists=/usr/lib/initrd-release
ConditionDirectoryNotEmpty=|/lib/dracut/hooks/mount
ConditionKernelCommandLine=|rd.break=mount
DefaultDependencies=no
Conflicts=shutdown.target emergency.target
[Service]
Environment=DRACUT_SYSTEMD=1
Environment=NEWROOT=/sysroot
Type=oneshot
ExecStart=-/bin/dracut-mount
StandardInput=null
StandardOutput=syslog
StandardError=syslog+console
KillMode=process
RemainAfterExit=yes
# Bash ignores SIGTERM, so we send SIGHUP instead, to ensure that bash
# terminates cleanly.
KillSignal=SIGHUP
该阶段主要完成 root 的切换,并将控制权交给新的 systemd 进程:
# /usr/lib/systemd/system/../../dracut/modules.d/98dracut-systemd/dracut-pre-pivot.service
# This file is part of dracut.
#
# See dracut.bootup(7) for details
[Unit]
Description=dracut pre-pivot and cleanup hook
Documentation=man:dracut-pre-pivot.service(8)
DefaultDependencies=no
After=initrd.target initrd-parse-etc.service sysroot.mount
After=dracut-initqueue.service dracut-pre-mount.service dracut-mount.service
Before=initrd-cleanup.service
Wants=remote-fs.target
After=remote-fs.target
ConditionPathExists=/usr/lib/initrd-release
ConditionDirectoryNotEmpty=|/lib/dracut/hooks/pre-pivot
ConditionDirectoryNotEmpty=|/lib/dracut/hooks/cleanup
ConditionKernelCommandLine=|rd.break=pre-pivot
ConditionKernelCommandLine=|rd.break=cleanup
ConditionKernelCommandLine=|rd.break
ConditionPathExists=|/dev/root
ConditionPathExists=|/dev/nfs
Conflicts=shutdown.target emergency.target
[Service]
Environment=DRACUT_SYSTEMD=1
Environment=NEWROOT=/sysroot
Type=oneshot
ExecStart=-/bin/dracut-pre-pivot
StandardInput=null
StandardOutput=syslog
StandardError=syslog+console
KillMode=process
RemainAfterExit=yes
# Bash ignores SIGTERM, so we send SIGHUP instead, to ensure that bash
# terminates cleanly.
KillSignal=SIGHUP
# /usr/lib/systemd/system/initrd-cleanup.service
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Cleaning Up and Shutting Down Daemons
DefaultDependencies=no
ConditionPathExists=/etc/initrd-release
OnFailure=emergency.target
OnFailureJobMode=replace-irreversibly
After=initrd-root-fs.target initrd-fs.target initrd.target
[Service]
Type=oneshot
ExecStart=/usr/bin/systemctl --no-block isolate initrd-switch-root.target
# /usr/lib/systemd/system/initrd-switch-root.service
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Switch Root
DefaultDependencies=no
ConditionPathExists=/etc/initrd-release
OnFailure=emergency.target
OnFailureJobMode=replace-irreversibly
AllowIsolate=yes
[Service]
Type=oneshot
ExecStart=/usr/bin/systemctl --no-block switch-root /sysroot
# /usr/lib/systemd/system/systemd-logind.service
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Login Service
Documentation=man:systemd-logind.service(8) man:logind.conf(5)
Documentation=https://www.freedesktop.org/wiki/Software/systemd/logind
Documentation=https://www.freedesktop.org/wiki/Software/systemd/multiseat
Wants=user.slice
After=nss-user-lookup.target user.slice
# Ask for the dbus socket.
Wants=dbus.socket
After=dbus.socket
[Service]
ExecStart=/usr/lib/systemd/systemd-logind
Restart=always
RestartSec=0
BusName=org.freedesktop.login1
WatchdogSec=3min
CapabilityBoundingSet=CAP_SYS_ADMIN CAP_MAC_ADMIN CAP_AUDIT_CONTROL CAP_CHOWN CAP_KILL CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE CAP>
MemoryDenyWriteExecute=yes
RestrictRealtime=yes
RestrictNamespaces=yes
RestrictAddressFamilies=AF_UNIX AF_NETLINK
RestrictSUIDSGID=yes
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
SystemCallArchitectures=native
LockPersonality=yes
FileDescriptorStoreMax=512
# Increase the default a bit in order to allow many simultaneous
# logins since we keep one fd open per session.
LimitNOFILE=16384
# /usr/lib/systemd/system/getty.target
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=Login Prompts
Documentation=man:systemd.special(7) man:systemd-getty-generator(8)
Documentation=http://0pointer.de/blog/projects/serial-console.html
至此,从加电到登录界面 Linux 的整个启动流程梳理完毕,只是粗略的介绍了大致流程,整个启动过程非常复杂,很多细节还没有搞清楚,所以没有展开。
1. UEFI 启动:实际工作原理
2. DOS分区表(Boot Sector引导扇区)
3. Linux磁盘管理——MBR 与 GPT
4. grub2 详解(翻译和整理官方手册)
5. linux内核启动流程(文章最后流程图)
6. Linux内核Ramdisk(initrd)机制
7. dracut.bootup(7) — Linux manual page
8. bootup(7) — Linux manual page
9. boot(7) — Linux manual page
10. dracut.cmdline(7) — Linux manual page
11. 鳥哥的 Linux 私房菜 - 基礎學習篇
12. 金步国 systemd 中文手册