中断机制和上下文切换

中断机制和上下文切换

2024 南京大学《操作系统:设计与实现》
中断机制和上下文切换

处理器和中断

理想的处理器

  • 无情的执行指令的机器
for (day = TODAY;
    day != FOREVER; day++);
        say("I love you\n");

实际的处理器并不是 “无情地执行指令”

  • 还 “有情” 地响应外部的中断
    • 你在图书馆陷入了自习的死循环……
    • 清场的保安打断了你
2024 南京大学《操作系统:设计与实现》
中断机制和上下文切换

中断 = 一根线

center

  • “告诉处理器:停停,有事来了”,剩下全是处理器的事
2024 南京大学《操作系统:设计与实现》
中断机制和上下文切换

处理器的中断行为

如果处理器中断打开

  • x86 Family (CISC 的历史遗迹;处理器实现的噩梦)
    • 询问中断控制器获得中断号 nn
    • 保存 CS, EIP, EFLAGS, SS, ESP 到堆栈
    • 跳转到 IDT[n] 中的 “Gate”
      • 一个描述带权限切换长跳转的数据结构
  • RISC-V (M-Mode, Direct Exception Mode)
    • 检查 mie 是否屏蔽此次中断
    • 跳转 PC = (mtvec & ~0xf)
    • 更新 mcause.Interrupt = 1
2024 南京大学《操作系统:设计与实现》
中断机制和上下文切换

另一种理解中断的方式

强制 “插入” 的 syscall

  • 中断
    • 保存 mepc = PC
    • 跳转 PC = (mtvec & ~0xf)
    • 更新 mcause.Interrupt = 1
  • 系统调用 (ecall)
    • 保存 mepc = PC
    • 跳转 PC = (mtvec & ~0xf)
    • 更新 mcause.Ecall = 1
  • 无论你现在在做什么,都去执行一下操作系统内核的代码吧
2024 南京大学《操作系统:设计与实现》
中断机制和上下文切换

中断:奠定操作系统 “霸主地位” 的机制

操作系统内核 (代码)

  • 想开就开,想关就关

应用程序

  • 对不起,没有中断
    • 在 gdb 里可以看到 flags 寄存器 (FL_IF)
    • CLI — Clear Interrupt Flag
      • #GP(0) If CPL is greater than IOPL and less than 3
      • 试一试 asm volatile ("cli");
  • 无论什么样的代码,都会被打断
2024 南京大学《操作系统:设计与实现》
中断机制和上下文切换

假想一个中断

操作系统代码应该做什么?

  • mov (kernel_rsp), %rsp
    • 这将是致命
    • 进程 (状态机) 的状态就永远丢失了
  • 首先:封存状态机 (寄存器)
    • 内存由数据结构控制,
  • 然后:执行操作系统代码
    • C 代码可以任意使用寄存器
    • 操作系统代码选择一个返回的状态机
    • 恢复寄存器状态,执行 sysret (iret)
2024 南京大学《操作系统:设计与实现》
中断机制和上下文切换

实现上下文切换

操作系统的实现技巧

  • 设置一个 “current context”
  • 保存寄存器现场 & 恢复寄存器现场
    • AbstractMachine 已经帮你获得了寄存器
Context *on_interrupt(Event ev, Context *ctx) {
    // Save context.
    current->context = *ctx;

    // Thread schedule.
    current = current->next;

    // Restore current thread's context.
    return &current->context;
}
2024 南京大学《操作系统:设计与实现》