中断详解(三)——中断和异常的硬件处理

来源:互联网 发布:网盘php源码整站 编辑:程序博客网 时间:2024/06/03 22:59

    假定内核已被初始化,CPU在保护模式下运行
    当执行了一条指令后,CS和eip这对寄存器包含下一条将要执行的指令的逻辑地址.在处理那条指令之前,控制单元会检查在运行前一条指令时是否已经发生了一个中断或异常。如果发生了一个中断或异常,那么控制单元执行下列操作:
    1)确定与中断或异常关联的向量i (0 ≤ i ≤ 255)
    2)读由idtr寄存器指向的IDT表中的第i项(在下面的描述中,我们假定IDT表项中包含的是一个中断门或一个陷阱门)。
    3)从gdtr寄存器获得GDT的基地址,并在GDT中查找,以读取IDT表项中的选择符所标识的段描述符.这个描述符指定中断或异常处理程序所在段的基地址.
    4)确信中断是由授权的(中断)发生源发出的。首先将当前特权组CPL(存放在cs寄存器的低两位)与段描述符(存放在GDT中)的描述符特权级DPL比较,如果CPL小于DPL. 就产生一个"Generalprotection" 异常.因为中断处理程序的特权不能
低于引起中断的程序的特权.对于编程异常,则做进一步的安全检查:比较CPL与处于IDT中的门描述符的DPL,如果DPL小于CPL,就产生一个"General protection"异常。这最后一个检查可以避免用户应用程序访问特殊的陷阱门或中断门.
    5)检查是否发生了特权级的变化,也就是说,CPL是否不同于所选择的段描述符的DPL. 如果是,控制单元必须开始使用与新的特权级相关的栈。通过执行以下步骤来做到这点:
        a.  读tr寄存器,以访问运行进程的TSS段.
        b.  用与新特权级相关的钱段和战指针的正确值装载ss和esp寄存器。这些值可以在TSS中找到
        c.  在新的栈中保存ss和esp以前的值. 这些值定义了与旧特权级相关的梭的逻辑地址.
    6)如果故障已发生,用引起异常的指令地址装载cs和elp客存器,从而使得这条指令能再次被执行。    
    7)在战中保存eflags、 cs及eip的内容.
    8)如果异常产生了一个硬件出错码,则将它保存在战中.
    9)装载cs和eip寄存器,其值分别是IDT表中第i项门描述符的段选择符和偏移量字段.这些值给出了中断或者异常处理程序的第一条指令的逻辑地址。

控制单元所执行的最后一步就是跳转到中断或者异常处理程序.换句话说.处理完中断
信号后.控制单元所执行的指令就是被选中处理程序的第一条指令.
中断或异常被处理完后,相应的处理程序必须产生一条iret指令,把控制权转交给被
中断的进程,这将迫使控制单元:
    l) 用保存在校中的值装载cs、 eip或eflags寄存器。如果一个硬件出错码曾被压入校中,并且在eip内容的上面,那么,执行iret指令前必须先弹出这个硬件出错码.
    2)检查处理程序的CPL是否等于cs中最低两位的值(这意味着被中断的进程与处理程序运行在同一特权级). 如果是,iret终止执行, 否则,转入下一步.
    3)从战中装载ss和esp寄存器,因此,返回到与旧特权级相关的钱。
    4) 检查ds、 es、 fs,&gs段寄存器的内容,如果其中一个寄存器包含的选择符是一个段描述符,并且其DPL值小子CPL,那么,清相应的段寄存器.控制单元这么做是为了禁止用户态的程序(CPL=3)利用内核以前所用的段客存器(DPL=O).如果不清这些寄存器,怀有恶意的用户态程序就可能利用它们采访问内核地址空间.
0 0
原创粉丝点击