MIT_6.828_Lab_3: User Environments Part B

项目地址:Lab 3

Handling Page Faults

Exercise 5. Modify trap_dispatch() to dispatch page fault exceptions to page_fault_handler(). You should now be able to get make grade to succeed on the faultread, faultreadkernel, faultwrite, and faultwritekernel tests. If any of them don’t work, figure out why and fix them. Remember that you can boot JOS into a particular user program using make run-x or make run-x-nox. For instance, make run-hello-nox runs the hello user program.

解答如下:

	switch(tf->tf_trapno)
	{
		case T_BRKPT:
//			monitor(tf);
			break;
		case T_PGFLT:
			page_fault_handler(tf);
			break;
		case T_SYSCALL:
		/*
						tf->tf_regs.reg_eax = syscall(tf->tf_regs.reg_eax,tf->tf_regs.reg_edx,
								tf->tf_regs.reg_ecx,tf->tf_regs.reg_ebx,tf->tf_regs.reg_edi,
								tf->tf_regs.reg_esi);
		*/
								break;

		default:
			print_trapframe(tf);
			if (tf->tf_cs == GD_KT)
				panic("unhandled trap in kernel");
			else {
				env_destroy(curenv);
				return;
				}
		break;
	}

在当前这一步,只需要将页错误的case添加进去就行了。当然也要有case T_SYSCALL,不然测试结果会不对。
然后添加错误处理函数:

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.
	//
	if ((tf->tf_cs & 3) == 0)
		panic("in function page_fault_handler:pge fault in kernel mode!\n");

	// LAB 3: Your code here.
	
	// We've already handled kernel-mode exceptions, so if we get here,
	// the page fault happened in user mode.
	if (fault_va <= UTOP)
	{
	struct 	PageInfo* p;	
	p =  page_alloc(ALLOC_ZERO);
	assert(p);
	page_insert(curenv->env_pgdir,p,(void*)fault_va,PTE_U|PTE_W|PTE_P);

	}

	// Destroy the environment that caused the fault.
	cprintf("[%08x] user fault va %08x ip %08x\n",
		curenv->env_id, fault_va, tf->tf_eip);
	print_trapframe(tf);
	env_destroy(curenv);
}

注意要判断出错的地址是否超出了范围,如果超出了范围,则不要分配物理页。

The Breakpoint Exception

Exercise 6. Modify trap_dispatch() to make breakpoint exceptions invoke the kernel monitor. You should now be able to get make grade to succeed on the breakpoint test.

添加case:

	
	switch(tf->tf_trapno)
	{
		case T_BRKPT:
			monitor(tf);
			break;
		case T_PGFLT:
			page_fault_handler(tf);
			break;
		case T_SYSCALL:
		/*
						tf->tf_regs.reg_eax = syscall(tf->tf_regs.reg_eax,tf->tf_regs.reg_edx,
								tf->tf_regs.reg_ecx,tf->tf_regs.reg_ebx,tf->tf_regs.reg_edi,
								tf->tf_regs.reg_esi);
		*/
								break;

		default:
			print_trapframe(tf);
			if (tf->tf_cs == GD_KT)
				panic("unhandled trap in kernel");
			else {
				env_destroy(curenv);
				return;
				}
		break;
	}

另外,需要将中断向量表里面的DPL改为3:

	SETGATE(idt[T_BRKPT],0,GD_KT,handler_brkpt,3);

System calls

Exercise 7. Add a handler in the kernel for interrupt vector T_SYSCALL. You will have to edit kern/trapentry.S and kern/trap.c’s trap_init(). You also need to change trap_dispatch() to handle the system call interrupt by calling syscall() (defined in kern/syscall.c) with the appropriate arguments, and then arranging for the return value to be passed back to the user process in %eax. Finally, you need to implement syscall() in kern/syscall.c. Make sure syscall() returns -E_INVAL if the system call number is invalid. You should read and understand lib/syscall.c (especially the inline assembly routine) in order to confirm your understanding of the system call interface. Handle all the system calls listed in inc/syscall.h by invoking the corresponding kernel function for each call.
Run the user/hello program under your kernel (make run-hello). It should print “hello, world” on the console and then cause a page fault in user mode. If this does not happen, it probably means your system call handler isn’t quite right. You should also now be able to get make grade to succeed on the testbss test.

