RISCV 汇编编写贴士

切换页表

在切换页表时,为了防止出现不一致的情况,我们需要先清空 TLB(这个过程保证了旧的页表的数据是正确的),然后切换页表,之后再清空 TLB。

在 RISCV 中,我们可以通过 sfence.vma 指令来清空 TLB。

比如在切换页表时,我们可以这样做:(假设 t0 是新的 satp)

    # clear TLB
    sfence.vma

    # switch page table
    csrw satp, t0

    # clear TLB
    sfence.vma

利用 scratch 储存临时变量

在编写一些代码时(尤其是 trap vectors),我们需要使用除了通用寄存器之外的寄存器储存临时变量。比如将所有的通用寄存器保存到特定内存地址时,我们还需要寄存器储存内存地址。我们可以利用 RISCV 中的 mscratch/sscratch 寄存器来储存这些临时变量。

通常情况下,我们会先将一个寄存器的值储存在 scratch 上,然后完成操作后,再还原这个寄存器的值。

比如当我们需要将所有通用寄存器储存到 TRAP_CONTEXT 开始的地址时,我们可以:

    # save user a0 in sscratch so a0 can be used to get at TRAP_CONTEXT.
    csrw sscratch, a0
    li a0, TRAP_CONTEXT

    # save the user registers except a0 in TRAP_CONTEXT
    ...
    ...

    # save previous a0 to TRAP_CONTEXT
    csrr t0, sscratch
    sd t0, 112(a0)