Interrupt and System call

  • xv6 通过一个存放函数指针的数组来作为中断向量表,在 main 函数初始化过程中,调用tvinit 函数完成中断向量表的初始化。tvinit 将每一个中断处理程序的地址写入 idt 数组中,idtinit 将数组地址载入中断向量表寄存器,硬件能够根据中断向量表寄存器准确找出中断处理程序,xv6 使用 vector.pl 脚本生成 vector 数组,vector 数组存放着每个中断处理程序的入口地址,xv6 简单地将所有的中断处理程序指向 alltraps,由 alltraps 来负责具体的处理。在调用 alltraps 之前,xv6 统一压入 errnum 和 trapnum 来区分是 256 情况中的哪种。

    void
    tvinit(void)
    {
    int i;

    for(i = 0; i < 256; i++)
    SETGATE(idt[i], 0, SEG_KCODE<<3, vectors[i], 0);
    SETGATE(idt[T_SYSCALL], 1, SEG_KCODE<<3, vectors[T_SYSCALL], DPL_USER);

    initlock(&tickslock, "time");
    }

    void
    idtinit(void)
    {
    lidt(idt, sizeof(idt));
    }


    vector255:
    pushl $0
    pushl $255
    jmp alltraps
  • alltraps 继续压入寄存器保存现场,得到 trapframe 结构体,trapframe 结构体如图所示,其中 oesp 没有用处,这是 pushal 指令统一压栈的。

    .globl alltraps
    alltraps:
    # Build trap frame.
    pushl %ds
    pushl %es
    pushl %fs
    pushl %gs
    pushal