← LeisureLinux 文章索引
LeisureLinux · 微信公众号文章

手搓微型 Linux 发行版:从零开始打造你的专属系统

Linux/运维 阅读原文(微信)↗

>

原文:Making a micro Linux distro

━━━ ━━━ ━━━

写在前面

\"从零开始构建 Linux 发行版\"——听起来像是个疯狂的想法,对吧?毕竟现在有 Ubuntu、Debian、Arch 等上百个发行版,为什么还要自己造轮子?

答案是:理解内核、用户空间和操作系统之间那条看不见的分界线。这篇文章不走寻常路,它不是教你用 Yocto 或 Buildroot 去\"配菜\",而是真正从内核编译开始,手写 init 进程,看着屏幕上一个简单到几乎无用的系统启动起来,然后理解它为什么能启动。

更酷的是——作者选了 RISC-V 架构(QEMU riscv64 virt 模拟器),这意味着你完全可以在 x86 电脑上交叉编译一个 RISC-V 的微型系统跑着玩。

━━━ ━━━ ━━━

一、内核是什么?一个不太严谨但足够用的比喻

作者用一个很朴素的问题开场:在一台单核机器上,多个程序怎么\"同时\"运行?

答案是——内核干的。但内核干的不止这一件事:

  1. 硬件抽象:把那些晦涩的 I/O 地址和寄存器值,包装成简单的系统调用接口(比如 printf,背后是 write 系统调用)
  2. 文件系统:你以为文件就是硬盘上的数据?不一定。文件也可以是个管道、一个 socket、一个设备节点——文件系统其实是和内核对话的一种方式
  3. 编程模型:你的 Python Web 服务器不需要知道那个聊天 App 的存在——内核给了你\"进程隔离\"。反过来,你也可以让它们共享内存,只要你想。

一句话总结:内核是运行用户程序的底层基础设施。但它不会帮你打开 Chrome、播放 YouTube——这些事得交给上层。

━━━ ━━━ ━━━

二、什么叫 \"Linux 发行版\"?

光有内核,你连个 ls 命令都跑不了。作者给出了他的理解:

Linux 发行版 = Linux 内核 + 运行在内核之上的用户空间基础设施

这个\"基础设施\"包括:

  • init 进程(用户空间第一个程序,PID 1)
  • 各种 systemd 服务 / 守护进程
  • 你日常用的工具集(ls, cat, ps, grep...)
  • 包管理器
  • 桌面环境(如果有的话)

内核只管最低层——驱动网卡发信号出去。至于连哪个 Wi-Fi、用不用 VPN、IP 是静态还是 DHCP......这些通通发生在用户空间

━━━ ━━━ ━━━

三、init:所有进程的\"祖宗\"

内核启动完成后,会在文件系统上找一个叫 /init 的二进制文件(没找到的话再试其他几个位置),把它拉起来,分配 PID 1。

这个 init 进程是内核主动启动的唯一用户进程。之后所有进程都是 init 的\"子孙\"——init 启动 shell,shell 启动 ls,ls 执行完退出,shell 继续等着你的下一个命令。

一个重要的感悟:即使偶尔启动的临时工具(比如 cron 里每隔五分钟跑一次的脚本),在进程树上也是 init 的后代。

所以,一个 Linux 发行版的本质就是:内核 + 启动后拉起的那一堆进程 + 你能调用的所有工具命令

━━━ ━━━ ━━━

四、手搓一个\"几乎没用\"的微型发行版

好,来真的了。

4.1 编译内核

# 下载 Linux 6.5.2
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.5.2.tar.xz
tar -xf linux-6.5.2.tar.xz
cd linux-6.5.2

# 配置(RISC-V 交叉编译)
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- defconfig

# 如果你有强迫症,可以 menuconfig 微调
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- menuconfig

# 编译(-j 并发加速)
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- -j$(nproc)

输出文件:arch/riscv/boot/Image——这就是我们的内核镜像。

