Linux内核+BusyBox
This commit is contained in:
1 parent
c8b1bdc5e2
commit
a29929b378
1 file changed
+358
-2
@@ -1,3 +1,359 @@
|
|||||||
# DreamLife_Linux
|
# Linux 内核 + BusyBox 最小系统构建指南
|
||||||
|
|
||||||
最小Linux系统编译
|
> 基于 Linux 6.12 + BusyBox,使用 QEMU 启动的最小根文件系统。
|
||||||
|
> 本文档记录从零构建到成功进入 shell 的完整过程,包含故障排查。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 环境准备
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install -y build-essential libncurses-dev bison flex \
|
||||||
|
libssl-dev libelf-dev git bc rsync cpio gzip wget gcc-14 qemu-system-x86
|
||||||
|
```
|
||||||
|
|
||||||
|
目录结构:
|
||||||
|
|
||||||
|
```
|
||||||
|
/home/zmn/
|
||||||
|
├── linux-6.12/ # 内核源码
|
||||||
|
├── busybox/ # BusyBox 源码
|
||||||
|
├── rootfs/ # 根文件系统
|
||||||
|
└── initramfs.cpio.gz # 打包后的 initramfs
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第一步:下载并解压内核源码
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/zmn
|
||||||
|
wget https://mirrors.tuna.tsinghua.edu.cn/kernel/v6.x/linux-6.12.tar.xz
|
||||||
|
tar -xf linux-6.12.tar.xz
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第二步:配置内核
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/zmn/linux-6.12
|
||||||
|
make x86_64_defconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
### 关键配置项
|
||||||
|
|
||||||
|
`x86_64_defconfig` 已默认启用以下必需选项(可用 `grep` 验证):
|
||||||
|
|
||||||
|
| 配置项 | 作用 |
|
||||||
|
|--------|------|
|
||||||
|
| `CONFIG_SERIAL_8250=y` | 串口驱动 |
|
||||||
|
| `CONFIG_SERIAL_8250_CONSOLE=y` | 串口控制台(`console=ttyS0` 依赖此项) |
|
||||||
|
| `CONFIG_BLK_DEV_INITRD=y` | initramfs 支持(`-initrd` 依赖此项) |
|
||||||
|
| `CONFIG_RD_GZIP=y` | gzip 压缩的 initrd 解压支持 |
|
||||||
|
| `CONFIG_DEVTMPFS=y` | `/dev` 自动挂载 |
|
||||||
|
| `CONFIG_PRINTK=y` | 内核日志输出 |
|
||||||
|
|
||||||
|
验证:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep -E 'CONFIG_(SERIAL_8250_CONSOLE|BLK_DEV_INITRD|RD_GZIP|DEVTMPFS|PRINTK)=' .config
|
||||||
|
```
|
||||||
|
|
||||||
|
> **注意**:不要用 `make tinyconfig`,它几乎关闭所有驱动,导致没有串口控制台输出,
|
||||||
|
> QEMU 只会显示一个闪烁的光标。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第三步:编译内核
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/zmn/linux-6.12
|
||||||
|
make CC=gcc-14 -j$(nproc)
|
||||||
|
```
|
||||||
|
|
||||||
|
编译成功标志:
|
||||||
|
|
||||||
|
```
|
||||||
|
Kernel: arch/x86/boot/bzImage is ready (#1)
|
||||||
|
```
|
||||||
|
|
||||||
|
验证产物:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ls -la arch/x86/boot/bzImage
|
||||||
|
# 应输出类似:-rw-r--r-- 1 zmn zmn 13583360 ... bzImage
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第四步:下载并配置 BusyBox
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/zmn
|
||||||
|
git clone --depth 1 https://git.busybox.net/busybox
|
||||||
|
cd busybox
|
||||||
|
make defconfig
|
||||||
|
```
|
||||||
|
|
||||||
|
### 关键配置:静态编译
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 开启静态链接(不依赖 libc.so 等共享库)
|
||||||
|
sed -i 's/^# CONFIG_STATIC is not set/CONFIG_STATIC=y/' .config
|
||||||
|
|
||||||
|
# 禁用 tc(新版内核头文件已删除 CBQ 结构体,会导致编译失败)
|
||||||
|
sed -i 's/^CONFIG_TC=y/# CONFIG_TC is not set/' .config
|
||||||
|
|
||||||
|
grep -E '^CONFIG_STATIC=|^CONFIG_TC=' .config
|
||||||
|
# 应输出:
|
||||||
|
# CONFIG_STATIC=y
|
||||||
|
# # CONFIG_TC is not set
|
||||||
|
```
|
||||||
|
|
||||||
|
> **为什么必须静态编译**:initramfs 中没有 `/lib`、`/lib64`,
|
||||||
|
> 动态链接的 BusyBox 在启动时会因找不到 `ld-linux-x86-64.so.2` 而失败,
|
||||||
|
> 内核 panic,屏幕上什么都看不到。
|
||||||
|
>
|
||||||
|
> **为什么必须禁用 tc**:`make defconfig` 默认开启 `CONFIG_TC=y`,
|
||||||
|
> 但 `networking/tc.c` 引用的 `TCA_CBQ_*` 等结构体已在新版内核头文件中删除,
|
||||||
|
> 会导致编译报错 `TCA_CBQ_MAX undeclared`。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第五步:编译 BusyBox
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/zmn/busybox
|
||||||
|
make CC=gcc-14 -j$(nproc)
|
||||||
|
```
|
||||||
|
|
||||||
|
编译成功后验证:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
file busybox
|
||||||
|
# 应输出:ELF 64-bit LSB executable, x86-64, ... statically linked
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第六步:构建根文件系统
|
||||||
|
|
||||||
|
### 6.1 创建目录结构
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p /home/zmn/rootfs/{bin,sbin,etc,proc,sys,dev,tmp,root,usr/bin,usr/sbin}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 安装 BusyBox
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/zmn/busybox
|
||||||
|
make CONFIG_PREFIX=/home/zmn/rootfs install
|
||||||
|
```
|
||||||
|
|
||||||
|
验证:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
file /home/zmn/rootfs/bin/busybox
|
||||||
|
# 应输出:statically linked
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.3 编写 init 脚本
|
||||||
|
|
||||||
|
用 `cat` 写入 `/home/zmn/rootfs/init`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat > /home/zmn/rootfs/init << 'EOF'
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
mount -t proc none /proc
|
||||||
|
mount -t sysfs none /sys
|
||||||
|
mount -t devtmpfs none /dev
|
||||||
|
|
||||||
|
hostname minimal-linux
|
||||||
|
exec /bin/sh
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
赋予执行权限:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x /home/zmn/rootfs/init
|
||||||
|
```
|
||||||
|
|
||||||
|
验证:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ls -la /home/zmn/rootfs/init
|
||||||
|
# 应输出:-rwxr-xr-x ... /home/zmn/rootfs/init
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.4 init 脚本说明
|
||||||
|
|
||||||
|
| 命令 | 作用 |
|
||||||
|
|------|------|
|
||||||
|
| `mount -t proc` | 挂载进程信息系统,`ps`、`/proc` 依赖它 |
|
||||||
|
| `mount -t sysfs` | 挂载 sysfs,`/sys` 依赖它 |
|
||||||
|
| `mount -t devtmpfs` | 挂载设备文件系统,自动创建 `/dev/ttyS0` 等设备节点 |
|
||||||
|
| `exec /bin/sh` | 用 shell 替换当前进程,进入交互式命令行 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第七步:打包 initramfs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /home/zmn/rootfs
|
||||||
|
find . | cpio -o -H newc 2>/dev/null | gzip > /home/zmn/initramfs.cpio.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
验证:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ls -la /home/zmn/initramfs.cpio.gz
|
||||||
|
zcat /home/zmn/initramfs.cpio.gz | cpio -t 2>/dev/null | grep '^init$'
|
||||||
|
# 应输出:init
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 第八步:QEMU 启动
|
||||||
|
|
||||||
|
```bash
|
||||||
|
qemu-system-x86_64 \
|
||||||
|
-kernel /home/zmn/linux-6.12/arch/x86/boot/bzImage \
|
||||||
|
-initrd /home/zmn/initramfs.cpio.gz \
|
||||||
|
-append "console=ttyS0 rdinit=/init" \
|
||||||
|
-nographic \
|
||||||
|
-m 256M
|
||||||
|
```
|
||||||
|
|
||||||
|
### 参数说明
|
||||||
|
|
||||||
|
| 参数 | 作用 |
|
||||||
|
|------|------|
|
||||||
|
| `-kernel` | 指定内核 bzImage 路径 |
|
||||||
|
| `-initrd` | 指定 initramfs 路径 |
|
||||||
|
| `console=ttyS0` | 内核日志输出到串口(配合 `-nographic` 显示在终端) |
|
||||||
|
| `rdinit=/init` | 指定 initramfs 中的初始进程为 `/init` |
|
||||||
|
| `-nographic` | 不使用图形窗口,串口重定向到当前终端 |
|
||||||
|
| `-m 256M` | 分配 256MB 内存 |
|
||||||
|
|
||||||
|
### 启动成功标志
|
||||||
|
|
||||||
|
滚动的内核日志结束后出现:
|
||||||
|
|
||||||
|
```
|
||||||
|
Run /init as init process
|
||||||
|
/bin/sh: can't access tty; job control turned off
|
||||||
|
~ #
|
||||||
|
```
|
||||||
|
|
||||||
|
`~ #` 即为 shell 提示符,此时可以输入命令:
|
||||||
|
|
||||||
|
```
|
||||||
|
~ # uname -r
|
||||||
|
6.12.0
|
||||||
|
~ # ls
|
||||||
|
bin etc linuxrc root sys usr
|
||||||
|
dev init proc sbin tmp
|
||||||
|
```
|
||||||
|
|
||||||
|
### 退出 QEMU
|
||||||
|
|
||||||
|
- 方法一:shell 中输入 `poweroff`
|
||||||
|
- 方法二:按 `Ctrl+A` 再按 `X`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 故障排查
|
||||||
|
|
||||||
|
### 症状:只有一个闪烁的光标,其他什么都没有
|
||||||
|
|
||||||
|
按以下顺序排查:
|
||||||
|
|
||||||
|
| 序号 | 检查项 | 排查命令 | 修复方法 |
|
||||||
|
|------|--------|----------|----------|
|
||||||
|
| 1 | bzImage 是否存在 | `ls -la arch/x86/boot/bzImage` | 重新编译内核 |
|
||||||
|
| 2 | 是否启用了串口控制台 | `grep SERIAL_8250_CONSOLE .config` | 改用 `x86_64_defconfig` |
|
||||||
|
| 3 | 是否启用了 initrd 支持 | `grep BLK_DEV_INITRD .config` | 改用 `x86_64_defconfig` |
|
||||||
|
| 4 | BusyBox 是否静态链接 | `file rootfs/bin/busybox` | 开启 `CONFIG_STATIC=y` 重编 |
|
||||||
|
| 5 | init 是否存在且可执行 | `ls -la rootfs/init` | `chmod +x rootfs/init` |
|
||||||
|
| 6 | initramfs 是否包含 init | `zcat initramfs.cpio.gz \| cpio -t \| grep init` | 重新打包 |
|
||||||
|
|
||||||
|
### 常见错误对照
|
||||||
|
|
||||||
|
| 错误信息 | 原因 | 解决 |
|
||||||
|
|----------|------|------|
|
||||||
|
| `qemu: could not open kernel file` | bzImage 不存在 | 编译内核 |
|
||||||
|
| `Run /init as init process` 后无输出 | init 不可执行或 BusyBox 动态链接缺库 | 检查权限、改静态编译 |
|
||||||
|
| `tc.c: error: 'TCA_CBQ_MAX' undeclared` | `CONFIG_TC=y` 但内核已删除 CBQ 结构体 | 禁用 `CONFIG_TC` 后重编 |
|
||||||
|
| `busybox: cannot open ... No such file or directory` | 上次编译失败,二进制未生成 | 修复编译错误后重新 `make` |
|
||||||
|
| `can't access tty; job control turned off` | 正常现象,无需处理 | 忽略 |
|
||||||
|
| 内核 panic `No working init found` | initramfs 未加载或 init 路径错误 | 检查 `rdinit=` 和 `BLK_DEV_INITRD` |
|
||||||
|
| 终端完全没有内核日志 | 缺少串口控制台支持 | 检查 `SERIAL_8250_CONSOLE` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 完整构建脚本
|
||||||
|
|
||||||
|
将以下内容保存为 `build.sh`,可一键完成整个构建流程:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
KERNEL_DIR=/home/zmn/linux-6.12
|
||||||
|
BB_DIR=/home/zmn/busybox
|
||||||
|
ROOTFS=/home/zmn/rootfs
|
||||||
|
INITRAMFS=/home/zmn/initramfs.cpio.gz
|
||||||
|
|
||||||
|
echo "=== [1/6] 配置内核 ==="
|
||||||
|
cd "$KERNEL_DIR"
|
||||||
|
make x86_64_defconfig
|
||||||
|
|
||||||
|
echo "=== [2/6] 编译内核 ==="
|
||||||
|
make CC=gcc-14 -j"$(nproc)"
|
||||||
|
test -f arch/x86/boot/bzImage && echo "bzImage OK"
|
||||||
|
|
||||||
|
echo "=== [3/6] 配置 BusyBox(静态编译,禁用 tc)==="
|
||||||
|
cd "$BB_DIR"
|
||||||
|
make defconfig
|
||||||
|
sed -i 's/^# CONFIG_STATIC is not set/CONFIG_STATIC=y/' .config
|
||||||
|
sed -i 's/^CONFIG_TC=y/# CONFIG_TC is not set/' .config
|
||||||
|
grep -E '^CONFIG_STATIC=|^CONFIG_TC=' .config
|
||||||
|
|
||||||
|
echo "=== [4/6] 编译 BusyBox ==="
|
||||||
|
make CC=gcc-14 -j"$(nproc)"
|
||||||
|
file busybox | grep -q "statically linked" && echo "static OK"
|
||||||
|
|
||||||
|
echo "=== [5/6] 安装到 rootfs 并写 init ==="
|
||||||
|
mkdir -p "$ROOTFS"/{bin,sbin,etc,proc,sys,dev,tmp,root,usr/bin,usr/sbin}
|
||||||
|
make CONFIG_PREFIX="$ROOTFS" install
|
||||||
|
cat > "$ROOTFS/init" << 'INITEOF'
|
||||||
|
#!/bin/sh
|
||||||
|
mount -t proc none /proc
|
||||||
|
mount -t sysfs none /sys
|
||||||
|
mount -t devtmpfs none /dev
|
||||||
|
hostname minimal-linux
|
||||||
|
exec /bin/sh
|
||||||
|
INITEOF
|
||||||
|
chmod +x "$ROOTFS/init"
|
||||||
|
|
||||||
|
echo "=== [6/6] 打包 initramfs ==="
|
||||||
|
cd "$ROOTFS"
|
||||||
|
find . | cpio -o -H newc 2>/dev/null | gzip > "$INITRAMFS"
|
||||||
|
echo "Done: $INITRAMFS"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "启动命令:"
|
||||||
|
echo "qemu-system-x86_64 -kernel $KERNEL_DIR/arch/x86/boot/bzImage -initrd $INITRAMFS -append \"console=ttyS0 rdinit=/init\" -nographic -m 256M"
|
||||||
|
```
|
||||||
|
|
||||||
|
运行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x build.sh
|
||||||
|
./build.sh
|
||||||
|
```
|
||||||
Reference in new issue
Block a user