天天看点

只能在保护模式下执行的指令

下面介绍的指令只能在保护模式下执行,如果在实模式下执行这些指令,将引起非法操作码故障(向量号为6)。

1.装载和存储局部描述符表寄存器指令

(1)装载局部描述符表寄存器指令

    装载局部描述符表寄存器指令的格式如下:

    LLDT    SRC

    其中,操作数SRC可以是16位通用寄存器或存储单元。该指令的功能是把SRC中的内容作为指示局部描述符表LDT的选择子装入到LDTR寄存器。该指令不影响标志。

    操作数SRC给定的选择子应该指示GDT中的类型为LDT的描述符。但LRC也可是一个空选择子,如果这样的话,表示暂时不使用局部描述符表LDT。

    若CPL不为0,那么执行该指令将产生出错码为0的通用保护故障。若被装载的选择子不指示GDT中的描述符,或者描述符类型不是LDT描述符,那么产生通用保护故障,错误码由该选择子构成。

    象段寄存器那样,LDTR也有两部分。在把指示LDT的选择子装入到LDTR可见部分时,处理器自动把选择子所索引的LDT描述符中的段基地址等信息保存到不可见的高速缓冲寄存器中。

(2)存储局部描述符表寄存器指令

    存储局部描述符表寄存器指令的格式如下:

    SLDT    DST

    其中,操作数DST可以是16位通用寄存器或存储单元。该指令的功能是把局部描述符表寄存器 LDTR的内容存储到存储单元DST中,也即把指向当前任务LDT的选择子存储到DST中。该指令不影响标志。

2.装载和存储任务寄存器指令

    任务寄存器TR指示当前任务状态段TSS。随着任务的切换,TR的内容也随之改变;如果任务嵌套,那么TR的原值作为链接字保存到新任务的TSS中。但有时候需要直接地装载或者保存TR,这就需要使用装载TR指令和存储TR指令。

(1)装载任务寄存器指令

    装载任务寄存器指令的格式如下:

    LTR     SRC

    其中,操作数SRC可以是16位通用寄存器或存储单元。该指令的功能是将SRC作为指示TSS描述符的选择子装载到任务寄存器TR。由前文可知,TR分为两部分,即程序员可见部分和不可见的高速缓冲寄存器部分。在把TSS的选择子装入到TR可见部分时,处理器自动把选择子所索引的描述符中的段基地址等信息保存到不可见的高速缓冲寄存器中。所以,SRC表示的选择子不能为空,必须索引位于GDT中的描述符,并且描述符类型必须是可用TSS,该加载的TSS被处理器自动标为 “忙”。该指令对标志没有影响。

    若CPL不为0,那么执行该指令将产生错误码为0的通用保护故障。若被加载的选择子不指示GDT中的可用TSS描述符,那么产生通用保护故障,错误码由该选择子构成。

(2)存储任务寄存器指令

    存储任务寄存器指令的格式如下:

    STR     DST

    其中,操作数DST可以是16位通用寄存器或存储单元。该指令的功能是把TR所含的指示当前任务TSS描述符的选择子存储到DST。该指令不影响标志。

3.调整申请特权级指令

    调整申请特权级指令的格式如下:

    ARPL    OPRD1,OPRD2

    其中,操作数OPRD1可以是16位通用寄存器或存储单元,操作数OPRD2是16位通用寄存器。该指令把操作数OPRD1和OPRD2视为两个选择子,用OPRD2的申请特权级(RPL)去检查OPRD1的RPL。选择子OPRD1和OPRD2的RPL分别由它们的最低2个位规定。如果OPRD1的RPL小于OPRD2的RPL,那么零标志ZF被置1,并把OPRD2的RPL值赋予OPRD1的RPL(使两个操作数的最低2位相等);否则,零标志ZF被清0。OPRD1和OPRD2都可为空选择子。该指令只影响ZF标志。

