惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Engineering at Meta
Engineering at Meta
人人都是产品经理
人人都是产品经理
大猫的无限游戏
大猫的无限游戏
博客园 - 三生石上(FineUI控件)
量子位
腾讯CDC
The Cloudflare Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
云风的 BLOG
云风的 BLOG
Vercel News
Vercel News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LangChain Blog
aimingoo的专栏
aimingoo的专栏
The Hacker News
The Hacker News
T
The Exploit Database - CXSecurity.com
B
Blog
S
SegmentFault 最新的问题
P
Privacy & Cybersecurity Law Blog
T
Threatpost
博客园 - 聂微东
T
Tailwind CSS Blog
The Last Watchdog
The Last Watchdog
C
Check Point Blog
N
Netflix TechBlog - Medium
D
DataBreaches.Net
爱范儿
爱范儿
IT之家
IT之家
S
Secure Thoughts
M
MIT News - Artificial intelligence
NISL@THU
NISL@THU
C
Cisco Blogs
TaoSecurity Blog
TaoSecurity Blog
有赞技术团队
有赞技术团队
A
Arctic Wolf
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
P
Proofpoint News Feed
Spread Privacy
Spread Privacy
Schneier on Security
Schneier on Security
Simon Willison's Weblog
Simon Willison's Weblog
G
GRAHAM CLULEY
雷峰网
雷峰网
Project Zero
Project Zero
博客园 - Franky
H
Heimdal Security Blog
A
About on SuperTechFans
Security Latest
Security Latest
Webroot Blog
Webroot Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Hugging Face - Blog
Hugging Face - Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More

Oskyla 烹茶室

