我正在使用 DOS Extender 为 FreeDOS 开发一个保护模式应用程序。我的应用程序执行密集的 I/O。
由于所有的 DOS 扩展程序都在 Ring3(即 CPL=3)上运行他们的应用程序,而它们自己在 Ring 0(即 CPL=0)上运行,我想到了一些关于 I/O 保护的问题。
从 x86 文档,我得到以下信息:
IOPL 敏感指令:IN、INS、OUT、OUTS、CLI 和 STI。
如果 CPL <= IOPL,则不产生异常并执行 IOPL 敏感指令。
如果 CPL > IOPL,并且指令是这些指令之一(IN、OUT、INS 或 OUTS),则处理器检查当前任务的 IO 权限位图(在其 TSS 中)以确定当前应用程序是否被允许访问寻址 IO 端口。如果位图指示允许任务访问指示的 IO 端口,则不产生异常并执行 IO 指令。否则,将生成 GP 异常。
如果 CPL > IOPL,并且指令是 CLI 或 STI,则处理器会生成 GP 异常。
这意味着如果我们的应用程序。在 Ring3 上运行,然后要执行 IN,OUT,INS,OUTS 指令,我们必须有 CPL <= IOPL(在我们的例子中这转换为 IOPL=3),或者如果 CPL > IOPL(这转换为 IOPL <= 2 ,即 IOPL = 0,因为通常不使用 Ring1 和 Ring2。)I/O 权限位图必须由 DOS Extender 设置(在启动我们的应用程序时),这样我们的应用程序。允许访问任何I/O 端口。
但在后一种情况下,我们仍然不能使用 Ring3 应用程序中的 CLI 和 STI 指令,因为 CPL > IOPL。
因此,事实证明,只有当 CPL <= IOPL 时才能执行以下指令:IN、INS、OUT、OUTS、CLI 和 STI。在我们的例子中,这转换为 3 <= IOPL,即 IOPL = 3。
现在我的问题是,所有 dos 扩展程序是否在它们启动的任务/应用程序的 TSS 中设置 IOPL = 3?
如果他们不这样做,那么他们必须在 Ring0 (CPL=0) 中运行任务/应用程序,否则应用程序无法执行 IOPL 敏感指令。
文档还指出:
程序或任务只能通过 POPF 和 IRET 指令更改其 IOPL;然而,这样的改变是有特权的。除非以特权级别 0 即 CPL=0 运行,否则任何程序都不能更改当前的 IOPL。较低特权的过程尝试更改 IOPL 不会导致异常;IOPL 保持不变。
这意味着:如果在 Ring 3 代码中遇到 POPF 或 IRET 指令,则不会修改/恢复 IOPL 字段,CPU 不会产生异常。
没关系,因为我们不想修改 IOPL 字段,让它由 DOS Extender 处理。但这是否意味着其他标志(EFLAGS reg. 的 bit0 到 bit11)将被恢复?
我的应用程序。可能还需要执行 POPF 指令和 IRET。
该文档还指出:
只有当 CPL <= IOPL 时,程序才可以使用 POPF 指令更改 IF 标志的设置。较低特权的过程尝试更改 IF 标志不会导致异常;IF 标志保持不变。
这意味着:如果在 Ring3 代码中遇到 POF 指令,则仅当 CPL <= IOPL,即 3 <= IOPL 或 IOPL = 3 时修改 IF 标志。我们再次需要 IOPL 为 3。:)
我正在寻找一个通用的答案——即不是特定于 DOS Extender 的。这是因为,看起来虽然它们在实现上有所不同,但基本原理仍然是相同的 b/w DOS 扩展器——例如它们在 Ring3 中运行应用程序。