Lab 5

删除 sbrk的原调用,并添加 lazy allocated,也就是只增长(减小) p->sz,不做立即的页面分配。

uint64
sys_sbrk(void)
{
  int addr;
  int n;

  if(argint(0, &n) < 0)
    return -1;
  struct proc* p = myproc();
  uint64 sz = p->sz;
  addr = p->sz;

  if(n > 0) {
    p->sz += n;
  } else if(sz + n > 0) {
    // 这种情况是 n < 0,但n + sz > 0的情况,是合法的,需要减小页面
    sz = uvmdealloc(p->pagetable, sz, sz + n);
    p->sz = sz;
  } else {
    return -1;
  }
  return addr;
}

修改usertrap()来解决 sbrk()调用页错误的情况:也就是r_scause() == 13 || 15的情况

void
usertrap(void)
{
  int which_dev = 0;
  if((r_sstatus() & SSTATUS_SPP) != 0)
    panic("usertrap: not from user mode");

  // send interrupts and exceptions to kerneltrap(),
  // since we're now in the kernel.
  w_stvec((uint64)kernelvec);

  struct proc *p = myproc();
  
  // save user program counter.
  p->trapframe->epc = r_sepc();
  
  if(r_scause() == 8){
    // system call

    if(p->killed)
      exit(-1);

    // sepc points to the ecall instruction,
    // but we want to return to the next instruction.
    p->trapframe->epc += 4;

    // an interrupt will change sstatus &c registers,
    // so don't enable until done with those registers.
    intr_on();

    syscall();
  } else if((which_dev = devintr()) != 0){
    // ok
  } else if(r_scause() == 15 || r_scause() == 13) {
    // char *mem;
    // uint64 errAddr = r_stval();
    // mem = (char *)kalloc();
    // if(mem == 0) {
    //   printf("usertrap:kalloc()");
    //   p->killed = 1;
    // } else if(errAddr < p->sz){
    //   memset(mem,0,PGSIZE);
    //   uint64 va = PGROUNDDOWN(errAddr);
    //   if(mappages(p->pagetable, va, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U) != 0){
    //     kfree(mem);
    //     printf("usertrap(): mappages\n");
    //     p->killed = 1;
    //   }
    // } else {
    //   p->killed = 1;
    //   kfree(mem);
    //   printf("usertrap(): unknow error\n");
    // }
    char *mem; 
    uint64 errAddr = r_stval();
    if(errAddr < p->sz && PGROUNDUP(p->trapframe->sp) - 1 < errAddr && (mem = kalloc()) != 0) {
      memset(mem,0,PGSIZE);
      uint64 va = PGROUNDDOWN(errAddr);
      if(mappages(p->pagetable, va, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U) != 0){
        kfree(mem);
        printf("usertrap(): mappages\n");
        p->killed = 1;
      }
    } else {
      p->killed = 1;
    }
  }else {
    printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);
    printf("            sepc=%p stval=%p\n", r_sepc(), r_stval());
    p->killed = 1;
  }

  if(p->killed)
    exit(-1);

  // give up the CPU if this is a timer interrupt.
  if(which_dev == 2)
    yield();

  usertrapret();
}

按照错误提示来修改 xv6即可:

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){
      // 因为是lazy allocate,这个页可能还没被分配,因此不能panic
    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;
  }
}

int
uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
{
  pte_t *pte;
  uint64 pa, i;
  uint flags;
  char *mem;

  for(i = 0; i < sz; i += PGSIZE){
    if((pte = walk(old, i, 0)) == 0)
      continue;
    if((*pte & PTE_V) == 0)
      continue;
    pa = PTE2PA(*pte);
    flags = PTE_FLAGS(*pte);
    if((mem = kalloc()) == 0)
      goto err;
    memmove(mem, (char*)pa, PGSIZE);
    if(mappages(new, i, PGSIZE, (uint64)mem, flags) != 0){
      kfree(mem);
      goto err;
    }
  }
  return 0;

 err:
  uvmunmap(new, 0, i / PGSIZE, 1);
  return -1;
}
  • 处理这种情形:进程从sbrk()向系统调用(如readwrite)传递有效地址,但尚未分配该地址的内存。

int
argaddr(int n, uint64 *ip)
{
  *ip = argraw(n);
  struct proc *p = myproc();
  if(walkaddr(p->pagetable,*ip) == 0) {
    if (*ip < p->sz) {
      char *mem = (char *)kalloc();
      if(!mem) {
        return -1;
      }
      memset(mem,0,PGSIZE);
      uint64 va = PGROUNDDOWN(*ip);
      if(mappages(p->pagetable, va, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U) != 0){
        kfree(mem);
        return -1;
      }
    } else {
      return -1;
    }
  }
  return 0;
}

Last updated