page 60,132 ;----------------------------------------------------------------------------- ; ; VME_2.ASM ; ; Copyright (c) 1995-Present Robert Collins ; ; You have my permission to copy and distribute this software for ; non-commercial purposes. Any commercial use of this software or ; source code is allowed, so long as the appropriate copyright ; attributions (to me) are intact, *AND* my email address is properly ; displayed. ; ; Basically, give me credit, where credit is due, and show my email ; address. ; ;----------------------------------------------------------------------------- ; ; Robert R. Collins email: rcollins@x86.org ; ;----------------------------------------------------------------------------- ; ; Synopsis: This set of programs (VME_n.ASM) will demonstrate how to ; reflect a software interrupt back to the v86 task. ; ;----------------------------------------------------------------------------- ; ; DPL INTR ; VME IOPL IGATE BITMAP ; VME_1.ASM 0 3 0 X ; VME_2.ASM 0 2 X X *** This Program *** ; VME_3.ASM 0 3 3 X ; VME_4.ASM 1 3 0 1 ; VME_5.ASM 1 2 X 1 ; VME_6.ASM 1 3 3 1 ; VME_7.ASM 1 3 X 0 ; VME_8.ASM 1 2 X 0 ; ; ;----------------------------------------------------------------------------- ; ; VME_2.ASM ; ;----------------------------------------------------------------------------- ;----------------------------------------------------------------------------- ; Assembler directives ;----------------------------------------------------------------------------- .xlist ; disable list file .model small .586P ;----------------------------------------------------------------------------- ; Include files ;----------------------------------------------------------------------------- Include Struct.inc Include Macros.inc Include SysSeg.inc ; System segments, GDT, IDT, TSS Include DataSeg.inc ; Normal data segment IDT_SEG segment para public use16 'DATA' ;----------------------------------------------------------------------------- ; Interrupt descriptor table ;----------------------------------------------------------------------------- org 13 * 8 IDT0D INT_Desc ; INT0d IDT_SEG ENDS Data1 segment para public use16 'DATA' ;----------------------------------------------------------------------------- ; All other data ;----------------------------------------------------------------------------- SwapContext label far dd Offset ReflectV86Interrupt,SEL_IDTCS dd Offset BackToV86Task,SEL_IDTCS dd Offset @v86Exit,SEL_CPL0CS ;----------------------------------------------------------------------------- ; End of data segment ;----------------------------------------------------------------------------- Data1 ENDS .list Code1 segment para public use16 'CODE' ASSUME CS:Code1, DS:Data1, ES:GDT_SEG, FS:TSS_SEG, GS:DS4G, SS:STACK ;----------------------------------------------------------------------------- ; Code starts here ;----------------------------------------------------------------------------- ; Setup return from SMM ;----------------------------------------------------------------------------- Init: xor ax,ax ; clear it pushf push ds ; save far return on stack push ax mov ax,seg Data1 ; set current data segment mov ds,ax mov ax,seg GDT_SEG mov es,ax mov ax,seg TSS_SEG mov fs,ax xor ax,ax ; set segment to virtual interrupts mov gs,ax mov eax,RMINT255 ; get original INT-255 pointer mov SaveINT255,eax ; save it mov ax,ss shl eax,10h mov ax,sp mov VMEStackPtr,eax ; save it ;----------------------------------------------------------------------------- ; Check that this processor supports VME. ;----------------------------------------------------------------------------- xor eax,eax ; clear it db 66h ; were're going to do something smsw ax ; undocumented here, don't look test eax,80000001h ; page mode or pretected mode enabled? jz @F ; nope, continue mov dx,offset PG_Msg ; shl eax,1 ; check for PE jc @ErrorExit ; oops mov dx,offset PE_Msg @ErrorExit: mov ah,9 int 21h ; print message mov ax,4c01h ; set error code int 21h iret ; go split, just in case @@: mov eax,1 ; get CPUID flags cpuid ; test dx,10y ; does this processor support VME? mov dx,offset NotVME_Msg ; set message for failure jz @ErrorExit ; nope, go split INIT_GDT ; Initialize system structures GDT INIT_IDT ; IDT INIT_TSS ; TSS ;----------------------------------------------------------------------------- ; Test INT-255 when VME=1, DPL=0, CPL=0, IOPL=3, IRBitMap[255]=1 ;----------------------------------------------------------------------------- cli pushfd ; save 'em and dword ptr ss:[esp],not 111y SHL 0ch ; make IOPL=0, clear NT popfd Lidt fword ptr IDT3_Ptr ENTERPM JMPFAR @F,SEL_CPL0CS ASSUME CS:Code1, DS:Data1, ES:IDT_SEG, FS:TSS_SEG, GS:DS4G, SS:STACK ;----------------------------------------------------------------------------- ; Setup segments as follows: ; DS = Data segment ; ES = IDT segment ; FS = TSS segment ; GS = 4G segment ; SS = 32-bit stack segment ;----------------------------------------------------------------------------- @@: mov ax,SEL_CPL0SS mov ss,ax mov esp,Stack2Len ; initialize SS:ESP mov eax,SEL_CPL0DS ; set up DS mov ds,ax mov eax,SEL_IDTDS ; set up ES mov es,ax mov eax,SEL_TSSDS ; set up FS mov fs,ax mov eax,SEL_CPL0DS4G ; set up GS mov gs,ax mov ax,SEL_TSS386 ltr ax ; load task register pushfd ; save 'em pop ebx or ebx,10y SHL 0ch ; make IOPL=2 or ebx,1 SHL 11h ; set VM=1 mov eax,4567h ; GS push eax mov eax,3456h ; FS push eax mov eax,1234h ; DS push eax mov eax,2345h ; ES push eax movzx eax,word ptr VMEStackPtr[2] ; SS push eax movzx eax,word ptr VMEStackPtr[0] ; ESP push eax push ebx ; EFLAGS mov eax,seg Code1 ; get v86 code segment push eax mov eax,offset @v86 push eax iretd ; RET FAR to CPL=3 ;----------------------------------------------------------------------------- ; Now in v86 mode. Set up segment registers. ;----------------------------------------------------------------------------- @v86: mov ax,seg Data1 ; set current data segment mov ds,ax mov ax,seg IDT_SEG mov es,ax mov ax,seg TSS_SEG mov fs,ax xor ax,ax ; set segment to virtual interrupts mov gs,ax ;----------------------------------------------------------------------------- ; Modify real-mode interrupt table ;----------------------------------------------------------------------------- mov eax,cs ; get CS shl eax,10h mov ax,offset VMINT0FF mov RMINT255,eax ; save new interrupt vector ;----------------------------------------------------------------------------- ; This will fault to monitor ;----------------------------------------------------------------------------- mov TestVector,0 ; make sure initialize to 0 int 0ffh ; This interrupt will be reflected nop ; two dummy NOP's nop ; on purpose! int 0ffh ; This interrupt will exit this program @v86Exit: mov bx,SEL_CPL0DS ; set CPL=0 data segments mov ds,bx mov es,bx mov fs,bx mov gs,bx mov bx,SEL_RMSS mov ss,bx EXITPM @@: lidt ds:fword ptr RM_IDT3_Ptr mov bx,seg Data1 mov ds,bx mov es,bx mov fs,bx lss sp,VMEStackPtr xor ax,ax ; set segment to virtual interrupts mov gs,ax mov eax,SaveINT255 ; get original INT-255 pointer mov RMINT255,eax ; restore it mov ah,9 ; set interrupt function call mov dx,offset FailMsg cmp ExpectedResults,0aa55aa55h ; expected results? jne @F mov dx,offset PassMsg @@: int 21h iret ; split to DOS VMINT0FF: mov ax,seg Data1 ; set current data segment mov ds,ax not ExpectedResults ; invert pattern iret Code1 ends Code3 segment para public use32 'CODE' ;----------------------------------------------------------------------------- ; Interrupt routines ;----------------------------------------------------------------------------- INT0d label word mov eax,SEL_CPL0DS ; set up DS mov ds,ax mov eax,SEL_IDTDS ; set up ES mov es,ax mov eax,SEL_TSSDS ; set up FS mov fs,ax mov eax,SEL_CPL0DS4G ; set up GS mov gs,ax mov eax,TestVector ; get status add TestVector,2 ; point to next table entry jmp far ptr SwapContext[eax*4] ; jump destination ;----------------------------------------------------------------------------- ; Get original opcode, and use the interrupt vector number as a pointer into ; the real-mode interrupt vector table. Modify our return address on the ; stack, to return control back to the v86 task. ;----------------------------------------------------------------------------- ReflectV86Interrupt: call StoreV86Context ; save original context mov ebx,v86.v86CS ; get CS shl ebx,4 ; make into flat virtual address mov eax,v86.v86EIP ; get current EIP mov ax,word ptr gs:[ebx][eax] ; get opcode movzx eax,ah ; get interrupt vector number mov edx,gs:[eax*4] ; get interrupt vector movzx ecx,dx ; get initial EIP mov v86.v86EIP,ecx ; save it shr edx,10h ; now get CS mov v86.v86CS,edx ; save CS and v86.v86EFLAGS,not 200h ; clear interrupt flag add esp,4 ; ignore error code on stack iretd ;----------------------------------------------------------------------------- ; All we need to do here, is point EIP past the INT-255, and split back to ; the V86 task. ;----------------------------------------------------------------------------- BackToV86Task: call RestoreV86Context ; restore the original v86 context add v86.v86EIP,2 ; point past INT-255 instruction add esp,4 ; ignore error code on stack iretd ;----------------------------------------------------------------------------- StoreV86Context proc near ;----------------------------------------------------------------------------- ; Store the v86 context into the TSS ;----------------------------------------------------------------------------- mov eax,v86.v86EIP[4] ; get EIP mov TSS_386.TSS_EIP,eax ; save EIP mov eax,v86.v86CS[4] ; get CS mov TSS_386.TSS_CS,eax ; save CS mov eax,v86.v86EFLAGS[4] ; get EFLAGS mov TSS_386.TSS_EFLAGS,eax ; save EFLAGS mov eax,v86.v86ESP[4] ; get ESP mov TSS_386.TSS_ESP,eax ; save ESP mov eax,v86.v86SS[4] ; get SS mov TSS_386.TSS_SS,eax ; save SS mov eax,v86.v86DS[4] ; get DS mov TSS_386.TSS_DS,eax ; save DS mov eax,v86.v86ES[4] ; get ES mov TSS_386.TSS_ES,eax ; save ES mov eax,v86.v86FS[4] ; get FS mov TSS_386.TSS_FS,eax ; save FS mov eax,v86.v86GS[4] ; get GS mov TSS_386.TSS_GS,eax ; save GS ret StoreV86Context endp ;----------------------------------------------------------------------------- RestoreV86Context proc near ;----------------------------------------------------------------------------- ; Store the v86 context into the TSS ;----------------------------------------------------------------------------- mov eax,TSS_386.TSS_EIP ; save EIP mov v86.v86EIP[4],eax ; get EIP mov eax,TSS_386.TSS_CS ; save CS mov v86.v86CS[4],eax ; get CS mov eax,TSS_386.TSS_EFLAGS ; save EFLAGS mov v86.v86EFLAGS[4],eax ; get EFLAGS mov eax,TSS_386.TSS_ESP ; save ESP mov v86.v86ESP[4],eax ; get ESP mov eax,TSS_386.TSS_SS ; save SS mov v86.v86SS[4],eax ; get SS mov eax,TSS_386.TSS_DS ; save DS mov v86.v86DS[4],eax ; get DS mov eax,TSS_386.TSS_ES ; save ES mov v86.v86ES[4],eax ; get ES mov eax,TSS_386.TSS_FS ; save FS mov v86.v86FS[4],eax ; get FS mov eax,TSS_386.TSS_GS ; save GS mov v86.v86GS[4],eax ; get GS ret RestoreV86Context endp INT00 label word ICEBP iretd Code3 ENDS END Init