COMMENT $

                      DOS32           Version 0.1

           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.



   Written by Adam Seychell 	SEP-1993

   email   s921880@minyos.xx.rmit.oz.au



$

.386p   		; Enable "REAL"  CPU instuctions.

Normal_stack	equ 200h	; Size of your protected mode stack
V86_stack_size 	equ 200h	; Size of stack for V86 interrupt calls

PIC_Base	equ 80h		; Base interrupt address for the 8259s


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


RealData struc
Real_GS		dd 0
Real_FS		dd 0
Real_DS		dd 0
Real_ES		dd 0
Real_SS		dd 0
Real_ESP	dd 0
tmp_Real_intNum	db 0
ends

DATA32	SEGMENT PUBLIC 'DATA'	USE32

global	CODE32_sel	:word
global	CODE16_sel	:word
global	DATA_sel	:word
global	TheSTACK_sel	:word
global	VIDEO_sel	:word
global	FLAT_DATA_sel	:word
global	FLAT_CODE32_sel	:word
global	XMS_sel		:word
global	BASE_sel	:word
global	PSP_sel		:word
global	xms_usage	:dword
global	xms_base	:dword
global	Base_Segment	:word
global	PSP_segment	:word
ENDS


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

DATA32	SEGMENT PUBLIC 'DATA'	USE32

DOS_CODE_sel	dw DOS_CODE_Desc - GDT
DOS_DATA_sel	dw DOS_DATA_Desc - GDT

tss_Level0ESP	dd 0
V86_Lv0_StkSave	dd 10h dup (0)     ; TSS level 0 ESP save for V86 calls.
IDT_base	dd 0
_tmp0_		dd 0
_tmp1_		dd 0
tmp_Real_Flags	dd 0
V86_irq_Count	db 0

DATA32 ENDS



CODE16	SEGMENT PUBLIC 'CODE' USE16
CODE16	ends

DATA16	SEGMENT PUBLIC 'DATA' USE16
DATA16	ends

CODE32	SEGMENT PUBLIC 'CODE' USE32
assume	DS:DATA32 , CS:CODE32 , es:DATA32


;ЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗ
Setup_Pmode:   		; first 32bit protected mode point


        sti
	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,TheStack_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:
	mov	esp,100h
;	jmp _Pmode_exit_error

;ЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗ
_Pmode_exit_error:
	mov	ax,TheSTACK_Desc - GDT
        mov	ss,ax
	mov	ebp,'ERRA'
        int	21h		; Exit with error