4.装载存取权指令

    装载存取权指令的格式如下:

    LAR     OPRD1,OPRD2

    其中,操作数OPRD1可以是16位或32位通用寄存器,操作数OPRD2是16位通用寄存器或存储单元,也可以是32位通用寄存器或存储单元。操作数OPRD1和OPRD2的尺寸必须一致。该指令把操作数OPRD2视为选择子(当为32位时,仅使用低16位),如果OPRD2所指示的描述符满足如下条件,那么零标志ZF被置1,并把描述符内的属性字段装入OPRD1;否则,ZF清0,OPRD1保持不变。

    (1)在描述符表的范围内;

    (2)是存储段描述符或系统段描述符或任务门描述符或调用门描述符;

    (3)CPL和OPRD2的RPL都不大于DPL。

    在满足条件的情况下,装入到OPRD1的由OPRD2所指示的描述符中的属性字段是指描述符的高4字节和00FXFF00H相与的结果,其中X表示第16位到第19位无定义。注意,如果指令使用16位操作数,那么只有高4字节中的低字被装入到OPRD1,即装入到OPRD1的属性字段不包括G位和AVL位等。该指令只影响ZF标志。

5.装载段界限指令

    装载界限指令的格式如下:

    LSL     OPRD1,OPRD2

    其中,操作数OPRD1可以是16位或32位通用寄存器,操作数OPRD2是16位通用寄存器或存储单元,也可以是32位通用寄存器或存储单元。操作数OPRD1和OPRD2的尺寸必须一致。该指令把操作数OPRD2视为选择子(当为32位时,仅使用低16位),如果OPRD2所指示的描述符满足如下条件,那么零标志ZF被置1,并把描述符内的界限字段装入OPRD1;否则,ZF清0,OPRD1保持不变。

    (1)在描述符表的范围内;

    (2)是存储段描述符或系统段描述符,而非门描述符;

    (3)CPL和OPRD2的RPL都不大于DPL。

    在满足条件的情况下,装入到OPRD1的由OPRD2所指示的描述符中的界限字段以字节位为单位。如果描述符中的界限字段以4K字节为单位(G=1),那么装入到OPRD1时被左移12位,空出的低位全部填成1。注意,如果指令使用16位操作数,那么只有段界限的低16位被装入到OPRD1。该指令只影响ZF标志。

6.读写检验指令

    利用读检验指令和写检验指令可分别检查在当前特权级上指定的段能否读或写,从而避免引起不必要的异常。

(1)读检验指令

    读检验指令的一般格式如下:

    VERR    OPRD

    其中,操作数OPRD可以是16位通用寄存器或存储单元,也可以是32位通用寄存器或存储单元。该指令的功能是把OPRD的内容作为一个选择子(当32位时仅使用低16位),判断在当前特权级上该选择子所指示的段是否可读。如果该选择子指示合法的一个存储段描述符,并且在当前特权级上可读所描述的段,那么零标志ZF被置为1,否则ZF被清0。该指令只影响ZF标志。

(2)写检验指令

    写读检验指令的一般格式如下:

    VERW    OPRD

    其中,操作数OPRD可以是16位通用寄存器或存储单元,也可以是32位通用寄存器或存储单元。该指令的功能是把OPRD的内容作为一个选择子(当32位时仅使用低16位),判断在当前特权级上该选择子所指示的段是否可写。如果该选择子指示合法的一个存储段描述符,并且在当前特权级上可写所描述的段,那么零标志ZF被置为1,否则ZF被清0。该指令只影响ZF标志。

<四>显示关键寄存器内容的实例(实例八)

    为了更好地说明操作系统类指令的使用,下面给出一个显示80386关键寄存器内容的实例。该实例的逻辑功能是,显示系统中GDTR、IDTR、LDTR和TR等关键寄存器的当前内容。实例八的源程序清单如下:

;名称:ASM8.ASM

;功能:显示关键寄存器内容及说明操作系统类指令的使用

;编译:TASM ASM8.ASM

;连接:TLINK ASM8.OBJ

;----------------------------------------------------------------------------

INCLUDE         386SCD.INC

;----------------------------------------------------------------------------

GDTSeg          SEGMENT PARA USE16                ;全局描述符表数据段(16位)

