8.2 I/O Instructions I/O指令
The I/O instructions of the 80386 provide access to the processor's I/O ports for the transfer of data to and from peripheral devices. These instructions have as one operand the address of a port in the I/O address space. There are two classes of I/O instruction:
80386IO指令用来访问处理器的IO端口,来和外围设备之间传送数据。这些指令有一个位于IO地址空间的端口地址作为操作数。IO指令分成两类:
- Those that transfer a single item (byte, word, or doubleword) located in a register.
传送寄存器中的单个项目(字节、字或双字)。
- Those that transfer strings of items (strings of bytes, words, or doublewords) located in memory. These are known as "string I/O instructions" or "block I/O instructions".
传送内存中的字符串项目(字节、字或双字构成的字符串)。这些指令也被叫做“字符串IO指令”或“块传送IO指令”。
8.2.1 Register I/O Instructions 寄存器IO指令
The I/O instructions IN and OUTare provided to move data between I/O ports and the EAX (32-bit I/O), the AX (16-bit I/O), or AL (8-bit I/O) general registers. IN andOUTinstructions address I/O ports either directly, with the address of one of up to 256 port addresses coded in the instruction, or indirectly via the DX register to one of up to 64K port addresses.
IN、OUT这两个IO指令用来在EAX(32位IO)、AX(16位IO)或AL(8位IO)这些通用寄存器和IO端口之间传送数据。IN和OUT指令寻址IO端口即可以是直接的,好使用最多256个端口之一的地址编码在指令中,也可以是非直接的,而是通过DX寄存器使用最多达64K的端口地址。
IN (Input from Port) transfers a byte, word, or doubleword from an input port to AL, AX, or EAX. If a program specifies AL with the IN instruction, the processor transfers 8 bits from the selected port to AL. If a program specifies AX with the IN instruction, the processor transfers 16 bits from the port to AX. If a program specifies EAX with the IN instruction, the processor transfers 32 bits from the port to EAX.
IN(从端口输入)从一个输入端口传送一个字节、字或双字到AL、AX或EAX寄存器。如果程序在IN指令中指定AL,处理器从选定的端口中传送8位数据到AL中。如果指定AX,则传送16位数据,如果指定EAX,则处理器传送32位数据。
OUT(Output to Port) transfers a byte, word, or doubleword to an output port from AL, AX, or EAX. The program can specify the number of the port using the same methods as the IN instruction.
OUT(向端口输出)将AL、AX或EAX寄存器中的字节、字或双字传送到输出端口。正如IN指令一样,程序可以使用同样的方式来指定一个端口号码。
8.2.2 Block I/O Instructions 块传送IO指令
The block (or string) I/O instructions INS and OUTS move blocks of data between I/O ports and memory space. Block I/O instructions use the DX register to specify the address of a port in the I/O address space. INS and OUTSuse DX to specify:
块(或叫字符串)传送IO指令INS和OUTS在IO端口与内存空间之间传送数据块。块IO指令使用DX寄存器来指定一个在IO地址上的端口地址。
- 8-bit ports numbered 0 through 65535
8位端口,数值从0到65535
- 16-bit ports numbered 0, 2, 4, . . . , 65532, 65534
16位端口,数值从0,2,4,...,65532,65534
- 32-bit ports numbered 0, 4, 8, . . . , 65528, 65532
32位端口,数值从0,4,8,...,65528,65532
Block I/O instructions use either SI or DI to designate the source or destination memory address. For each transfer, SI or DI are automatically either incremented or decremented as specified by the direction bit in the flags register.
块IO指令使用SI或DI来指定源或目的内存地址。每次传送,根据标志寄存器中的方向位的设置,SI或DI都自动增加或减少。
INS and OUTS, when used with repeat prefixes, cause block input or output operations. REP, the repeat prefix, modifies INS and OUTS to provide a means of transferring blocks of data between an I/O port and memory. These block I/O instructions are string primitives (refer also to Chapter 3 for more on string primitives). They simplify programming and increase the speed of data transfer by eliminating the need to use a separate LOOP instruction or an intermediate register to hold the data.
在使用重复前缀时,INS和OUTS都会引发块输入或输出操作。REP,重复前缀,用来修饰INS和OUTS指令,以能够提供内存与IO端口之间的数据块传输。这些块IO指令是字符串原语(参见第3章关于字符串原语的更多内容)。它们使程序更加简化,并通过删除对独立的LOOP指令或保存数据的中间寄存器的需求从而加快了数据传输。
The string I/O primitives can operate on byte strings, word strings, or doubleword strings. After each transfer, the memory address in ESI or EDI is updated by 1 for byte operands, by 2 for word operands, or by 4 for doubleword operands. The value in the direction flag (DF) determines whether the processor automatically increments ESI or EDI (DF=0) or whether it automatically decrements these registers (DF=1).
字符串IO原语可以对字节、字或双字构成的字符串进行操作。在每次传输后,ESI或EDI中的内存地址以1(字节操作数)、2(字操作数)或4(双字操作数)的变化量更新。方向标志(DF)的值决定处理器自动增加ESI或EDI的值(DF = 0)或减少这些寄存器值(DF = 1)。
INS(Input String from Port) transfers a byte or a word string element from an input port to memory. The mnemonics INSB, INSW, and INSD are variants that explicitly specify the size of the operand. If a program specifies INSB, the processor transfers 8 bits from the selected port to the memory location indicated by ES:EDI. If a program specifies INSW, the processor transfers 16 bits from the port to the memory location indicated by ES:EDI. If a program specifies INSD, the processor transfers 32 bits from the port to the memory location indicated by ES:EDI. The destination segment register choice (ES) cannot be changed for the INS instruction. Combined with the REP prefix, INS moves a block of information from an input port to a series of consecutive memory locations.
INS(从端口输入字符串)从内存中的输入端口传输一个字节或字的字符串元素。助记符INSB、INSW和INSD是变形指令,用来指定操作数的大小。如果程序使用INSB,处理器从选择的端口中传送8位到ES:EDI指定上的内存中。而INSW则传送16位,INSD则传送32位。INS指令中的目的段寄存器选择(ES)不能被修改。与REP前缀组合使用时,INS从一个输入端口移动一个信息块到指定上的连续内存中。
OUTS (Output String to Port) transfers a byte, word, or doubleword string element to an output port from memory. The mnemonics OUTSB, OUTSW, and OUTSD are variants that explicitly specify the size of the operand. If a program specifies OUTSB, the processor transfers 8 bits from the memory location indicated by ES:EDI to the the selected port. If a program specifies OUTSW, the processor transfers 16 bits from the memory location indicated by ES:EDI to the the selected port. If a program specifies OUTSD, the processor transfers 32 bits from the memory location indicated by ES:EDI to the the selected port. Combined with the REP prefix, OUTS moves a block of information from a series of consecutive memory locations indicated by DS:ESI to an output port.
OUTS(向端口输出字符串)从内存中向输出端口传送一个字、字节或双字的字符串元素。助记符OUTSB、OUTSW和OUTSD是变形指令,用来指定操作数大小。如果程序指定OUTSB,则处理器从ES:EDI指明的内存地址中取8位数据输出到选定的端口上。同理,如果指定OUTSW,则传送16位数据,指定OUTSD,则传送32位数据。与REP前缀组合时,OUTS从DS:ESI指定的连续内存中取信息块移到输出端口。(译注:这里是不是有错误呢?为什么OUTS不与REP组合时,使用的是EDI寄存器?)
8.3 Protection and I/O 保护与I/O
Two mechanisms provide protection for I/O functions:
对于I/O功能有两种保护机制:
- The IOPL field in the EFLAGS register defines the right to use I/O-related instructions.
EFLAGS寄存器的IOPL字段定义了使用I/O相关指令的权限。
- The I/O permission bit map of a 80386 TSS segment defines the right to use ports in the I/O address space.
80386的TSS段的I/O允许位图定义了使用位于I/O地址空间端口的权限。
These mechanisms operate only in protected mode, including virtual 8086 mode; they do not operate in real mode. In real mode, there is no protection of the I/O space; any procedure can execute I/O instructions, and any I/O port can be addressed by the I/O instructions.
这些机制仅在保护模式下使用,包括虚拟8086模式;不能在实模式下使用。在实模式下,不对I/O空间进行保护;任何程序都可以执行I/O指令,任何I/O端口都可以被I/O指令寻址。
8.3.1 I/O Privilege Level I/O特权级别
Instructions that deal with I/O need to be restricted but also need to be executed by procedures executing at privilege levels other than zero. For this reason, the processor uses two bits of the flags register to store the I/O privilege level (IOPL). The IOPL defines the privilege level needed to execute I/O-related instructions.
处理I/O的指令需要被约束,那些运行在除特权0级外的程序也需要执行它们。为此,处理器使用标志寄存器的两个位来存储I/O特权级别(IOPL)。IOPL定义了需要运行I/O相关指令的特权级别。
The following instructions can be executed only if CPL <= IOPL:
下面的指令仅当CPL小于或等于IOPL时可以被执行:
- IN -- Input 输入
- INS -- Input String 输入串
- OUT -- Output 输出
- OUTS -- Output String 输出串
- CLI -- Clear Interrupt-Enable Flag 清除中断使能标志位
- STI -- Set Interrupt-Enable 设置中断使能
These instructions are called "sensitive" instructions, because they are sensitive to IOPL.
因类它们对IOPL敏感,所以这些指令被叫做“敏感”指令。
To use sensitive instructions, a procedure must execute at a privilege level at least as privileged as that specified by the IOPL (CPL <= IOPL). Any attempt by a less privileged procedure to use a sensitive instruction results in a general protection exception.
为使用敏感指令,程序必须执行在IOPL指定的特权级别上(CPL <= IOPL)。任何较低特权的程序企图使用敏感指令,都会引发一般性保护异常。
Because each task has its own unique copy of the flags register, each task can have a different IOPL. A task whose primary function is to perform I/O (a device driver) can benefit from having an IOPL of three, thereby permitting all procedures of the task to perform I/O. Other tasks typically have IOPL set to zero or one, reserving the right to perform I/O instructions for the most privileged procedures.
因为每个任务都有自己的唯一的标志寄存器的拷贝,每个任务都可以有不同的IOPL。一个主要功能是操作I/O的任务(设备驱动)都可以从下面受益,拥有一个3级的IOPL,这样允许该任务的所有程序执行I/O操作。典型的,其他任务的IOPL都被设为0或1,这样就将执行I/O指令的权力保留给了更高级特权的程序。
A task can change IOPL only with the POPF instruction; however, such changes are privileged. No procedure may alter IOPL (the I/O privilege level in the flag register) unless the procedure is executing at privilege level 0. An attempt by a less privileged procedure to alter IOPL does not result in an exception; IOPL simply remains unaltered.
任务仅可通过POPF指令修改IOPL;然而,这个修改是特权级的。没有程序可以更改IOPL(标志寄存器中的I/O特权级别),除非这个程序执行在特权级0上。较低特权级别的程序企图更改IOPL不会导致异常;IOPL简单地保持未被变更状态。
The POPF instruction may be used in addition to CLI and STI to alter the interrupt-enable flag (IF); however, changes to IF by POPF are IOPL-sensitive. A procedure may alter IF with a POPF instruction only when executing at a level that is at least as privileged as IOPL. An attempt by a less privileged procedure to alter IF in this manner does not result in an exception; IF simply remains unaltered.
POPF指令也被CLI和STI指令来更改中断使能标志(IF);然而,通过POPF修改IF是IOPL敏感的。仅当一个程序运行在与IOPL相比最小的特权级别上时,才可以使用POPF来更改IF。较低特权上的程序企图以这种方式变更IF不会引发异常;IF简单地保持原值。
8.3.2 I/O Permission Bit Map I/O权限位图
The I/O instructions that directly refer to addresses in the processor's I/O space are IN, INS, OUT, OUTS. The 80386 has the ability to selectively trap references to specific I/O addresses. The structure that enables selective trapping is the I/O Permission Bit Map in the TSS segment (see Figure 8-2). The I/O permission map is a bit vector. The size of the map and its location in the TSS segment are variable. The processor locates the I/O permission map by means of the I/O map base field in the fixed portion of the TSS. The I/O map base field is 16 bits wide and contains the offset of the beginning of the I/O permission map. The upper limit of the I/O permission map is the same as the limit of the TSS segment.
直接引用处理器的I/O空间的地址的I/O操作指令有IN、INS、OUT和OUTS。80386可以指定I/O地址。这个可以精心选择的trapping结构是TSS段中的I/O权限位图(见图8-2)。I/O权限位图是一个位向量。图的大小和在TSS段中的位置是可变的。处理器通过在TSS中定长部分的I/O位图基址字段的含义来定位I/O权限图。I/O图基址字段16位宽,包含I/O权限图的开始处的偏移量。I/O权限图的限长等于TSS段的限长。
In protected mode, when it encounters an I/O instruction (IN, INS, OUT, or OUTS), the processor first checks whether CPL <= IOPL. If this condition is true, the I/O operation may proceed. If not true, the processor checks the I/O permission map. (In virtual 8086 mode, the processor consults the map without regard for IOPL . Refer to Chapter 15.)
在保护模式下,当最到一个I/O指令(IN、INS、OUT或OUTS)时,处理器首先检查CPL是否大于或等于IOPL。如果条件为真,I/O操作可以执行。如果不为真,处理器检查I/O权限图。(在虚拟8086模式,处理器不管IOPL,只参考位图。参见第15章。)
Each bit in the map corresponds to an I/O port byte address; for example, the bit for port 41 is found at I/O map base + 5, bit offset 1. The processor tests all the bits that correspond to the I/O addresses spanned by an I/O operation; for example, a doubleword operation tests four bits corresponding to four adjacent byte addresses. If any tested bit is set, the processor signals a general protection exception. If all the tested bits are zero, the I/O operation may proceed.
图中的每一位都对应一个I/O端口的字节地址;例如,端口41的对应位在I/O图的基址 + 5处,位的偏移为1。处理器对I/O操作涉及的所有I/O地址的对应位都进行测试;例如,一个双字操作测试一个以4对齐的字节地址所对应的4个位。如果任何位被设置,处理器发送一个一般保护异常。如果所以测试的位都是0,则I/O操作可以执行。
It is not necessary for the I/O permission map to represent all the I/O addresses. I/O addresses not spanned by the map are treated as if they had one bits in the map. For example, if TSS limit is equal to I/O map base + 31, the first 256 I/O ports are mapped; I/O operations on any port greater than 255 cause an exception.
对于IO权限位图,代表所有的I/O地址是不必要的。不被图所包含的I/O地址被视为在图中的位为1。例如,如果TSS限长等于I/O图基址 + 31,第一个256I/O端口被映射;任何对端口大于255的I/O操作都会导致异常。
If I/O map base is greater than or equal to TSS limit, the TSS segment has no I/O permission map, and all I/O instructions in the 80386 program cause exceptions when CPL > IOPL.
如果I/O图基址大于或等于TSS限长,则TSS段没有I/O权限位图,所有80386程序中的IO指令在CPL > IOPL时都会引发异常。
Because the I/O permission map is in the TSS segment, different tasks can have different maps. Thus, the operating system can allocate ports to a task by changing the I/O permission map in the task's TSS.
因为I/O权限图在TSS段中,不同任务可以有不同的位图。这样,操作系统可以通过修改在任务TSS中的I/O权限位图来给任务分配端口。