操作系统实战——QEMU模拟器搭建【rCore 操作系统】
操作系统大作业——QEMU模拟器搭建rCore操作系统
按照本篇步骤走,帮你少走很多弯路!博主在自己做的过程中踩了很多坑,过程还是很痛苦的,走了很多弯路,现在都已经在文章中把坑填平了,把弯路修直了。
创作不易,还请 点赞👍、收藏⭐,也欢迎 分享📤
任务描述
使用QEMU模拟器搭建rCore操作系统的实验环境,了解rCore的基本架构和启动流程。在此基础上,编写一个会产生异常的应用程序,并简要解释操作系统的处理结果。要求给出详细的配置过程、程序代码和运行时的截图。
任务分解
- 搭建 rCore 实验环境:
- 安装必要的工具(QEMU、Rust 工具链等)。
- 克隆 rCore 仓库并配置环境。
- 使用 QEMU 运行 rCore。
- 了解 rCore 架构和启动流程:
- 简要分析 rCore 的基本架构。
- 描述 rCore 的启动流程。
- 编写产生异常的应用程序:
- 创建一个用户态程序,触发异常(如非法内存访问)。
- 集成到 rCore 并运行。
- 分析操作系统处理结果:
- 解释异常处理机制。
- 描述运行结果和预期输出。
- 提供运行说明和截图指导:
- 给出运行命令和预期终端输出。
- 说明如何截图。
步骤 1:搭建 rCore 实验环境
1.1 环境要求
- 操作系统:推荐 Ubuntu 22.04 或更高版本(其他 Linux 发行版或 WSL2 也可)。
- 硬件:4GB 以上内存,10GB 以上磁盘空间。
- 工具:
- QEMU(推荐版本 5.0 或以上)。
- Rust 工具链(支持 RISC-V 目标)。
- Git、Make、GCC 等基本开发工具。
1.2 安装依赖
- 配置镜像源
由于下载源的服务器在国外,国内网络环境下载会非常慢,甚至会失败,所以需要先配置一下国内的镜像源。
由于写在一起会很多,这里单独写在了另一篇文章中:
详细配置教程链接🔗Ubuntu中配置【Rust 镜像源】
- 在 Ubuntu 上执行命令安装必要的工具
# 更新包索引并安装基本工具
sudo apt update
sudo apt install -y git build-essential curl wget libssl-dev pkg-config# 安装 QEMU
sudo apt install -y qemu-system-riscv64# 验证 QEMU 版本,需要确保版本为7.0.0以上,否则之后会因为版本过低无法运行rCore,需要升级到7.0.0以上
qemu-system-riscv64 --version# 安装 Rust 工具链
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
source $HOME/.cargo/env# 添加 RISC-V 目标支持
rustup target add riscv64gc-unknown-none-elf# 安装 rust-src(用于 rCore 编译)
rustup component add rust-src --toolchain nightly# 安装 cargo-binutils(用于生成二进制文件)
cargo install cargo-binutils
rustup component add llvm-tools-preview
1.3 克隆 rCore 仓库
- 安装配置 git
方式一:
这里需要使用到版本控制工具 git ,请确保你的实验机器(Ubuntu虚拟机)中已经安装了git,并且已经配置完成(能与GitHub正常建立连接)。
注:博主自己在做实验的时候,使用https协议克隆仓库会失败,只能使用ssh协议克隆才能成功,所以建议读者也直接使用ssh协议进行克隆,而且这也是GitHub官方推荐的克隆方式。
由于写在一起会很多,这里单独写在了另一篇文章中,这里也附上Ubuntu中使用SSH协议克隆的教程链接🔗:使用SSH协议克隆详细步骤
方式二:
如果读者之前没有接触过git,或者不是很熟悉,不想在这里折腾的话,你可以直接用自己的本地主机(你自己的电脑,而非虚拟机)先登录GitHub找到rCore的仓库(项目地址:https://github.com/rcore-os/rCore-Tutorial-v3),将压缩包下载下来(如下图所示),然后再从本地主机上传到你的虚拟机上,然后再进行解压缩,也能得到rCore的项目代码。
- 克隆 rCore 仓库
rCore 是一个基于 Rust 语言的教学操作系统,支持 RISC-V 架构。我们这里使用 rCore-Tutorial-v3:
# 克隆 rCore-Tutorial-v3 仓库
git clone git@github.com:rcore-os/rCore-Tutorial-v3.git
cd rCore-Tutorial-v3
1.4 配置和编译 rCore
rCore 使用 Rust 编写,编译需要指定目标架构为 RISC-V。
# 进入内核目录
cd os# 编译内核
make build# 运行 QEMU 模拟 rCore
make run
预期输出:
-
编译完成后,
make run
会启动 QEMU,模拟 RISC-V 64 位架构。 -
终端将显示 rCore 启动日志,例如:
[kernel] Booting rCore... Lilliputian [kernel] Hello, world! ...
-
你将看到 rCore 的 shell 提示符,说明环境搭建成功。
1.5 验证环境
运行 make run
后,确认 rCore 正常启动并进入用户 shell。尝试运行一些基本命令(如启动之后列出的程序 hello_world
、cat
)以验证环境正常。
步骤 2:了解 rCore 架构和启动流程
2.1 rCore 基本架构
rCore 是一个基于 Rust 语言的微内核操作系统,专为教学设计,支持 RISC-V 架构。它的主要模块包括:
- 内核(Kernel):
- 负责初始化硬件、管理内存、调度进程和线程、处理中断和异常。
- 提供系统调用接口,供用户态程序使用。
- 文件系统(File System):
- 实现简单的文件系统,支持基本的文件读写操作。
- 基于 FAT32 格式,挂载到虚拟磁盘上。
- 进程管理(Process Management):
- 支持多进程和线程,基于优先级调度。
- 使用上下文切换实现并发执行。
- 内存管理(Memory Management):
- 实现虚拟内存、页面映射和动态内存分配。
- 支持页面置换算法(例如 FIFO)。
- 异常和中断(Exception and Interrupt):
- 处理硬件中断(如定时器中断)和软件异常(如非法指令、内存访问错误)。
- 使用异常处理机制恢复或终止进程。
- 用户态库(User Libraries):
- 提供标准 C 库(libc)的子集,支持基本的 I/O、字符串处理和内存操作。
- 包含简单的 shell 和测试程序。
2.2 rCore 启动流程
rCore 的启动流程如下:
- 硬件初始化:
- QEMU 加载 rCore 内核镜像到内存。
- 初始化 CPU 寄存器、栈指针和全局指针。
- 内核初始化:
- 设置中断控制器和定时器。
- 初始化内存管理单元(MMU),启用虚拟内存。
- 加载文件系统和设备驱动。
- 进程初始化:
- 创建第一个用户进程(init 进程)。
- 加载用户 shell 和测试程序。
- 进入用户态:
- 切换到用户模式,运行 shell。
- 用户可以通过 shell 执行命令或运行程序。
启动日志分析:
- 运行
make run
时,观察日志中的关键步骤,例如:[kernel] Initialize interrupt controller
[kernel] Setup virtual memory
[kernel] Mount filesystem
[kernel] Start init process
[user] Welcome to rCore shell
步骤 3:编写产生异常的应用程序
(仅供参考)编写一个简单的用户态 C 程序,尝试访问非法内存地址,触发段错误(Segmentation Fault),并观察 rCore 的处理结果。
3.1 创建用户程序
在 rCore-Tutorial-v3/user/src/bin
目录下创建文件 segfault.c
:
#include <stdio.h>int main() {// 尝试写入非法内存地址int *ptr = (int *)0xdeadbeef;*ptr = 42; // 触发段错误printf("This line should not be reached.\n");return 0;
}
3.2 编译运行C语言异常程序
- 下载RISC-V 交叉编译器(
riscv64-linux-gnu-gcc
),以手动编译C语言程序
sudo apt install riscv64-linux-gnu-gcc
验证安装:
riscv64-linux-gnu-gcc --version
- 编译
在 user/src/bin/ 下编译 segfault.c:
cd ~/rCore-Tutorial-v3/user/src/bin
riscv64-linux-gnu-gcc -static -march=rv64g -mabi=lp64d -o segfault segfault.c
说明:
- static:生成静态链接的可执行文件,避免依赖动态库。
- march=rv64g:针对 RISC-V 64 位架构。
- mabi=lp64d:使用 LP64D ABI(long, pointer 为 64 位,double 为 64 位)。
-
转换为二进制格式:
使用
riscv64-linux-gnu-objcopy
将 ELF 文件转为二进制:riscv64-linux-gnu-objcopy -O binary segfault segfault.bin
-
移动到目标目录
将 segfault 和 segfault.bin 移动到 编译输出目录:
mv segfault ~/rCore-Tutorial-v3/user/target/riscv64gc-unknown-none-elf/release/ mv segfault.bin ~/rCore-Tutorial-v3/user/target/riscv64gc-unknown-none-elf/release/
-
更新文件系统
返回 os 目录,重新打包文件系统:
cd ~/rCore-Tutorial-v3/os make clean make build
-
运行并测试 运行 rCore:
make run
预期输出:
-
触发异常。
-
rCore 检测到非法内存访问,终止程序并返回 shell。
-
输出类似于:
[kernel] Exception: Store/AMO access fault at 0xdeadbeef [kernel] Process terminated
步骤 4:分析操作系统处理结果
4.1 异常处理机制
rCore 的异常处理流程如下:
- 异常检测:
- CPU 检测到非法内存访问(
0xdeadbeef
不在合法地址空间)。 - 触发异常,保存当前程序计数器(PC)和异常原因到寄存器。
- CPU 检测到非法内存访问(
- 中断处理:
- 内核的中断控制器捕获异常,调用异常处理程序。
- 根据异常类型(Store/AMO access fault),决定处理策略。
- 进程终止:
- 对于不可恢复的段错误,内核终止进程。
- 释放进程的资源(如内存、文件描述符)。
- 返回到 shell,打印错误信息。
- 日志记录:
- 内核记录异常的详细信息(如地址
0xdeadbeef
和异常类型)。
- 内核记录异常的详细信息(如地址
4.2 运行结果解释
- 程序行为:
segfault
程序尝试写入非法地址,触发硬件异常。 - 内核反应:rCore 正确识别异常,终止进程以保护系统稳定性。
- 用户体验:用户收到错误提示,系统恢复到 shell 状态,未受进一步影响。
- 健壮性:rCore 的异常处理机制确保单一程序的错误不会导致系统崩溃,体现了微内核设计的安全性。
步骤 5:运行说明和截图指导
5.1 运行命令
以下是关键命令的汇总:
# 安装依赖
sudo apt install -y qemu-system-riscv64 git build-essential curl
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup target add riscv64gc-unknown-none-elf
rustup component add rust-src --toolchain nightly
cargo install cargo-binutils
rustup component add llvm-tools-preview# 克隆和编译 rCore
git clone https://github.com/rcore-os/rCore-Tutorial-v3.git
cd rCore-Tutorial-v3
git checkout Book
cd os
make build
make run# 运行 segfault 程序
# 在 rCore shell 中输入:
segfault
5.2 预期终端输出
-
启动 rCore:
[kernel] Booting rCore... [kernel] Initialize interrupt controller [kernel] Setup virtual memory [kernel] Mount filesystem [kernel] Start init process [user] Welcome to rCore shell
-
运行 segfault:
segfault Attempting to access invalid memory... [kernel] Exception: Store/AMO access fault at 0xdeadbeef [kernel] Process terminated
5.3 截图指导
在运行 make run
和 segfault
时,截取以下终端输出:
- rCore 启动日志:显示从
[kernel] Booting rCore...
到[user] Welcome to rCore shell
的完整日志。 - segfault 运行结果:显示
segfault
命令的输入和异常终止的输出。 - QEMU 窗口(可选):如果 QEMU 打开图形界面,截图显示 rCore shell 界面。
截图工具:
- Ubuntu:使用
gnome-screenshot
或scrot
。 - 命令:
scrot screenshot.png
- 确保截图清晰,包含完整的终端窗口或 QEMU 界面。
保存和提交:
- 将截图保存为 PNG 或 JPEG 格式,命名为
rcore_boot.png
和segfault_output.png
。 - 提交时附上截图和代码文件
segfault.c
。
注意事项
-
常见问题:
- QEMU 未安装或版本过旧:确保使用
qemu-system-riscv64
且版本 ≥ 5.0。 - Rust 工具链配置错误:运行
rustc --version
和cargo --version
确认安装成功。 - 编译失败:检查
make build
的错误日志,可能缺少依赖或目标架构未设置。 - 异常未触发:确保
segfault.c
中的地址0xdeadbeef
未被意外映射到合法内存。
- QEMU 未安装或版本过旧:确保使用
-
调试:
-
使用
make debug
启动 QEMU 并连接 GDB,检查异常时的寄存器状态。 -
示例 GDB 命令:
target remote :1234 info registers backtrace
-
-
性能优化:
- 如果 QEMU 运行缓慢,增加
-smp 4
参数以使用多核。 - 示例:
make QEMU_ARGS="-smp 4" run
- 如果 QEMU 运行缓慢,增加
总结
通过以上步骤,已成功:
- 搭建了 rCore 的 QEMU 实验环境。
- 了解了 rCore 的架构和启动流程。
- 编写并运行了一个触发段错误的程序。
- 分析了 rCore 的异常处理机制。
- 获得了运行结果的截图指导。