;----------------------------------------------------------------------------

GDT             LABEL   BYTE

                ;空描述符

DUMMY           Desc    &lt;&gt;

                ;规范段描述符及选择子

Normal          Desc    &lt;0ffffh,,,ATDW,,&gt;

Normal_Sel      =       Normal-GDT

;----------------------------------------------------------------------------

EFFGDT          LABEL   BYTE

                ;临时任务代码段描述符及选择子

TempCode        Desc    &lt;0ffffh,TempCodeSeg,,ATCE,,&gt;

TempCode_Sel    =       TempCode-GDT

                ;缓冲区段描述符及选择子

Buffer          Desc    &lt;BufferLen-1,BufferSeg,,ATDW,,&gt;

Buffer_Sel      =       Buffer-GDT

                ;测试描述符1及选择子

Test1           Desc    &lt;1111h,,,92h,87h,&gt;

Test1_Sel       =       Test1-GDT

TestR_Sel       =       Test1-GDT+RPL3

                ;测试描述符2及选择子

Test2           Desc    &lt;2222h,,,82h,17h,&gt;

Test2_Sel       =       Test1-GDT

;----------------------------------------------------------------------------

GDNum           =       ($-EFFGDT)/(SIZE Desc)    ;需特殊处理的描述符数

GDTLen          =       $-GDT                     ;全局描述符表长度

;----------------------------------------------------------------------------

GDTSeg          ENDS                              ;全局描述符表段定义结束

;----------------------------------------------------------------------------

BufferSeg       SEGMENT PARA USE16                ;缓冲区数据段

;----------------------------------------------------------------------------

GDTR_V          PDesc   &lt;&gt;                        ;存放GDTR

IDTR_V          PDesc   &lt;&gt;                        ;存放IDTR

;----------------------------------------------------------------------------

MSW_V           DW      0                         ;存放机器状态字

LDTR_V          DW      0                         ;存放LDTR选择子

TR_V            DW      0                         ;存放TR选择子

CR0_V           DD      0                         ;存放控制寄存器CR0

CR3_V           DD      0                         ;存放控制寄存器CR3

DR7_V           DD      0                         ;存放调试寄存器DR7

Test_RPL        DW      0

;----------------------------------------------------------------------------

Test1_SLD       DD      0                         ;演示用变量

Test1_ARD       DD      0

Test1_SLW       DW      0

Test1_ARW       DW      0

Test1_RF        DW      0

Test1_WF        DW      0

;----------------------------------------------------------------------------

Test2_SLD       DD      0                         ;演示用变量

Test2_ARD       DD      0

Test2_SLW       DW      0

Test2_ARW       DW      0

Test2_RF        DW      0

Test2_WF        DW      0

;----------------------------------------------------------------------------

BufferLen       =       $

BufferSeg       ENDS

;----------------------------------------------------------------------------

TempCodeSeg     SEGMENT PARA USE16                ;临时代码段

                ASSUME  CS:TempCodeSeg,DS:BufferSeg

;----------------------------------------------------------------------------

Virtual         PROC    FAR

                mov     ax,Buffer_Sel

                mov     ds,ax

                mov     eax,cr0                   ;存储CR0

                mov     CR0_V,eax

                mov     eax,cr3                   ;存储CR3

                mov     CR3_V,eax

                mov     eax,DR7                   ;存储DR7

                mov     DR7_V,eax

                str     TR_V                      ;存储TR

                sldt    LDTR_V                    ;存储LDTR

                mov     Test_RPL,Test1_Sel

                mov     ax,TestR_Sel

                arpl    Test_RPL,ax               ;说明调整申请特权及指令

                mov     bx,0

                mov     ax,Test1_Sel

Lab1:           mov     edx,0

                mov     cx,0

                lsl     edx,eax                   ;说明装载段界限指令

                lsl     cx,ax

                mov     Test1_SLD[bx],edx

                mov     Test1_SLW[bx],cx

                mov     edx,0

                mov     cx,0

                lar     edx,eax                   ;说明装载存取权指令

                lar     cx,ax

                mov     Test1_ARD[bx],edx

                mov     Test1_ARW[bx],cx

                mov     Test1_RF[bx],0

                verr    ax                        ;说明读检验指令

                jnz     Lab2

                mov     Test1_RF[bx],1