修复 Joplin on KDE 菜单栏显示问题 Copy Fail:Linux 内核 2017 年至今的高危漏洞(附临时缓解方案) | CVE-2026-31431 Hermes Agent — 在 K3s / K8s 中运行指南 在 K3s 节点上安装并使用 nerdctl Mouser:轻量开源的罗技鼠标驱动替代方案 Claude Opus 4.7:优缺点与评测信息汇总 openFuyao NPU-Operator故障排查 openFuyao 2603 共测测试报告 openFuyao InferNex AI推理集成部署 310P(300I Pro) 环境问题记录及解决 ceph mon Operation not permitted 问题解决 Ascend 310P + openFuyao + NPU-Operator 故障排查 KDE Plasma6 禁用全局菜单,恢复正常应用菜单 终极指南:在 Linux 裸机服务器上快速部署 Moltbot (原 Clawbot) 并集成飞书 Windows 配置 Claude Code 解决 settings.json 不生效 Windows 配置 Claude Code 全流程 2025-12-31 | 年终总结 AI 生图精品提示词|第二期:城市星球 AI 生图精品提示词|第一期 Kubernetes kubectl --raw 使用指南 彻底解决阿里云和 tailscale 冲突 2025-10-21 | 沉淀思维 macOS 单独为鼠标或触控板开启自然滚动 2025-10-16 | 负载高低 2025-10-15 | 睡眠周期 2025-10-14 | 转换情绪与独立观点 go 拉取 gitcode.com 私有 mod Git 将某个文件恢复到其他分支的状态 SSH 通过跳板机连接 lxc 使用 chronyc 构建 ntp 服务 2025-10-13 | 独立思考于未来能源 2025-10-12|AI Review 及高质量工作流 2025-10-11 | 人生阶段 2025-10-10 | AI Logo | 远程操控 AI 2025-10-09 | 去班味|银杏|域名 2025-10-08 2025-10-07 2025-10-06 2025-10-05 优秀的 SubReddit 清单 Synology 群晖重置 Syncthing 密码 让 LLM 看到真实世界的 Playwright MCP 磁盘占用分析利器 ncdu 自建 gitlab 徽标问题导致项目 500 问题解决 harbor Chartmuseum helm 图表缓存刷新 grep exclude 排除 Debian 11 + PVE LACP Mac 冲突问题调查与解决方案 Claude Code 实用技巧 CentOS 7 重置 root 密码 telnet 如何退出 kubernetes 的挂载传播(mount propagation)机制 vim 将命令输出到当前位置 harbor 替换 ssl 证书 AI提效之使用 cherry-studio + k8sgpt 实现 AI 巡检 k8s Claude Code Subagents 快速开始 《我看见的世界:李飞飞自传》 Lyra - AI Prompt Optimization Specialist Linux 自签名 CA 证书安装方法 超级玛丽、魂斗罗等经典小游戏聚合站 | PlayUnb 个人业余开发项目清单 快速选出收益最高的理财产品 | finance-calculator 苹果液态玻璃风格图像生成和模拟器 | LiquedGlass.icu Linux 进程绑定NUMA节点或CPU核心 判断GPT是否降智的几个问题 Harmony next hap 安装 名侦探柯南贝尔摩德出场集数 k3s k8s 快速部署轻量节点监控方案 beszel k3s-k8s 实现 DevOps 方案横向对比 k8s 配置访问私有镜像仓库 GoAccess 分析多网站日志方法 Octant - 以开发人员为中心的开源 Kubernetes Web 界面 Tailscale 自建 DERP 并配置 SSL 完整教程 OpenManus 使用记录 Plausible 缺失 location 信息的研究 解决 Nginx Ingress returns 413 Entity Too Large 绘图模型效果对比之城市气象 【转】k8s 认知路线 OpenFOAM 两大分支的详细比较 第一个 CUDA 程序之矩阵运算计算效能对比 Archlinux KDE Apache JMeter 配置高分屏缩放 解决 gitlab-runner 移除残留文件 permission denied nginx-ingress 配置路由 302 k8s 触发 pod 重新拉取镜像平滑升级的方法 Clickhouse 迁移后 permission denied 问题解决 Linux CPU 运行模式及功耗分析 Linux vim vi 翻页跳转命令快捷键 git 拉取所有 branch 和 tag 到本地并推送到远程 Rails 性能分析工具 rack-mini-profiler 和 bullet 全球国家、城市、地区开源数据库 Rails Active Record 常用命令 Rails Rake 简介与编写 如何调试 Vim 脚本 名侦探柯南松田阵平出场集数(最新1069话) 名侦探柯南妃英理出场集数(最新1069话) 《名侦探柯南》官方人气投票结果 名侦探柯南TV安室透出场集数(最新1110话) 名侦探柯南TV赤井秀一出场集数(更新至1194话) [转]名侦探柯南TV主线集数整理(截止1165集) 架构风格总结 [转译] 如何成为一个好的开发者? 【影评】名侦探柯南·零的执行人
深入理解 Linux 启动过程 | QEMU 启动 linux 内核和自制根文件系统
Tianlun Song · 2021-11-17 · via Oskyla 烹茶室

本文 首发于 🌱 煎茶转载 请注明 来源

故事开始的地方,深入 Linux 系统的启动流程,自己编译内核并制作根文件系统,并使用 QEMU 模

拟启动.

跟我一起来到故事开始的地方,深入 Linux 系统的启动流程,自己编译内核并制作根文件系统,并使用 QEMU 模拟启动。

前置知识

昨天看到阮老师两篇文章 《计算机是如何启动的?》和 《Linux 的启动流程》,对计算机的启动流程有了更加深入的理解,正好最近在做国产申威处理器的虚拟化支持性调研,称此机会深入了解一下 Linux 系统的启动流程,并使用 QEMU 模拟这一流程。

https://cdn-imagehost.frytea.com/images/2021/11/17/imageb68194bae57a49fc.png

说明:本文介绍的方法同样可用于内核调试,但侧重于介绍 使用 QEMU 模拟 Linux 的启动流程 。本文核心内容参考了 USTC 2021年春季『操作系统原理与设计』 课程实验,结合网络文献和自己的实验整理而来。

如果对于 Linux 的启动流程不够熟悉,可以先看一下上面提到的文章,之后回到本文继续。

