跳至主要內容
Plus's NoteBook

Plus's NoteBook

项目名称
项目详细描述
链接名称
链接详细描述
书籍名称
书籍详细描述
文章名称
文章详细描述
伙伴名称
伙伴详细介绍
自定义项目
自定义项目
自定义详细介绍
Lab6:Copy-on-Write Fork for xv6

虚拟内存提供了一层间接性:内核可以通过将页表项(PTE)标记为无效或只读来拦截内存引用,从而引发页错误,并通过修改 PTE 来改变地址的含义。计算机系统中有一种说法,任何系统问题都可以通过一层间接性来解决。惰性分配实验室提供了一个例子。本实验将探索另一个例子:写时复制(Copy-on-Write, COW)的 fork。

要开始实验,切换到 cow 分支:

$ git fetch 
$ git checkout cow 
$ make clean

Plus大约 8 分钟操作系统MITXV6riscvC
Lab5:xv6 lazy page allocation

操作系统可以通过页表硬件实现的众多巧妙技巧之一是对用户空间堆内存的延迟分配(lazy allocation)。Xv6应用程序通过sbrk()系统调用向内核请求堆内存。在我们提供的内核中,sbrk()会分配物理内存并将其映射到进程的虚拟地址空间。对于大型请求,内核分配和映射内存可能需要很长时间。例如,1GB的内存由262,144个4096字节的页面组成;即使每个分配操作都很廉价,但如此大量的分配操作仍然非常耗时。此外,一些程序分配的内存比实际使用的要多(例如,用于实现稀疏数组),或者提前分配内存但并未立即使用。为了在这些情况下让sbrk()更快地完成,复杂的内核会采用延迟分配用户内存的方式。也就是说,sbrk()不会立即分配物理内存,而是只记住哪些用户地址被分配,并在用户页表中将这些地址标记为无效。当进程首次尝试使用任何延迟分配的内存页面时,CPU会生成一个页错误(page fault),内核通过分配物理内存、将其清零并映射来处理这个错误。在这个实验中,你将向xv6添加这种延迟分配功能。


Plus大约 6 分钟操作系统MITXV6riscvC
Lab 2: System Calls

在上一个实验中,你使用系统调用编写了一些实用程序。在这个实验中,你将向 xv6 添加一些新的系统调用,这将帮助你理解它们的工作原理,并让你接触到 xv6 内核的一些内部机制。在后续的实验中,你将添加更多的系统调用。

注意

开始编码之前,请阅读 xv6 书籍的第 2 章,以及第 4 章的第 4.3 节和第 4.4 节,并阅读相关的源文件:

  • 用户空间的系统调用代码 在 user/user.h 和 user/usys.pl 中。
  • 内核空间的系统调用代码 在 kernel/syscall.h 和 kernel/syscall.c 中。
  • 与进程相关的代码 在 kernel/proc.h 和 kernel/proc.c 中。

Plus大约 7 分钟操作系统MITCriscvXV6
Lab 4:traps

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

注意

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

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

Plus大约 12 分钟操作系统MITXV6riscvC
Chapter 1 操作系统接口(Operating system interfaces)

操作系统的工作是在多个程序之间共享计算机,并提供比硬件本身支持的更有用的服务。操作系统管理和抽象低级硬件,使得例如文字处理器不必关心使用的是哪种类型的磁盘硬件。操作系统在多个程序之间共享硬件资源,使它们能够同时运行(或表现为同时运行)。最后,操作系统提供了受控的程序交互方式,以便它们可以共享数据或共同工作。

操作系统通过接口向用户程序提供服务。设计一个良好的接口实际上是困难的。一方面,我们希望接口简单且窄,因为这样更容易正确实现。另一方面,我们可能会想要向应用程序提供许多复杂的功能。解决这种张力的技巧在于设计依赖于少量机制的接口,这些机制可以组合提供很大的通用性。


Plus大约 24 分钟操作系统MITXV6riscv
Chapter 4 陷阱和系统调用 (Traps and system calls)

有三种事件会导致CPU暂停普通指令的执行,并且强制将控制权转换到处理该事件的特殊代码上。第一种情况是系统调用,当用户程序执行ecall指令时请求内核为其执行某些操作时。第二种情况是是一种异常,指令(用户或者内核)执行了非法操作,例如除以零或者使用了无效的虚拟地址。第三种情况是设备中断,当设备发出需要关注的信号时,例如当硬盘完成了读写请求。

这本书使用trap陷阱作为这些情况的通用术语。通常,任何在陷阱发生时正在执行的代码在之后都要被恢复,并且不该意识到发生了任何特殊事件。换句话说,我们通常希望陷阱是透明的;这对于中断尤其重要,因为被中断的代码通常不会预料到中断的发生。通常的顺序是一个陷阱强制把控制权转入内核;内核保存寄存器和其他状态这样正在执行的进程才能够被恢复;内核执行相应的处理程序代码(例如,系统调用实现或设备驱动程序);内核恢复保存的状态并从陷阱返回;原始代码在中断发生的地方恢复执行。


Plus大约 23 分钟操作系统MITXV6riscv
Chapter 2 操作系统的组织(Perating system organization)

一个操作系统的关键需求是支持同时进行多个活动。例如,使用第1章中描述的系统调用接口,一个进程可以使用fork启动新的进程。操作系统必须在这些进程之间分时共享计算机的资源。例如,即使进程的数量多于硬件CPU的数量,操作系统也必须确保所有进程都有机会执行。操作系统还必须安排进程之间的隔离。也就是说,如果一个进程有一个错误并且故障,不应该影响到那些不依赖于这个有问题的进程的其他进程。然而,完全的隔离过于严格,因为进程之间应该可以有意地进行交互;管道就是一个例子。因此,一个操作系统必须满足三个要求:多路复用、隔离和交互。

本章概述了操作系统如何组织以实现这三个要求。事实证明,有许多方法可以做到这一点,但本文集中在围绕单一内核(monolithic kernel)的主流设计上,许多Unix操作系统都采用这种设计。本章还概述了xv6进程,这是xv6中隔离的基本单元,以及xv6启动时第一个进程的创建。Xv6运行在多核的RISC-V微处理器上,其许多低级功能(例如,进程实现)特定于RISC-V。RISC-V是一种64位CPU,而xv6用“LP64”C语言编写,这意味着在C语言中,长整型(long)和指针(pointer)是64位的,而整型(int)是32位的。


Plus大约 17 分钟操作系统MITXV6riscv
Chapter 3 页表(Page tables)

​ 页表是操作系统为每个进程提供其独立的地址空间和内存的机制。页表决定了内存地址的意义以及哪些部分的物理内存可以被访问。它们使得xv6能够隔离不同进程的地址空间,并将它们多路复用到单个物理内存上。页表还提供了一种间接层,使得xv6可以执行一些技巧:在多个地址空间中映射相同的内存(例如跳板页),并通过未映射的页面来保护内核和用户栈。本章的其余部分将解释RISC-V硬件提供的页表以及xv6如何使用它们。

3.1 分页硬件(Paging hardware)

​ 提醒一下,RISC-V指令(包括用户和内核指令)操作虚拟地址。机器的RAM或物理内存是通过物理地址索引的。RISC-V的页表硬件通过将每个虚拟地址映射到一个物理地址来连接这两种地址。


Plus大约 22 分钟操作系统MITXV6riscv
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