29.9. 灵活返回和事件传递 (FRED)

29.9.1. 概述

FRED 架构定义了简单的新的特权级别更改(环转换)。FRED 架构的设计目标如下:

  1. 通过使用低延迟转换替换通过中断描述符表(IDT 事件传递)的事件传递和通过 IRET 指令的事件返回,来提高整体性能和响应时间。

  2. 通过确保事件传递建立完整的管理程序上下文,以及事件返回建立完整的用户上下文,来提高软件的健壮性。

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.9.2. 基于软件的事件分派

FRED 在事件处理方面与 IDT 的运作方式不同。FRED 不是直接基于事件向量将事件分派到其处理程序,而是要求软件基于事件的类型和向量将事件分派到其处理程序。因此,必须实现一个事件分派框架来促进事件到处理程序的分派过程。一旦事件被传递,FRED 事件分派框架将接管,并采用两级分派。

第一级分派基于事件类型,第二级分派基于事件向量。

29.9.3. 完整的管理程序/用户上下文

FRED 事件传递在事件传递和返回时原子地保存和恢复完整的管理程序/用户上下文。因此,它避免了由于 %cr2 和/或 %dr6 引起的瞬态状态问题,并且不再需要处理由于半完成的入口状态引起的所有棘手的角落情况。

FRED 允许使用新的事件返回指令 ERETS/ERETU 显式取消阻塞 NMI,从而避免了 IRET 无条件取消阻塞 NMI 引起的混乱,例如,当在 NMI 处理期间发生异常时。

FRED 始终恢复 %rsp 的完整值,因此启用 FRED 后不再需要 ESPFIX。

29.9.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.9.5. 堆栈级别

引入了 4 个堆栈级别 0~3 来替换用于事件处理的不可重入 IST,并且每个堆栈级别应配置为使用专用堆栈。

当前堆栈级别可以在 FRED 事件传递时保持不变或升高。如果保持不变,CPU 将继续使用当前的事件堆栈。如果升高,CPU 将切换到由新堆栈级别的 MSR 指定的新事件堆栈,即 MSR_IA32_FRED_RSP[123]。

只有执行 FRED 返回指令 ERET[US] 才能降低当前堆栈级别,从而使 CPU 切换回之前提升堆栈级别的先前事件传递之前的堆栈。