1. 项目背景与核心目标
武汉大学网络安全专业的操作系统实验课程(OSLAB)是国内顶尖的计算机科学实践教学项目之一。这个实验仓库涵盖了从进程调度到虚拟内存管理的完整操作系统核心机制实现,是理解现代操作系统原理的绝佳实践平台。
我在参与该项目时发现,大多数操作系统教材仅停留在理论层面,而OSLAB最珍贵的价值在于:
- 提供可运行的代码框架(基于x86架构)
- 每个实验模块都有清晰的演进路径
- 配套的测试用例能验证实现正确性
- 特别适合结合Linux内核源码对照学习
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 实验环境搭建与工具链配置
2.1 基础环境准备
实验推荐使用Ubuntu 20.04 LTS作为开发环境,需要安装以下工具链:
bash复制sudo apt install build-essential qemu-system-x86 gdb-multiarch git
注意:不要使用Windows Subsystem for Linux(WSL),因为需要完整的QEMU虚拟化支持
2.2 代码仓库结构解析
克隆官方仓库后,目录结构如下:
code复制oslab/
├── boot/ # 引导加载程序
├── kernel/ # 内核核心代码
│ ├── mm/ # 内存管理
│ ├── sched/ # 调度器实现
│ └── ...
├── libs/ # 基础库函数
└── user/ # 用户态测试程序
2.3 调试技巧
使用QEMU+GDB调试内核时,建议在Makefile中添加:
makefile复制QEMU_EXTRA = -s -S
这样可以在启动时开启GDB调试端口,配合VS Code的调试配置:
json复制{
"name": "Debug OSLAB",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/kernel.elf",
"miDebuggerServerAddress": "localhost:1234"
}
3. 进程调度器实现详解
3.1 调度框架设计
OSLAB采用类似Linux的调度类架构,核心数据结构包括:
c复制struct task_struct {
pid_t pid;
volatile long state;
struct mm_struct *mm;
struct list_head run_list;
// ...
};
struct sched_class {
const struct sched_class *next;
void (*enqueue_task)(struct rq *rq, struct task_struct *p);
void (*dequeue_task)(struct rq *rq, struct task_struct *p);
// ...
};
3.2 时间片轮转实现
在kernel/sched/rr.c中实现的核心逻辑:
c复制static void rr_enqueue_task(struct rq *rq, struct task_struct *p)
{
list_add_tail(&p->run_list, &rq->rr_queue);
p->time_slice = RR_TIMESLICE;
}
static struct task_struct *rr_pick_next_task(struct rq *rq)
{
struct task_struct *next;
next = list_first_entry(&rq->rr_queue, struct task_struct, run_list);
list_move_tail(&next->run_list, &rq->rr_queue);
return next;
}
3.3 与CFS调度器的对比实验
通过修改sched_class指针可以切换不同调度器:
c复制// 在init/main.c中
void sched_init(void)
{
#ifdef CONFIG_SCHED_RR
current->sched_class = &rr_sched_class;
#elif defined(CONFIG_SCHED_CFS)
current->sched_class = &fair_sched_class;
#endif
}
4. 虚拟内存管理系统剖析
4.1 页表初始化流程
x86架构下的页表建立过程:
- 在boot/head.S中开启CR0.PG标志位
- 建立临时页目录(Page Directory)
- 映射内核代码区(恒等映射)
- 设置CR3寄存器
关键汇编代码:
assembly复制movl $swapper_pg_dir, %eax
movl %eax, %cr3
movl %cr0, %eax
orl $0x80000000, %eax
movl %eax, %cr0
4.2 缺页异常处理
在kernel/mm/fault.c中的处理逻辑:
c复制void do_page_fault(struct pt_regs *regs, unsigned long error_code)
{
unsigned long address = read_cr2();
struct vm_area_struct *vma;
vma = find_vma(current->mm, address);
if (!vma || address < vma->vm_start) {
goto bad_area;
}
if (expand_stack(vma, address)) {
goto bad_area;
}
// 处理COW、文件映射等特殊情况
// ...
}
4.3 物理内存分配器
实现类似Linux的buddy系统:
c复制struct free_area {
struct list_head free_list;
unsigned long nr_free;
};
#define MAX_ORDER 11
struct zone {
struct free_area free_area[MAX_ORDER];
};
void __free_pages(struct page *page, unsigned int order)
{
unsigned long mask = (1UL << order);
// 合并空闲块逻辑
// ...
}
5. 实验进阶与调试技巧
5.1 常见问题排查
-
三重错误(Triple Fault):
- 检查IDT表项是否正确填充
- 确认栈指针没有越界
- 使用QEMU的-d int参数输出中断日志
-
页表映射错误:
- 在QEMU中使用info mem查看当前页表
- 通过info registers cr3确认页目录基址
-
调度死锁:
- 检查spin_lock的配对使用
- 确认没有在中断上下文中睡眠
5.2 性能优化方向
- 实现TLB shootdown机制
- 添加调度器统计信息:
c复制struct sched_statistics {
u64 run_time;
u64 wait_time;
u64 nr_switches;
};
- 实现透明大页(THP)支持
6. 扩展学习建议
-
对照Linux内核源码:
- 调度器:linux/kernel/sched/
- 内存管理:linux/mm/
-
推荐调试工具:
- QEMU的trace功能:-trace events=events.txt
- GDB的Python扩展脚本
-
进阶实验:
- 添加系统调用
- 实现简单的文件系统
- 移植到ARM架构
在完成基础实验后,可以尝试将这些机制与现代操作系统特性(如eBPF、容器隔离机制)进行对比分析。例如,思考如何在内核中添加简单的eBPF虚拟机,或者如何通过命名空间实现进程隔离。
