QEMU训练营2025专业阶段实验解析
本人的研究方向主要是操作系统与虚拟化,平时接触最多的开源项目除了 Linux 内核外,便是 QEMU 了,不只是将它作为一个全系统模拟器和 VMM 来使用,还涉及到基于它的增量开发的工作。但这些基本都还是边做边学的,主要原因在于市面上一直缺乏系统性介绍 QEMU 的书籍和资料(我知道的仅有一本《QEMU/KVM 源码解析与应用》,但其主要专注于 QEMU 的 VMM 用途,对模拟器的介绍不是重点)。得知 OpenCamp 将举办 QEMU 训练营,我也是在持续关注,并且在第一时间报名并开展了学习。
截至现在,我已经完成了基础阶段和专业阶段的学习,正在等待项目阶段的开放。本文将分享我专业阶段实验的解题思路和方法,作为个人的一个记录,也为后续参与训练营的同学提供参考。
实验概述专业阶段的实验平台是由训练营主办方专门设计的一个简易的教学用板卡 G233,对它的介绍可以参考文档:b. G233 Datasheet - Learning QEMU Docs。
实验共有十个,归类下来总共有三类:lab1 主要是根据手册的说明,补全对 G233 板卡的模拟代码;lab2 ~ lab5 则是为 RI ...
Linux内核物理内存管理器的建立过程
本文将介绍 Linux 内核中物理内存管理结构的建立过程,主要分为获取物理内存布局、早期内存管理器和最终内存管理器三个阶段,本文将以 x86_64 架构为例,内核代码基于 Linux 5.10 版本来介绍。
获取物理内存布局当 x86_64 系统启动,BIOS 将控制权交给 Bootloader(如 GRUB) 之后,此时 CPU 模式还处于 实模式 下,可以进行 BIOS 中断调用,Bootloader 将会通过反复调用(每次只能获取一段内存区域的信息) int 0x15 eax=0xE820 这个中断来获取计算机的物理内存布局。
0x15 号中断还有 0xE801, 0x88 的功能号,都用于获取物理内存布局,只不过功能更简单。
存储获取到的每段内存区域信息的数据结构如下,包括起始地址、大小、类型。
/* arch/x86/include/uapi/asm/bootparam.h */
struct boot_e820_entry {
__u64 addr;
__u64 size;
__u32 type;
} __attribute__((packe ...
鸿蒙内核论文阅读分享
国庆假期,无心工作,便把之前一直想读却没时间读的鸿蒙内核论文:《Microkernel Goes General: Performance and Compatibility in the HongMeng Production Microkernel》拿出来读了一读,并记录下我的一些总结和想法。虽然操作系统内核是我的主要研究方向之一,但是平时的工作接触的都是 Linux 这样的宏内核操作系统,对微内核的了解只停留在理论层面,没有具体读过 Minix、seL4 等微内核的源码,甚至也没做过上交 IPADS 团队的 ChCore 操作系统实验,因此也只是一些粗浅的想法,图一乐就好。
实现了哪些特性下图是论文中关于鸿蒙内核的架构图:
首先是同时实现了对 Linux API 和 ABI 的兼容,因此不仅能够通过编译源码的方式运行面向 Linux 开发的应用程序,对于那些不开放源代码,直接以二进制形式进行分发的应用程序,也能够基于兼容层——ABI-compliant Shim 实现运行时兼容。除此之外,还实现了一个设备驱动的兼容层——Linux Driver Container,能够直接 ...
QEMU内存后端文件与FUSE兼容性问题及其定位
最近想要将文件系统和 QEMU 模拟器结合起来做一些实验性的工作,需要使用 QEMU 内存后端文件的特性。前面的进展都很顺利,但是待准备工作都完成后,却遇到了模拟器无法启动的问题,好在最终还是解决了,接下来便一一细说。
环境准备我的基本开发环境为 QEMU 6.2 版本,Linux 5.10 版本内核,面向架构为 x86_64。这部分环境的准备没有遇到什么大问题,只是需要注意我选用的版本相对较老,在使用较新的编译器编译时可能会报出警告,因此需要在编译前的 configure 阶段将 Werror 的 flag 禁用,以免在编译时将警告当作错误来对待。
例如对于 QEMU 来说,configure 的命令为:
$ ./configure --target-list=x86_64-softmmu --disable-docs --disable-werror
这里最好也加上 --disable-docs,因为编译文档的工具链同样容易由于版本问题导致编译失败。
文件系统方面,我当前的需求是需要实现一个最简的堆叠式加密文件系统,无需关注具体的加密算法是什么。一般来说,有两种方案:内核文件 ...
QEMU内存后端文件的用法及分析
本文将介绍 QEMU 中内存后端文件参数用法和代码实现,基于的版本为 QEMU 6.2。
参数用法首先是参数的用法,下面是 官方文档 中对此的说明:
memory-backend=’id’
An alternative to legacy -mem-path and mem-prealloc options. Allows to use a memory backend as main RAM.
For example:
-object memory-backend-file,id=pc.ram,size=512M,mem-path=/hugetlbfs,prealloc=on,share=on
-machine memory-backend=pc.ram
-m 512M
接下来我们做一个测试,首先创建一个空文件 mem,使用 du 查看其空间占用大小:
$ du -sh mem
0 mem
然后利用参数指定该文件为内存后端文件,并启动一个模拟器,启动参数如下:
qemu-system-riscv64 \
-cpu rv64 \
-object mem ...
关于Linux信号的一些思考
今天偶然间看到一个介绍 Linux 信号的视频:别再杀进程了!让 Ctrl+C 变成“喵”…(用信号实现)哔哩哔哩_bilibili ,虽然讲的东西很基础,但也引发了我思考一些之间没有很关注的问题。在与 LLM “讨论” 一番过后,便想将这些思考记录下来,算是查漏补缺吧。
信号的一面有关信号的具体用法,不是本文关注的重点,这部分内容可以翻看《深入理解计算机系统》(CSAPP)的异常控制流章节,这也是我最早建立对“信号”认识的地方。
先下定义:信号的本质是操作系统提供的一种进程间通信(IPC)机制,其他两种主要的进程间通信进制为共享内存和消息传递。
其中管道通常也被认为是一种特殊的消息传递机制,它们的核心设计都是不依赖于两个进程(以下称作 A 和 B)共享一段内存空间,而是将内核作为一个中间层,将数据代为转发,即 A -> kernel -> B。只不过常规的消息传递转发的是结构化的数据,而管道通常直接进行数据流的传递。
与共享内存和消息传递不同,信号通常并不直接传送数据,而是传达一系列预设编号的通知,进程在收到通知后,根据通知类别的不同,进行分发处理。简单类比就像是进 ...
AMD SEV机密虚拟机ASID管理
本文将介绍 Linux 内核中,AMD SEV 机密虚拟机对虚拟机号 ASID 的管理设计,基于的内核版本为 Linux 5.10。
数据结构AMD SEV 中对 ASID 管理的核心代码位于 arch/x86/kvm/svm/sev.c 中,以下是与之相关的数据结构定义:
/* 定义保护位图的互斥锁 */
static DEFINE_MUTEX(sev_bitmap_lock);
/* SEV 同时支持的最大 ASID */
unsigned int max_sev_asid;
/* SEV 应该使用的最小的 ASID */
static unsigned int min_sev_asid;
/* 待分配的 ASID 位图 */
static unsigned long *sev_asid_bitmap;
/* 回收的 ASID 位图 */
static unsigned long *sev_reclaim_asid_bitmap;
AMD SEV 的 ASID 管理采用了 双位图 的设计,包含一张分配位图 sev_asid_bitmap 和一张回收位图 sev_recla ...
Linux内核initcall初始化机制
本文将介绍 Linux 内核的初始化函数结构,其通过 initcall 机制来实现,其核心是一系列优先级不同的宏,用于控制初始化函数的执行顺序。本文的实验的内核环境基于 Linux 5.10。
initcall 的级别与执行顺序Linux 内核定义了多个初始化级别(按照执行顺序从高到低排列):
宏定义
级别名
优先级值
用途说明
early_initcall(fn)
early
-
早期的初始化,在 SMP 初始化之前
pure_initcall(fn)
pure
0
用于初始化不能被静态初始化的变量
core_initcall(fn)
core
1
核心子系统初始化
postcore_initcall(fn)
postcore
2
核心子系统之后的初始化
arch_initcall(fn)
arch
3
架构相关初始化
subsys_initcall(fn)
subsys
4
子系统初始化
fs_initcall(fn)
fs
5
文件系统初始化
rootfs_initcall(fn)
rootfs
-
根文件系统初始化
device ...
使用QEMU TCG模拟一个硬件虚拟化环境
本文将介绍如何使用 QEMU TCG 模拟的方式,构建一个支持硬件虚拟化的环境,使得能够在该模拟器环境下启动一个 KVM 虚拟机。
编译最新 QEMU首先需要下载并编译 QEMU,我们以 x86_64 架构为例,QEMU 选择使用最新版本。
# 下载最新仓库
$ git clone https://git.qemu-project.org/qemu.git
$ cd qemu
# 配置编译目标
$ ./configure --target-list=x86_64-softmmu
# 编译
$ make -j$(nproc)
准备 Linux 内核(选用 6.12.0)接下来,需要准备 Linux 内核,我这里选用的是 6.12.0 版本。硬件虚拟化技术使用 AMD-V,需要在 menuconfig 中启用 KVM for AMD processor support。
# 下载 6.12 版本内核
$ wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.12.tar.xz
$ tar -xvf linux-6.12.t ...
QEMU softmmu模型
本文将分析 QEMU TCG 模式下的访存模型,也就是 softmmu 的设计,基于的版本为 QEMU 6.2,架构则以 RISC-V 为例。
基本调用链1. target/riscv/translate.c 访存指令翻译。
2. accel/tcg/cputlb.c 调用 helper 加载函数(如 helper_le_ldq_mmu)。
3. 调用 load_helper 函数
1. 查 TLB,若未命中,则 tlb_fill 进行填充。
2. 处理各种特殊情况(MMIO、不对界访问等)。
3. 计算得到对应的宿主机虚拟地址 haddr = addr + entry->addend,并根据字长进行访问。
TLB 数据结构QEMU 的 softmmu 模型的核心数据结构为其 TLB 的设计,结构如下:
CPUTLBtypedef struct CPUTLB {
CPUTLBCommon c; // 存储 TLB 的一系列元数据。
CPUTLBDesc d[NB_MMU_MODES]; // ...










