做嵌入式 Linux 開發最煩人的事是什么?
燒 SD 卡。插板子。等啟動。看串口。掛了。拔電源。重燒。
上一篇文章寫了 busybox,已經有了最小的根文件系統,那我們是不是就可以構建自己的嵌入式 Linux 系統了?
所以這篇文章就來了,用 QUME 搭建自己的嵌入式 Linux 系統,讓我們對 Linux 更加貼切的認識。。。。。

用 QEMU 模擬的話:
改一行代碼 → make → 啟動虛擬機 → 看 dmesg,30 秒。5 分鐘夠你試 10 次。
這不是「替代真機測試」——QEMU 沒有 SPI Flash,沒有 I2C 傳感器,沒有 DMA。它解決的是真機開發中那 80% 的「能不能編譯過」「能不能加載」「會不會 panic」的快速驗證。剩下 20% 硬件相關的 bug,你還是要買板子來測試實驗。
精髓是——QEMU 讓你在辦公室就把內核玩爛了再上真機。
整個環境不到 50MB。一個 Linux 內核,一個 Busybox 根文件系統,一個 QEMU 虛擬機。從零到能跑,15 分鐘。
三個零件——這是 Linux 初學者到進階的核心,這也是理解 Linux 的核心,我們所有談論的 Linux 就不應該只談論 Linux 內核,因為它只是 Linux 系統的一部分。

內核(大腦):
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.12.40.tar.xz
tar -xf linux-6.12.40.tar.xz && cd linux-6.12.40
make x86_64_defconfig
make -j$(nproc)輸出 `arch/x86/boot/bzImage`,壓縮后約 12MB,QEMU 直接用。
`x86_64_defconfig` 這個配置值得說一句——它是內核自帶的「能跑就行」配置,包含了 Virtio 驅動(QEMU 的虛擬磁盤/網絡)、ext4 文件系統、PCI 總線支持,剛好夠在 QEMU 里啟動到 shell。你要做 ARM 開發,換 `ARCH=arm64 make defconfig`,一樣流程。做 RISC-V 也一樣。
Busybox(工具集):
嵌入式 Linux 的瑞士軍刀——一個不到 2MB 的二進制,提供了 ls、cp、mount、ifconfig、vi、wget 等 300 多個常用命令。
wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
tar -xf busybox-1.36.1.tar.bz2 && cd busybox-1.36.1
make defconfig
sed -i 's/# CONFIG_STATIC is not set/CONFIG_STATIC=y/' .config
make -j$(nproc)
make install靜態編譯這里有一個坑,我當年卡了一整個下午。
如果你的 Busybox 是動態鏈接的,在 initramfs 里啟動后 `/bin/sh` 會提示 `not found`——不是 sh 不存在,是動態鏈接器 `ld-linux.so` 不在 initramfs 里。錯誤信息極其誤導人,你盯著文件看了半天,文件明明在,權限也對,它就是起不來。
所以一定記得 `CONFIG_STATIC=y`,或者把動態庫手動拷進 initramfs。
initramfs(根文件系統):
內核啟動后第一個掛載的文件系統。目錄結構長這樣:
/tmp/initramfs/
├── bin/
│ ├── busybox
│ └── sh -> busybox
├── sbin/
│ └── init
├── etc/
├── proc/
├── sys/
└── dev/最關鍵的 `init` 腳本:
#!/bin/sh
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t devtmpfs devtmpfs /dev
echo "=== Embedded Linux Ready ==="
echo "Kernel: $(uname -r)"
echo "Free memory: $(free -m | awk 'NR==2{print $4}') MB"
exec /bin/sh打包:
cd /tmp/initramfs
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ~/initramfs.cpio.gz最終產物 `initramfs.cpio.gz`,大約 1-2MB。
東西齊了,一行命令啟動:
qemu-system-x86_64 \
-kernel ~/linux-6.12.40/arch/x86/boot/bzImage \
-initrd ~/initramfs.cpio.gz \
-append "console=ttyS0 nokaslr quiet" \
-nographic \
-m 256M \
-smp 2`-kernel` 直接加載內核,跳過 BIOS/UEFI 引導,省 2-3 秒。
`-initrd` 把 initramfs 加載到內存。
`-append "console=ttyS0"` 讓內核日志輸出到串口,`-nographic` 模式下顯示在你的終端里。`nokaslr` 關掉內核地址隨機化——調試時需要固定地址,不然斷點打不上。`-m 256M` 分 256MB 內存,內核對 Busybox 綽綽有余。`-smp 2` 給兩個 CPU 核心,你能在上頭測試 SMP 內核模塊。
3 秒開始滾屏。然后:

