You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XV6(RISC-V)中sz为何可作为mappages的虚拟地址参数?

关于xv6中growproc与uvmalloc的地址疑问解答

首先看相关代码片段:

growproc函数

int
growproc(int n)
{
  uint sz;
  struct proc *p = myproc();

  sz = p->sz;
  if(n > 0){
    if((sz = uvmalloc(p->pagetable, sz, sz + n)) == 0) {
      return -1;
    }
  } else if(n < 0){
    sz = uvmdealloc(p->pagetable, sz, sz + n);
  }
  p->sz = sz;
  return 0;
}

uvmalloc函数

uint64
uvmalloc(pagetable_t pagetable, uint64 oldsz, uint64 newsz)
{
  char *mem;
  uint64 a;

  if(newsz < oldsz)
    return oldsz;

  oldsz = PGROUNDUP(oldsz);
  for(a = oldsz; a < newsz; a += PGSIZE){
    mem = kalloc();
    if(mem == 0){
      uvmdealloc(pagetable, a, oldsz);
      return 0;
    }
    memset(mem, 0, PGSIZE);
    if(mappages(pagetable, a, PGSIZE, (uint64)mem, PTE_W|PTE_X|PTE_R|PTE_U) != 0){
      kfree(mem);
      uvmdealloc(pagetable, a, oldsz);
      return 0;
    }
  }
  return newsz;
}

你的疑问核心是:为什么作为进程内存大小的sz,能当作mappages的虚拟地址参数?

这是因为xv6的用户进程地址空间设计特性:

  • xv6的用户虚拟地址是从0地址开始向上连续分配的,进程的内存大小sz(p->sz)同时也是用户虚拟地址空间的上边界——也就是说,sz的值刚好等于当前已分配虚拟地址的最高位置的下一个地址,也就是下一个要分配的虚拟页的起始地址。

举个具体例子:
假设当前进程的sz是4096(即PGSIZE,xv6中一页的大小),这意味着用户虚拟地址0~4095已经被分配使用,下一个要扩展的虚拟页的起始地址就是4096,也就是此时的sz值。

在uvmalloc中,oldsz被PGROUNDUP对齐后(确保是页大小的整数倍),循环变量a从这个对齐后的oldsz开始,每次递增PGSIZE,这个a就是明确的虚拟页起始地址,完全符合mappages对第二个参数(虚拟地址)的要求。

所以这里的sz身兼两职:既表示进程已用内存的总大小,也表示虚拟地址空间的下一个可用起始地址,因此可以直接作为虚拟地址传入mappages。

内容的提问来源于stack exchange,提问作者anru

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 06:13:00