在kern/trap.c里面添加case:

	switch(tf->tf_trapno)
	{
		case T_BRKPT:
			monitor(tf);
			break;
		case T_PGFLT:
			page_fault_handler(tf);
			break;
		case T_SYSCALL:
						tf->tf_regs.reg_eax = syscall(tf->tf_regs.reg_eax,tf->tf_regs.reg_edx,
								tf->tf_regs.reg_ecx,tf->tf_regs.reg_ebx,tf->tf_regs.reg_edi,
								tf->tf_regs.reg_esi);
								break;

		default:
			print_trapframe(tf);
			if (tf->tf_cs == GD_KT)
				panic("unhandled trap in kernel");
			else {
				env_destroy(curenv);
				return;
				}
		break;
	}

然后在kern/syscall.c添加处理函数:

int32_t
syscall(uint32_t syscallno, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
{
	// Call the function corresponding to the 'syscallno' parameter.
	// Return any appropriate return value.
	// LAB 3: Your code here.

//	panic("syscall not implemented");

	int32_t ret = 0;
	switch (syscallno) {
	case SYS_cputs:
		sys_cputs((const char*)a1,a2);
		break;
	case SYS_cgetc:
		ret = sys_cgetc();
		break;
	case SYS_env_destroy:
		ret = sys_env_destroy(a1);
		break;
	case SYS_getenvid:
		ret = sys_getenvid();
		break;
	default:
		return -E_INVAL;
	}

	return ret;
}

User-mode startup

Exercise 8. Add the required code to the user library, then boot your kernel. You should see user/hello print “hello, world” and then print “i am environment 00001000”. user/hello then attempts to “exit” by calling sys_env_destroy() (see lib/libmain.c and lib/exit.c). Since the kernel currently only supports one user environment, it should report that it has destroyed the only environment and then drop into the kernel monitor. You should be able to get make grade to succeed on the hello test.

在lib/libmain.c里面添加:

	// LAB 3: Your code here.
	thisenv = 0;
	thisenv = (struct Env*)(envs+ENVX(sys_getenvid()));

Page faults and memory protection

Ex9,Ex10都是关于这个主题的。

首先,在kern/pmap.c中添加:

int
user_mem_check(struct Env *env, const void *va, size_t len, int perm)
{
	// LAB 3: Your code here.
	/*
	uint32_t begin = (uint32_t) ROUNDDOWN(va, PGSIZE); 
    uint32_t end = (uint32_t) ROUNDUP(va+len, PGSIZE);
    uint32_t i;
    for (i = (uint32_t)begin; i < end; i += PGSIZE) {
        pte_t *pte = pgdir_walk(env->env_pgdir, (void*)i, 0);
        if ((i >= ULIM) || !pte || !(*pte & PTE_P) || ((*pte & perm) != perm)) {        //具体检测规则
            user_mem_check_addr = (i < (uint32_t)va ? (uint32_t)va : i);                //记录无效的那个线性地址
            return -E_FAULT;
        }
    }
	*/
	return 0;
}

然后,在kern/syscall.c里面添加:

static void
sys_cputs(const char *s, size_t len)
{
	// Check that the user has permission to read memory [s, s+len).
	// Destroy the environment if not.

	// LAB 3: Your code here.
	
	user_mem_assert(curenv,s,len,0);
	// Print the string supplied by the user.
	cprintf("%.*s", len, s);
}

最后make grade:

divzero: OK (2.7s) 
softint: OK (1.8s) 
badsegment: OK (2.0s) 
Part A score: 30/30

faultread: OK (1.0s) 
faultreadkernel: OK (1.8s) 
faultwrite: OK (2.2s) 
faultwritekernel: OK (2.0s) 
breakpoint: OK (2.0s) 
testbss: OK (1.8s) 
hello: OK (2.3s) 
buggyhello: OK (1.9s) 
    (Old jos.out.buggyhello failure log removed)
buggyhello2: OK (2.1s) 
    (Old jos.out.buggyhello2 failure log removed)
evilhello: OK (1.8s) 
    (Old jos.out.evilhello failure log removed)
Part B score: 50/50

Score: 80/80

草草记录,完事。

END.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值