4.2 写一个最简 init(C 语言版)

#include <stdio.h>

int main() {
printf("Hello world\n");
return 0;
}

编译成静态链接:

riscv64-linux-gnu-gcc -static -o init init.c

4.3 打包 initramfs

Linux 内核启动后,需要一个初始文件系统(initramfs)来加载 init 和其他必要工具。最小化方案:

echo init | cpio -o -H newc > initramfs.cpio

这里的关键是 -H newc——Linux 内核要求 initramfs 使用 newc 格式

4.4 启动!

qemu-system-riscv64 -machine virt -kernel arch/riscv/boot/Image -initrd /path/to/initramfs.cpio

你会看到:

[ 0.351894] Run /init as init process Hello world [ 0.379006] Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000000

Kernel panic!

不过别慌——init 打印了 \"Hello world\",然后 return 0 退出了。内核的规则是:PID 1 不能退出。init 挂了,系统就崩了。

解决方案:让 init 一直运行,别停

4.5 修复版 init:加上循环

#include <stdio.h>
#include <unistd.h>

int main() {
int count = 1;
while (1) {
printf("Hello from init! %d\n", count);
count++;
sleep(10);
}
return 0;
}

重新编译打包启动,这次不会 panic 了——但你也只能看着 \"Hello from init! N\" 每 10 秒刷新一次。没 shell、没命令,毫无用处,但确实是一个活着的微型 Linux 系统

━━━ ━━━ ━━━

五、让它\"有用\"起来:加上一个小 shell5.1 改造 init:fork + exec

Linux 启动子进程的标准姿势是 fork + exec

pid_t pid = fork();
if (pid == 0) {
// 子进程,执行 shell
execl("/little_shell", "irrelevant", NULL);
}
// 父进程继续每 10 秒打印一次

fork() 克隆当前进程,返回 0 表示你在子进程里。然后 execl() 告诉内核:\"把我现在跑的代码替换成这个二进制的代码\"。

5.2 用 Go 写 shell——老古董玩新花样

作者决定不用 C,而是用 Go 来写这个简单 shell:

package main

import (

"bufio" "fmt" "os"

)

func main() {
fmt.Println("Hello world from Go!")
reader := bufio.NewReader(os.Stdin)
for {
fmt.Print("Enter your command: ")
line, _ := reader.ReadString('\n')
fmt.Printf("Your command is: %s", line)
}
}

交叉编译:

GOOS=linux GOARCH=riscv64 go build little_shell.go

注意:Go 编译出来的二进制差不多 1.9MB,而 C 版的 init 只有 454KB。这是 Go 的优势(开箱即用的静态链接 + 丰富的标准库)和代价(更大的体积)。在动辄几百 GB 存储的电脑上这不是问题,但在嵌入式场景就值得权衡。

另外,Go 程序对内核特性有依赖(比如 futex),默认的 RISC-V 内核配置够用——但如果遇到 Go panic,仔细读 panic 信息就能定位缺少的内核配置。

5.3 启动,见证奇迹

Hello from the original init! 1 Hello world from Go! Enter your command: mkdir hello Your command is: mkdir hello Enter your command: ls Your command is: ls Hello from the original init! 2 Enter your command: exit Your command is: exit Hello from the original init! 3

能交互了!虽然 shell 只会\"回声\",不懂 mkdirls 的真正含义——但进程隔离、文件系统、标准输入输出流......一代微型 Linux 发行版诞生了

━━━ ━━━ ━━━

六、回顾:内核兑现了哪些承诺?

作者在实现这个玩具后,回头检验内核的核心价值:

承诺 兑现情况
硬件抽象 ✅ init 和 shell 完全不知道 UART 的存在,只管向文件描述符写数据
高级编程范式(文件系统) ✅ init 通过文件路径 /little_shell 定位并加载 shell 二进制
进程隔离 ✅ fork 后 init 和 shell 各自独立运行,内存隔离
文件描述符继承(有待理解) ⚠️ shell 继承了 init 的标准输出,所以两者输出混在一起------这是 fork 的行为,不是 bug

