跳至主要內容
Lab 4:traps

本实验探索系统调用如何实现陷入。你将使用栈先进行一些热身训练,之后你将实现一个用户计陷入处理的例子。

注意

在你开始编码之前,请阅读 xv6 书的第四章以及相关文件:

  • kernel/trampoline.S: 涉及从用户空间切换到内核空间以及返回的汇编过程。
  • kernel/trap.c: 处理所有中断的代码。

Plus大约 12 分钟操作系统MITXV6riscvC
XV6源码精读 -- vm.c

uvmcreate()

在操作系统中,每个进程都有自己的页表,用于管理其虚拟地址空间。当操作系统创建新的进程时,需要为该进程分配一个新的页表。

// 创建一个空的用户页表
// 如果没有内存了就返回0
pagetable_t
uvmcreate()
{
  pagetable_t pagetable;
  pagetable = (pagetable_t) kalloc();
  if(pagetable == 0)
    return 0;
  //将此页表都填充成0
  memset(pagetable, 0, PGSIZE);
  return pagetable;
}

Plus大约 2 分钟操作系统MITXV6riscvC
Lab 3: page tables

实验原文地址:Lab: page tables (mit.edu)

在这个实验中,你将探索页面表并修改它们以加速特定的系统调用,并检测哪些页面已被访问。

注意

在你开始编码之前,请阅读 xv6 书的第三章以及相关文件:

  • kernel/memlayout.h,其中包含内存布局的信息。
  • kernel/vm.c,其中包含大部分虚拟内存(VM)代码。
  • kernel/kalloc.c,其中包含分配和释放物理内存的代码。 同时,参考 RISC-V 特权架构手册可能也会有所帮助。

Plus大约 11 分钟操作系统MITXV6riscvC
XV6源码精读 -- proc.c

proc_pagetable(struct proc *p)

此函数的作用是创建一个新的用户页表,并在其中映射跳板代码和陷阱帧页。这个函数通常用于操作系统内核中创建进程时初始化进程的页表。

// 创建给定进程的用户页表,没有用户内存,但有跳板和陷阱帧页。
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;
}

Plus大约 2 分钟操作系统MITXV6riscvC