看过文章后应该对启动流程有了大概认识,本文会介绍自制一个简单的根文件系统,即 initramfs (基于 ramfs 的临时文件系统,一种以 cpio 格式压缩后的 rootfs 文件系统),如果对这个概念不太理解,可以来看一下 《 USTC 2021年春季操作系统原理与设计 课程实验一:编译运行Linux内核并通过QEMU+GDB调试》中 实验说明 的『先导知识部分』。

本文会分别使用一个 helloworld 程序busybox 分别生成根文件系统并启动。

简单说一下环境:

  • 硬件平台: Lenovo 台式机
  • 操作系统: Ubuntu 20.04.3 LTS
  • 系统内核: 5.11.0-40-generic
  • QEMU: QEMU emulator version 4.2.1 (Debian 1:4.2-3ubuntu6.18)
  • 实验内核: 4.9.263
  • busybox: busybox-1.32.1

模拟启动

下面介绍使用 QEMU 模拟启动内核和根文件系统的方法,让 Linux 启动流程有一个更加具体的认识。为了模拟启动,需要准备编译好的内核 bzImage 和根文件系统,下面分别介绍。

编译内核

本文使用 linux-4.9.263 版本内核为例,首先获取内核源码:

$ mkdir ~/kvm
$ cd ~/kvm
$ wget https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.9.263.tar.xz
#下载备用链接: https://od.srpr.cc/acgg0/linux-4.9.263.tar.xz
$ tar -Jvxf linux-4.9.263.tar.xz #解压
# 安装编译内核所需的依赖
$ sudo apt-get install git build-essential libelf-dev xz-utils libssl-dev bc libncurses5-dev libncursesw5-dev

准备好编译环境后,开始对接下来的编译做一个配置,这里提供两种方案,选一即可。

  • 方案一: 精简配置,减少不必要的驱动编译(速度快,存储小)
cd ~/kvm/linux-4.9.263
wget https://gitee.com/songtianlun/USTC_OS/raw/master/term2021/lab1/.config 
# 备用链接:
# https://git.lug.ustc.edu.cn/gloomy/ustc_os/-/raw/master/term2021/lab1/.config 
# http://222.186.10.65:8080/directlink/3/.config
# https://raw.githubusercontent.com/ZacharyLiu-CS/USTC_OS/master/term2021/lab1/.config
# https://gitee.com/songtianlun/USTC_OS/raw/master/term2021/lab1/.config

# 说明:直接使用 USTC 提供的配置好的精简 .config ,可以用于快速看到效果,若想深入了解配置含义需自行查阅资料。
cd ~/oslab/linux-4.9.263
make menuconfig   #本次实验直接选择Save,然后exit

有了内核编译配置,即可开始编译:

make -j $((`nproc`-1)) 
# 编译线程数的选择上,一种说法是使用(你的CPU核心数-1)个线程进行编译,一种说法是使用 CPU核心数*2,自行调整即可,只影响编译速度,对编译结果没有影响。

