page 60,132 ;----------------------------------------------------------------------------- ; ; VME_5.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 ; VME_3.ASM 0 3 3 X ; VME_4.ASM 1 3 0 1 ; VME_5.ASM 1 2 X 1 *** This Program *** ; VME_6.ASM 1 3 3 1 ; VME_7.ASM 1 3 X 0 ; VME_8.ASM 1 2 X 0 ; ; ;----------------------------------------------------------------------------- ; ; VME_5.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 @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 eax,cr4 or al,1 mov cr4,eax ; enable VME 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 ;----------------------------------------------------------------------------- ; Modify IR bit map to make this interrupt transition to protected mode ;----------------------------------------------------------------------------- mov bx,word ptr TSS_386.TSS_T_IOMAP[2] ; get IO Map base dec bx ; point to last byte if IR bit map or byte ptr fs:[bx],80h ; disable INT 0FF from bit map ;----------------------------------------------------------------------------- ; 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 eax,cr4 and al,not 1 ; disable VME mov cr4,eax 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 ReflectV86Interrupt: mov ebx,v86.v86SS ; get SS shl ebx,4 ; make into flat virtual address sub v86.v86ESP,6 ; manipulate v86 stack mov esi,v86.v86ESP ; add offset mov ecx,v86.v86EFLAGS ; get current EFLAGS mov edx,v86.v86CS ; get current CS mov eax,v86.v86EIP ; get current EIP add eax,2 ; point past INT-255 instruction mov gs:[ebx][esi][4],cx ; put in return FLAGS mov gs:[ebx][esi][2],dx ; put in return CS mov gs:[ebx][esi][0],ax ; put in return EIP ;----------------------------------------------------------------------------- ; 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. ;----------------------------------------------------------------------------- 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 INT00 label word ICEBP iretd Code3 ENDS END Init