ITPub博客

首页 > 应用开发 > IT综合 > 演示中断处理的实例(实例六)(转)

演示中断处理的实例(实例六)(转)

原创 IT综合 作者:heying1229 时间:2007-07-28 10:35:32 0 删除 编辑
断处理的实例(实例六):
下面给出一个用于演示中断处理的实例。该实例的逻辑功能是,在屏幕的左上角以倒计时方式显示秒为单位的时间,在时间用完后结束。该实例演示内容包括:外部中断处理程序和陷阱处理程序。

1.源程序组织和清单

本实例由如下几部分组成:
(1)全局描述符表GDT。GDT中除了含有常见的几个描述符外,还含有描述时钟中断处理程序所使用的代码段和数据段描述符,以及描述显示程序所使用的代码段和数据段描述符。
(2)中断描述符表IDT。为了在保护模式下响应中断和处理异常,必须有IDT。IDT含有256个门描述符。8号安排的是一个通向时钟中断处理程序的中断门,0FEH号安排的是通向显示处理程序的陷阱门,其它均安排成通向其它中断或异常处理程序的陷阱门。
(3)时钟中断处理程序的代码段和数据段。
(4)实现直接写显示缓冲区进行显示的程序代码段和数据段。
(5)处理其它中断或异常的处理程序的代码段。
(6)演示程序的代码段、数据段和堆栈段。
(7)实模式下执行的启动和结束程序代码段和数据段。
源程序清单如下:
;名称:ASM6.ASM;功能:演示中断处理的实现;编译:TASM ASM6.ASM;连接:TLINK ASM6.OBJ;----------------------------------------------------------------------------INCLUDE         386SCD.INC;----------------------------------------------------------------------------;部分常量定义;----------------------------------------------------------------------------EOICOM          =       20h                       ;外部中断处理结束命令ICREGP          =       20h                       ;中断控制寄存器端口地址IMREGP          =       21h                       ;中断屏蔽寄存器端口地址;----------------------------------------------------------------------------GDTSeg          SEGMENT PARA USE16                ;全局描述符表数据段(16位);----------------------------------------------------------------------------                ;全局描述符表GDTGDT             LABEL   BYTE                ;空描述符DUMMY           Desc    <>                ;规范段描述符Normal          Desc    <0ffffh,,,ATDW,,>                ;视频缓冲区段描述符(DPL=3)VideoBuf        Desc    <0ffffh,8000h,0bh,ATDW,,>;----------------------------------------------------------------------------EFFGDT          LABEL   BYTE                ;临时代码段描述符TempCode        Desc    <0ffffh,TempCodeSeg,,ATCE,,>                ;演示代码段描述符DemoCode        Desc    <DemoCodeLen-1,DemoCodeSeg,,ATCE,,>                ;演示数据段描述符DemoData        Desc    <DemoDataLen-1,DemoDataSeg,,ATDW,,>                ;演示堆栈段描述符DemoStack       Desc    <DemoStackLen-1,DemoStackSeg,,ATDWA,,>                ;0feh号中断处理程序(显示程序)代码段描述符EchoCode        Desc    <EchoCodeLen-1,EchoCodeSeg,,ATCE,,>                ;0feh号中断处理程序(显示程序)数据段描述符EchoData        Desc    <EchoDataLen-1,EchoDataSeg,,ATDW,,>                ;8号中断处理程序代码段描述符TICode          Desc    <TICodeLen-1,TICodeSeg,,ATCE,,>                ;8号中断处理程序数据段描述符TIData          Desc    <TIDataLen-1,TIDataSeg,,ATDW,,>                ;其它中断或异常处理程序代码段描述符Other           Desc    <OtherCodeLen-1,OtherCodeSeg,,ATCE,,>;----------------------------------------------------------------------------GDTLen          =       $-GDT                     ;全局描述符表长度GDNum           =       ($-EFFGDT)/(SIZE Desc)    ;需特殊处理的描述符数;----------------------------------------------------------------------------Normal_Sel      =       Normal-GDT                ;规范段描述符选择子Video_Sel       =       VideoBuf-GDT              ;视频缓冲区段描述符选择子;----------------------------------------------------------------------------TempCode_Sel    =       TempCode-GDT              ;临时代码段的选择子DemoCode_Sel    =       DemoCode-GDT              ;演示代码段的选择子DemoData_Sel    =       DemoData-GDT              ;演示数据段的选择子DemoStack_Sel   =       DemoStack-GDT             ;演示堆栈段的选择子EchoCode_Sel    =       EchoCode-GDT              ;0feh号中断程序代码段选择子EchoData_Sel    =       EchoData-GDT              ;0feh号中断程序数据段选择子TICode_Sel      =       TICode-GDT                ;8号中断程序代码段选择子TIData_Sel      =       TIData-GDT                ;8号中断程序数据段选择子Other_Sel       =       Other-GDT                 ;其它中断或异常代码段选择子;----------------------------------------------------------------------------GDTSeg          ENDS                              ;全局描述符表段定义结束;----------------------------------------------------------------------------IDTSeg          SEGMENT PARA USE16                ;中断描述符表数据段(16位);----------------------------------------------------------------------------IDT             LABEL   BYTE                      ;中断描述符表                ;0--7的8个陷阱门描述符                REPT    8                Gate    <OtherBegin,Other_Sel,,AT386TGate,>                ENDM                ;对应8号(时钟)中断处理程序的门描述符                Gate    <TIBegin,TICode_Sel,,AT386IGate,>                ;从9--0fdh的245个陷阱门描述符                REPT    245                Gate    <OtherBegin,Other_Sel,,AT386TGate,>                ENDM                ;对应0feh号中断处理程序的陷阱门描述符                Gate    <EchoBegin,EchoCode_Sel,,AT386TGate,>                ;对应0ffh号中断处理程序的陷阱门描述符                Gate    <OtherBegin,Other_Sel,,AT386TGate,>;----------------------------------------------------------------------------IDTLen          =       $-IDT;----------------------------------------------------------------------------IDTSeg          ENDS                              ;中断描述符表段定义结束;----------------------------------------------------------------------------;其它中断或异常处理程序的代码段;----------------------------------------------------------------------------OtherCodeSeg    SEGMENT PARA USE16                ASSUME  CS:OtherCodeSeg;----------------------------------------------------------------------------OtherBegin      PROC    FAR                mov     ax,Video_Sel                mov     es,ax                mov     ah,17h                    ;在屏幕左上角显示兰底白字                mov     al,'!'                    ;符号"!"                mov     WORD PTR es:[0],ax                jmp     $                         ;无限循环OtherBegin      ENDP;----------------------------------------------------------------------------OtherCodeLen    =       $OtherCodeSeg    ENDS;----------------------------------------------------------------------------;8号中断处理程序的数据段;----------------------------------------------------------------------------TIDataSeg       SEGMENT PARA USE16Count           DB      0                         ;中断发生的计数器TIDataLen       =       $TIDataSeg       ENDS;----------------------------------------------------------------------------;8号中断处理程序的代码段;----------------------------------------------------------------------------TICodeSeg       SEGMENT PARA USE16                ASSUME  CS:TICodeSeg,DS:TIDataSeg;----------------------------------------------------------------------------TIBegin         PROC    FAR                push    eax                       ;保护现场                push    ds                push    fs                push    gs                mov     ax,TIData_Sel             ;置中断处理程序数据段                mov     ds,ax                mov     ax,EchoData_Sel           ;置显示过程数据段                mov     fs,ax                mov     ax,DemoData_Sel           ;置演示程序数据段                mov     gs,ax                cmp     Count,0                jnz     TI2                       ;计数非0表示未到1秒                mov     Count,18                  ;每秒约18次                int     0feh                      ;调用0FEH号中断处理程序显示                cmp     BYTE PTR fs:Mess,'0'                jnz     TI1                mov     BYTE PTR gs:Flag,1        ;显示符号'0'时置标记TI1:            dec     BYTE PTR fs:Mess          ;调整显示符号TI2:            dec     Count                     ;调整计数                pop     gs                        ;恢复现场                pop     fs                pop     ds                mov     al,EOICOM                 ;通知中断控制器中断处理结束                out     ICREGP,al                pop     eax                iretd                             ;中断返回TIBegin         ENDP;----------------------------------------------------------------------------TICodeLen       =       $TICodeSeg       ENDS;----------------------------------------------------------------------------;0FEH号中断处理程序数据段;----------------------------------------------------------------------------EchoDataSeg     SEGMENT PARA USE16Mess            DB      '8',4ehEchoDataLen     =       $EchoDataSeg     ENDS;----------------------------------------------------------------------------;0FEH号中断处理程序(显示程序)的代码段;----------------------------------------------------------------------------EchoCodeSeg     SEGMENT PARA USE16                ASSUME  CS:EchoCodeSeg,DS:EchoDataSeg;----------------------------------------------------------------------------EchoBegin       PROC    FAR                push    ax                        ;保护现场                push    ds                push    es                mov     ax,EchoData_Sel           ;置显示过程数据段                mov     ds,ax                mov     ax,Video_Sel              ;置视频缓冲区数据段                mov     es,ax                mov     ax,WORD PTR Mess                mov     WORD PTR es:[0],ax                pop     es                pop     ds                pop     ax                iretdEchoBegin       ENDP;----------------------------------------------------------------------------EchoCodeLen     =       $EchoCodeSeg     ENDS;----------------------------------------------------------------------------;演示任务的堆栈段;----------------------------------------------------------------------------DemoStackSeg    SEGMENT PARA USE16DemoStackLen    =       1024                DB      DemoStackLen DUP(0)DemoStackSeg    ENDS;----------------------------------------------------------------------------;演示任务的数据段;----------------------------------------------------------------------------DemoDataSeg     SEGMENT PARA USE16Flag            DB      0DemoDataLen     =       $DemoDataSeg     ENDS;----------------------------------------------------------------------------;演示任务的代码段;----------------------------------------------------------------------------DemoCodeSeg     SEGMENT PARA USE16                ASSUME  CS:DemoCodeSeg,DS:DemoDataSeg;----------------------------------------------------------------------------DemoBegin       PROC    FAR                mov     ax,DemoStack_Sel          ;置堆栈                mov     ss,ax                mov     sp,DemoStackLen           ;置数据段                mov     ax,DemoData_Sel                mov     ds,ax                mov     es,ax                mov     fs,ax                mov     gs,ax                mov     al,11111110b              ;置中断屏蔽字                out     IMREGP,al                 ;只开发时钟中断                sti                               ;开中断DemoConti:      cmp     BYTE PTR Flag,0           ;判标志                jz      DemoConti                 ;直到不为0                cli                               ;关中断                ;转回临时代码段,准备回实方式                JUMP16  TempCode_Sel,<OFFSET ToDos>DemoBegin       ENDP;----------------------------------------------------------------------------DemoCodeLen     =       $DemoCodeSeg     ENDS;----------------------------------------------------------------------------TempCodeSeg     SEGMENT PARA USE16                ;临时任务的代码段                ASSUME  CS:TempCodeSeg;----------------------------------------------------------------------------Virtual         PROC    FAR                JUMP16  DemoCode_Sel,DemoBegin    ;转演示任务ToDos:          mov     ax,Normal_Sel             ;恢复实方式段描述符高速缓存                mov     ds,ax                mov     es,ax                mov     fs,ax                mov     gs,ax                mov     ss,ax                mov     eax,cr0                   ;准备返回实模式                and     al,11111110b                mov     cr0,eax                JUMP16  <SEG Real>,<OFFSET Real>Virtual         ENDP;----------------------------------------------------------------------------TempCodeSeg     ENDS;============================================================================RDataSeg        SEGMENT PARA USE16                ;实方式数据段VGDTR           PDesc   <GDTLen-1,>               ;GDT伪描述符VIDTR           PDesc   <IDTLen-1,>               ;IDT伪描述符NORVIDTR        PDesc   <3ffh,>                   ;用于保存原IDTR值SPVar           DW      ?                         ;用于保存实方式下的SPSSVar           DW      ?                         ;用于保存实方式下的SSIMaskRegV       DB      ?                         ;用于保存原中断屏蔽寄存器值RDataSeg        ENDS;----------------------------------------------------------------------------RCodeSeg        SEGMENT PARA USE16                ;实方式代码段                ASSUME  CS:RCodeSeg,DS:RDataSeg;----------------------------------------------------------------------------Start           PROC                mov     ax,RDataSeg                mov     ds,ax                cld                call    InitGDT                   ;初始化全局描述符表GDT                call    InitIDT                   ;初始化中断描述符表IDT                mov     SSVar,ss                  ;保存堆栈指针                mov     SPVar,sp                sidt    QWORD PTR NORVIDTR        ;保存IDTR                in      al,IMREGP                mov     BYTE PTR IMaskRegV,al                lgdt    QWORD PTR VGDTR           ;装载GDTR                cli                               ;关中断                lidt    QWORD PTR VIDTR           ;装载IDTR                mov     eax,cr0                or      al,1                mov     cr0,eax                JUMP16  <TempCode_Sel>,<OFFSET Virtual>Real:           mov     ax,RDataSeg                mov     ds,ax                lss     sp,DWORD PTR SPVar        ;又回到实方式                lidt    QWORD PTR NORVIDTR                mov     al,IMaskRegV                out     IMREGP,al                sti                mov     ax,4c00h                int     21hStart           ENDP;----------------------------------------------------------------------------InitGDT         PROC                push    ds                mov     ax,GDTSeg                mov     ds,ax                mov     cx,GDNum                mov     si,OFFSET EFFGDTInitG:          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                retInitGDT         ENDP;----------------------------------------------------------------------------InitIDT         PROC                mov     bx,16                mov     ax,IDTSeg                mul     bx                mov     WORD PTR VIDTR.Base,ax                mov     WORD PTR VIDTR.Base+2,dx                retInitIDT         ENDP;----------------------------------------------------------------------------RCodeSeg        ENDS                END     Start