内核给了你一个扎实、可移植的基础设施,你可以在上面开发高层软件,同时很大程度忽略底层硬件的复杂性。

━━━ ━━━ ━━━

七、Bonus:用 u-root 让系统真正可用

自己写工具链太累?作者推荐了 u-root 项目——一个用 Go 写的全能型用户空间工具集。

一步到位:

git clone https://github.com/u-root/u-root.git
cd u-root

GOOS=linux GOARCH=riscv64 u-root

# 输出:/tmp/initramfs.linux_riscv64.cpio (约 14MB)

直接用这个 initramfs 启动:

qemu-system-riscv64 -machine virt -kernel arch/riscv/boot/Image -initrd /tmp/initramfs.linux_riscv64.cpio

你会看到一个完整的 shell,支持 Tab 补全!ls、pwd、echo 全都正常。

更刺激的:从虚拟机里访问 google.com

加几个 QEMU 设备参数:

-device virtio-net-device,netdev=usernet

-netdev user,id=usernet,hostfwd=tcp::10000-:22 \

-device virtio-rng-pci

启动进入 shell 后:

# DHCP 获取 IP

dhclient -ipv6=false

# 访问 Google
wget http://google.com
cat index.html

一堆混淆过的 JavaScript 跳出来——你成功地从自己手搓的微型发行版里访问了 Google!

━━━ ━━━ ━━━

八、延伸思考包管理器

你现在理解了,自制发行版其实是\"整体镜像\"模式——想更新一个工具?重新编译整个 initramfs,重新烧录。这不适合桌面和手机场景。包管理器就是用来打破这个模式的——增量安装、卸载、更新,按需取用。

init 系统不是儿戏

玩具归玩具,实际上 init 是现代 Linux 系统里最举足轻重的组件之一。它不只是一个\"启动 shell 然后循环打印\"的程序——它要挂载文件系统、创建设备节点、配置网络、拉起各种守护进程。这也是为什么 systemd、OpenRC、runit 等 init 系统之间的争论可以打上十年。

小练习:当你的 u-root 系统启动后,ls /dev 看看有多少设备节点——大部分都是 init 帮你设置的。

━━━ ━━━ ━━━

写在最后

从下载内核源码,到亲手写 init,到用 Go 写一个只会\"回声\"的 shell,再到用 u-root 启动一个能上网的微型系统——这篇文章带着我们走了一遍 Linux 最底层也最浪漫的旅程。

作者说:\"内核给了你一个扎实可移植的基础设施。\" 而我更愿意说:从按下电源到看见 shell 提示符,这之间发生的一切,你都可以理解,也可以亲手构建。

这就是开源和 Linux 精神最动人的地方。

━━━ ━━━ ━━━

资源

  • GitHub 代码仓库

━━━ ━━━ ━━━

*🤖 本文翻译解读自 Uros Popovic 的技术文章 + LeisureLinux 视角重写。关注 LeisureLinux 公众号,获取更多底层技术深度解读。*

一个字符就能提权到 root?Linux 内核 CVE-2026-23111 深度剖析

Linux SLUB 分配器深度拆解:malloc 背后内核在干什么?

Arm 推进 Linux 内核适配 128 位页表条目扩展 \'FEAT_D128\'

内核纪元新篇章:Linux 7.0 深度技术解析与架构演进

【内核前沿】Linux 7.0 手动内联优化:UDP 吞吐量暴力提升 12%

剑指核心:uutils coreutils 0.9.0,Linux 底层江湖的又一波澜

本文整理自微信公众号 LeisureLinux 的原创内容(Linux / AI / 安全 硬核技术)。

· 阅读原文(微信公众号)

· 关注公众号 LeisureLinux,第一时间获取技术深度内容。

LeisureLinux 公众号二维码(微信扫一扫关注)