...
Kernel: arch/x86/boot/bzImage is ready  (#1)
# 最后出现这个即为成功,我们后面会启动这个 bzImage

制作根文件系统

在这里也提供两种方案,后面可以分别启动,实测均可启动成功。

  • 方案一:自制简单 helloworld 程序:

这里写一个简单的 helloworld 程序,正常启动后在终端打印 hello world! ,源码如下:

/*************************************************************************
	> File Name: hello.c
	> Description: hello.c
	> Author: songtianlun
	> Mail: songtianlun@frytea.com 
	> Created Time: 2021-11-16 12:39:37
 ************************************************************************/
#include <stdio.h>
void main()
{
    printf("Hello World\n");
    printf("世界,你好!\n");
    printf("Hello World\n");
    fflush(stdout);
    while(1);
}

之后使用静态链接编译,使用 cpio 制作成 rootfs

$ cd ..
使用静态编译链接.
$ gcc -static -o helloworld hello.c
将helloworld制作成cpio
$ echo helloworld | cpio -o --format=newc > rootfs
1776 blocks
$ ls -la rootfs
-rw-rw-r-- 1 seijia seijia 909312 12月 21 13:15 rootfs
  • 方案二:使用busybox生成:

BusyBox是一个遵循GPL协议、以自由软件形式发行的应用程序。Busybox在单一的可执行文件中提供了精简的Unix工具集,可运行于多款POSIX环境的操作系统,例如Linux(包括Android)、Hurd、FreeBSD等等。由于BusyBox可执行文件的文件比较小,使得它非常适合使用于嵌入式系统。作者将BusyBox称为“嵌入式Linux的瑞士军刀”。 —— BusyBox By Wikipedia

首先获取源码:

$ cd ~/kvm
$ wget https://busybox.net/downloads/busybox-1.32.1.tar.bz2
#下载备用链接: https://od.srpr.cc/acgg0/busybox-1.32.1.tar.bz2
$ tar -jxvf busybox-1.32.1.tar.bz2
$ cd ~/kvm/busybox-1.32.1

之后编译并安装:

# 编译busybox
$ make menuconfig
#修改配置如下:(空格键勾选)
Settings –>
  Build Options
   [*] Build static binary(no share libs)

# 编译并安装
$ make -j $((`nproc`-1))
$ sudo make install

现在我们已经有了 busybox 相关的源程序,下面开始准备根文件系统:

cd ~/kvm/busybox-1.32.1/_install
sudo mkdir dev 
sudo mknod dev/console c 5 1
sudo mknod dev/ram b 1 0 
sudo touch init

这里的 mknode 分别创建了一个面向块设备和一个面向字符设备的特殊文件。

将以下内容写入 init

#!/bin/sh
echo "INIT SCRIPT"
mkdir /proc
mkdir /sys
mount -t proc none /proc
mount -t sysfs none /sys
mkdir /tmp
mount -t tmpfs none /tmp
echo -e "\nThis boot took $(cut -d' ' -f1 /proc/uptime) seconds\n"
exec /bin/sh

下面开始生成 rootfs

# 首先为 init 赋予可执行权限
$ sudo chmod +x init
# 进入 busybox 编译成果目录
cd ~/kvm/busybox-1.32.1/_install
# 使用 cpio 制作成 rootfs,为区分方法一,这里使用另一个名称并压缩
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ~/kvm/initramfs-busybox-x64.cpio.gz
# 注意:该命令一定要在busybox的 _install 目录下执行
# 注意:每次修改_install,都要重新执行该命令

启动

经过上述准备,终于要启动了!

根文件制作过程如果是采用了 方案一 ,使用下面命令启动:

$ qemu-system-x86_64 -s \
    -kernel ./linux-4.9.263/arch/x86/boot/bzImage  \
    -initrd ./rootfs \
    -append "root=/dev/ram rdinit=/helloword"
# 注意指定正确的内核和根文件系统位置

https://cdn-imagehost.frytea.com/images/2021/11/17/2021-11-17_11-15_1c71a5e8d7ec6eb0e.png

可以看到启动成功后打印出了 hello world。

如果采用 方案二 ,使用下面命令启动:

$ qemu-system-x86_64 -s \
    -kernel ./linux-4.9.263/arch/x86/boot/bzImage  \
    -initrd initramfs-busybox-x64.cpio.gz \
    --append "nokaslr root=/dev/ram init=/init"
# 注意指定正确的内核和根文件系统位置

https://cdn-imagehost.frytea.com/images/2021/11/17/2021-11-17_11-15a11489946556119d.png

使用 busybox 制作的 rootfs 提供了一些基础的命令可供使用。

总结

为了在 QEMU 中模拟 Linux 的启动流程,在网上找了许多教程,踩了很多坑,最后找到的 USTC 实验说明真是帮助很大,做完后对 Linux 启动流程有了更加深刻的理解,果然在计算机的世界里,必须亲眼看到才能真正正确的理解。希望这份教程能够帮到你。

参考文献