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

修改xv6为多线程系统,trampoline写入栈触发Store/AMO页错误

问题

我正在将xv6修改为多线程系统,为了让每个线程找到唯一的TRAMPFRAME虚拟地址,需要在trampoline的uservec段中执行计算操作,具体是用栈临时存储寄存器,修改后的汇编代码如下:

uservec:    
    #
        # trap.c sets stvec to point here, so
        # traps from user space start here,
        # in supervisor mode, but with a
        # user page table.
        #

        # store intermediate registers on the stack
        addi sp, sp, -32
        sd a0, 0(sp)
        sd a1, 8(sp)
        sd a2, 16(sp)

现在遇到的问题是:每次从用户空间返回时(仍使用用户页表),执行这段代码写入栈都会触发错误,陷入无限循环。我检查了sp指向地址的权限,该地址已在用户页表中映射,相关代码如下:

首个进程初始化代码:

uvmfirst(p->mm.pagetable, initcode, sizeof(initcode));
  p->sz = PGSIZE; 

  // prepare for the very first "return" from kernel to user.

  t->trapframe->epc = 0;      // user program counter
  t->trapframe->sp = PGSIZE;  // user stack pointer

uvmfirst函数实现:

void
uvmfirst(pagetable_t pagetable, uchar *src, uint sz)
{
  char *mem;

  if(sz >= PGSIZE)
    panic("uvmfirst: more than a page");
  mem = kalloc();
  memset(mem, 0, PGSIZE);
  mappages(pagetable, 0, PGSIZE, (uint64)mem, PTE_W|PTE_R|PTE_X|PTE_U);
  memmove(mem, src, sz);
}

确认权限设置正确,但写入操作仍然失败,对原版xv6做相同修改也出现该问题,请问原因是什么?

原因分析

问题核心在于**uservec执行时CPU处于supervisor模式,但栈指针sp指向的是用户栈地址**。

根据RISC-V架构的权限规则:用户页表项的PTE_U标志仅允许CPU在用户模式(U-mode)下访问对应页面;当CPU处于supervisor模式(S-mode)时,会直接忽略PTE_U位,此时即使页表项包含PTE_W权限,也无法对用户页表中的页面执行写入操作——这会直接触发页错误,而页错误又会再次进入trap流程,最终导致无限循环。

你在uservec中尝试写入用户栈,但uservec本身是在S-mode下执行的,自然会触发权限错误。

解决办法

不能在uservec中直接使用用户栈存储寄存器,应该改用trampoline页自身的栈空间。trampoline页被映射到所有进程的同一个虚拟地址(通常为TRAMPOLINE),其页表项具备S-mode可读写权限,且没有PTE_U限制,适合在S-mode下临时存储数据。

具体实现时,可以在trampoline的汇编代码中预留一段固定的栈空间,或者利用trampoline页末尾的空闲区域作为临时栈,这样就能避开用户页的权限限制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 21:32:41