set1STirqm macro nt
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	eax,[esp+5*4]	 	; Put new V86 stack pointer
        mov	SS:[real_ESP],eax
        mov	eax,[esp+6*4]		; Put new V86 stack segment
        mov	SS:[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 ---------------
;ммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммм
General_Exeption_Handler:

        test dword ptr [esp+4*3],0020000h	;	Test VM bit
	jnz V86_Monitor
        mov dx,offset e_13
        jmp All_Exceptions



     ;*****************************************
;*********  Virtual 8086 exception handler *********
     ;*****************************************
V86_Monitor proc
        add	esp,4	; delete the undocumented pushed error code
        pushad
	mov	ax,Flat_DATA_Desc - GDT
        mov	fs,ax

	 ;;; 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:

 ;****; 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
        popad			; Clear DF & IF flags on prev. 0 Stack
        iretd                           ; Return to V86 mode

;ЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗ
Exit_V86:
	mov	ax,DATA_Desc - GDT
	mov	ds,ax
        popad
        mov	[_tmp0_],eax
        mov	[_tmp1_],ebx

        add	esp,8				; ignore EIP & CS
        pop	word ptr [esp+12*4+2]           ; Get V86 EFLAGS onto
        add	esp,2				;  stack from the int 20h
        pop	ss:[Real_ESP]
        pop	ss:[Real_SS]
	pop	ss:[Real_ES]
	pop	ss:[Real_DS]
	pop	ss:[Real_FS]
	pop	ss:[Real_GS]


;Must return the TSS Level 0 ESP to the previous V86 call's Level 0 ESP value.
        movzx	eax,V86_irq_Count
        sub	al,1
        jle   jH98_V86		; Only do it if a V86 call inside a call.
 	  dec	V86_irq_Count
	  dec	eax				
          mov	eax,[V86_Lv0_StkSave+EAX*4]     ; Get previous TSS Lv0 ESP
          mov	ebx,[tss_Level0ESP]             ; Get address of TSS Lv0 ESP
          mov	fs:[ebx],eax 		        ; Load it.
jH98_V86:

        mov	eax,[_tmp0_]		;Return temperaly saved registers
        mov	ebx,[_tmp1_]

	pop     fs ds 		; pop seg reg from the entering V86
	pop	gs es		; call; see  My_EmulateRealInterupt proc

        iretd			; Return to main program


;ЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗ
;ммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммм
; Emulate the SYSTEM BIOS - COPY EXTENDED MEMORY Srevice for V86 application
; INT 15  & AH = 87h
;ммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммм

COMMENT $

NOTE.
  There is a problem with the BIOS int 15h ah = 87 emulation
  when HIMEM.SYS calls it to transfer a XMS block while MSDOS is loaded
  in the Upper Memeory Block. It seems to be called with the location
  of the GDT ( for int 15 ah=87 ) in the ROM area. This gives an invalid GDT.
 When DOS is loaded into convention memory everything work fine because
  HIMEM.SYS returns a valid GDT on this call.
$

Emulate_XMS_COPY:		; A20 gate always seems to be on ?
;	mov	ax,DATA_Desc - GDT
;	mov	ds,ax

	mov	ecx,ss:[esp+(6)*4]	; Get Number of words to copy
        and	ecx,0ffffh
	cmp	cx,8000h
        ja _error_1587
	shr	ecx,1

        xor	eax,eax
        mov	ax,ss:[esp+(8+5)*4]		; Get ES
        shl	eax,4
        add     ax,ss:[esp+(1)*4]		; Get SI
        adc	eax,0			; EAX has location of GDT
        mov	ebx,eax
;         sub	ebx,0f0000h
;         cmp	ebx,010000h
;         ja _error_1587
;        push    eax
        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


;       write 'Source ',12
;        mov edx,esi
;        call hex_dword

;        write ' Destination ',12
;        mov edx,edi
;        call hex_dword

;        write ' Cout ',12
;        mov edx,ecx
;        shl edx,2
;        call hex_dword

;        write ' GDT ',12
;        pop	edx
;        call hex_dword

;        write ' CS:EIP ',10
;	movzx edx,word ptr [esp+36]	; Get CS from stack
;	shl edx,4
;	add edx,[esp+32]		; Get EIP form stack
;        call hex_dword
;
;        write 'int 15 vect',11
;	movzx edx,word ptr fs:[15h*4+2]
;	shl edx,4
;	add dx,fs:[15h*4]
;        adc edx,0
;        call hex_dword
;        writeln

	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

;ммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммм
;		PROCEDURE TO EMULATE REAL MODE INTERRUPT
;
;ммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммм
DPMI_EmulateRealInterupt proc far
	push	ax
	push  0 0 0
	push	word ptr ss:[Real_DS]
        push	word ptr ss:[Real_ES]
        push	word ptr [esp+18+8]
        pushad
	mov	edi,esp
        push es
	push ss
        pop es
        mov	ax,0300h
        mov	bl,ss:[tmp_Real_intNum]
        xor	ecx,ecx
        int	31h     			; Use the DPMI service
        pop es
        popad
        pop	word ptr [esp+26]		; return eflags
        pop	word ptr ss:[Real_ES]
        pop	word ptr ss:[Real_DS]
        add	esp,14
        iretd
ENDP


;ЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗ
My_EmulateRealInterupt proc far

	push	es gs ds fs		; save segment registers.
        push eax

        mov	ax,data_desc  - gdt	; Load seg regs.
        mov	ds,ax
	mov	fs,[flat_data_sel]

        pop	_tmp0_			; temperly save  eax.

        mov	eax,[esp+4*6]		; Get flags from stack.
        mov 	[tmp_Real_Flags],eax	; Temperaly saved them.

	mov	eax,[tss_Level0esp]	; Set Level 0 stack to current ESP
        mov	fs:[eax],esp

        movzx	eax,V86_irq_Count
        mov	[V86_Lv0_StkSave+EAX*4], ESP
	inc	V86_irq_Count

        pushfd				; Clear Nested Task, ( bit 14 )
        pop eax				; If set then the 386 will
        and ah,10111111b		; use the back link field in the TSS
        push eax			; to switch tasks. A no no.
        popfd

        mov	eax,seg V86IntNumber
        shl	eax,4

        push ebx			; Load the V86 interrupt number
        mov bl,SS:[tmp_Real_intNum]			; get it
	mov byte ptr fs:[offset V86IntNumber+1+EAX],BL	; put it
        pop ebx
	push	SS:[Real_GS]			; GS
	push	SS:[Real_FS]			; FS
	push	SS:[Real_DS]			; DS
	push	SS:[Real_ES]			; ES
	push	SS:[Real_SS]			; SS
	push	SS:[Real_ESP]			; ESP
	mov	eax,00023000h           	; IOPL = 3 , VM = 1
        or	ax,word ptr [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:

V86IntNumber:  	int 000h
	        int 0ffh	; exit V86 mode

CODE32 ENDS









DOS_CODE	SEGMENT PUBLIC 'CODE' USE16
assume CS:dos_CODE , DS:DOS_CODE , fs:data32

;
; 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		ends


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,0,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,0,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,0,0,0,01h>		; G,B,0,avl,Limit[19..16]
	        db 0				; Base[31..24]


;	Data DESCRIPTOR	 for the STACK
TheSTACK_Desc	dw Normal_stack-1	 	; 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,1,0,0,00h>		; 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 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]

Code16_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,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,0,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

;----------------------------------------------------------------------------
;ддддддддддддддддддддд  INTERNAL ROUTINES ддддддддддддддддддддддддддддддддддд
;----------------------------------------------------------------------------

;ЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗ
;ЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗ
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 proteceded mode and restore hardware configeration.
; Then exits back to MSDOS. ( only for non-DPMI )
;ддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддддд
	cli

	mov al,00110100b	; SLOW DOWN TIMER
	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
        mov	ax,DOS_Data_Desc - GDT
        mov	ss,ax
        mov	es,ax
        mov	ds,ax
        mov	fs,ax
        mov	gs,ax


        cli
        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

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,TheStack		; 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
        out 20h,al
        out 0a0h,al

        in al,60h

        cmp	ebp,'ERRA'
        jnz normal_terminate
			; Print error message if need to
                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
        int	21h
assume ds:dos_code

endp

;---------------- finished exiting routine -------------------------

COMMENT $

 All data below this point of this segment is not needed after initalization.
 Thus it can be (next Version) over witten after all the setting up is done.
  This saves a bytes.  See the 32bit setup code at "Setup_Pmode:" above.

  >->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->->
$

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,' 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

CALL_DATA	Data_sruct <>


DosStart proc
        mov	ax,DATA32
        mov	fs,ax
        mov	fs:[psp_segment],DS		; store psp_segment

	mov	ax,DOS_CODE
        mov	ds,ax

         ; Get end of program address segment
	mov	bx,SP
	shr	bx,4
	inc     bx
	mov	ax,SS
	add	bx,ax
	mov	FS:Base_Segment,bx



; SET GLOBAL DISCRIPTOR TABLE Base Values ( USEING THE MACRO )

Fix_Desc_BASE Macro  Descriptor,RealSeg
        xor eax,eax
	mov ax,RealSeg
        shl eax,4
        mov word ptr [Descriptor  +2 ],ax
        shr eax,16
        mov byte ptr [Descriptor+ 4 ],al
ENDM

	Fix_Desc_BASE  PSP_desc		,fs:[psp_segment]

	Fix_Desc_BASE  CODE32_desc	,CODE32

	Fix_Desc_BASE  CODE16_desc	,CODE16

	Fix_Desc_BASE  DATA_desc	,DATA32

	Fix_Desc_BASE  DOS_CODE_desc	,DOS_CODE

	Fix_Desc_BASE  DOS_DATA_desc	,DOS_CODE

	Fix_Desc_BASE  TheStack_desc 	, TheSTACK



;------------------------- 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_XMS_OK
		mov dx,offset xms_mesgA20_err
                jmp exit_InitError
A20_XMS_OK:

                 jmp A20_Controlled	    	; ready to go protecded mode

;-- 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

exit_InitError:	mov ah,9	; Prints error mesage and terminates
		int 21h
		call free_XMS_memory
		mov ah,4ch
		int 21h


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




;----- 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]
        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_InitError	; print error mesg and exit