=== Embedded Linux Ready ===
Kernel: 6.12.40
Free memory: 232 MB
/ #到這里,你有了一個完整的、可調試的 Linux 環境。寫內核模塊、改調度器、測試 eBPF 程序,全在這個沙箱里。
真正有價值的是 GDB 直接連 QEMU。
真機調試內核得用 JTAG 調試器,斷點經常不穩,一套下來幾千塊。QEMU 內置 GDB server,零成本:
qemu-system-x86_64 -kernel bzImage -initrd initramfs.cpio.gz \
-append "console=ttyS0 nokaslr" -nographic -m 256M -s -S另一個終端:
$ gdb vmlinux
(gdb) target remote :1234
(gdb) break start_kernel
(gdb) continue你可以在內核啟動過程中下斷點,單步跟蹤你自己的內核模塊,看內存和寄存器狀態,測試 oops/panic 時的調用棧回溯。用這套東西學內核源碼,效率是「讀代碼然后猜行為」的十倍以上。
寫一個 hello world 內核模塊,真機和 QEMU 的差距有多大?
真機流程:寫代碼 → 交叉編譯 → 復制到 SD 卡(或 NFS)→ 插卡上電 → 等啟動 → insmod → panic,板子掛了 → 拔電源 → 從頭來。
QEMU 流程:寫代碼 → make → insmod → panic → Ctrl+C → 修復 → 重啟,2 秒。
這是一種根本性的心理變化。
在真機上你不敢寫冒險的代碼——掛一次成本太高,重新燒卡接串口打開終端,心態已經崩了。在 QEMU 里掛就掛了,代碼還在編輯器里,改完 20 秒后又是全新內核。
make -C ~/linux-6.12.40 M=$PWD modules
insmod my_driver.ko
dmesg | tail -5這種「你敢寫、敢改、敢試」的節奏,是內核開發學習曲線最陡那段最好的緩沖。
換 ARM 或者 RISC-V,改兩行:
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc)
qemu-system-aarch64 -M virt -cpu cortex-a53 -kernel Image -initrd initramfs.cpio.gz \
-append "console=ttyAMA0" -nographic -m 256M
make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- defconfig
qemu-system-riscv64 -M virt -kernel Image -initrd initramfs.cpio.gz \
-append "console=ttyS0" -nographic -m 256M`-M virt` 是 QEMU 的虛擬平臺,沒有真實硬件對應,但包含了 ARM/RISC-V 架構的通用外設(PCIe、virtio-blk、PL011 串口)。適合軟件驗證,不適合硬件驅動開發。
說實話,QEMU 不是萬能的。
硬件外設不存在。QEMU 不會模擬你的 SPI Flash、I2C 傳感器、CAN 控制器。如果你的內核模塊是操作具體硬件的,最終還是要上真機。這不是 QEMU 的缺陷,是虛擬化本身的邊界。
時序不可信。QEMU 的指令執行時間是模擬的,中斷延遲、DMA 傳輸時間跟真實硬件沒有可比性。依賴精確定時的代碼——比如用 `ndelay()` 做時序控制——在 QEMU 能跑不代表真機能跑。
內存模型簡化。QEMU 默認平坦內存模型。如果你的代碼涉及 cache coherency、內存屏障、DMA 緩存一致性——這些在 QEMU 里都不會暴露。必須上真機。
Buildroot 是更完整的替代方案。如果你需要的不只是內核加 shell,還要 Qt、OpenSSL、Python、藍牙協議棧,手動編譯不是好主意。
git clone git://git.busybox.net/buildroot
cd buildroot
make qemu_x86_64_defconfig
make -j$(nproc)
./output/images/start-qemu.shBuildroot 幫你管了工具鏈、庫依賴、文件系統打包。代價是 build 一次 30 分鐘,失去手寫 init 腳本的透明度。兩個都得會——開發實驗階段用手工環境,驗證完整功能切到 Buildroot。
嵌入式 Linux 開發環境搭建,說到底就是「快速失敗」的問題。
你把「改一行代碼到看到結果」從 5 分鐘壓到 30 秒,就能多試 10 種方案。多試的 10 次里,至少有一次能讓你少燒一張 SD 卡。
今天的腳本,明天就能出第一個內核模塊。

END
來源:嵌入式Linux