The SYSCALL instruction does not save the stack pointer (RSP).
现在考虑指令
mov rsp, -999
syscall
<interrupt>
由于syscall
进入环0,中断将使用rsp
的堆栈,这将扰乱内核。操作系统不能做任何事情,因为它甚至没有准备好做任何事情。
文档还提到了SSP
,看起来最有可能解决这个问题,但我不明白RSP
之间的关系。
The SYSCALL instruction does not save the stack pointer (RSP).
现在考虑指令
mov rsp, -999
syscall
<interrupt>
由于syscall
进入环0,中断将使用rsp
的堆栈,这将扰乱内核。操作系统不能做任何事情,因为它甚至没有准备好做任何事情。
文档还提到了SSP
,看起来最有可能解决这个问题,但我不明白RSP
之间的关系。
1条答案
按热度按时间tkqqtvp11#
这就是为什么
syscall
使用IA32_FMASK MSR屏蔽RFLAGS的原因,因此在正常的操作系统中,这将是一个问题,可以通过禁用中断来避免。(但是IF=0
不能阻止NMI; TSS可提供替代堆叠1.)当AMD 64首次在论文中提出时,Linux内核开发人员指出了在内核设置SS:RSP之前能够屏蔽中断的必要性,导致了当前的设计:
syscall
/sysret
中添加EFLAGS掩码并保存R11中的旧RFLAGSsyscall
写入RCX和R11之后)。为什么不把
syscall
做得更复杂一些,同时也为您切换到一个内核堆栈,这样一旦它完成了,就有一个有效的内核堆栈了?sysenter
一样,让用户空间把它藏在内核可以找到的地方。)我猜如果syscall
这样做的话,它可能会被推到这个新的内核堆栈上,但是syscall
会访问内存。(微代码可以使用临时寄存器,而这些临时寄存器在体系结构上是不可见的。)但它可能是一个非规范的地址,如果内核想要使用可分页内存(或在一个坏地址上),它可能会出现页面错误,或者可能只是速度很慢。swapgs
中,由内核决定如何/在何处存储每个任务的信息。内核只需要更新上下文切换(内核GS库)上的一件事,而不需要更新带有内核堆栈指针的MSR。syscall
是一个执行障碍:以后的指令可以开始乱序执行,直到它完全完成。)保持系统调用指令较轻量(例如 * 不 * 接触内存)是Intel的
sysenter
和AMD的syscall
作为int 0x80
或其他更快的替代品的设计动机。脚注1:Nate Eldredge查阅了手册,有一个单独的机制可以使用固定的堆栈地址进行NMI处理,不容易允许嵌套:
似乎x86-64添加了一个特殊的中断堆栈切换机制-他们重新利用TSS来保存多达7个指定堆栈区域的指针,每个IDT条目都有一个字段,可以选择其中一个堆栈进行切换。除了NMI之外,它没有太多用处,因为例如您不能轻松地嵌套此类中断,但它确实解决了这个问题。