2.关于实例六的说明

(1)时钟中断仍使用8H号中断向量

为了即简单又清楚地演示在保护模式下响应外部中断并进行处理,实例使用了时钟中断源,但没有通过重新设置中断控制器的方法改变对应的中断向量。所以,时钟中断使用的8H号中断向量号就与双重故障异常使用的中断向量号发生冲突。但实例仅是演示程序,所以只要保证不发生双重故障异常,就可避免冲突,从而不会影响演示。
设置中断屏蔽寄存器,仅开放时钟中断。所以,在开中断状态下,也只可能发生时钟中断,而不会发生其它外部中断。

(2)时钟中断处理程序的设计

由于通过中断门转时钟中断处理程序,所以在控制转移时不发生任务切换。但外部中断随时可能发生,因此中断处理程序必须采取保护现场等措施。作为演示程序,该中断处理程序检查和调整在其数据段中的计数器,满18次后,就认为已满一秒,再调整用于显示的倒计数信息。如果倒计数信息为0,那么就设置演示程序数据段中的时间为0标志。该中断处理程序通过约定的数据区与显示程序及演示程序交换信息。

(3)利用一个软中断(陷阱处理)程序实现显示

为了演示陷阱及其处理,把显示过程安排成陷阱处理程序。上述时钟中断处理程序通过软中断调用指令INT调用该显示程序,以显示倒计数。在控制转移时,也没有任务切换。该陷阱处理程序相当于一个“软中断”处理程序,类似实模式下的BIOS中断INT 10H。

