6.3.5 Some Instructions are Reserved for Operating System 为操作系统保留的一些指令
Instructions that have the power to affect the protection mechanism or to influence general system performance can only be executed by trusted procedures. The 80386 has two classes of such instructions:
那些有能力影响保护机制或影响系统性能的指令只能被信任的程序执行。80386有两类这种情况:
- Privileged instructions -- those used for system control.
特权指令——被用来控制系统。
- Sensitive instructions -- those used for I/O and I/O related activities.
敏感指令——被用在I/O和与I/O相关的活动上。
Table 6-3. Interlevel Return Checks 特权级间返回检验
SF = Stack Fault 栈错误
GP = General Protection Exception 一般保护性异常
NP = Segment-Not-Present Exception 段不存在异常
Type of Check Exception Error Code
ESP is within current SS segment SF 0
ESP + 7 is within current SS segment SF 0
RPL of return CS is greater than CPL GP Return CS
Return CS selector is not null GP Return CS
Return CS segment is within descriptor
table limit GP Return CS
Return CS descriptor is a code segment GP Return CS
Return CS segment is present NP Return CS
DPL of return nonconforming code
segment = RPL of return CS, or DPL of
return conforming code segment <= RPL
of return CS GP Return CS
ESP + N + 15 is within SS segment
N Immediate Operand of RET N Instruction SF Return SS
SS selector at ESP + N + 12 is not null GP Return SS
SS selector at ESP + N + 12 is within
descriptor table limit GP Return SS
SS descriptor is writable data segment GP Return SS
SS segment is present SF Return SS
Saved SS segment DPL = RPL of saved
CS GP Return SS
Saved SS selector RPL = Saved SS
segment DPL GP Return SS
6.3.5.1 Privileged Instructions 特权指令
The instructions that affect system data structures can only be executed when CPL is zero. If the CPU encounters one of these instructions when CPL is greater than zero, it signals a general protection exception. These instructions include:
影响系统数据结构的指令只能在CPL是0时被指令。如果CPL大于0时,CPU最到这些指令,它发送一个一般保护异常。这引起指令包括:
- CLTS -- Clear Task-Switched Flag CLTS——清除任务切换标志
- HLT -- Halt Processor HLT——处理器停止
- LGDT -- Load GDT Register LGDT —— 装载GDT寄存器
- LIDT -- Load IDT Register LIDT —— 装入IDT寄存器
- LLDT -- Load LDT Register LLDT —— 装载LDT寄存器
- LMSW -- Load Machine Status Word LMSW —— 装载机器状态字
- LTR -- Load Task Register LTR —— 装载任务寄存器
- MOV to/from CRn -- Move to Control Register n 读写控制寄存器
- MOV to /from DRn -- Move to Debug Register n 读写调试寄存器
- MOV to/from TRn -- Move to Test Register n 读写测试寄存器
6.3.5.2 Sensitive Instructions 敏感指令
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. The mechanisms for restriction of I/O operations are covered in detail in Chapter 8, "Input/Output".
处理I/O的指令需要被限制,也需要被特权级0以上的程序执行。I/O操作的限制机制会在第8章(输入/输出)涉及。
6.3.6 Instructions for Pointer Validation 指针验证指令
Pointer validation is an important part of locating programming errors. Pointer validation is necessary for maintaining isolation between the privilege levels. Pointer validation consists of the following steps:
指针验证是定位程序错误重要的部分。指针验证对于隔离不同特权级是必要的。指针验证包含以下步骤:
- Check if the supplier of the pointer is entitled to access the segment.
检查指针提供者是否具有对段的访问资格。
- Check if the segment type is appropriate to its intended use.
检查是否段类型对于它的预期用途是否适当。
- Check if the pointer violates the segment limit.
检查指针是否违反段限长。
Although the 80386 processor automatically performs checks 2 and 3 during instruction execution, software must assist in performing the first check. The unprivileged instruction ARPL is provided for this purpose. Software can also explicitly perform steps 2 and 3 to check for potential violations (rather than waiting for an exception). The unprivileged instructions LAR, LSL, VERR, and VERW are provided for this purpose.
尽管80386在指令执行过程中自动进行检查2和3,软件必须坚持实施第1号检查。软件也要显示地实施步骤2和3的检查潜在的违例(而不是等着发生异常)。非特权指令LAR、LSL、VERR和VERW可以实现此目的。
LAR (Load Access Rights) is used to verify that a pointer refers to a segment of the proper privilege level and type. LAR has one operand selector for a descriptor whose access rights are to be examined.
LAR(装载访问权限)被用来检验指针引用的段其拥有合适的特权级别和类型。LAR有一个操作数是描述符的选择子,它的访问权限被检测。
The descriptor must be visible at the privilege level which is the maximum of the CPL and the selector's RPL. If the descriptor is visible, LAR obtains a masked form of the second doubleword of the descriptor, masks this value with 00FxFF00H, stores the result into the specified 32-bit destination register, and sets the zero flag. (The x indicates that the corresponding four bits of the stored value are undefined.)
这个描述符必须对于CPL和选择子的RPL中的最大特权级别可见。如果不可见,LAR对描述符的第二个双字使用一个屏蔽位来获得一个结果,这个屏蔽字其值为00FxFF00H,然后将结果保存在目的寄存器指定上的32位中,然后设置0标志。(这里x表明相关的4位没有定义)
Once loaded, the access-rights bits can be tested. All valid descriptor types can be tested by the LAR instruction. If the RPL or CPL is greater than DPL, or if the selector is outside the table limit, no access-rights value is returned, and the zero flag is cleared. Conforming code segments may be accessed from any privilege level.
装入后,即可测试访问权限位。LAR指令可以测试所有有效的描述符类型。如果RPL或者CPL大于DPL,或如果选择子超出了表限长,返回没有访问权限的值,而且0标志被清空。一致性代码段可以被任何特权级别访问。
LSL (Load Segment Limit) allows software to test the limit of a descriptor. If the descriptor denoted by the given selector (in memory or a register) is visible at the CPL, LSL loads the specified 32-bit register with a 32-bit, byte granular, unscrambled limit that is calculated from fragmented limit fields and the G-bit of that descriptor.
LSL(装载段限长)允许软件测试一个描述符的限长。如果给定选择子(在内存或寄存器中)指出的描述符对于CPL是可见的,LSL使用32位、字节颗粒、从段限长字段中和G位计算出的限长来装载指定的32位寄存器。
This can only be done for segments (data, code, task state, and local descriptor tables); gate descriptors are inaccessible. (Table 6-4 lists in detail which types are valid and which are not.) Interpreting the limit is a function of the segment type.
这仅可对段使用(数据、代码、任务状态和本地描述符表);门描述符不可访问。(表6-4列出了哪些类型是合法的哪些不是。)解释限长是段类型的功能。
For example, downward expandable data segments treat the limit differently than code segments do. For both LAR and LSL, the zero flag (ZF) is set if the loading was performed; otherwise, the ZF is cleared.
例如,向下扩展的数据段对于限长的解释就不同于代码段。LAR和LSL两条指令,如果装载被执行了,0标志(ZF)都会置位;否则ZF被清除。
Table 6-4. Valid Descriptor Types for LSL
Type Descriptor Type Valid?
Code
0 (invalid) NO
1 Available 286 TSS YES
2 LDT YES
3 Busy 286 TSS YES
4 286 Call Gate NO
5 Task Gate NO
6 286 Trap Gate NO
7 286 Interrupt Gate NO
8 (invalid) NO
9 Available 386 TSS YES
A (invalid) NO
B Busy 386 TSS YES
C 386 Call Gate NO
D (invalid) NO
E 386 Trap Gate NO
F 386 Interrupt Gate NO
6.3.6.1 Descriptor Validation 描述符检验
The 80386 has two instructions, VERR and VERW, which determine whether a selector points to a segment that can be read or written at the current privilege level. Neither instruction causes a protection fault if the result is negative.
80386有两个指令,VERR和VERW来决定选择子指向的段在当前特权级别下是否可以被读或写。如果结果是消极的,不会引发保护错误。
VERR (Verify for Reading) verifies a segment for reading and loads ZF with 1 if that segment is readable from the current privilege level. VERR checks that:
VERR(读取检验)检验一个段是否可读取,如果在当前特权级别下可读取,置ZF位为1。VERR检验以下内容:
- The selector points to a descriptor within the bounds of the GDT or LDT.
选择子指向的描述符是否在GDT或LDT的边界之内。
- It denotes a code or data segment descriptor.
选择子是否指向一个代码段或数据段描述符。
- The segment is readable and of appropriate privilege level.
段是可读取的,并且具有适当的特权级别。
The privilege check for data segments and nonconforming code segments is that the DPL must be numerically greater than or equal to both the CPL and the selector's RPL. Conforming segments are not checked for privilege level.
对于数据段和非一致性代码段而言,特权检验是指其DPL必须在数值上均大于或等于CPL和选择子的RPL。一致性段无需特权检验。
VERW (Verify for Writing) provides the same capability as VERR for verifying writability. Like the VERR instruction, VERW loads ZF if the result of the writability check is positive. The instruction checks that the descriptor is within bounds, is a segment descriptor, is writable, and that its DPL is numerically greater or equal to both the CPL and the selector's RPL. Code segments are never writable, conforming or not.
VERW(检验是否可写)提供了VERR相同的能力来检验段是否可写。就象VERR指令一样,VERW在检验结果是可写时将ZF置位。指令相依相偎描述符是否在边界之内,是否为一个段描述符,其段是否可写入,其DPL是否在数值上均大于或等于CPL和选择子的RPL。代码段从不是可写入的,一致段也一样。
6.3.6.2 Pointer Integrity and RPL 指针完整性和RPL
The Requestor's Privilege Level (RPL) feature can prevent inappropriate use of pointers that could corrupt the operation of more privileged code or data from a less privileged level.
A common example is a file system procedure, FREAD (file_id, n_bytes, buffer_ptr). This hypothetical procedure reads data from a file into a buffer, overwriting whatever is there. Normally, FREAD would be available at the user level, supplying only pointers to the file system procedures and data located and operating at a privileged level. Normally, such a procedure prevents user-level procedures from directly changing the file tables. However, in the absence of a standard protocol for checking pointer validity, a user-level procedure could supply a pointer into the file tables in place of its buffer pointer, causing the FREAD procedure to corrupt them unwittingly.
Use of RPL can avoid such problems. The RPL field allows a privilege attribute to be assigned to a selector. This privilege attribute would normally indicate the privilege level of the code which generated the selector. The 80386 processor automatically checks the RPL of any selector loaded into a segment register to determine whether the RPL allows access.
To take advantage of the processor's checking of RPL, the called procedure need only ensure that all selectors passed to it have an RPL at least as high (numerically) as the original caller's CPL. This action guarantees that selectors are not more trusted than their supplier. If one of the selectors is used to access a segment that the caller would not be able to access directly, i.e., the RPL is numerically greater than the DPL, then a protection fault will result when that selector is loaded into a segment register.
ARPL (Adjust Requestor's Privilege Level) adjusts the RPL field of a selector to become the larger of its original value and the value of the RPL field in a specified register. The latter is normally loaded from the image of the caller's CS register which is on the stack. If the adjustment changes the selector's RPL, ZF (the zero flag) is set; otherwise, ZF is cleared.