MIT6.s081 lab lazy allocation

LAB:xv6 lazy page allocation

1.实验概述

本节的实验内容是给xv6加上一个延迟分配内存的功能,具体内容为,在用户态调用系统调用sys_bark时,只设置进程控制块中内存大小,不进行具体分配,等待用户需要使用上次调用的内存时,会产生一个pagefault,此时在中断处理程序中进行具体分配并返回重新执行指令

2.重点代码

uint64
sys_sbrk(void)
{
  int addr;
  int n;
  struct proc *p = myproc();

  addr = p->sz;
  if(argint(0, &n) < 0)
    return -1;    
  if (n < 0) {
    uint64 sz = p->sz;
    p->sz = uvmdealloc(p->pagetable, sz, sz + n);
  } else {
    (p->sz) += n;
  }
  return addr;
}
// usertrap
else if(r_scause() == 15 || r_scause() == 13){
    uint64 falut_addr = r_stval();
    if (falut_addr >= p->sz || falut_addr < p->trapframe->sp) {
      p->killed = 1;
    } else {
      falut_addr = PGROUNDDOWN(falut_addr);
      uint64 ka = (uint64)kalloc();
      if(ka == 0) {
        p->killed = 1;
      } else {
        memset((void *)ka, 0, PGSIZE);
        if (mappages(p->pagetable, falut_addr, PGSIZE, ka, PTE_W | PTE_U | PTE_R) != 0) {
          kfree((void*)ka);
          p->killed = 1;
        }
      }
    }
  } 

此时你还需要处理一种情况:当进程的内存未被分配就需要释放时,uvmunmap在去除pagetable上的ptes时,可能查找不到那块尚未分配的内存的pte,且上面的PTE_V不存在,所以我们需要处理一下uvmunmap

// uvmunmap
void
uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
{
  uint64 a;
  pte_t *pte;

  if((va % PGSIZE) != 0)
    panic("uvmunmap: not aligned");

  for(a = va; a < va + npages*PGSIZE; a += PGSIZE){
    if((pte = walk(pagetable, a, 0)) == 0)
      continue;
    if((*pte & PTE_V) == 0)
      continue;
    if(PTE_FLAGS(*pte) == PTE_V)
      panic("uvmunmap: not a leaf");
    if(do_free){
      uint64 pa = PTE2PA(*pte);
      kfree((void*)pa);
    }
    *pte = 0;
  }
}

此时可以正常调用echo hi了,但想要完美通过lazytestsusertests,需要处理这种情况:当用户态调用系统调用writeread时,可能会访问到未被分配的内存块,但此时是从内核态进入中断的,usertrap并不会处理,所以我们需要处理一下copyincopyout函数,这两个函数被write调用

int
copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len)
{
  uint64 n, va0, pa0;
  struct proc *p = myproc();
  
  while(len > 0){
    va0 = PGROUNDDOWN(srcva);
    pa0 = walkaddr(pagetable, va0);
    if(pa0 == 0) {
      if (va0 >= p->sz || va0 < p->trapframe->sp) {
        return -1;
      }
      pa0 = (uint64)kalloc();
      if (pa0 == 0) {
        p->killed = 1;
      } else {
        memset((void *)pa0, 0, PGSIZE);
        if (mappages(p->pagetable, va0, PGSIZE, pa0, PTE_W | PTE_U | PTE_R) != 0) {
          kfree((void*)pa0);
          p->killed = 1;
        }
      }
    }
    n = PGSIZE - (srcva - va0);
    if(n > len)
      n = len;
    memmove(dst, (void *)(pa0 + (srcva - va0)), n);

    len -= n;
    dst += n;
    srcva = va0 + PGSIZE;
  }
  return 0;
}
int
copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
{
  uint64 n, va0, pa0;
  struct proc *p = myproc();
  

  while(len > 0){
    va0 = PGROUNDDOWN(dstva);
    pa0 = walkaddr(pagetable, va0);
    if(pa0 == 0) {
      if (va0 >= p->sz || va0 < p->trapframe->sp)
        return -1;
      pa0 = (uint64)kalloc();
      if (pa0 == 0) {
        p->killed = 1;
      } else {
        memset((void *)pa0, 0, PGSIZE);
        if (mappages(p->pagetable, va0, PGSIZE, pa0, PTE_W | PTE_U | PTE_R) != 0) {
          kfree((void*)pa0);
          p->killed = 1;
        }
      }
    }
      
    n = PGSIZE - (dstva - va0);
    if(n > len)
      n = len;
    memmove((void *)(pa0 + (dstva - va0)), src, n);

    len -= n;
    src += n;
    dstva = va0 + PGSIZE;
  }
  return 0;
}

posted @   silly19  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示