(4)对其它中断或异常的响应

为了简单,除了8H号和0FEH号外,IDT中其它的门均通向一个处理程序。该处理程序用于处理其它中断或异常。处理过程也极其简单,在屏幕左上角显示蓝底白字的符号“!”,然后进入无限循环。实际上,按演示程序现在的安排,不可能发生这种情况。

(5)没有特权级变换

为了简单,实例涉及的中断处理程序和异常处理程序都保持特权级0。所以,控制转移时不发生特权级变换。因此,没有使用其它堆栈。

(6)对IDT的初始化

由于IDT中门描述符没有32位段基地址,并且入口点偏移较小,所以就直接填写门描述符结构变量,没有额外再初始化。过程InitIDT只是设置IDT伪描述符。

(7)装载和保存IDTR寄存器

再使IDT发挥作用之前,还要装载中断描述符表寄存器IDTR;但为了回到实模式后,恢复原来的IDTR之内容,所以先保存IDTR的内容。实例使用如下指令保存IDTR:
    sidt    QWORD PTR NORVIDTR
该指令的功能是把IDTR的内容保存到存储器中的伪描述符NORVIDTR中。该伪描述符的结构如前文所述的结构类型PDESC所示,低字是以字节为单位的界限,高双字是基地址。在后面的文章中将对SIDT指令作详细说明。
本实例使用如下指令装载IDTR寄存器:
    lidt    QWORD PTR VIDTR    lidt    QWORD PTR NORVIDTR
LIDT指令类似于LGDT指令,在后面的文章中将对LIDT指令作详细说明。
[@more@]

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/10172717/viewspace-928727/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
  • 博文量
    1688
  • 访问量
    9438726