• 任务门,调用门,中断门,陷阱门 [转]


    每个任务有一个任务状态段TSS,用于保存任务的有关信息,在任务内变换特权级和任务切换时,要用到这些信息。为了控制任务内发生特权级变换的转移,为了控制任务切换,一般要通过控制门进行这些转移。本文将介绍任务状态段和控制门。

    <一>系统段描述符

    系统段是为了实现存储管理机制所使用的一种特别的段。在80386中,有两种系统段:任务状态段TSS和局部描述符表LDT段。用于描述系统段的描述符称为系统段描述符。

    1.系统段描述符的格式

    系统段描述符的一般格式如下表所示。

     

    系统段
    描述符
    m+7 m+6 m+5 m+4 m+3 m+2 m+1 m+0
    Base(31...24) Attributes Segment Base(23...0) Segment Limite(15...0)

     

    系统段
    描述符
    的属性
    Byte m+6 Byte m+5
    BIT7 BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0 BIT7 BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0
    G X 0 AVL Limit(19...16) P DPL DT0 TYPE

     

    存储段描述符[注:存储段是存放可由程序直接进行访问的代码和数据的段。存储段描述符描述存储段,所以存储段描述符也被称为代码和数据段描述符。]相比,它们很相似,区分的标志是属性字节中的描述符类型位DT的值。DT=1表示存储段,DT=0表示系统段。系统段描述符中的 段基地址和段界限字段与存储段描述符中的意义完全相同;属性中的G位、AVL位、P位和DPL字段的作用也完全相同。存储段描述符属性中的D位在系统段描 述符中不使用,现用符号X表示。系统段描述符的类型字段TYPE仍是4位,其编码及表示的类型列于下表,其含义与存储段描述符的类型却完全不同。

     

    系统段
    类   型
    类型编码 说       明
    0 未定义
    1 可用286TSS
    2 LDT
    3 忙的286TSS
    4 286调用门
    5 任务门
    6 286中断门
    7 286陷阱门
     
    系统段
    类   型
    类型编码 说       明
    8 未定义
    9 可用386TSS
    A 未定义
    B 忙的386TSS
    C 386调用门
    D 未定义
    E 386中断门
    F 386陷阱门

     

    从上表可见,只有类型编码为2、1、3、9和B的描述符才是真正的系统段描述符,它们用于描述系统段LDT和任务状态段TSS,其它类型的描述符是门描述符。
    利用前文定义的存储段描述符结构类型DESC仍能方便地在程序中说明系统段描述符。需要注意的是,系统段描述符的选择子不能用来读写系统段,要想读写系统段,必须使用别名技术。

    2.LDT段描述符

    LDT段描述符描述任务的局部描述符表段。例如:下面的描述符LDTABLE描述一个局部描述符表段,基地址是654321H,以字节为单位的界限是1FH,描述符特权级是0。
    LDTABLE  DESC  <1FH,4321H,65H,82H,,>
    LDT段描述符必须安排在全局描述符表中才有效。在装载LDTR寄存器时,描述符中的LDT段基地址和段界限等信息被装入LDT段描述符高速缓冲寄存器中。

    3.任务状态段描述符

    任务状态段TSS用于保存任务的各种状态信息。任务状态段描述符描述某个任务状态段TSS描述符分为286TSS和386TSS两类。TSS描 述符规定了任务状态段的基地址和任务状态段的大小等信息。例如,下面的描述符TempTask描述一个可用的386任务状态段,基地址是123456H, 以字节为单位的界限是104,描述符特权级是0。
    TempTask  DESC  <104,3456H,12H,89H,,>
    在装载任务状态段寄存器TR时,描述符中的段基地址和段界限等信息被装入到TR的高速缓冲寄存器中。在任务切换或执行LTR指令时,要装载TR寄存器。
    TSS描述符中的类型规定:TSS要么为“忙”,要么为“可用”。如果一个任务是当前正执行的任务,或者是用TSS中的链接字段沿挂起任务链接到当前任务上的任务,那么该任务是“忙”的任务;否则该任务为“可用”任务。
    利用段间转移指令JMP和段间调用指令CALL,直接通过TSS描述符或通过任务门可实现任务切换。

    <二>门描述符

    除存储段描述符和系统段描述符外,还有一类门描述符。门描述符并不描述某种内存段,而是描述控制转移的入口点。这种描述符好比一个同向另一代码段的门。通过这种门,可实现任务内特权级的变换和任务间的切换。所以,这种门描述符也称为控制门。

    1.门描述符的一般格式

    门描述符的一般格式如下图所示。门描述符只有位于描述符内偏移5的类型字节与系统段保持一致,也由该字节标示门描述符和系统段描述符。该字节内的P和DPL的意义与其它描述符种中的意义相同。其它字节主要用于存放一个48位的全指针(16位的选择子和32位的偏移量)。

     

    门描述符 m+7 m+6 m+5 m+4 m+3 m+2 m+1 m+0
    Offset(31...16) Attributes Selector Offset(15...0)

     

    门描述
    符属性
    Byte m+5 Byte m+4
    BIT7 BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0 BIT7 BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0
    P DPL DT0 TYPE 000 Dword Count

     

    根据上图给出的门描述符的结构,可定义如下的门描述符结构类型:
    GATE     STRUC      ;门结构类型定义
        OFFSETL  DW      0  ;32位偏移的低16位
        SELECTOR DW      0  ;选择子
        DCOUNT   DB      0  ;双字计数字段
        GTYPE    DB      0  ;类型
        OFFSETH  DW      0  ;32位偏移的高16位
        GATE     ENDS
    利用门描述符结构类型GATE能方便地在程序中说明门描述符。
    例如,下面的门描述符SUBRG描述一个386调用门,门内的选择子是10H,入口偏移是123456H,门描述符特权级是3,双字计数是0。
    SUBRG    GATE  <3456,10H,,8CH+60H,12H>
    从上述描述符类型的列表中可见,门描述符又可分为:任务门、调用门、中断门和陷阱门,并且除任务门外,其它描述符还各分成286和386两种。

    2.调用门

    调用门描述某个子程序的入口。调用门内的选择子必须实现代码段描述符,调用门内的偏移是对应代码段内的偏移。利用段间调用指令CALL,通过调用门可实现任务内从外层特权级变换到内层特权级。
    在上图所示的门描述符内偏移4字节的位0至位4是双字计数字段,该字段只在调用门描述符中有效,在其它门描述符中无效。主程序通过堆栈把入口参 数传递给子程序,如果在利用调用门调用子程序时引起特权级的转换和堆栈的改变,那么就需要将外层堆栈中的参数复制到内层堆栈。该双字计数字段就是用于说明 这种情况发生时,要复制的双字参数的数量。

    3.任务门

    任务门指示任务。任务门内的选择子必须指示GDT中的任务状态段TSS描述符,门中的偏移无意义。任务的入口点保存在TSS中。利用段间转移指令JMP和段间调用指令CALL,通过任务门可实现任务切换。

    4.中断门和陷阱门

    中断门和陷阱门描述中断/异常处理程序的人口点。中断门和陷阱门内的选择子必须指向代码段描述符,门内的偏移就是对应代码段的人口点的偏移。中断门和陷阱门只有在中断描述符表IDT中才有效。关于中断门和陷阱门的区别将在以后的文章中论述。

    <三>任务状态段

    任务状态段(Task State Segment)是保存一个任务重要信息的特殊段。任务状态段描述符用于描述这样的系统段。任务状态段寄存器TR的可见部分含有当前任务的任务状态段描述 符的选择子,TR的不可见的高速缓冲寄存器部分含有当前任务状态段的段基地址和段界限等信息。
    TSS在任务切换过程中起着重要作用,通过它实现任务的挂起和恢复。所谓任务切换是指,挂起当前正在执行的任务,恢复或启动另一任务的执行。在 任务切换过程中,首先,处理器中各寄存器的当前值被自动保存到TR所指定的TSS中;然后,下一任务的TSS的选择子被装入TR;最后,从TR所指定的 TSS中取出各寄存器的值送到处理器的各寄存器中。由此可见,通过在TSS中保存任务现场各寄存器状态的完整映象,实现任务的切换。
    任务状态段TSS的基本格式如下图所示。

     























    BIT31—BIT16 BIT15—BIT1 BIT0 Offset
    0000000000000000 链接字段 0
    ESP0 4
    0000000000000000 SS0 8
    ESP1 0CH
    0000000000000000 SS1 10H
    ESP2 14H
    0000000000000000 SS2 18H
    CR3 1CH
    EIP 20H
    EFLAGS 24H
    EAX 28H
    ECX 2CH
    EDX 30H
    EBX 34H
    ESP 38H
    EBP 3CH
    ESI 40H
    EDI 44H
    0000000000000000 ES 48H
    0000000000000000 CS 4CH
    0000000000000000 SS 50H
    0000000000000000 DS 54H
    0000000000000000 FS 58H
    0000000000000000 GS 5CH
    0000000000000000 LDTR 60H
    I/O许可位图偏移 000000000000000 T 64H

     

    从图中可见,TSS的基本格式由104字节组成。这104字节的基本格式是不可改变的,但在此之外系统软件还可定义若干附加信息。基本的104字节可分为链接字段区域、内层堆栈指针区域、地址映射寄存器区域、寄存器保存区域和其它字段等五个区域。

    1.寄存器保存区域

    寄存器保存区域位于TSS内偏移20H至5FH处,用于保存通用寄存器、段寄存器、指令指针和标志寄存器。当TSS对应的任务正在执行时,保存 区域是未定义的;在当前任务被切换出时,这些寄存器的当前值就保存在该区域。当下次切换回原任务时,再从保存区域恢复出这些寄存器的值,从而,使处理器恢 复成该任务换出前的状态,最终使任务能够恢复执行。
    从上图可见,各通用寄存器对应一个32位的双字,指令指针和标志寄存器各对应一个32位的双字;各段寄存器也对应一个32位的双字,段寄存器中的选择子只有16位,安排再双字的低16位,高16位未用,一般应填为0。

    2.内层堆栈指针区域

    为了有效地实现保护,同一个任务在不同的特权级下使用不同的堆栈。例如,当从外层特权级3变换到内层特权级0时,任务使用的堆栈也同时从3级变 换到0级堆栈;当从内层特权级0变换到外层特权级3时,任务使用的堆栈也同时从0级堆栈变换到3级堆栈。所以,一个任务可能具有四个堆栈,对应四个特权 级。四个堆栈需要四个堆栈指针。
    TSS的内层堆栈指针区域中有三个堆栈指针,它们都是48位的全指针(16位的选择子和32位的偏移),分别指向0级、1级和2级堆栈的栈顶, 依次存放在TSS中偏移为4、12及20开始的位置。当发生向内层转移时,把适当的堆栈指针装入SS及ESP寄存器以变换到内层堆栈,外层堆栈的指针保存 在内层堆栈中。没有指向3级堆栈的指针,因为3级是最外层,所以任何一个向内层的转移都不可能转移到3级。
    但是,当特权级由内层向外层变换时,并不把内层堆栈的指针保存到TSS的内层堆栈指针区域。实际上,处理器从不向该区域进行写入,除非程序设计 者认为改变该区域的值。这表明向内层转移时,总是把内层堆栈认为是一个空栈。因此,不允许发生同级内层转移的递归,一旦发生向某级内层的转移,那么返回到 外层的正常途径是相匹配的向外层返回。

    3.地址映射寄存器区域

    从虚拟地址空间到线性地址空间的映射由GDT和LDT确定,与特定任务相关的部分由LDT确定,而LDT又由LDTR确定。如果采用分页机制, 那么由线性地址空间到物理地址空间的映射由包含页目录表起始物理地址的控制寄存器CR3确定。所以,与特定任务相关的虚拟地址空间到物理地址空间的映射由 LDTR和CR3确定。显然,随着任务的切换,地址映射关系也要切换。
    TSS的地址映射寄存器区域由位于偏移1CH处的双字字段(CR3)和位于偏移60H处的字字段(LDTR)组成。在任务切换时,处理器自动从要执行任务的TSS中取出这两个字段,分别装入到寄存器CR3和LDTR。这样就改变了虚拟地址空间到物理地址空间的映射。
    但是,在任务切换时,处理器并不把换出任务但是的寄存器CR3和LDTR的内容保存到TSS中的地址映射寄存器区域。事实上,处理器也从来不向 该区域自动写入。因此,如果程序改变了LDTR或CR3,那么必须把新值人为地保存到TSS中的地址映射寄存器区域相应字段中。可以通过别名技术实现此功 能。

    4.链接字段

    链接字段安排在TSS内偏移0开始的双字中,其高16位未用。在起链接作用时,地16位保存前一任务的TSS描述符的选择子。
    如果当前的任务由段间调用指令CALL或中断/异常而激活,那么链接字段保存被挂起任务的 TSS的选择子,并且标志寄存器EFLAGS中的NT位被置1,使链接字段有效。在返回时,由于NT标志位为1,返回指令RET或中断返回指令IRET将 使得控制沿链接字段所指恢复到链上的前一个任务。

    5.其它字段

    为了实现输入/输出保护,要使用I/O许可位图。任务使用的I/O许可位图也存放在TSS中,作为TSS的扩展部分。在TSS内偏移66H处的字用于存放I/O许可位图在TSS内的偏移(从TSS开头开始计算)。关于I/O许可位图的作用,以后的文章中将会详细介绍。
    在TSS内偏移64H处的字是为任务提供的特别属性。在80386中,只定义了一种属性,即调试陷阱。该属性是字的最低位,用T表示。该字的其 它位置被保留,必须被置为0。在发生任务切换时,如果进入任务的T位为1,那么在任务切换完成之后,新任务的第一条指令执行之前产生调试陷阱。

    6.用结构类型定义TSS

    根据上图给出的任务状态段TSS的结构,可定义如下的TSS结构类型:
    ;----------------------------------------------------------------------------
    ;任务状态段结构类型定义
    ;----------------------------------------------------------------------------
    TSS             STRUC
    TRLink          DW      0      ;链接字段
                    DW      0      ;不使用,置为0
    TRESP0          DD      0      ;0级堆栈指针
    TRSS0           DW      0      ;0级堆栈段寄存器
                    DW      0      ;不使用,置为0
    TRESP1          DD      0      ;1级堆栈指针
    TRSS1           DW      0      ;1级堆栈段寄存器
                    DW      0      ;不使用,置为0
    TRESP2          DD      0      ;2级堆栈指针
    TRSS2           DW      0      ;2级堆栈段寄存器
                    DW      0      ;不使用,置为0
    TRCR3           DD      0      ;CR3
    TREIP           DD      0      ;EIP
    TREFlag         DD      0      ;EFLAGS
    TREAX           DD      0      ;EAX
    TRECX           DD      0      ;ECX
    TREDX           DD      0      ;EDX
    TREBX           DD      0      ;EBX
    TRESP           DD      0      ;ESP
    TREBP           DD      0      ;EBP
    TRESI           DD      0      ;ESI
    TREDI           DD      0      ;EDI
    TRES            DW      0      ;ES
                    DW      0      ;不使用,置为0
    TRCS            DW      0      ;CS
                    DW      0      ;不使用,置为0
    TRSS            DW      0      ;SS
                    DW      0      ;不使用,置为0
    TRDS            DW      0      ;DS
                    DW      0      ;不使用,置为0
    TRFS            DW      0      ;FS
                    DW      0      ;不使用,置为0
    TRGS            DW      0      ;GS
                    DW      0      ;不使用,置为0
    TRLDTR          DW      0      ;LDTR
                    DW      0      ;不使用,置为0
    TRTrip          DW      0      ;调试陷阱标志(只用位0)
    TRIOMap         DW      $+2    ;指向I/O许可位图区的段内偏移
    TSS             ENDS

     

    参考资料 书         名 出   版   社 作     者
    《保护方式下的80386及其编程》 清华大学出版社 周明德主编
    《80X86汇编语言程序设计教程》 清华大学出版社 扬季文主编

     

    [转] http://blog.csdn.net/barech/article/details/4401417

     

    -----------------------------------

    [from: http://stackoverflow.com/questions/3425085/the-difference-between-call-gate-interrupt-gate-trap-gate ]

    A gate (call, interrupt, task or trap) is used to transfer control of execution across segments. Privilege level checking is done differently depending on the type of destination and instruction used.

    A call gate uses the CALL and JMP instructions. Call gates transfer control from lower privilege code to higher privilege code. The gate DPL is used to determine what privilege levels have access to the gate. Call gates are (or have been, probably) gradually abandoned in favour of the SYSENTER/SYSEXIT mechanism, which is faster.

    Task gates are used for hardware multitasking support. A hardware task switch can occur voluntarily (CALL/JMP to a task gate descriptor), or through an interrupt or an IRET when the NT flag is set. It works the same way with interrupt or trap gates. Task gates are not used, to the best of my knowledge, as kernels usually want extra work done when task switching.

    Interrupt & trap gates, together with task gates, are known as the Interrupt Descriptor Table. They work the same as call gates, except the transfer of parameters, from one privilege stack to another. One difference is that interrupt gates clear the IF bit in EFLAGS, while trap gates do not. This makes them ideal for serving hardware interrupts. Traps are widely used in hardware-assisted virtualization.

    For more information, see the Intel Architecture Manuals on the processors that interest you.

    Update

    To answer the comment:

    There are many reasons to distinguish interrupts from traps. One is the difference in scope: interrupt gates point to kernel space (after all, it's the kernel who manages the hardware) while traps are called in userspace. Interrupt handlers are called in response to hardware events, while traps are executed in response to an CPU instruction.

    For a simple (but impractical) example to better understand why interrupt and trap gates treat EFLAGS differently, consider what would happen in case we were writing an interrupt handler for hardware events on a uniprocessor system and we couldn't clear the IF bit while we were serving one. It would be possible for a second interrupt to arrive while we were busy serving the first. Then our interrupt handler would be called by the processor at some random point during our IH execution. This could lead to data corruption, deadlocking, or other bad magic. Practically, interrupt disabling is one of the mechanisms to ensure that a series of kernel statements is treated like a critical section.

    The above example is assuming maskable interrupts, though. You wouldn't want to ignore NMIs, anyway.

    It's largely irrelevant today, too. Today there's practically no distinction between fast and slow interrupt handlers (search for "Fast and Slow Handlers"), interrupt handlers can execute in nested fashion, SMP processors make it mandatory to couple local interrupt disabling with spin locks, and so forth.

    Now, trap gates are indeed used to service software interrupts, exceptions, etc. A page fault or division by zero exception in your processor is probably handled through a trap gate. The simplest example of using trap gates to control program execution is the INT 3 instruction, which is used to implement breakpoints in debuggers. When doing virtualization, what happens is that the hypervisor runs in ring 0, and the guest kernel usually in ring 1 - where privileged code would fail with general exception fault. Witchel and Rosenblum developed binary translation, which is basically rewriting instructions to simulate their effects. Critical instructions are discovered and replaced with traps. Then when the trap executes, control is yielded to the VMM/hypervisor, which is responsible for emulating the critical instructions in ring 0.

    With hardware-assisted virtualization, the trap-and-emulate technique has been somewhat limited in its use (since it's quite expensive, especially when it's dynamic) but the practice of binary translation is still widely used.

    For more information, I'd suggest you check out:

    • Linux Device Drivers, Third Edition (available online)
    • For binary translation, QEMU is an excellent start.
    • Regarding trap-and-emulate, check out a comparison between software/hardware techniques.

    Hope this helps!


    -----------------------------------------------------

    [另一个相关网页: http://www.mouseos.com/arch/gate_descriptor.html ]

  • 相关阅读:
    Linux操作_常用命令操作练习
    Linux编程_Shell脚本练习题
    Linux操作_grep/egrep工具的使用
    Linux中的链接文件_软链接和硬链接
    Linux操作_磁盘管理_增加虚拟磁盘
    Linux命令_磁盘管理_查看磁盘或目录的容量
    Linux命令_用户身份切换
    使用Unity中的Box Collider组件完成游戏场景中的碰撞检测功能
    在Unity场景中更改天空盒的步骤
    Linux命令_用户和用户组管理
  • 原文地址:https://www.cnblogs.com/longdouhzt/p/2749902.html
Copyright © 2020-2023  润新知