上下文处理

我们已经知道,在发生中断的时候, CPU会跳到stvec.我们准备采用Direct模式,也就是只有一个中断处理程序, stvec直接跳到中断处理程序的入口点,那么需要我们对stvec寄存器做初始化.

上下文

中断的处理需要“放下当前的事情但之后还能回来接着之前往下做”,对于CPU来说,实际上只需要把原先的寄存器保存下来,做完其他事情把寄存器恢复回来就可以了。这些寄存器也被叫做CPU的context(上下文,情境)

我们要用汇编实现上下文切换(context switch)机制,这包含两步:

  • 保存CPU的寄存器(上下文)到内存中(栈上)

  • 从内存中(栈上)恢复CPU的寄存器

通用寄存器的介绍见中文手册42页。

为了方便我们组织上下文的数据(几十个寄存器),我们定义一个结构体。

// kern/trap/trap.h
#ifndef __KERN_TRAP_TRAP_H__
#define __KERN_TRAP_TRAP_H__

#include <defs.h>

struct pushregs {
    uintptr_t zero;  // Hard-wired zero
    uintptr_t ra;    // Return address
    uintptr_t sp;    // Stack pointer
    uintptr_t gp;    // Global pointer
    uintptr_t tp;    // Thread pointer
    uintptr_t t0;    // Temporary
    uintptr_t t1;    // Temporary
    uintptr_t t2;    // Temporary
    uintptr_t s0;    // Saved register/frame pointer
    uintptr_t s1;    // Saved register
    uintptr_t a0;    // Function argument/return value
    uintptr_t a1;    // Function argument/return value
    uintptr_t a2;    // Function argument
    uintptr_t a3;    // Function argument
    uintptr_t a4;    // Function argument
    uintptr_t a5;    // Function argument
    uintptr_t a6;    // Function argument
    uintptr_t a7;    // Function argument
    uintptr_t s2;    // Saved register
    uintptr_t s3;    // Saved register
    uintptr_t s4;    // Saved register
    uintptr_t s5;    // Saved register
    uintptr_t s6;    // Saved register
    uintptr_t s7;    // Saved register
    uintptr_t s8;    // Saved register
    uintptr_t s9;    // Saved register
    uintptr_t s10;   // Saved register
    uintptr_t s11;   // Saved register
    uintptr_t t3;    // Temporary
    uintptr_t t4;    // Temporary
    uintptr_t t5;    // Temporary
    uintptr_t t6;    // Temporary
};

struct trapframe {
    struct pushregs gpr;
    uintptr_t status; //sstatus
    uintptr_t epc; //sepc
    uintptr_t badvaddr; //sbadvaddr
    uintptr_t cause; //scause
};

void trap(struct trapframe *tf);

C语言里面的结构体,是若干个变量在内存里直线排列。也就是说,一个trapFrame结构体占据36个uintptr_t的空间(在64位RISCV架构里我们定义uintptr_t为64位无符号整数),里面依次排列通用寄存器x0x31,然后依次排列4个和中断相关的CSR, 我们希望中断处理程序能够利用这几个CSR的数值。

保存上下文

我们在理论课上也学到了保存上下文是用汇编语言实现的。首先我们定义一个汇编宏 SAVE_ALL, 用来保存所有寄存器到栈顶(实际上把一个trapFrame结构体放到了栈顶)。

恢复上下文

然后是恢复上下文的汇编宏,恢复的顺序和当时保存的顺序反过来,先加载两个CSR, 再加载通用寄存器。

中断入口

真正的入口点就是去调用这两个宏定义

我们可以看到,trapentry.S这个中断入口点的作用是保存和恢复上下文,并把上下文包装成结构体送到trap函数那里去。下面我们就去看看trap函数里面做些什么。

最后更新于

这有帮助吗?