; --- A20 is deffently enabled ---
A20_enabled:


A20_Controlled:    ; The A20 line should be enabled at this point


;-------------------------- A20 ACTIVE ------------------------------------
;-----------------------------------------------------------------------------

;мммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммм
;мммммммммммммммммм SEE IF NEED TO USE DPMI OR NOT  ммммммммммммммммммммм
;мммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммммм

;	 USE  DPMI TO ENTER  PROTECTED  MODE

	; Obtain the Real (V86) to Protected Mode Switch Entry Point
        mov	ax,1687h
        int	2Fh
        and	ax,ax
        jnz   No_DPMI	
	mov [DPMI_entry],di		; DPMI is installed
	mov [DPMI_entry+2],es

        mov	fs:[Base_Segment],SS

        mov	ax,theStack    		; use Protected Mode stack area
        mov	ss,ax
        mov	sp,Normal_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
        jae no_mem

 	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]
        Jc Cant_Enter_dmpiPMode


	;************** 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+08h	; get lockable size (pages)
        shl	eax,12			; convert limit  pages into Bytes

		; 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 + 13
setDPL:
	or	byte ptr [si],01100000b
        add	si,8
        cmp	si, 12*8 +5
        jbe setDPL

; Allocate 12 descriptors
	mov	AX,0000h
	mov	CX,12
        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,12		; must set 12 descriptors
        jb set_Descr

        pop DS		; Pop all the selector values that were pushed.

