29.8. 灵活返回和事件传递 (FRED)¶
29.8.1. 概述¶
FRED 架构定义了简单的新过渡,可以改变特权级别(环过渡)。FRED 架构的设计目标如下:
通过以更低延迟的过渡替换通过中断描述符表 (IDT 事件传递) 的事件传递和通过 IRET 指令的事件返回,从而提高整体性能和响应时间。
通过确保事件传递建立完整的管理程序上下文,并且事件返回建立完整的用户上下文,从而提高软件的健壮性。
FRED 架构定义的新过渡是 FRED 事件传递,以及用于从事件返回的两个 FRED 返回指令。FRED 事件传递可以实现从环 3 到环 0 的过渡,但它也用于传递环 0 的事件。一个 FRED 指令 (ERETU) 实现从环 0 到环 3 的返回,而另一个指令 (ERETS) 返回时保持在环 0 中。总的来说,FRED 事件传递和 FRED 返回指令就是 FRED 过渡。
除了这些过渡之外,FRED 架构还定义了一个新的指令 (LKGS),用于管理 GS 段寄存器的状态。LKGS 指令可以被不使用新的 FRED 过渡的 64 位操作系统使用。
此外,FRED 架构易于扩展,以适应未来的 CPU 架构。
29.8.2. 基于软件的事件分发¶
FRED 在事件处理方面与 IDT 的运作方式不同。FRED 不是根据事件向量直接将事件分发到其处理程序,而是要求软件根据事件的类型和向量将其分发到其处理程序。因此,必须实现一个事件分发框架,以促进事件到处理程序的分发过程。FRED 事件分发框架在事件传递后接管控制,并采用两级分发。
第一级分发基于事件类型,第二级分发基于事件向量。
29.8.3. 完整的管理程序/用户上下文¶
FRED 事件传递在事件传递和返回时自动保存和恢复完整的管理程序/用户上下文。因此,它避免了由于 %cr2 和/或 %dr6 导致的瞬态状态问题,并且不再需要处理由半生不熟的条目状态导致的所有难看的角落情况。
FRED 允许使用新的事件返回指令 ERETS/ERETU 显式取消阻塞 NMI,从而避免了 IRET 无条件取消阻塞 NMI 造成的混乱,例如,当在 NMI 处理期间发生异常时。
FRED 总是恢复 %rsp 的完整值,因此启用 FRED 后不再需要 ESPFIX。
29.8.4. LKGS¶
LKGS 的行为类似于 MOV 到 GS 指令,只是它将基地址加载到 IA32_KERNEL_GS_BASE MSR 中,而不是 GS 段的描述符缓存中。使用 LKGS,最终避免了篡改内核 GS,也就是说,操作系统始终可以使用自己的 GS 基地址运行。
由于来自环 3 的 FRED 事件传递和 ERETU 都交换了 GS 基地址的值和 IA32_KERNEL_GS_BASE MSR 的值,加上 LKGS 指令的引入,因此启用 FRED 后不再需要 SWAPGS 指令,因此被禁止 (#UD)。
29.8.5. 堆栈级别¶
引入了 4 个堆栈级别 0~3 来代替用于事件处理的不可重入 IST,并且每个堆栈级别都应配置为使用专用堆栈。
当前堆栈级别可以在 FRED 事件传递时保持不变或升高。如果保持不变,CPU 将继续使用当前事件堆栈。如果升高,CPU 将切换到由新堆栈级别的 MSR 指定的新事件堆栈,即 MSR_IA32_FRED_RSP[123]。
只有执行 FRED 返回指令 ERET[US] 才能降低当前堆栈级别,从而导致 CPU 切换回之前的事件传递提升堆栈级别之前所在的堆栈。