本实验探索系统调用如何实现陷入。你将使用栈先进行一些热身训练,之后你将实现一个用户计陷入处理的例子。
注意
在你开始编码之前,请阅读 xv6 书的第四章以及相关文件:
kernel/trampoline.S
: 涉及从用户空间切换到内核空间以及返回的汇编过程。kernel/trap.c
: 处理所有中断的代码。
大约 12 分钟
本实验探索系统调用如何实现陷入。你将使用栈先进行一些热身训练,之后你将实现一个用户计陷入处理的例子。
注意
在你开始编码之前,请阅读 xv6 书的第四章以及相关文件:
kernel/trampoline.S
: 涉及从用户空间切换到内核空间以及返回的汇编过程。kernel/trap.c
: 处理所有中断的代码。在操作系统中,每个进程都有自己的页表,用于管理其虚拟地址空间。当操作系统创建新的进程时,需要为该进程分配一个新的页表。
// 创建一个空的用户页表
// 如果没有内存了就返回0
pagetable_t
uvmcreate()
{
pagetable_t pagetable;
pagetable = (pagetable_t) kalloc();
if(pagetable == 0)
return 0;
//将此页表都填充成0
memset(pagetable, 0, PGSIZE);
return pagetable;
}
实验原文地址:Lab: page tables (mit.edu)
在这个实验中,你将探索页面表并修改它们以加速特定的系统调用,并检测哪些页面已被访问。
注意
在你开始编码之前,请阅读 xv6 书的第三章以及相关文件:
此函数的作用是创建一个新的用户页表,并在其中映射跳板代码和陷阱帧页。这个函数通常用于操作系统内核中创建进程时初始化进程的页表。
// 创建给定进程的用户页表,没有用户内存,但有跳板和陷阱帧页。
pagetable_t
proc_pagetable(struct proc *p)
{
pagetable_t pagetable;
// 创建一个空白页表
pagetable = uvmcreate();
if(pagetable == 0)
return 0;
//将跳板代码(用于系统调用返回)映射到最高的用户地址
//只有内核使用该代码进出用户空间,所以不用设置PTE_U
if(mappages(pagetable, TRAMPOLINE, PGSIZE,
(uint64)trampoline, PTE_R | PTE_X) < 0){
uvmfree(pagetable, 0);
return 0;
}
// 将陷阱帧页映射到跳板页的下方,用于 trampoline.S
if(mappages(pagetable, TRAPFRAME, PGSIZE,
(uint64)(p->trapframe), PTE_R | PTE_W) < 0){
uvmunmap(pagetable, TRAMPOLINE, 1, 0);
uvmfree(pagetable, 0);
return 0;
}
return pagetable;
}