MIT 6.828 操作系统工程 lab4BC 笔记

这篇博客详细记录了MIT 6.828操作系统工程lab4B和lab4C的学习过程,涵盖了Copy-on-Write Fork的实现,包括用户级页面错误处理、写时复制分叉的C库例程,并介绍了lab4C中的抢占式多任务和进程间通信(IPC)机制,涉及时钟中断、中断处理和IPC系统调用的实现。
摘要由CSDN通过智能技术生成

MIT 6.828 操作系统工程 lab4B:Copy-on-Write Fork

这篇是我自己探索实现 MIT 6.828 lab 的笔记记录,会包含一部分代码注释和要求的翻译记录,以及踩过的坑/个人的解决方案

这里是我实现的完整代码仓库,也包含其他笔记等等:https://github.com/yunwei37/6.828-2018-labs

如前所述,Unix 提供fork()系统调用作为其主要的进程创建原语。该fork()系统调用将调用进程的地址空间(父)创建一个新的进程(孩子)。

在本实验的下一部分中,您将实现一个“正确的”类 Unix fork() 和写时复制,作为用户空间库例程。

用户级页面错误处理

用户级写时复制fork()需要了解写保护页面上的页面错误,因此这是您首先要实现的。写时复制只是用户级页面错误处理的众多可能用途之一。

为了处理自己的页面错误,用户环境需要向JOS 内核注册一个页面错误处理程序入口点。用户环境通过新的sys_env_set_pgfault_upcall系统调用注册其页面错误入口点。

练习 8. 实现sys_env_set_pgfault_upcall系统调用

// Set the page fault upcall for 'envid' by modifying the corresponding struct
// Env's 'env_pgfault_upcall' field.  When 'envid' causes a page fault, the
// kernel will push a fault record onto the exception stack, then branch to
// 'func'.
//
// Returns 0 on success, < 0 on error.  Errors are:
//	-E_BAD_ENV if environment envid doesn't currently exist,
//		or the caller doesn't have permission to change envid.
static int
sys_env_set_pgfault_upcall(envid_t envid, void *func)
{
   
	// LAB 4: Your code here.
	struct Env* new_env;
	int result;

	if ((result = envid2env(envid, &new_env, 1)) < 0){
   
		return result;
	}
	new_env->env_pgfault_upcall = func;
	return 0;
}

用户环境中的正常和异常堆栈

在正常执行过程中,JOS用户环境将在运行正常的用户堆栈:它的ESP注册开始了在指向USTACKTOP且堆栈数据之间是推动在页面上驻留USTACKTOP-PGSIZE和USTACKTOP-1包容性。然而,当在用户模式下发生页面错误时,内核将重新启动用户环境,在不同的堆栈上运行指定的用户级页面错误处理程序,即用户异常堆栈。本质上,我们将让 JOS 内核代表用户环境实现自动“堆栈切换”,这与 x86处理器 在从用户模式转换到内核模式时已经代表 JOS 实现堆栈切换非常相似!

JOS 用户异常栈也是一页大小,其顶部定义为虚拟地址UXSTACKTOP.

练习 9.page_fault_handler

实现将页面错误分派到用户模式处理程序所需 的代码。写入异常堆栈时一定要采取适当的预防措施。


void
page_fault_handler(struct Trapframe *tf)
{
   
	uint32_t fault_va;

	// Read processor's CR2 register to find the faulting address
	fault_va = rcr2();

	// Handle kernel-mode page faults.

	// LAB 3: Your code here.
	if ((tf->tf_cs & 3) != 3) {
   
		panic("[%08x] kernel fault va %08x ip %08x\n",
		curenv->env_id, fault_va, tf->tf_eip);
	}

	// We've already handled kernel-mode exceptions, so if we get here,
	// the page fault happened in user mode.

	// Call the environment's page fault upcall, if one exists.  Set up a
	// page fault stack frame on the user exception stack (below
	// UXSTACKTOP), then branch to curenv->env_pgfault_upcall.
	//
	// The page fault upcall might cause another page fault, in which case
	// we branch to the page fault upcall recursively, pushing another
	// page fault stack frame on top of the user exception stack.
	//
	// It is convenient for our code which returns from a page fault
	// (lib/pfentry.S) to have one word of scratch space at the top of the
	// trap-time stack; it allows us to more easily restore the eip/esp. In
	// the non-recursive case, we don't have to worry about this because
	// the top of the regular user stack is free.  In the recursive case,
	// this means we have to leave an extra word between the current top of
	// the exception stack and the new stack frame because the exception
	// stack _is_ the trap-time stack.
	//
	// If there's no page fault upcall, the environment didn't allocate a
	// page for its exception stack or can't write to it, or the exception
	// stack overflows, then destroy the environment that caused the fault.
	// Note that the grade script assumes you will first check for the page
	// fault upcall and print the "user fault va" message below if there is
	// none.  The remaining three checks can be combined into a single test.
	//
	// Hints:
	//   user_mem_assert() and env_run() are useful here.
	//   To change what the user environment runs, modify 'curenv->env_tf'
	//   (the 'tf' variable points at 'curenv->env_tf').

	// LAB 4: Your code here.
	
	if (curenv->env_pgfault_upcall) {
   
		struct UTrapframe *utf;
		user_mem_assert(curenv, curenv->env_pgfault_upcall, 1, PTE_P|PTE_U);

		if (curenv->env_tf.tf_esp <= UXSTACKTOP-1 && curenv->env_tf.tf_esp >= UXSTACKTOP - PGSIZE) {
   
			utf = (struct UTrapframe*)(curenv->env_tf.tf_esp - sizeof(size_t) - sizeof(*utf));
			if (utf < (struct UTrapframe*)(UXSTACKTOP - PGSIZE)) {
   
				cprintf("the exception stack overflows.");
				goto out;
			}
		} else {
   
			utf = (struct UTrapframe*)(UXSTACKTOP - sizeof(*utf));
		}
		user_mem_assert(curenv, utf, sizeof(*utf), PTE_P|PTE_U|PTE_W);
		utf->utf_regs = curenv->env_tf.tf_regs;
		utf->utf_esp = curenv->env_tf.tf_esp;
		utf->utf_eflags 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值