MIT6.828学习之homework4:xv6 lazy page allocation

xv6应用程序使用sbrk()系统调用向内核请求堆内存。在我们给出的内核中,sbrk()分配物理内存并将其映射到进程的虚拟地址空间。有些程序分配内存,但从不使用它,例如实现大型稀疏数组。复杂的内核会延迟对每个内存页的分配,直到应用程序尝试使用该页面——这是由页面错误发出的信号。
就是只修改进程大小值实际上不分配页面(让进程误以为分配了),等需要使用对应页面再来分配

Part One

修改sbrk(n),本来是将进程的内存大小增加n个字节,然后返回新分配区域的开始;改成只需将进程的大小(myproc()->sz)增加n不分配区域,并返回原来的大小。比较简单

//将进程的大小(myproc()->sz)增加n不分配区域,其中n为用户传入的参数
int
sys_sbrk(void)
{
  int addr;
  int n;

  if(argint(0, &n) < 0)
    return -1;
  addr = myproc()->sz;
  /*if(growproc(n) < 0)
    return -1;*/
  myproc()->sz += n;
  return addr;
}

改之前
在这里插入图片描述
改之后
在这里插入图片描述
“addr 0x4004”表示导致页面错误的虚拟地址是0x4004。“pid 3 sh: trap…”消息来自trap.c中的内核陷阱处理程序。它捕获了一个页面错误(trap 14,或T_PGFLT),所以为什么发生这个错误?

//traps.h中
#define T_PGFLT         14      // page fault

这个错误肯定是因为代码改成了只增加大小,不分配物理区域导致找不到虚拟地址对应的物理页引发报错。
但我有个疑问,echo hi只是把hi输出而已,需要用到物理页吗?还是说hi作为参数存在argv[1]中,也就是需要物理页保存。

Part Two

将新分配的物理内存页映射到故障地址然后返回到用户空间,让进程继续执行。
有很多提示,就相对容易。

Hint: look at the cprintf arguments to see how to find the virtual address that caused the page fault.
(找到引起错误的虚拟地址)

Hint: steal code from allocuvm() in vm.c, which is what sbrk() calls (via growproc()).

Hint: use PGROUNDDOWN(va) to round the faulting virtual address down to a page boundary.
(4k对齐)

Hint: break or return in order to avoid the cprintf and the myproc()->killed = 1.
(及时返回防止再次输出那段提示)

Hint: you'll need to call mappages(). 
In order to do this you'll need to delete the static in the declaration of mappages() in vm.c, and you will need to declare mappages() in trap.c. 
Add this declaration to trap.c before any call to mappages():
      int mappages(pde_t *pgdir, void *va, uint size, uint pa, int perm);

Hint: you can check whether a fault is a page fault by checking if tf->trapno is equal to T_PGFLT in trap(). 
//#define T_PGFLT         14      // page fault
//将引发缺页异常的线性地址保存在address变量里面  
    __asm__("movl %%cr2,%0":"=r" (address));   

让程序继续执行缺的是什么,如何让程序返回用户空间?

default:
    if(myproc() == 0 || (tf->cs&3) == 0){
      // In kernel, it must be our mistake.
      cprintf("unexpected trap %d from cpu %d eip %x (cr2=0x%x)\n",
              tf->trapno, cpuid(), tf->eip, rcr2());
      panic("trap");
    }
	
	char *mem;
    uint a;
	a = PGROUNDDOWN(rcr2()); //将引起错误的虚拟地址向下4K对齐
	for(; a < myproc()->sz; a += PGSIZE){ //从a开始对大小为myproc()->sz-a的区域分配并映射物理页
	  mem = kalloc(); //分配物理页
	  if(mem == 0){
	    cprintf("allocuvm out of memory\n");
	    //这里的 myproc()->tf->eax瞎写的,我以为sys_sbrk()返回值即oldsz存在tf->eax中
	    deallocuvm(myproc()->pgdir, myproc()->sz, myproc()->tf->eax); 
	    return;
	  }
	  memset(mem, 0, PGSIZE); //初始化物理页
	  if(mappages(myproc()->pgdir, (char*)a, PGSIZE, V2P(mem), PTE_W|PTE_U) < 0){ 
	  //映射刚分配的物理页到虚拟地址失败
	    cprintf("allocuvm out of memory (2)\n");
	    deallocuvm(myproc()->pgdir, myproc()->sz, myproc()->tf->eax);
	    kfree(mem);
	    return;
	  }
	}
	break;
	  
    // In user space, assume process misbehaved.
    cprintf("pid %d %s: trap %d err %d on cpu %d "
            "eip 0x%x addr 0x%x--kill proc\n",
            myproc()->pid, myproc()->name, tf->trapno,
            tf->err, cpuid(), tf->eip, rcr2());
    myproc()->killed = 1;
  }

我随便改了下,就成功运行了???什么情况?
在这里插入图片描述
我看到别人的代码好像没有for循环,只是加了分配了一个PGSIZE大小的页,难道出错的只是cr2内那一个虚拟地址吗?我先不改,等后面出错了再回来改,至少现在可以运行

参考文档

xv6 中文文档
缺页异常处理

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值