8.3 保护和I/O(Protection and I/O)

有两种机制用于I/O保护:

1、 FLAGS里的IOPL字段定义了使用I/O指令的特权级。

2、 TSS段里的I/O许可位图定义了使用I/O地址空间的特权级。

这些机制只在保护模式下工作,包含虚拟8086模式。在实模式中他们不会起作用。在实模式中,I/O空间没有任何保护。任何子程序可执行I/O指令。任意I/O端口都是可以被I/O指令寻址的。

8.3.1 I/O 特权级(I/O Privilege Level)

处理I/O的指令应该被限制执行,但不在特权级0执行I/O指令也是需要的。所以,处理器用了标志寄存器里的两位来存储I/O的特权级(IOPL)。IOPL定义了要执行I/O指令所需要的特权级。

以下指令只有当CPL <= IOPL时才可以执行:

这些指令被称作“敏感指令”,因为他们对I/O敏感的。

为了执行敏感指令,子程序必须执行在至少小于或等于(数值上)IOPL(CPL <= IOPL)的特权级。任何没有足够特权级的程序执行I/O指令时将引起通用保护异常。

因为每个任务都有自已的标志寄存器,每个程序都有不同的IOPL。一个任务如果主要任务是完成I/O操作的话(设备驱动程序)可以让IOPL为3,所以他的任何子程序都可以执行I/O。其它一些程可以把IOPL设成0或1,只让特权级高的子程序可以执行I/O。

一个任务只有通过POPF指令才能改变IOPL。但是,这样的改变是特权级的。只有在特权级0执行的程序才可以改变IOPL。不够特权级的程如果试图更改IOPL的话,不会产生任何异常,而IOPL只是保持不变。

一条POPF指令可以用来副加的开中断和关中断。但是,通过POPF来改变IF标志位也是特权级的。一个想通过POPF指令来改变IF标志的程序,必须要执行在到少IOPL的特权级上(数值上小于或等于)。同样,不够特权级的试图更改并不会产生任何异常,而IF只是保持不变。

8.3.2 I/O 许可位图(I/O permission Bit Map)

直接指定处理器I/O地址空间的I/O指令是IN,INS,OUT,OUTS。80386可以有选择性的把一些I/O地址空间访问设成陷阱。允计这样做的数据结构是在TSS段(请看图8-2)中的I/O 许可位图(I/O Permission Bit Map)I/O许可位图是一个位向量。位图的大小是可变的,这个值存放在TSS段中。处理器通过TSS中的位图基址来定位这个位图。I/O位图基址是一个16位宽的字段,包含了I/O许可位图的偏移。位图的上限也是TSS段的上限。

在保护模式下,当遇到一条I/O指令时(IN,INS,OUT,或OUTS),处理器首先检查是否CPL<=IOPL。如果是的话,I/O操作可以继续。如果不是的话,处理器检查I/O许可位图。(在虚拟8086模式,处理器不管IOPL而直接查看位图,参看第15章)

位图中的每一位都对应着一个I/O端口字节地址。例如,端口41的位可以在I/O位图基址+5,位偏移1,处找到。处理器会检测I/O指令访问到的每个字节,以看是否允许访问。例如,一个双字操作,将测试4位,对应着4个连续的字节地址空间。如果任一个测试是置位的,处理器引发一个通用保护异常。如果所有的测试都有为0,I/O操作被允许。

没有必要为所有的I/O地址设置I/O许可位图。没有被覆盖到的I/O地址空间,将被假设该位图对应位已设置为1。例如,如果TSS界限等于I/O位图基址+31的话,前256的端口被映射。对于更大的端口号作的I/O操作将引起异常。

如果I/O映射位图基址大于或等于TSS界限的话,TSS段则没有I/O许可位图,所以只要当CPL>IOPL时,所有的I/O操作将引起异常。

因为I/O许可位图在TSS段中,不同的任务有不同的映射位图。操作系统可以通过修改一个任务的TSS段中的I/O许可位图,来为某个任务分配端口,