裸机启动 Linux:不到一秒启动一个单进程内核
还记得小时候的电脑吗?开机后不到一秒就开始加载磁盘内容了。如今即便 16 核怪兽配上高速 SSD,启动也要一分钟。我决定试一种替代方案——保留 Linux 内核,剥离一切不必要的东西。
Hello, World!
Linux 系统启动时首先运行一个 init 程序。我们可以写一个超级简单的 C 语言 init:
#include <stdio.h>
#include <stdlib.h>
#include <sys/reboot.h>
int main(int argc, char **argv) {
fprintf(stderr, "Hello from init.c!");
reboot(RB_POWER_OFF);
}
它只做一件事:打印一条消息,然后关闭计算机。如果 init 进程退出,内核 panic。我们用 reboot(RB_POWER_OFF) 来有序关机。
构建 initrd
现代 Linux 的引导流程:引导加载器加载内核和 initrd → 内核将 initrd 解包到 RAM 中的 initramfs → 查找并运行 /init → 如果 init 退出,内核 panic。
大多数发行版提供的 initrd 非常庞大(我的电脑上是 73MB,2163 个文件)。我只需要一个文件:
gcc -static init.c -o init
echo "init" | cpio -o --format=newc | gzip -c > initrd
然后用 KVM 启动(不到一秒就运行了我们的程序):
kvm -m 1G -nographic -kernel vmlinuz
-initrd initrd -append "console=ttyS0"
访问设备
init 运行时还没有挂载根文件系统。通过 devtmpfs 激活设备。QEMU 用 -hda 将主机文件暴露为客户机块设备(显示为 /dev/sda):
mount("devtmpfs", "/dev", "devtmpfs", 0, NULL);
int fd = open("/dev/sda", O_RDWR);
uint32_t buffer[2];
read(fd, buffer, sizeof(buffer));
close(fd);
从开机到读取磁盘数据同样不到一秒。
在真实硬件上启动

在 UEFI 系统上需要制作统一内核镜像:
ukify build --linux=vmlinuz --initrd=initrd
sudo cp vmlinuz.unsigned.efi /mnt/EFI/BOOT/BOOTX64.EFI
构建微内核

之前的演示用的是标准发行版内核(~16MB)。用 make tinyconfig 从零构建一个裁剪版(1-2MB):
关键配置选项:启用 Initramfs/initrd 支持、ELF 二进制支持、devtmpfs、TTY、8250 串口驱动,编译器优化选 -Os。根据需求启用 ext3/ext4/FAT/exFAT 文件系统支持。
值得折腾吗?
节省磁盘空间、启动更快;移除未使用的内核部分也减少了攻击面。还可以将 initrd 编译进内核,最终只需要一个文件就能从启动加载程序。构建自己的内核也是支持嵌入式设备的必经之路。