;//Patch for XMS-driver to prevent A20 shutdown
;//Note: You can't compile this source directly 
;//      to executable

.386c

CS_SEG segment byte use16
	assume cs:CS_SEG

XMSDRVADDRESS   dd      ?
REALXMSSTUFF    db      5 dup (?)
FAKEXMSSTUFF    db      0EAh
		dw      offset FAKEHIMEM, ?
RMEM_GDT        db      000h,000h,000h,000h,000h,000h,000h,000h
		db      0FFh,0FFh,000h,000h,000h,092h,0CFh,0FFh
RMEM_48         db      6 dup (?)

getvect MACRO vect,var
	mov ah,035h
	mov al,vect
	int 021h
	mov word ptr var[2],es
	mov word ptr var[0],bx
endm
;// AL=VECT, DS:DX-->INT
setvect MACRO vect,var1,var2,var3
	mov ah,025h
	mov al,vect
	push ds
	mov dx,var1
	mov ds,dx
	mov dx,var2 var3
	int 021h
	pop ds
endm

setFAKE MACRO
	cli
	mov es,word ptr XMSDRVADDRESS[2]
	mov di,word ptr XMSDRVADDRESS[0]
	mov si,offset FAKEXMSSTUFF
	mov ecx,5
	rep movs byte ptr [di],cs:[si]
	sti
endm

setREAL MACRO
	cli
	mov es,word ptr XMSDRVADDRESS[2]
	mov di,word ptr XMSDRVADDRESS[0]
	mov si,offset REALXMSSTUFF
	mov ecx,5
	rep movs byte ptr [di],cs:[si]
	sti
endm

XMScall MACRO func,data
	mov dx,data
	mov ah,func
	call dword ptr XMSDRVADDRESS
endm

XMSinit proc near
	mov ax,04300h
	int 02Fh
	cmp al,080h
	jne XM@ERROR
	mov ax,04310h
	int 02Fh
	mov word ptr XMSDRVADDRESS[0],bx
	mov word ptr XMSDRVADDRESS[2],es
	XMScall 0,0
	cmp ah,2
	jb XM@ERROR
	clc
	ret
	XM@ERROR:
	stc
	ret
XMSinit endp

FAKEHIMEM proc far
	cmp ah,04h
	je A20PROTECT
	cmp ah,06h
	je A20PROTECT
	push si di cx es
	setREAL
	pop es cx di si
	call dword ptr XMSDRVADDRESS
	push si di cx es
	setFAKE
	pop es cx di si
	retf
	A20PROTECT:
		xor ax,ax
		mov bl,094h
		retf
FAKEHIMEM endp

REALMEMORYINIT proc near
	call XMSinit
	XMScall 05h,00h
		push ds
		mov word ptr FAKEXMSSTUFF[3],cs
		mov ds,word ptr XMSDRVADDRESS[2]
		mov si,word ptr XMSDRVADDRESS[0]
		push cs
		pop es
		mov di,offset REALXMSSTUFF
		mov cx,5
		rep movsb
		pop ds
	setFAKE
	ret
REALMEMORYINIT endp

REALMEMORYDEINIT proc near
	setREAL
	ret
REALMEMORYDEINIT endp

CS_SEG ends
end
