2.源程序组织和清单 为了达到演示目的,实例除了演示任务外,还涉及四个测试任务和一个通用保护故障处理任务。实例由如下几部分组成。 (1)全局描述符表GDT和中断描述符表IDT; (2)其它中断/异常处理程序代码段; (3)通用保护故障处理任务的任务状态段、堆栈段和代码段; (4)四个测试任务合用的任务状态段、堆栈段和代码段; (5)演示任务的任务状态段、堆栈段和代码段; (6)演示任务的临时代码段; (7)实模式下执行的启动与结束程序代码段和数据段。 实例九源程序清单如下: ;名称:ASM9.ASM;功能:演示I/O保护及I/O敏感指令的作用;编译:TASM ASM9.ASM;连接:TLINK /32 ASM9.OBJ;----------------------------------------------------------------------------INCLUDE 386SCD.INC;----------------------------------------------------------------------------GDTSeg SEGMENT PARA USE16 ;全局描述符表段(16位)GDT LABEL BYTE ;空描述符DUMMY Desc <> ;规范段描述符及选择子Normal Desc <0ffffh,,,ATDW,,>Normal_Sel = Normal-GDT ;视频缓冲区段描述符(DPL=3)及选择子(任何特权级可写)VideoBuf Desc <07fffh,8000h,0bh,ATDW,,>VideoBuf_Sel = VideoBuf-GDT;----------------------------------------------------------------------------EFFGDT LABEL BYTE ;演示任务TSS段描述符及选择子DemoTSS Desc <DemoTSSLen-1,DemoTSSSeg,,AT386TSS,,>DemoTSS_Sel = DemoTSS-GDT ;演示任务堆栈段描述符及选择子DemoStack Desc <DemoStackLen-1,DemoStackSeg,,ATDW,D32,>DemoStack_Sel = DemoStack-GDT ;演示代码段描述符及选择子DemoCode Desc <DemoCodeLen-1,DemoCodeSeg,,ATCE,D32,>DemoCode_Sel = DemoCode-GDT ;属于演示任务的临时代码段描述符及选择子TempCode Desc <0ffffh,TempCodeSeg,,ATCE,,>TempCode_Sel = TempCode-GDT ;指向GDT的存储段描述符及选择子ToGDT Desc <GDTLen-1,GDTSeg,,ATDW,,>ToGDT_Sel = ToGDT-GDT ;指向通用保护故障处理任务TSS的存储段描述符及选择子ToGPTSS Desc <GPTSSLen-1,GPTSSSeg,,ATDW,,>ToGPTSS_Sel = ToGPTSS-GDT ;指向测试任务TSS的存储段描述符及选择子ToTestTSS Desc <TestTSSLen-1,TestTSSSeg,,ATDW,,>ToTestTSS_Sel = ToTestTSS-GDT ;测试任务TSS段描述符及选择子TestTSS Desc <TestTSSLen-1,TestTSSSeg,,AT386TSS,,>TestTSS_Sel = TestTSS-GDT ;测试任务1堆栈段描述符(DPL=1)及选择子Test1Stack Desc <TestStackLen-1,TestStackSeg,,ATDW+DPL1,D32,>Test1Stack_Sel = Test1Stack-GDT+RPL1 ;测试任务1代码段描述符(DPL=1)及选择子Test1Code Desc <TestCodeLen-1,TestCodeSeg,,ATCE+DPL1,D32,>Test1Code_Sel = Test1Code-GDT+RPL1 ;测试任务2堆栈段描述符(DPL=2)及选择子Test2Stack Desc <TestStackLen-1,TestStackSeg,,ATDW+DPL2,D32,>Test2Stack_Sel = Test2Stack-GDT+RPL2 ;测试任务2代码段描述符(DPL=2)及选择子Test2Code Desc <TestCodeLen-1,TestCodeSeg,,ATCE+DPL2,D32,>Test2Code_Sel = Test2Code-GDT+RPL2 ;测试任务3堆栈段描述符(DPL=3)及选择子Test3Stack Desc <TestStackLen-1,TestStackSeg,,ATDW+DPL3,D32,>Test3Stack_Sel = Test3Stack-GDT+RPL3 ;测试任务3代码段描述符(DPL=3)及选择子Test3Code Desc <TestCodeLen-1,TestCodeSeg,,ATCE+DPL3,D32,>Test3Code_Sel = Test3Code-GDT+RPL3 ;通用保护故障处理任务的TSS段描述符及选择子GPTSS Desc <GPTSSLen-1,GPTSSSeg,,AT386TSS,,>GPTSS_Sel = GPTSS-GDT ;通用保护故障处理任务的堆栈段描述符及选择子GPStack Desc <GPStackLen-1,GPStackSeg,,ATDW,D32,>GPStack_Sel = GPStack-GDT ;通用保护故障处理任务的代码段描述符及选择子GPCode Desc <GPCodeLen-1,GPCodeSeg,,ATCE,D32,>GPCode_Sel = GPCode-GDT ;其它中断或异常处理程序代码段(一致可读)描述符及选择子ErrCode Desc <ErrCodeLen-1,ErrCodeSeg,,ATCCOR,D32,>ErrCode_Sel = ErrCode-GDT;----------------------------------------------------------------------------GDNum = ($-EFFGDT)/(SIZE Desc) ;需处理基地址的描述符个数;---------------------------------------------------------------------------- ;指向测试任务的任务门TestTask Gate <,TestTSS_Sel,,ATTaskGate,>Test_Sel = TestTask-GDT;----------------------------------------------------------------------------GDTLen = $-GDT ;全局描述符表长度GDTSeg ENDS ;全局描述符表段定义结束;----------------------------------------------------------------------------IDTSeg SEGMENT PARA USE16 ;中断描述符表段(16位)IDT LABEL BYTE ;中断描述符表 REPT 13 Gate <ErrBegin,ErrCode_Sel,,AT386TGate,> ENDM Gate <,GPTSS_Sel,,ATTaskGate,> ;通用故障处理程序门描述符 REPT 242 Gate <ErrBegin,ErrCode_Sel,,AT386TGate,> ENDM;----------------------------------------------------------------------------IDTLen = $-IDT;----------------------------------------------------------------------------IDTSeg ENDS ;中断描述符表段定义结束;----------------------------------------------------------------------------;其它中断或异常处理程序的代码段(一致可读);----------------------------------------------------------------------------ErrCodeSeg SEGMENT PARA USE32 ASSUME CS:ErrCodeSeg;----------------------------------------------------------------------------ErrMess DB 'Error!!!'ErrMessLen = $-ErrMess;----------------------------------------------------------------------------ErrBegin PROC FAR cld mov ax,ErrCode_Sel mov ds,ax lea esi,ErrMess mov ax,VideoBuf_Sel mov es,ax mov edi,1992 mov ecx,ErrMessLen mov ah,4ehErr1: lodsb stosw loop Err1 jmp $ErrBegin ENDP;----------------------------------------------------------------------------ErrCodeLen = $ErrCodeSeg ENDS;----------------------------------------------------------------------------GPTSSSeg SEGMENT PARA USE16 ;通用保护故障处理任务的TSSGPTaskSS LABEL BYTE DD 0 ;任务嵌套时的链接指针 DD 0 ;0级堆栈偏移 DW 0,0 ;0级堆栈选择子 DD 0 ;1级堆栈偏移 DW 0,0 ;1级堆栈选择子 DD 0 ;2级堆栈偏移 DW 0,0 ;2级堆栈选择子 DD 0 ;CR3 DW GPBegin,0 ;EIP DD 0 ;EFLAGS DD 0 ;EAX DD 0 ;ECX DD 0 ;EDX DD 0 ;EBX DD GPStackLen ;ESP DD 0 ;EBP DD 0 ;ESI DD 0 ;EDI DW VideoBuf_Sel,0 ;ES DW GPCode_Sel,0 ;CS DW GPStack_Sel,0 ;SS DW ToTestTSS_Sel,0 ;DS DW ToGPTSS_Sel,0 ;FS DW 0,0 ;GS DW 0,0 ;LDTR DW 0 ;调试陷阱标志 DW $+2 ;指向I/O许可位图的偏移 DB 0ffh ;I/O许可位图结束标志GPTSSLen = $GPTSSSeg ENDS;----------------------------------------------------------------------------GPStackSeg SEGMENT PARA USE32 ;通用保护故障处理任务堆栈段GPStackLen = 512 DB GPStackLen DUP(0)GPStackSeg ENDS;----------------------------------------------------------------------------;通用保护故障处理程序代码段;----------------------------------------------------------------------------GPCodeSeg SEGMENT PARA USE32 ASSUME CS:GPCodeSeg;----------------------------------------------------------------------------GPBegin PROC FAR ;在屏幕左上角显示故障点 xor edi,edi mov ebx,OFFSET TestTaskSS mov edx,DWORD PTR [ebx].TRCS call EchoEDX mov ax,(17h SHL 8)+':' stosw mov edx,[ebx].TREIP call EchoEDX ;演示以便看清故障点 mov ecx,1234567h loop $ ;调整任务链接指针,中止故障任务 mov ebx,OFFSET GPTaskSS mov ax,DemoTSS_Sel mov fs:[ebx].TRLink,ax add esp,4 iretd jmp GPBeginGPBegin ENDP;----------------------------------------------------------------------------;显示edx内容的子程序;----------------------------------------------------------------------------EchoEDX PROC mov ah,17h mov ecx,8EchoEDX1: rol edx,4 mov al,dl call HToASCII stosw loop EchoEDX1 retEchoEDX ENDP;----------------------------------------------------------------------------;把4位二进制数转换成对应的ASCII码;----------------------------------------------------------------------------HToASCII PROC and al,0fh add al,90h daa adc al,40h daa retHToASCII ENDP;----------------------------------------------------------------------------GPCodeLen = $GPCodeSeg ENDS;----------------------------------------------------------------------------;测试任务的TSS段TestTSSSeg SEGMENT PARA USE16TestTaskSS TSS <> ;TSS的固定格式部分IOMap LABEL BYTE ;I/O许可位图 DB 8 DUP(0ffh) ;端口00h--3fh DB 11111011b ;端口40h--47h DB 3 DUP(0ffh) ;端口48h--5fh DB 11111101b ;端口60h--67h DB 0 ;端口68h--6fh DB 0ffh ;I/O许可位图结束标志TestTSSLen = $TestTSSSeg ENDS;----------------------------------------------------------------------------;测试任务的堆栈段TestStackSeg SEGMENT PARA USE32TestStackLen = 1024 DB TestStackLen DUP(0)TestStackSeg ENDS;----------------------------------------------------------------------------;测试任务的代码段TestCodeSeg SEGMENT PARA USE32 ASSUME CS:TestCodeSeg;----------------------------------------------------------------------------Test3Begin PROC FAR cli ;I/O敏感指令 clts ;特权指令 iretd jmp Test3BeginTest3Begin ENDP;----------------------------------------------------------------------------TestBegin PROC FAR mov al,0b6h ;使扬声器发出一长声 out 43h,al mov al,2 out 42h,al mov al,34h out 42h,al in al,61h mov ah,al or al,3 out 61h,al mov ecx,1234567h loop $ mov al,ah out 61h,al iretd jmp TestBeginTestBegin ENDP;----------------------------------------------------------------------------TestCodeLen = $TestCodeSeg ENDS;----------------------------------------------------------------------------;演示任务TSS段DemoTSSSeg SEGMENT PARA USE16DemoTaskSS TSS <> DB 0ffh ;I/O许可位图结束字节DemoTSSLen = $DemoTSSSeg ENDS;----------------------------------------------------------------------------;演示任务的堆栈段DemoStackSeg SEGMENT PARA USE32DemoStackLen = 1024 DB DemoStackLen DUP(0)DemoStackSeg ENDS;----------------------------------------------------------------------------;演示任务的代码段DemoCodeSeg SEGMENT PARA USE32 ASSUME CS:DemoCodeSeg;----------------------------------------------------------------------------DemoBegin PROC FAR mov ax,ToTestTSS_Sel mov ds,ax mov ebx,OFFSET TestTaskSS ;把测试任务1的入口点,堆栈指针和标志值(含IOPL)填入测试任务TSS mov WORD PTR [ebx].TRSS,Test1Stack_Sel mov DWORD PTR [ebx].TRESP,TestStackLen mov WORD PTR [ebx].TRCS,Test1Code_Sel mov DWORD PTR [ebx].TREIP,OFFSET TestBegin mov DWORD PTR [ebx].TREFLAG,IOPL1 ;通过任务门调用测试任务 CALL32 Test_Sel,0 ;把测试任务2的入口点,堆栈指针和标志值(含IOPL)填入测试任务TSS mov WORD PTR [ebx].TRSS,Test2Stack_Sel mov DWORD PTR [ebx].TRESP,TestStackLen mov WORD PTR [ebx].TRCS,Test2Code_Sel mov DWORD PTR [ebx].TREIP,OFFSET TestBegin mov DWORD PTR [ebx].TREFLAG,IOPL1 ;通过任务门调用测试任务 CALL32 Test_Sel,0 ;把测试任务TSS描述符内的属性置为"可用" mov ax,ToGDT_Sel mov fs,ax mov fs:TestTSS.Attributes,AT386TSS ;把测试任务3的入口点,堆栈指针和标志值(含IOPL)填入测试任务TSS mov WORD PTR [ebx].TRSS,Test3Stack_Sel mov DWORD PTR [ebx].TRESP,TestStackLen mov WORD PTR [ebx].TRCS,Test3Code_Sel mov DWORD PTR [ebx].TREIP,OFFSET Test3Begin mov DWORD PTR [ebx].TREFLAG,IOPL2 ;通过任务门调用测试任务 CALL32 Test_Sel,0 ;把测试任务TSS描述符内的属性置为"可用" mov ax,ToGDT_Sel mov fs,ax mov fs:TestTSS.Attributes,AT386TSS ;把测试任务4的入口点,堆栈指针和标志值(含IOPL)填入测试任务TSS mov WORD PTR [ebx].TRSS,Test3Stack_Sel mov DWORD PTR [ebx].TRESP,TestStackLen mov WORD PTR [ebx].TRCS,Test3Code_Sel mov DWORD PTR [ebx].TREIP,OFFSET Test3Begin mov DWORD PTR [ebx].TREFLAG,IOPL3 ;通过任务门调用测试任务 CALL32 Test_Sel,0 JUMP32 TempCode_Sel,<OFFSET ToDOS>DemoBegin ENDP;----------------------------------------------------------------------------DemoCodeLen = $DemoCodeSeg ENDS;----------------------------------------------------------------------------TempCodeSeg SEGMENT PARA USE16 ;演示任务的临时代码段 ASSUME CS:TempCodeSeg;----------------------------------------------------------------------------Virtual PROC FAR ;置数据段寄存器为空 mov ax,0 mov ds,ax mov es,ax mov fs,ax mov gs,ax ;置堆栈指针 mov ax,DemoStack_Sel mov ss,ax mov esp,DemoStackLen ;置任务寄存器 mov ax,DemoTSS_Sel ltr ax ;转演示代码段 JUMP16 DemoCode_Sel,DemoBeginToDOS: clts 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 ? ;用于保存实方式下的SSRDataSeg 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 lgdt QWORD PTR VGDTR ;装载GDTR mov SSVar,ss ;保存堆栈指针 mov SPVar,sp sidt QWORD PTR NORVIDTR ;保存IDTR 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 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 3.关于实例九的说明 为了节省篇幅,同时也反映任务状态段的作用,实例通过任务门调用的四个测试任务合用一个任务状态段。从源程序可见,这种合用,实际上是串行的。先把测试任务1的入口点填入测试任务状态段,同时填入堆栈指针,然后调用测试任务1。在测试任务1完成后,再填入测试任务2的入口点,也填入堆栈指针,然后调用测试任务2。依次类推。 通用保护故障处理程序作为一个独立的任务出现。再发生通用保护故障后,通用保护故障处理程序在屏幕上显示故障点的选择子和偏移,然后通过调整存放在任务状态段内的任务连接指针的方法,中止引起故障的测试任务。  
2/2 首页 上一页 1 2 |