Lab2:           mov     Test1_WF[bx],0

                verw    ax                        ;说明写检验指令

                jnz     Lab3

                mov     Test1_WF[bx],1

Lab3:           add     bx,16

                mov     ax,Test2_Sel

                cmp     bx,32

                jb      Lab1

                ;准备返回实方式

                mov     ax,Normal_Sel

                mov     ds,ax

                mov     eax,cr0

                and     al,11111110b

                mov     cr0,eax                   ;返回实方式

                JUMP16  &lt;SEG Real&gt;,&lt;OFFSET Real&gt;

Virtual         ENDP

;----------------------------------------------------------------------------

TempCodeSeg     ENDS

;----------------------------------------------------------------------------

RCodeSeg        SEGMENT PARA USE16

                ASSUME  CS:RCodeSeg,DS:BufferSeg

;----------------------------------------------------------------------------

VGDTR           PDesc   &lt;GDTLen-1,&gt;

;----------------------------------------------------------------------------

Start           PROC

                mov     ax,BufferSeg

                mov     ds,ax

                sgdt    GDTR_V

                sidt    IDTR_V

                smsw    MSW_V

                ;准备转入保护方式

                push    cs

                pop     ds

                cld

                call    InitGDT

                mov     bx,OFFSET VGDTR

                lgdt    [bx]

                cli

                mov     eax,cr0

                or      al,1

                ;转入保护方式

                mov     cr0,eax

                JUMP16  &lt;TempCode_Sel&gt;,&lt;OFFSET Virtual&gt;

Real:           ;回到实方式

                sti

                ;为了简单,略去了显示相关变量内容的部分代码

                mov     ax,4c00h

                int     21h

Start           ENDP

;----------------------------------------------------------------------------

InitGDT         PROC

                push    ds

                mov     ax,GDTSeg

                mov     ds,ax

                mov     cx,GDNum

                mov     si,OFFSET EFFGDT

InitG:          mov     ax,[si].BaseL

                movzx   eax,ax

                shl     eax,4

                shld    edx,eax,16

                mov     WORD PTR [si].BaseL,ax

                mov     BYTE PTR [si].BaseM,dl

                mov     BYTE PTR [si].BaseH,dh

                add     si,SIZE Desc

                loop    InitG

                pop     ds

                mov     bx,16

                mov     ax,GDTSeg

                mul     bx

                mov     WORD PTR VGDTR.Base,ax

                mov     WORD PTR VGDTR.Base+2,dx

                ret

InitGDT         ENDP

;----------------------------------------------------------------------------

RCodeSeg        ENDS

                END     Start

<五>特权指令

    特权指令是指保护方式下只有当前特权级CPL=0时,才可执行的指令。如果CPL不等于0而执行它们,那么会引起通用保护异常。从上面介绍的操作系统类指令可归纳出如下表所示的80386特权指令。这些特权指令在构成完善的保护机制方面起了重要的作用。 

                                          特权指令功能

                                    CLTS 清除CR0中的TS位 LTR 装入TR寄存器

                                    HLT 停机 MOV CRn,reg 装入控制寄存器

                                    LGDT 装入GDTR寄存器 MOV reg,CRn 保存控制寄存器

                                    LIDT 装入IDTR寄存器 MOV DRn,reg 装入调试寄存器

                                    LLDT 装入LDTR寄存器 MOV reg,DRn 保存调试寄存器

                                    LMSW 装入MSW寄存器(CR0的低16位)  

    从上表可见,装入GDTR、IDTR、LDTR、TR和MSW的指令都是特权指令,而存储上述寄存器的指令不是特权指令。这表示,保护模式下任何程序可获得这些寄存器的值,但只有特权级0的程序才能够改变这些寄存器的值。从上表还可以看出,设置和存储控制寄存器及调试寄存器的指令都是特权指令。