ASSUME  DS:DATA32
        MOV DATA_sel,DS

	POP  CODE16_sel
	POP  CODE32_sel
	POP  PSP_sel
	POP  DOS_DATA_sel
	POP  DOS_CODE_sel
	POP  TheStack_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

        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
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	ss,[TheStack_sel]
        mov	ss:[Real_ESP],0
        mov	ss:[Real_SS],0

	mov	esp,Normal_Stack

        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



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
        jz in_Real_mode
              mov dx,offset _inV86_err
              jmp exit_InitError

in_Real_mode:
       ;	See if enough base memory
        cmp fs:Base_Segment,09A00h
        ja no_mem

	cmp xms_driver,00
        jz No_XMS_MEMORY

;ЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗ
; Use the XMS services to allocate extended memoey
	        cmp	fs:xms_usage,0
	        jz Extended_mem_set

               ; Must have XMS V3.0 to work
               mov	ah,00		; Get XMS Version number
               call	XMS_Driver
               cmp	ah,3
               jae xms_V3
;              mov dx,offset xms_vers_err
;              jmp exit_InitError
xms_V3:


             	; 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_allod
		 mov dx,offset xms_alloc_err
                jmp exit_InitError
xms_allod:
                mov	XMS_handle,dx

                ; LOCK THE ALLOCATED EXTENDED MEMORY BLOCK
		mov	ah,0ch
                mov	dx,XMS_handle
                call	XMS_Driver
                cmp ax,1
                jz xms_locked
		 mov dx,offset xms_lock_err
                jmp exit_InitError
xms_locked:                              ; 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
       		mov	fs:xms_usage,eax
                call	set_xms_limit		; set limit to eax
		mov	fs:xms_base,100000h	; 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

	cli

;	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 hardware and 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        ; Store address level0 ESP of TSS
        add fs:tss_Level0ESP,offset tss_esp0

	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
   ; The level0 ESP field is set when real mode interrupt emulation is called
	mov	es:tss_ss0, TheSTACK_Desc - GDT		; Priv. 0 SS
	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.

	add	fs:Base_Segment,(TSS_Ends+15)/16		; inc 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

        jmp FlushP			; Flush instruction prefetch counter

FlushP:


        mov	ax,MyMain_TSS_Desc - GDT	; Set TR to any valid TSS
        ltr	ax

        mov	ax,data_desc - GDT
        mov	ds,ax
assume ds:data32

	mov	ss,ds:[TheStack_sel]     	; Setup Protected mode stack
	mov	esp,Normal_Stack

	mov	SS:[Real_SS],V86_Stack		; Setup initial V86 stack
	mov	SS:[Real_ESP ],V86_stack_size

        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
;ЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗ
exit_error:	mov 	ah,9		; print error message
	        int	21h
	        jmp Exit_To_MSDOS

;ЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗЫЗ
Cant_Enter_dmpiPMode:	mov dx,offset pmiERr
		        jmp exit_error

No_Mem:			mov dx,offset No_Mem_err
		        jmp exit_error


align 16
NON_DPMI_initalize_Size equ $ - NON_DPMI_initalize_start:

dosstart endp
DOS_CODE ENDS

TheSTACK    SEGMENT public stack 'stack' USE32
db    Normal_stack dup (?)
TheSTACK    ENDS

V86_STACK    SEGMENT public stack 'stack' USE16
db    V86_stack_size dup (?)
V86_STACK    ENDS


END   DosStart
