home *** CD-ROM | disk | FTP | other *** search
- COMMENT $
-
- DOS32 Version 1.2
-
- A 32 bit MSDOS extender for assembly programmers
-
- supporting
-
- Dos Protected Mode Interrupt Specification
- and
- System BIOS extended memory copy service (INT 15h AH = 87h)
- for without DPMI.
-
- Unlike Version 1.0 this uses the only one protected mode segment.
- i.e Does not have a seperate code ,data and stack descriptor
- base addresses. A much better way to program
-
- Written by Adam Seychell SEP-1993
-
- email s921880@minyos.xx.rmit.oz.au
-
-
-
- $
- .SEQ
- .386p ; Enable "REAL" CPU instuctions.
-
- V86_stack_size equ 200h ; Size of stack for V86 interrupt calls
-
- PIC_Base equ 80h ; Base interrupt address for the 8259s
-
-
-
-
- ;
- ; Format of a 386DX TSS (Task State Segment)
- ;
- TSS struc
- tss_prev dw 0 ,0 ; back link to previous TSS
- tss_esp0 dd 0 ; Priv. 0 ESP
- tss_ss0 dw 0 ; Priv. 0 SS
- dw 0 ; unused
- tss_esp1 dd 0 ; Priv. 1 ESP
- tss_ss1 dw 0 ; Priv. 1 SS
- dw 0 ; unused
- tss_esp2 dd 0 ; Priv. 2 ESP
- tss_ss2 dw 0 ; Priv. 2 SS
- dw 0 ; unused
- tss_cr3 dd 0 ; PDBR
- tss_eip dd 0
- tss_eflags dd 0
- tss_eax dd 0
- tss_ecx dd 0
- tss_edx dd 0
- tss_ebx dd 0
- tss_esp dd 0
- tss_ebp dd 0
- tss_esi dd 0
- tss_edi dd 0
- tss_es dw 0,0
- tss_cs dw 0,0
- tss_ss dw 0,0
- tss_ds dw 0,0
- tss_fs dw 0,0
- tss_gs dw 0,0
- tss_ldt dw 0,0
- tss_t dw 0 ; if bit 0 set, exception on tsk switch
- tss_iobase dw 068h ; points to beg. of I/O permissions map
- tss_iomap db 2000h dup (0) ; I/O permissions bit map
- tss_ioend db 11111111b ; I/O map trailer
- TSS_ENDS equ $ - TSS
- tss ends
-
-
-
-
- Data_sruct struc
- C_EDI dd 0
- C_ESI dd 0
- C_EBP dd 0
- C_resrved dd 0
- C_EBX dd 0
- C_EDX dd 0
- C_ECX dd 0
- C_EAX dd 0
- C_FLAGS dw 0
- C_ES dw 0
- C_DS dw 0
- C_FS dw 0
- C_GS dw 0
- C_IP dw 0
- C_CS dw 0
- C_SP dw 0
- C_SS dw 0
- ends
-
-
- DOS_CODE SEGMENT PUBLIC 'CODE' USE16
- assume CS:DOS_CODE , DS:DOS_CODE , FS:CODE32
-
- s_ACCESS record d_P:1,d_DPL:2,s_S:1,d_TYPE:4
- s_INFO record d_G:1,d_D:1,d_nul:1,d_avl:1,d_lim:4
-
- align 8
- GDT dd 0,0 ; First descriptor is always NULL.
-
- ; Data DESCRIPTOR for a FLAT memory model
- Flat_Data_Desc dw 0ffffh ; Limit[15..0]
- db 0,0,0 ; Base[23..0]
- s_ACCESS <1,00b,1,0010b> ; P,DPL,1,type[E=0,ED,W,A ]
- s_INFO <1,1,0,0,0fh> ; G,B,0,avl,Limit[19..16]
- db 0 ; Base[31..24]
-
- ; Code DESCRIPTOR for a FLAT memory model
- Flat_CODE32_Desc dw 0ffffh ; Limit[15..0]
- db 0,0,0 ; Base[23..0]
- s_ACCESS <1,00,1,1010b> ; P,DPL,1,type[E=1,C,R,A ]
- s_INFO <1,1,0,0,0fh> ; G,D,0,avl,Limit[19..16]
- db 0 ; Base[31..24]
-
- ; Data DESCRIPTOR for the free extented memory block
- XMS_Desc dw 0000h ; Limit[15..0]
- db 00,00,10h ; Base[23..0]
- s_ACCESS <1,00b,1,0010b> ; P,DPL,1,type[E=0,ED,W,A ]
- s_INFO <1,1,0,0,00h> ; G,B,0,avl,Limit[19..16]
- db 0 ; Base[31..24]
-
- ; Data DESCRIPTOR with base = start of free base memory
- BASE_Desc dw 0ffffh ; Limit[15..0]
- db ?,?,? ; Base[23..0]
- s_ACCESS <1,00,1,0010b> ; P,DPL,1,type[E=0,ED,W,A ]
- s_INFO <0,1,0,0,0fh> ; G,B,0,avl,Limit[19..16]
- db 0 ; Base[31..24]
-
- ; Data DESCRIPTOR with base = 0A0000h
- Video_Desc dw 0ffffh ; Limit[15..0]
- db 00,00,0Ah ; Base[23..0]
- s_ACCESS <1,00,1,0010b> ; P,DPL,1,type[E=0,ED,W,A ]
- s_INFO <0,1,0,0,01h> ; G,B,0,avl,Limit[19..16]
- db 0 ; Base[31..24]
-
-
- ; 16bit data and code DESCRIPTORS for real mode ( DOS )
- DOS_Code_Desc dw 0ffffh ; Limit[15..0]
- db ?,?,? ; Base[23..0]
- s_ACCESS <1,00,1,1010b> ; P,DPL,1,type[E=1,C,R,A ]
- s_INFO <0,0,0,0,00h> ; G,D,0,avl,Limit[19..16]
- db 0 ; Base[31..24]
-
- Dos_Data_Desc dw 0ffffh ; Limit[15..0]
- db ?,?,? ; Base[23..0]
- s_ACCESS <1,00,1,0010b> ; P,DPL,1,type[E=0,ED,W,A ]
- s_INFO <0,0,0,0,0h> ; G,B,0,avl,Limit[19..16]
- db 0 ; Base[31..24]
-
-
- ; Data PSP Descr with base = PSP , limit = 100h
- PSP_desc dw 0ffh ; Limit[15..0]
- db 00,00,00h ; Base[23..0]
- s_ACCESS <1,00,1,0010b> ; P,DPL,1,type[E=0,ED,W,A ]
- s_INFO <0,0,0,0,00h> ; G,B,0,avl,Limit[19..16]
- db 0 ; Base[31..24]
-
-
- ; Data Descr for program ENVIRONMENT
- ENVIRONMENT_desc dw 0ffh ; Limit[15..0]
- db 00,00,00h ; Base[23..0]
- s_ACCESS <1,00,1,0010b> ; P,DPL,1,type[E=0,ED,W,A ]
- s_INFO <0,0,0,0,0h> ; G,B,0,avl,Limit[19..16]
- db 0 ; Base[31..24]
-
- ; DATA and CODE DESCRIPTORS for your dos extender
-
- CODE32_Desc dw 0ffffh ; Limit[15..0]
- db ?,?,? ; Base[23..0]
- s_ACCESS <1,00,1,1010b> ; P,DPL,1,type[E=1,C,R,A ]
- s_INFO <0,1,0,0,0fh> ; G,D,0,avl,Limit[19..16]
- db 0 ; Base[31..24]
-
-
- Data_Desc dw 0ffffh ; Limit[15..0]
- db ?,?,? ; Base[23..0]
- s_ACCESS <1,00b,1,0010b> ; P,DPL,1,type[E=0,ED,W,A ]
- s_INFO <0,1,0,0,0fh> ; G,B,0,avl,Limit[19..16]
- db 0 ; Base[31..24]
-
-
- MyMain_TSS_Desc dw TSS_ends ; Limit[15..0]
- db ?,?,? ; Base[23..0]
- s_ACCESS <1,00,0,09h> ; P,DPL,0,(type = avalible 386 TSS )
- s_INFO <0,0,0,0,00h> ; G,0,0,0,Limit[19..16]
- db 0 ; Base[31..24]
-
-
- GDT_ends equ $ - GDT
-
-
- ;======== ERROR MESSAGES FOR PROGRAM TERMINATION IN NON-DPMI ===============
- unknown_int_exit_mesg db 'Exited from Unhandled protected mode interrupt',10,13,36
- _V86_illigal_err db 10,13,' Invalid Instuction in V86 mode ',10,13,36
- _exit_errror db 10,10,' PROGRAM TERMINATED ',10,13,7,36
- e_0 db '0 Divide error',10,13,36
- e_1 db '1 Debug exception',10,13,36
- e_2 db '2 Non-Maskable interrupt',10,13,36
- e_3 db '3 Breakpoint',10,13,36
- e_4 db '4 Overflow',10,13,36
- e_5 db '5 Range Exceeded',10,13,36
- e_6 db '6 Invalid opcode',10,13,36
- e_7 db '7 No math unit avalible',10,13,36
- e_8 db '8 Reserved',10,13,36
- e_9 db '9 Reserved',10,13,36
- e_10 db '10 Invalid TSS',10,13,36
- e_11 db '11 Segment Not Present',10,13,36
- e_12 db '12 Stack exception',10,13,36
- e_13 db '13 General Protection Exception',10,13,36
- e_14 db '14 Page fault',10,13,36
- e_15 db '14 Reserved',10,13,36
-
- DOS_IDT_value dw 03ffh,0,0,0
-
- DPMI_entry dw 0,0
- xms_usage_tmp dd 0
- _tmpL_xms_base dw 0
- _tmpH_xms_base dw 0
- xms_driver dd 0
- XMS_handle dw 0,0
- oirqMask db 0,0
- DPMI_Selector dw 0
- PIC1_Base db 0
- PIC2_Base db 0
-
- ;----------------------------------------------------------------------------
- ;───────────────────── INTERNALY USED ROUTINES ───────────────────────────────────
- ;----------------------------------------------------------------------------
-
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
- Exit_Error: mov ah,9 ; Prints error mesage and terminates
- int 21h
- call free_XMS_memory
- mov ah,4ch
- int 21h
-
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
- free_XMS_memory proc near
- cmp [xms_driver],0
- jz No_xms_driver
-
-
- ; UNLOCK THE ALLOCATED EXTENDED MEMORY BLOCK
- mov ah,0Dh
- mov dx,[XMS_handle]
- call [XMS_Driver]
-
- ; FREE ALLOCATED BLOCK
- MOV AH,0Ah
- mov dx,[XMS_handle]
- call [xms_driver]
- No_xms_driver: RET
-
- free_XMS_memory endp
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
- ;─────────────────────────────────────────────────────────────────────────────
- ; Set new IRQ vector numbers
- set_8259intvec proc ; Set IRQ vectors 0..7 to bl
- ; and IRQ vectors 8..15 to bh
-
- CLI ;∙·∙·∙·∙·∙·∙· set first 8259A PIC ∙·∙·∙·∙·∙·∙·
-
- mov al,00010001b ;ICW1
- out 20h,al ;icw4 is needed
- call Delay8259
- mov al,bl ;ICW2
- out 21h,al ;( Set PIC 1 Base interrupt number )
- call Delay8259
- mov al,4h ;ICW3
- out 21h,al
- call Delay8259
- mov al,1h ;ICW4
- out 21h,al
- call Delay8259 ;∙·∙·∙·∙·∙·∙· set second 8259A PIC ∙·∙·∙·∙·∙·∙·
- mov al,00010001b ;ICW1
- out 0a0h,al ;icw4 is needed
- call Delay8259
- mov al,bh ;ICW2
- out 0a1h,al ;( Set PIC 2 Base interrupt number )
- call Delay8259
- mov al,00000010b ;ICW3
- out 0a1h,al
- call Delay8259
- mov al,0000001b ;ICW4
- out 0a1h,al
- call Delay8259
- ret
-
- delay8259: mov ax,1000h
- @3del: dec ax
- jnz @3del
- ret
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
- ;─────────────────────────────────────────────────────────────────────────────
- endp
-
-
-
- Go_REAL_MODE proc near
-
- ;─────────────────────────────────────────────────────────────────────────────
- ; Entry point to exit protected mode and restore hardware configeration.
- ; Then exits back to MSDOS. ( only for non-DPMI )
- ;─────────────────────────────────────────────────────────────────────────────
- cli
-
- mov al,00110100b ; SLOW DOWN TIMER FOR POOR OLD DOS
- out 43h,al
- XOR AL,AL
- out 40h,al
- out 40h,al
-
- ; Exit protected mode and return to DOS
-
- ; Load Data registers with 8086 SEGMENTs (Fields B=0 and D=0 of descriptors)
- mov ax,DOS_Data_Desc - GDT
- mov ss,ax
- mov es,ax
- mov ds,ax
- mov fs,ax
- mov gs,ax
-
- lidt qword ptr DOS_IDT_value ; Set IDT to how DOS want's it
-
- ; Exit protecded mode
- mov eax,CR0
- and al,NOT 1 ;Clear PE bit
- mov CR0,eax
-
- db 0eah
- dw To_MSDOS , Dos_CODE ; reload CS:IP with real mode values
-
- To_MSDOS: ;-- remap IRQ int vectors ---
- mov bl,008h
- mov bh,070h
- call set_8259intvec
-
-
- assume ds:dos_code
- mov ax,dos_code
- mov ds,ax
- mov ax,V86_STACK ; Set up a bit of stack just to exit
- mov ss,ax
- mov esp,100h
-
- mov al,oirqMask ; return origonal values of the IRQ mask bits
- out 21h,al
- mov al,oirqMask+1
- out 0A1h,al
-
-
- mov al,20h ; Send PIC acknoledge
- out 20h,al
- out 0a0h,al
-
- in al,60h ; do a keyboard read to get out of buffer
- ; just in case program exits without so
- cmp ebp,'ERRA'
- jnz normal_terminate
- ; Print error message if need to
- push dx
- mov ax,3 ; Want to exit in text mode
- int 10h
- pop dx
- mov ah,9
- int 21h
- mov dx,offset _exit_errror
- int 21h
-
- normal_terminate:
-
- call free_XMS_memory ; deallocated XMS
-
- Exit_To_MSDOS:
- mov ax,4C00h ; Finaly get back to MSDOS in real mode.
- int 21h
- assume ds:dos_code
-
- endp
-
- ;---------------- finished exiting routine -------------------------
-
- align 16
- NON_DPMI_initalize_start:
-
-
- GDTR_value dw GDT_ends - 1
- dd offset GDT
- IDTR_value dq 0000000007ffh
-
- Label InterruptGATE_a dword
- dw offset exception ; Offset[15..0]
- dw CODE32_Desc - GDT ; Selector
- Label InterruptGATE_b dword
- db 00000000b ; 0,0,0,WordCnt[4..0]
- s_ACCESS <1,00b,0,0Eh> ; P,DPL,0,type = 386 interrupt Gate
- dw 0 ; Offset[31..16]
-
-
- ;═════════════════ INITALIZATION ERROR MESSAGES ════════════════════════════
- _inV86_err db ' Unable to enter protected mode because another protected mode ',10,13
- db 'application is operating and does not support Dos Protected Mode Interface',10,13
- db 'specifiaction.',10,13,10
- db ' Disable the protected mode sofware and try again.',10,13,36
- mesg_TimeOut8042 db 'Time out error in the keyboard controller (8042) failing to ',10,13
- db ' respond on enabling the A20 gate.',10,13
- all_DPMI_err db 'Encountered DPMI error: ',36
- pmiERr db 'Switching to protecded mode.',10,13,36
- No_Mem_err db 'Not Enough Base memory. 6000 bytes needed.',10,13,36
- erralc_mesg db 'Can''t allocate descriptors.',10,13,36
- errset_mesg db 'Can''t Set descriptors.',10,13,36
- dpmi_aloc_err db 'Can''t allocate extended memory.',10,13,36
- dpmi_lock_err db 'Unable to lock allocated memory.',10,13,36
- dpmi_free_err db 'Unable to get free memory information.',10,13,36
- mesgA20_err db 'ERROR: Physical A20 gate test failed.',10,13,36
- xms_mesgA20_err db 'ERROR: XMS enabling the A20 gate.',10,13,36
- ;xms_vers_err db 'Need XMS v3.0 or greater.',10,13,36
- xms_alloc_Err db 'Can''t allocate XMS memory.',10,13,36
- xms_lock_err db 'Can''t lock allocated XMS memory.',10,13,36
- wrongCPU_mseg db ' CPU was found but sorry to say, a 386 or higher needed',10,13,36
- got_286_mesg db '80286$'
- got_8086_mesg db '8086$'
- CALL_DATA Data_sruct <>
-
-
- .8086
-
- ;=========================================================================
- ; START OF THE DOS EXTENDER
- ;=========================================================================
- DosStart proc
- mov ax,DOS_CODE
- mov ds,ax
-
- ;========= make sure we running on a 386 or higher =============
-
- ;
- ; Bits 12-15 are always set on the 8086
- ;
-
- pushf ; save flags
- pop bx ; into BX
- mov ax,0fffh ;clear bits 12-15
- and ax,bx
- push ax ; put new flags value onto stack
- popf
- pushf
- pop ax
- and ax,0f000h
- cmp ax,0f000h ; if ax = 0f000h then it's a 8086
- mov dx,offset got_8086_mesg
- jz Not_a_386
-
- ;
- ; Bits 12-15 are always clear on the 80286
- ;
- or bx,0f000h ; try setting bits 12-15
- push bx
- popf
- pushf
- pop ax
- and ax,0f000h
- mov dx,offset got_286_mesg
- jnz Have_a_386_and_above
-
- Not_a_386:
- mov ah,9
- int 21H
- mov dx,offset wrongCPU_mseg
- jmp exit_error
-
- .386p
-
- Have_a_386_and_above:
-
- mov ax,CODE32
- mov fs,ax
- mov fs:[psp_segment],ES ; store psp_segment
-
-
-
- ; DOS loads from bottom to top, thus the end location of this program
- ; up to 9ffffh is free memory.)
-
- ; Get end of program address segment from the stack segment addrress
- mov bx,SP
- shr bx,4
- inc bx
- mov ax,SS
- add bx,ax
- mov FS:Base_Segment,bx ; store this ending address
-
-
-
- ; SET GLOBAL DISCRIPTOR TABLE BASE ADDRESSES
-
-
- ; ===== Set the 32bit CODE & DATA descriptor base address ==========
- mov eax,CODE32
- shl eax,4
- mov word ptr [CODE32_desc +2 ],ax
- mov word ptr [DATA_desc +2 ],ax
- shr eax,16
- mov byte ptr [CODE32_desc +4 ],al
- mov byte ptr [DATA_desc + 4 ],al
-
- ; ===== Set the DOS CODE & DATA descriptor base address ==========
- mov eax,DOS_CODE
- shl eax,4
- mov word ptr [DOS_CODE_desc +2 ],ax
- mov word ptr [DOS_DATA_desc +2 ],ax
- shr eax,16
- mov byte ptr [DOS_CODE_desc +4 ],al
- mov byte ptr [DOS_DATA_desc + 4 ],al
-
- ; ===== Set the program segment prefix base address ==========
- xor eax,eax
- mov ax,fs:[psp_segment]
- shl eax,4
- mov word ptr [PSP_desc +2 ],ax
- shr eax,16
- mov byte ptr [PSP_desc+ 4 ],al
-
- ; ===== Set the PROGRAM ENVIRONMENT base address ==========
- xor eax,eax
- mov ax,es:[2Ch]
- shl eax,4
- mov word ptr [ENVIRONMENT_desc +2 ],ax
- shr eax,16
- mov byte ptr [ENVIRONMENT_desc+ 4 ],al
-
-
- ;------------------------- A 2 0 G A T E -------------------------------
- ; ENABLE THE A20 GATE
- ; If a XMS Driver is installed then use the Driver to enable the A20
- ; If it's done directly (with 8042) ,the XMS Driver will not have
- ; track of the A20 state and usualy ends up hanging the system.
- ;
- ;-----------------------------------------------------------------------------
-
- ; Look for XMS driver installation
- mov ax,4300h
- int 2fh
- cmp al,80h
- jnz No_XMS
- ; ELSE A XMS Driver is installed
- push ES
- mov ax,4310h ; get Driver entry point
- int 2fh
- mov word ptr xms_Driver,bx
- mov word ptr xms_Driver+2,es
- POP ES
-
- ; LOCAL ENABLE A20 GATE
- mov ah,05h
- call xms_Driver
- cmp ax,1
- Jz A20_Controlled ; OK to go protecded mode
- mov dx,offset xms_mesgA20_err
- jmp Exit_Error
-
-
- ;-- Waiting procedures for enabling the A20 directly --
- Wait_until_status_bit0_is_1 proc
- st0_clear:
- xor cx,cx
- in al,64h
- test al,1
- jnz st0_set
- loop st0_clear
- jmp A20_8042_timeout
- st0_set: ret
- endp
-
- wait_until_status_bit1_is_0 proc
- st1set: xor cx,cx
- in al,64h
- test al,2
- jz st1_clear
- loop st1set
- jmp A20_8042_timeout
- st1_clear: ret
- endp
- ;----- jumps here if a time out error in enableing the A20 line ---
- A20_8042_timeout:
- mov dx,offset mesg_TimeOut8042
- jmp Exit_Error
-
-
-
- No_XMS: ;------- Jumps here if no XMS driver is installed ---------------
-
-
- ;--- Must enable A20 directly through the 8042 ( keyboard controller)----
- ; It does this by setting bit 1 of the 8042's output port wich is
- ; inaccessable to the CPU Bus.
-
- cli
- call wait_until_status_bit1_is_0
- mov al,0adh ;send disable keyboard command
- out 64h,al ; viar 8042
-
- call wait_until_status_bit1_is_0
- mov al,0d0h ;Send read 8042 output port cmd
- out 64h,al
-
- call wait_until_status_bit0_is_1
- in al,60h ; read the output port and save it
- push ax
-
- call wait_until_status_bit1_is_0
- mov al,0d1h ; write output port cmd
- out 64h,al
-
- call wait_until_status_bit1_is_0
- pop ax ; write data to the output port
- or al,2
- ; and al,not 2
- out 60h,al ; seting bit 1 > enables A20
-
- call wait_until_status_bit1_is_0
- mov al,0aeh ;enable keyboard again
- out 64h,al
-
- call wait_until_status_bit1_is_0 ; wait a bit more
-
- ; Don't really know if need to wait so many times
-
-
- ;----- check if A20 really is enabled -------------
- mov ax,0FFFFh
- mov es,ax
- mov ax,0
- mov gs,ax
- mov bl,gs:[0] ;Compare location 00000000 to 100000h
- cmp es:[10h],bl ; Check if the same
- jnz A20_enabled ; if not equal then A20 *MUST* be on.
-
- not byte ptr es:[10h] ; Cange byte at adreess 100000h.
- mov bl,es:[10h] ; And compare again
- mov al,gs:[00]
- not byte ptr es:[10h] ; Put back value
- cmp al,bl ; Now see if the same
- jnz A20_enabled
-
-
- ;--- EXIT on A20 error ----
- mov dx , offset mesgA20_err
- jmp Exit_Error ; print error mesg and exit
-
-
- ; --- A20 is deffently enabled ---
- A20_enabled:
-
-
- A20_Controlled: ; The A20 line should be enabled at this point
-
-
- ;-------------------------- A20 ACTIVE ------------------------------------
- ;-----------------------------------------------------------------------------
-
- align 4
- init_P_mode_Stack:
-
- ;════════════════════════════════════════════════════════════════════════
- ;══════════════════ SEE IF NEED TO USE DPMI OR NOT ═════════════════════
- ;════════════════════════════════════════════════════════════════════════
-
- ; USE DPMI TO ENTER PROTECTED MODE
-
- ; Obtain the Real Mode (acually V86) to Protected Mode Switch Entry Point
- mov ax,1687h
- int 2Fh
- and ax,ax
- jnz No_DPMI ; ax = 0 if DPMI is installed
- mov [DPMI_entry],di ; save entry point
- mov [DPMI_entry+2],es
-
- mov fs:[Base_Segment],SS
-
- mov ax,DOS_CODE ;set Tempery Protected Mode stack area
- mov ss,ax
- mov sp,offset init_P_mode_Stack
-
-
- ; Use memory for the DPMI OS private data area
- mov es,fs:[Base_Segment]
- add fs:Base_Segment,si
- cmp fs:Base_Segment,09900h ; See if enough base memory
- mov dx,offset No_Mem_err
- jae Exit_Error
-
- call Allocate_Base ; Set descriptor base to here
-
- mov eax,fs:[xms_usage]
- mov xms_usage_tmp,eax
-
- mov gs,fs:[psp_segment] ;Save environment pointer
- push word ptr gs:[2Ch]
-
-
- ; Call the V86 To Protected Mode Switch Entry Point
- mov ax,1 ; use 32 DPMI ( big stack )
- call dword ptr [DPMI_entry]
- mov dx,offset pmiERr
- Jc Exit_Error
-
-
- ;************** NOW IN DPMI PROTECTED MODE ******************
- ; as a 16 bit but want 32 bit
-
- push ds ; load ES to data segment
- pop es
-
- cmp xms_usage_tmp,0
- jz No_DPMI_MEMORY
-
- ; Get Free memory info
- mov ax,0500h
- mov edi,offset Call_data
- int 31h
- mov word ptr Call_data.c_edx,offset dpmi_free_err
- jc print_error
-
- mov eax,dword ptr Call_data+00h ; first get total avalible.
-
- mov ebx,dword ptr Call_data+08h ; get lockable size (pages)
- cmp ebx,-1 ; if 0ffffffffh then has invalid info
- jz _lesslck
- shl ebx,12 ; convert limit pages into Bytes
-
- cmp eax,ebx ; get the lowest of the two
- jb _lesslck
- mov eax,ebx
- _lesslck:
- ; Only Allocate memory defined in xms_usage
- cmp eax,xms_usage_tmp
- jbe LvDmpiSize
- mov eax,xms_usage_tmp
- LvDmpiSize: mov xms_usage_tmp,eax
-
- mov ebx,eax
- shr ebx,12
- dec ebx
- mov word ptr [XMS_desc+0],bx ; Set xms descriptor Limit
- shr ebx,16
- and bl,0fh
- or byte ptr [XMS_desc+6],bl
-
- ; Allocate memory Block
- mov cx,ax ; Olny allocate the Lockable memory
- shr eax,16
- mov bx,ax
- mov ax,0501h
- int 31h
- mov word ptr Call_data.c_edx,offset dpmi_aloc_err
- jc print_error
- ; Returns BX:CX with the linear address
- mov word ptr [XMS_Desc+2],cx ; Set Desciptor base
- mov byte ptr [XMS_Desc+4],bl
- mov byte ptr [XMS_desc+7],bh
- mov _tmpL_xms_base,CX ; store base address
- mov _tmpH_xms_base,BX
-
- No_DPMI_MEMORY:
- ; Set DPL for all descriptors to CPL
- mov si,offset GDT+8 + 5
- setDPL:
- or byte ptr [si],01100000b
- add si,8
- cmp si, 11*8 +5
- jbe setDPL
-
- ; Allocate 11 descriptors
- mov AX,0000h
- mov CX,11
- int 31h
- mov word ptr Call_data.c_edx,offset erralc_mesg
- jc print_error
-
-
- mov DPMI_Selector,ax
-
-
- ;---- Set Descriptors -----
- xor esi,esi
- set_Descr:
- mov ax,000Ch ; Set Descriptor
- mov bx,DPMI_Selector
- push bx
- mov edi,offset GDT +8
- mov edx,esi
- shl edx,3
- add edi,edx
- int 31h
- mov word ptr Call_data.c_edx,offset errset_mesg
- jc print_error
-
- mov ax,0003h ; Get Next Selector incremental value
- int 31h
- add DPMI_Selector,ax
- inc esi
- cmp esi,11 ; must set 11 descriptors
- jb set_Descr
-
-
- pop DS ; Pop all the selector values that were pushed.
-
- ASSUME DS:CODE32
- MOV DATA_sel,DS
-
- POP CODE32_sel
- POP ENVIRONMENT_sel
- POP PSP_sel
- POP DOS_DATA_sel
- POP DOS_CODE_sel
- POP VIDEO_sel
- POP BASE_sel
- POP XMS_sel
- POP FLAT_CODE32_sel
- POP FLAT_DATA_sel
-
- mov es,[PSP_Sel] ; Restore environment pointer
- pop word ptr es:[02Ch]
-
-
-
-
-
- mov es,DOS_data_sel
- ASSUME ES:DOS_CODE
-
-
- mov eax,ES:xms_usage_tmp
- mov xms_usage,eax ; return store the acual amout allocted
-
- mov eax,dword ptr ES:_tmpL_xms_base
- mov xms_base,eax ; store the base address
-
-
- ; Get the base interrupt values of the PIC's
- mov ax,0400h
- int 31h
- mov ES:PIC1_base,dh
- mov ES:PIC2_base,dl
-
- cli
-
- mov ax,0205h
- mov cx,CODE32_sel
-
- ; set int vector
- setdmpiInts macro in
- mov edx,offset irq&in
- int 31h
- inc bl
- endm
-
- mov bl,es:PIC1_base
- setdmpiInts 0
- x=0
- rept 8
- ; setdmpiInts %x
- x=x+1
- endm
- mov bl,es:PIC2_base
- x=8
- rept 8
- ; setdmpiInts %x
- x=x+1
- endm
-
- mov edx,offset DPMI_EmulateRealInterupt
- mov bl,20h
- int 31h
-
- mov es:DPMI_entry,offset Start32
- mov ax,CODE32_sel
- mov es:DPMI_entry+2,ax
-
-
- ;----- Jump to 32bit mode through CODE 32 descriptor -----
- jmp dword ptr es:DPMI_entry
-
-
- ASSUME DS:DOS_CODE
-
- print_error:
- push Call_data.c_edx
- mov Call_data.c_edx,offset all_DPMI_err
- call print
- pop Call_data.c_edx
- call print
- dpmi_exit:
- mov ah,4ch
- int 21h
-
- print proc near
- mov Call_data.c_eax,0900h
- mov Call_data.c_DS,DOS_CODE
- mov ax,0300h ; sim real int
- mov bl,21h
- mov bh,0
- mov edi,offset call_data
- xor cx,cx
- int 31h
- ret
- endp
- ;==================================================
- ; FINISHED SETTING PROTECTED MODE FOR DPMI
- ;===================================================
-
-
-
-
-
-
- No_DPMI:
- ;════════════════════════════════════════════════════════════════════════════
- ; Jups here if the operating system dos not support DPMI.
- ; Must enter protected mode directly.
- ;
- ;════════════════════════════════════════════════════════════════════════════
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
-
- ; See if in V86 mode Because if so we can't go any further
-
- smsw ax ; Not allowed to use, MOV EAX,CR0
- test al,1
- mov dx,offset _inV86_err
- jnz Exit_Error
-
- ; See if enough base memory for TSS, IDT that get build below.
- ; cmp fs:Base_Segment,09A00h
- ; ja no_mem
-
- cmp xms_driver,00 ; Can't use XMS sevices if got no XMS dirver.
- jz No_XMS_MEMORY
-
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
- ; Use the XMS services to allocate extended memoey
- cmp fs:xms_usage,0 ; if no memory is requested then
- jz Extended_mem_set ; don't bother allocating memory
-
- ; Must have XMS V3.0 to work
- ; mov ah,00 ; Get XMS Version number
- ; call XMS_Driver
- ; cmp ah,3
- ; mov dx,offset xms_vers_err
- ; jnae Exit_Error
-
-
- ; QUERY FREE EXTENDED MEMORY
- MOV AH,08h
- call XMS_Driver ; returns eax with KB free
- and eax,0ffffh
- and al,0FCh ; want page granular
- shl eax,10 ; put KB -> bytes
-
- ;Only Allocate memory defined in xms_usage
- cmp eax,fs:xms_usage
- jbe LvXmsSize
- mov eax,fs:xms_usage
- LvXmsSize: mov fs:xms_usage,eax
-
- mov edx,eax
- shr edx,10
- and dl,0FCh ; want page granular
-
- call set_xms_limit ; set limit to eax
-
- ; ALLOCATE ANY EXTENDED MEMORY BLOCK ( size in eDX )
- mov ah,09h
- call XMS_Driver
- cmp ax,1
- jz xms_alloc_OK
- mov dx,offset xms_alloc_err
- jmp Exit_Error
- xms_alloc_OK:
- mov XMS_handle,dx ; Save XMS block handle
-
-
- ; LOCK THE ALLOCATED EXTENDED MEMORY BLOCK
- mov ah,0ch
- call XMS_Driver
- cmp ax,1
- jz XMS_locked_OK
- mov dx,offset xms_lock_err
- jmp Exit_Error
- XMS_locked_OK:
-
- ; DX:BX has "PHYSICAL" address.
-
- mov word ptr [XMS_Desc+2],bx ;set xms descriptor
- mov byte ptr [XMS_Desc+4],dl ; Base.
- mov byte ptr [XMS_Desc+7],dh
- mov word ptr fs:xms_base,BX ; set base of block
- mov word ptr fs:xms_base+2,DX
-
- jmp Extended_mem_set
-
-
- No_XMS_MEMORY:
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
- ; ALLOCATE EVERY SINGLE BYTE OF EXTENDED MEMORY IF NO XMS DRIVER IS INSTALLED
-
- ; GET EXTENDED MEMORY SIZE FROM CMOS RAM -
- mov al,24 ; get MSB
- out 70h,al
- in al,71h
- shl ax,8
- mov al,23 ; get LSB
- out 70h,al
- in al,71h
-
- and eax,0ffffh
- shl eax,10 ; Kbytes -> bytes
- mov fs:xms_usage,eax
- call set_xms_limit ; set limit to eax
- mov fs:xms_base,100000h ;Always start block at 1MB
- Extended_mem_set:
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
-
- ; Extended memory is allocated at this point
-
- CLI
- in al,21h
- mov oirqMask,al
- in al,0a1h
- mov oirqMask+1,al
-
- ;-- remap IRQ int vectors ---
- mov bl,Pic_Base
- mov bh,Pic_Base+8
- call set_8259intvec
-
- mov al,oirqMask
- out 21h,al
- mov al,oirqMask+1
- out 0A1h,al
-
-
- ; THE INTERRUPT DESCRIPTOR TABLE
-
- ; Use memory for the Interrupt Descriptor Table and the TSS
-
- mov ax,fs:Base_Segment ; Set IDT Reg base
- mov es,ax
- and eax,0ffffh
- shl eax,4
- mov dword ptr IDTR_value+2,eax
- mov fs:[IDT_base],eax
-
- xor eax,eax ; Clear all the new memory
- xor edi,edi
- mov ecx,(8*256 +TSS_Ends+16)/4
- cld
- rep stosd
-
-
- ;--- Build the Interrupt Descriptor Table ---
- mov eax,InterruptGATE_a
- mov edx,InterruptGATE_B
- xor cl,cl
- xor si,si
- @MakeIDT:
- mov es:[si],eax ; Put into memory
- mov es:[si+4],edx ; Put into memory
- add si,8
- dec cl
- jnz @MakeIDT
-
-
- ;---- Set interrupt vector 31h ------
- mov word ptr es:[31h*8],offset MyDPMI_services
-
- ;---- Set interrupt vector 21h ------
- mov word ptr es:[21h*8],offset Go_REAL_MODE
- mov word ptr es:[21h*8+2], Dos_Code_desc - GDT
-
- ; ---- Set the 16 hardware and 16 exception interrupt handlers --------
- setexecp macro n
- mov word ptr es:[n*8],offset _386exception_&n
- mov word ptr es:[(Pic_Base+n)*8],offset firstIRQ&n
- endm
- x=0
- rept 16
- setexecp %x
- x=x+1
- endm
-
- ; ---- Set general protection exception handler interrupt --------
- mov word ptr es:[13*8],offset General_Exeption_Handler
-
- ; ---- Set real mode interrupt emulation handler interrupt --------
- mov word ptr es:[20h*8],offset My_EmulateRealInterupt
-
-
- ;-- Build the Task State Segment --
- add fs:Base_Segment,80h
- mov es,fs:Base_Segment
-
-
- xor eax,eax ; Get TSS base address
- mov ax,es
- shl eax,4
-
- mov fs:tss_Level0ESP,eax ;Save address of level0 ESP TSS field
- add fs:tss_Level0ESP,offset tss_esp0 ;Need to use it latter
-
- mov MyMain_TSS_Desc+2,ax ; Load Base address of TSS descriptor
- shr eax,16
- mov byte ptr MyMain_TSS_Desc+4,al
-
-
-
- ;Load important TSS fields
- ;
- ; NOTE: The level0 stack field is set when real mode interrupt emulation
- ; is called
- mov es:tss_iobase, 068h
- mov es:tss_ioend,11111111b
-
- ; TSS is now built . Time to set the base descriptor base address just
- ; after the TSS and IDT are located.
-
- add fs:Base_Segment,(TSS_Ends+15)/16 ;add to Base_Segment
- call Allocate_Base
-
- CLI ; Can't have interrupts anymore
-
- ; Load the Interrupt descriptor table register
- lidt qword ptr IDTR_value
-
- ; Load the Global descriptor table register
- mov EAX,DOS_CODE
- shl EAX,4
- add dword ptr GDTR_value+2 , EAX
- lgdt qword ptr GDTR_value
-
- ; Enter Protected Mode
- mov eax,CR0
- or al,1 ; Set PE bit of CR0
- mov CR0,eax
-
-
- db 0EAh ; Jump to 32bit mode through CODE 32 descr
- dw offset Setup_Pmode , CODE32_Desc - GDT
- ;--------------------------------------------------------------------------
- ; END OF PROTECTED MODE INITALIZATION
- ;--------------------------------------------------------------------------
-
- ;----------------------------------------------------------------------------
- ;───────────────────── INTERNAL ROUTINES ───────────────────────────────────
- ;----------------------------------------------------------------------------
- assume ds:dos_code
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
- set_xms_limit proc
- ; Set the xms descriptor limit.
- shr eax,12
- dec eax
- mov word ptr [XMS_Desc+0],ax ; set limit [0..15]
- shr eax,16
- or byte ptr [XMS_desc+6],al ; limit [16..19]
- ret
- endp
-
-
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
- Allocate_Base proc
- mov ax,fs:Base_Segment ; Set BASE data descriptor to this
- and eax,0ffffh
- shl eax,4
- mov word ptr [Base_Desc +2 ],ax
- shr eax,16
- mov byte ptr [Base_Desc +4 ],al
- ret
- ENDP
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
-
-
-
-
-
- dosstart endp
- DOS_CODE ENDS
-
-
- CODE32 SEGMENT PARA PUBLIC USE32
- assume DS:CODE32 , CS:CODE32 , ES:CODE32 ; Flat memory model segment
-
- align 4
- CODE32_sel dw CODE32_desc - gdt
- public CODE32_sel
- DATA_sel dw data_desc - gdt
- public DATA_sel
- VIDEO_sel dw video_desc - gdt
- public VIDEO_sel
- FLAT_DATA_sel dw FLAT_DATA_desc - gdt
- public FLAT_DATA_sel
- FLAT_CODE32_sel dw FLAT_CODE32_desc - gdt
- public FLAT_CODE32_sel
- XMS_sel dw XMS_desc - gdt
- public XMS_sel
- BASE_sel dw BASE_desc - gdt
- public BASE_sel
- PSP_sel dw PSP_desc - gdt
- public PSP_sel
- ENVIRONMENT_sel dw ENVIRONMENT_desc - gdt
- public ENVIRONMENT_sel
-
- align 4
- Real_GS dd 0
- public Real_GS
- Real_FS dd 0
- public Real_FS
- Real_DS dd 0
- public Real_DS
- Real_ES dd 0
- public Real_ES
- Real_SS dd V86_Stack ; Setup initial V86 stack
- public Real_SS
- Real_SP dd V86_stack_size
- public Real_SP
-
-
-
-
- global xms_usage :dword
- global xms_base :dword
- global Base_Segment :word
- global PSP_segment :word
-
- global START32 :near
- global IRQ0 :near
- global IRQ1 :near
- global IRQ2 :near
- global IRQ3 :near
- global IRQ4 :near
- global IRQ5 :near
- global IRQ6 :near
- global IRQ7 :near
- global IRQ8 :near
- global IRQ9 :near
- global IRQ10 :near
- global IRQ11 :near
- global IRQ12 :near
- global IRQ13 :near
- global IRQ14 :near
- global IRQ15 :near
-
-
-
- align 4
- tss_Level0ESP dd 0
- V86_Lv0_ESPSave dd 10h dup (0) ; TSS level 0 ESP save for V86 calls.
- V86_Lv0_SSSave dw 10h dup (0) ; TSS level 0 SS save for V86 calls.
- IDT_base dd 0
- _tmp0_ dd 0
- _tmp1_ dd 0
- _tmp2_ dd 0
- tmp_Real_Flags dw 0
- V86_irq_Count db 0
-
- DOS_CODE_sel dw DOS_CODE_Desc - GDT
- DOS_DATA_sel dw DOS_DATA_Desc - GDT
-
-
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
- Setup_Pmode: ; first 32bit protected mode point
- ;!! MUST LOAD SEGMENT REGISTERS VALID SELECTORS !!
- mov ax,cs:[Data_SEL]
- mov es,ax
- mov fs,ax
- mov gs,ax
- mov ds,ax
-
- mov ax,MyMain_TSS_Desc - GDT ; Set TR to any valid TSS
- ltr ax
-
- mov ss,[flat_data_sel] ; Setup initial Protected mode stack
- mov esp,seg init_P_mode_Stack
- shl esp,4
- add esp,offset init_P_mode_Stack
-
- db 0eah ; jump to start of main program
- dd offset start32 , CODE32_desc - gdt
-
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
- ;************** EXCEPTION HANDLERS ... *********************
- Exception:
- mov ax,DATA_desc - gdt
- mov ds,ax
- mov es,Flat_data_sel
- mov ss,DATA_sel
- mov fs,FLAT_data_sel
- mov gs,FLAT_data_sel
- mov esp,100h
- mov dx,offset unknown_int_exit_mesg
- mov ebp,'ERRA' ; Exit with error code
- int 21h
-
- getexeec macro n
- _386exception_&n&:
- mov dx,offset e_&n
- jmp All_exceptions
- endm
- x=0
- rept 16
- getexeec %x
- x=x+1
- endm
-
- ;═══════════════════════════════════════════════════════════════════════════
- All_exceptions:
- ; jmp _Pmode_exit_error
-
- ;∙·∙·∙·∙·∙·∙·∙·∙∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
- _Pmode_exit_error:
- cli
- mov ss,CS:[DATA_SEL] ; set up some stack to exit
- mov esp,offset CODE32_end_of + 100h
- mov ebp,'ERRA'
- int 21h ; Exit with error
-
- set1STirqm macro nt
- local not_v86_irq_
- firstIRQ&nt:
- push offset irq&nt
- jmp check_HardwareINT
- endm
-
- x = 0
- rept 16
- set1STirqm %x
- x=x+1
- endm
-
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
- ;═══════════════════════════════════════════════════════════════════════════
- check_HardwareINT proc near
- test dword ptr [esp+3*4],020000h
- jz not_v86_irq ; jump if IRQ was from P.mode
-
- push eax ; IRQ was from V86 mode.
- mov ds,cs:DATA_sel
- mov eax,[esp+5*4] ; Put new V86 stack pointer
- mov [Real_SP],eax
- mov eax,[esp+6*4] ; Put new V86 stack segment
- mov [real_SS],eax ; we Don't care about ES,DS,FS & GS
- pop eax
-
-
- mov fs,[esp+10*4] ; return segment reg selectors
- mov ds,[esp+11*4] ; as they were before entering V86
- mov gs,[esp+12*4]
- mov es,[esp+13*4]
- not_v86_irq:
- ret ; Go to IRQ handler
- endp
-
-
-
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
- ;═══════════════════════════════════════════════════════════════════════════
- ;------- The General Exception Handler ( Int 13 ) ---------------
- ;═══════════════════════════════════════════════════════════════════════════
- General_Exeption_Handler:
-
- test dword ptr [esp+4*3],0020000h ; Test VM bit
- jnz V86_Monitor
- mov dx,offset e_13 ; if exception from p.mode then terminate.
- jmp All_Exceptions
-
-
-
- ;*****************************************
- ;********* Virtual 8086 exception handler *********
- ;*****************************************
- V86_Monitor proc
- add esp,4 ; delete the undocumented pushed error code ??
- pushad
- mov fs,CS:Flat_DATA_SEL
-
- ;;; Find what instruction caused the exception ;;;;
- movzx ebx,word ptr [esp+36] ; Get CS from stack
- shl ebx,4
- add ebx,[esp+32] ; Get EIP form stack
- inc dword ptr [esp+32]
- mov dl,fs:[ebx] ; Get opcode
- mov al,3
- cmp dl,0cch ; see if INT 3 Breakpoint
- je short DO_v86int ; if so do it's int
- mov al,4
- cmp dl,0ceh ; See if INTO
- je short Do_v86int ; if so do it's int
- cmp dl,0cdh ; see if INT n
- jne V86exc ; if not then exception
- inc dword ptr [esp+32] ; It must be a INT n instruction
- mov al,fs:[ebx+1] ; get INT n number
-
- cmp al,0FFh ; If int 0ffh and Then
- jz Exit_V86 ; return to main Program
-
- cmp al,15h
- jnz NoXmsToCopy
-
- cmp byte ptr ss:[esp+7*4+1],87h ; Detect if v86 application
- jz Emulate_XMS_COPY ; wants to copy extended mem
- ; i.e ah = 87h
-
- NoXmsToCopy:
-
- public DO_v86int
-
- ;****; Emulate V86 interrupt ;****;
- DO_v86int: ; Do interrupt "AL" for V86 task
- movzx ebx,al
- shl ebx,2 ; Get 8086 Int Vector
- movzx edx,word ptr [esp+(8+4)*4] ; Get SS stored on stack
- shl edx,4
- sub word ptr [esp+(8+3)*4],6 ; Sub ESP stored on stack by 6
- add edx,[esp+(8+3)*4] ; edx = Phyical Address of V86 stack
- mov ax,[esp+(8+2)*4] ;Put FLAGS from Prev.0 Stack to V86 stack
- mov fs:[edx+4],ax
- mov ax,[esp+(8+1)*4] ;Put CS from Prev.0 Stack to V86 stack
- mov fs:[edx+2],ax
- mov ax,[esp+(8+0)*4] ;Put IP from Prev.0 Stack to V86 stack
- mov fs:[edx],ax
- mov eax,fs:[ebx] ; Get real mode int vector (CS:IP)
- mov [esp+(8+0)*4],ax ; Store it on prev. 0 Stack
- shr eax,16
- mov [esp+(8+1)*4],ax
- ret86: and word ptr [esp+(8+2)*4],0fcffh ; Clear DF & IF flags on prev. 0 Stack
- popad
- iretd ; Return to V86 mode
-
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
- ; Stop emulating V86 mode interrupts and return to main program.
- ; Jumps here when v86 code causes an exception from the Int 0FFh instuction
- Exit_V86:
- mov DS,CS:DATA_SEL ; Need to use data segment
-
- popad
- mov [_tmp0_],eax
- mov [_tmp1_],ebx
- mov [_tmp2_],ecx
- ; Pop off all the stuff pushed from V86 exception.
- add esp,8 ; ignore EIP & CS
- pop eax ; Get Efplags
- and eax,NOT 23000h ; Clear VM bit
- mov [esp+13*4],eax ; Put onto stack
- pop [Real_SP]
- pop [Real_SS]
- pop [Real_ES]
- pop [Real_DS]
- pop [Real_FS]
- pop [Real_GS]
-
-
- ;Must return the TSS Level 0 ESP to the previous V86 call's Level 0 ESP value.
- dec V86_irq_Count
- movzx eax,V86_irq_Count
- sub al,1
- jl jH98_V86 ; Only do it if a V86 call inside a call.
- mov bx,[V86_Lv0_SSSave +EAX*2] ; Get previous TSS Lv0 SS
- mov eax,[V86_Lv0_ESPSave+EAX*4] ; Get previous TSS Lv0 ESP
- mov ecx,[tss_Level0ESP] ; Get address of TSS Lv0 ESP
- mov fs:[ecx],eax ; Load ESP.
- mov fs:[ecx+4],bx ; Load SS.
- jH98_V86:
-
- mov eax,[_tmp0_] ;Return temperaly saved registers
- mov ebx,[_tmp1_]
- mov ecx,[_tmp2_]
-
- pop fs ds ; pop seg reg from the entering V86
- pop gs es ; call; see My_EmulateRealInterupt proc
-
- iretd ; Return to main program and continue.
-
-
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
- ;═══════════════════════════════════════════════════════════════════════════
- ; Emulate the SYSTEM BIOS - COPY EXTENDED MEMORY Srevice for V86 application
- ; INT 15 & AH = 87h
- ;═══════════════════════════════════════════════════════════════════════════
-
- Emulate_XMS_COPY: ; A20 gate always seems to be on ?
-
-
- mov ecx,[esp+(6)*4] ; Get Number of words to copy
- and ecx,0ffffh
- cmp cx,8000h
- ja _error_1587
- shr ecx,1
-
- ; CALCULATE THE LOCATION OF THE GDT.
- xor eax,eax
- mov ax,[esp+(8+5)*4] ; Get ES
- shl eax,4
- movzx ebx,word ptr [esp+(1)*4] ; Get SI
- add eax,ebx ;EAX has location of GDT
-
- mov esi,fs:[eax+7h+10h]
- shl esi,24
- mov edx,fs:[eax+2h+10h] ; Get 32bit Source address
- and edx,0ffffffh
- add esi,edx
-
- mov edi,fs:[eax+7h+18h]
- shl edi,24
- mov edx,fs:[eax+2h+18h] ; Get 32bit Destination address
- and edx,0ffffffh
- add edi,edx
-
- push fs
- pop es
- cld
- rep movs dword ptr es:[edi],es:[esi] ; do the transfer
-
- mov byte ptr [esp+(7*4)+1],00 ;return AH = 0
-
- and byte ptr [esp+(8+2)*4],NOT 01 ; Clear Carry flag on prev. 0 Stack
-
- jmp ret86
-
- _error_1587:
- or byte ptr [esp+(8+2)*4],01 ; Set Carry flag on prev. 0 Stack
- mov byte ptr [esp+(7*4)+1],03 ;return AH
- jmp ret86
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
-
-
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
- ;═══════════════════════════════════════════════════════════════════════════
- V86exc:
- mov dx,offset _V86_illigal_err
- jmp _Pmode_exit_error
-
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
-
- ;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡
-
-
- endp
-
-
-
- ;**********************************
- MyDPMI_services:;*********************
- ;**********************************
- cmp ax,0205h
- jz SetPmodeintVector
- cmp ax,0204h
- jz GetPmodeintVector
- cmp ax,0400h
- jz GetVersion
- iretd
-
- SetPmodeintVector:
- push edi ebx fs ds
- mov ax,data_desc - gdt
- mov ds,ax
- mov fs,[flat_DATA_sel]
- movzx ebx,bl
- mov edi,ebx
- sub edi,Pic_Base ; No allowed to set the hardware int vectors
- cmp edi,15
- jbe Set_irq_vec
- mov edi,[idt_base]
- mov fs:[ebx*8+edi],dx ; offset 0..15
- SHR EDX,16
- mov fs:[ebx*8+edi+6],dx ; offset 16..32
- mov fs:[ebx*8+edi+2],cx ; Code Selector
- pop ds fs ebx edi
- iretd
-
- GetPmodeintVector:
- push edi ebx fs ds
- mov ax,data_desc - gdt
- mov ds,ax
- mov fs,[flat_DATA_sel]
- movzx ebx,bl
- shl ebx,3
- add ebx,[idt_base]
- mov edi,[idt_base]
- mov dx,fs:[ebx+6] ; Get offset 16..32
- SHL EDX,16
- mov dx,fs:[ebx] ; Get offset 0..15
- mov cx,fs:[ebx+2] ; Get Code Selector
- ivec22: pop ds fs ebx edi
- iretd
-
- Set_irq_vec:
- stc
- jmp ivec22
-
-
- GetVersion: ; Emulate DPMI service Get Version
- ; only need to emulate the returned values of PIC bases
- mov dh,PIC_base
- mov dl,PIC_base+8
- iretd
-
- ;═══════════════════════════════════════════════════════════════════════════
- ; PROCEDURES TO EMULATE REAL MODE INTERRUPT
- ; FOR BOTH DPMI AND MY VERSIONS
- ;═══════════════════════════════════════════════════════════════════════════
- DPMI_EmulateRealInterupt proc far
- push ES DS ; save used seg registers
- mov DS, CS:[data_sel] ; Load DS data seg regs.
- push ax ; Push a 2 bytes to keep stack dword aligned for speed.
- push 0 ; Push the real mode SS:SP. If zero, DPMI set it up.
- push 0 ; ignore CS:IP not used by DPMI
- push word ptr [Real_GS]
- push word ptr [Real_FS]
- push word ptr [Real_DS]
- push word ptr [Real_ES]
- push word ptr [esp+4*6+2] ; get the flag register from INT 20h
- pushad
- mov edi,esp
- push ss
- pop es
- mov ax,0300h
- mov bl,[esp+4*18] ; get the V86 int number that was pushed
- xor ecx,ecx
- xor bh,bh
- int 31h ; Use the DPMI service
- popad
- pop word ptr [esp+14+6*4] ; return eflags
- pop word ptr [Real_ES]
- pop word ptr [Real_DS]
- pop word ptr [Real_FS]
- pop word ptr [Real_GS]
- add esp,10 ; Ignore CS:IP ,SS:SP and 2 bytes.
- pop DS ES ; Restore used seg registers.
- iretd ; Return from INT 20h
- ENDP
-
-
- ;∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·∙·
- My_EmulateRealInterupt proc far
- push es gs ds fs ; save segment registers.
-
- mov ds,cs:[data_sel] ; Load seg regs.
- mov fs,[flat_data_sel]
-
- mov _tmp0_,eax ; temperly save eax.
-
- mov eax,[esp+4*6] ; Get flags from stack.
- mov [tmp_Real_Flags],ax ; Temperaly saved them.
-
- mov eax,[tss_Level0esp] ; Set Level 0 stack to current SS:ESP
- mov fs:[eax],esp
- mov fs:[eax+4],SS
-
- movzx eax,V86_irq_Count ; Save the TSS LV0 Stack
- mov [V86_Lv0_ESPSave+EAX*4], ESP
- mov [V86_Lv0_SSSave+EAX*2], SS
- inc V86_irq_Count
-
- pushfd ; Clear Nested Task, ( bit 14 )
- pop eax ; If set then the 386 will
- and ah,10111101b ; use the back link field in the TSS
- push eax ; to switch tasks. A no no.
- popfd
-
-
- mov al,[esp+4*7] ; Get the V86 interrupt number
- mov byte ptr [ V86Int_instuction+1],AL ; put it
-
- push [Real_GS] ; GS
- push [Real_FS] ; FS
- push [Real_DS] ; DS
- push [Real_ES] ; ES
- push [Real_SS] ; SS
- push [Real_SP] ; ESP
- mov eax,00023000h ; IOPL = 3 , VM = 1
- or ax,[tmp_Real_Flags]
- push eax ; EFLAGS
- mov eax,seg TASK0_V86
- push eax ; CS
- mov eax,offset TASK0_V86
- push eax ; EIP
- mov eax,_tmp0_ ; Return origonal EAX value
- IRETD ; Enter V86 mode !!!!!
- endp
- ;¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡
-
- TASK0_V86:
-
- V86Int_instuction: int 000h
- int 0ffh ; Tell V86 exception handler to exit.
- CODE32_end_of:
- CODE32 ENDS
-
- V86_STACK SEGMENT public stack 'stack' USE16
- db V86_stack_size dup (?)
- V86_STACK ENDS
-
-
- END DosStart
-