我经常听到驱动程序开发人员说尽可能避免内核模式切换是件好事。我无法理解确切的原因。首先我的理解是——
在这些操作中,syscall 的工作方式与普通函数调用非常相似。尽管 sysenter 可能表现得像一个错误预测的分支,这可能导致处理器管道中的 ROB 刷新。即使那也不是很糟糕,就像任何其他错误预测的分支一样。
我听到一些人在 Stack Overflow 上回答:
while(1);
不保证无上下文切换。 实际的系统调用成本从何而来?
最佳答案
您没有说明您要询问的操作系统。无论如何,让我尝试一个答案。
CPU 指令 syscall
和 sysenter
不应与 system call 的概念混淆及其在相应操作系统中的表示。
通读 给出了每个指令所产生的开销差异的最佳解释。操作英特尔® 64 位和 IA-32 架构开发人员手册的部分 volume 2A (对于 int
,请参见第 3-392 页)和 volume 2B (对于 sysenter
,请参见第 4-463 页)。也不要忘记看一眼 iretd
和 sysexit
而在它。
对操作伪代码的随意计数产生:
int
sysenter
55 行注:尽管现有的答案是正确的
sysenter
和 syscall
不是中断或与中断有任何关系,Linux 和 Windows 世界中的旧内核 使用中断来实现他们的系统调用机制 .在 Linux 上,这曾经是 int 0x80
和在 Windows int 0x2E
.因此,在这些内核版本上,IDT 必须准备好为相应的中断提供中断处理程序。在较新的系统上,确实如此,sysenter
和 syscall
指令已经完全取代了旧的方式。与 sysenter
它是 MSR(机器特定寄存器)0x176
用 sysenter
的处理程序地址准备好(请参阅下面链接的阅读 Material )。在 Windows 上...
Windows 上的系统调用,就像在 Linux 上一样,会导致切换到内核模式。 NT 的调度程序不提供有关授予线程的时间的任何保证。此外,它会从线程中抽出时间,甚至可能最终导致线程饥饿。一般来说,可以说用户模式代码可以被内核模式代码抢占(除了极少数非常具体的异常(exception),您肯定会在“高级驱动程序编写类(class)”中遇到这种情况)。如果我们只看一个例子,这是完全有道理的。用户模式代码可以换出——或者,就此而言,它试图访问的数据。现在 CPU 对如何访问交换/分页文件中的页面一无所知,因此需要一个中间步骤。这也是内核模式代码必须能够抢占用户模式代码的原因。这也是 Windows 上最多产的错误检查代码之一的原因,并且主要由第三方驱动程序引起:
IRQL_NOT_LESS_OR_EQUAL
.这意味着当无法抢占触及该内存的代码时,驱动程序访问了分页内存。进一步阅读
KiFastSystemCall
关于系统调用与函数调用之间的性能差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11169809/