assembly SYSCALL后中断

syqv5f0l  于 2023-05-23  发布在  其他
关注(0)|答案(1)|浏览(133)

The SYSCALL instruction does not save the stack pointer (RSP).
现在考虑指令

mov rsp, -999
syscall
<interrupt>

由于syscall进入环0,中断将使用rsp的堆栈,这将扰乱内核。操作系统不能做任何事情,因为它甚至没有准备好做任何事情。
文档还提到了SSP,看起来最有可能解决这个问题,但我不明白RSP之间的关系。

tkqqtvp1

tkqqtvp11#

这就是为什么syscall使用IA32_FMASK MSR屏蔽RFLAGS的原因,因此在正常的操作系统中,这将是一个问题,可以通过禁用中断来避免。(但是IF=0不能阻止NMI; TSS可提供替代堆叠1.)
当AMD 64首次在论文中提出时,Linux内核开发人员指出了在内核设置SS:RSP之前能够屏蔽中断的必要性,导致了当前的设计:

为什么不把syscall做得更复杂一些,同时也为您切换到一个内核堆栈,这样一旦它完成了,就有一个有效的内核堆栈了?

  • 您需要将旧的用户空间堆栈指针存储在某个位置。(或者像sysenter一样,让用户空间把它藏在内核可以找到的地方。)我猜如果syscall这样做的话,它可能会被推到这个新的内核堆栈上,但是syscall会访问内存。(微代码可以使用临时寄存器,而这些临时寄存器在体系结构上是不可见的。)但它可能是一个非规范的地址,如果内核想要使用可分页内存(或在一个坏地址上),它可能会出现页面错误,或者可能只是速度很慢。
  • swapgs中,由内核决定如何/在何处存储每个任务的信息。内核只需要更新上下文切换(内核GS库)上的一件事,而不需要更新带有内核堆栈指针的MSR。
  • 一个大的微代码指令为微代码增加了更多的极端情况(包括在坏内核RSP上出错的可能性)。这也可能是更糟糕的性能。(至少对于Intel来说,syscall是一个执行障碍:以后的指令可以开始乱序执行,直到它完全完成。)

保持系统调用指令较轻量(例如 * 不 * 接触内存)是Intel的sysenter和AMD的syscall作为int 0x80或其他更快的替代品的设计动机。
脚注1:Nate Eldredge查阅了手册,有一个单独的机制可以使用固定的堆栈地址进行NMI处理,不容易允许嵌套:
似乎x86-64添加了一个特殊的中断堆栈切换机制-他们重新利用TSS来保存多达7个指定堆栈区域的指针,每个IDT条目都有一个字段,可以选择其中一个堆栈进行切换。除了NMI之外,它没有太多用处,因为例如您不能轻松地嵌套此类中断,但它确实解决了这个问题。

相关问题