home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Unsorted BBS Collection
/
thegreatunsorted.tar
/
thegreatunsorted
/
programming
/
asm_programming
/
DOS32.ASM
< prev
next >
Wrap
Assembly Source File
|
1993-10-17
|
48KB
|
1,710 lines
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