;
;CauseWay v2 main file.
;
;
;Things to note:
;
;The IDT has a page to itself even though it only needs 2k. For RAW/VCPI systems
;the top 2k could be used for something else.
;
;Things to do:
;
;Put in some sort of system stack overflow checking and terminate the program
;if it happens.
;
	option oldstructs

	include general.inc
	include strucs.inc
	include cw.inc
;	include cw-undoc.inc

	ifndef ENGLISH
ENGLISH	equ	0
	endif
	ifndef SPANISH
SPANISH	equ	0
	endif

;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
;
;Main code segment. This takes care of calling the right initialisation routines
;and generaly getting everything rolling.
;
_cwMain	segment para public 'Main thread' use16
	assume cs:_cwMain, ds:_cwMain, ss:_cwStack
;
;Want a copyright message embedded first.
;
Copyright	label byte
	db 'CauseWay DOS Extender v'
VersionMajor	db '3.'
VersionMinor	db '49'
	db " Copyright 1992-99 Michael Devore.",13,10,"All rights reserved.",13,10,0


	.386
;-------------------------------------------------------------------------------
;
;Final init stuff.
;
cwOpen	proc	near
	assume ds:nothing		;make our data addresable.
	mov	ds,cs:DataSegment
	assume ds:_cwMain
	;
	mov	d[TerminationHandler],offset cwClose
	mov	w[TerminationHandler+4],cs
;
;Now we know the machines details, re-size the program
;block again to release as much memory as possible.
;
	mov	edi,offset Int21Buffer
	push	ds
	pop	es
	mov	ax,RealPSPSegment
	mov	es:Real_ES[edi],ax
	mov	bx,_cwDPMIEMU
	cmp	ProtectedType,2
	jnz	@@KeepRaw
	mov	bx,_cwRaw
@@KeepRaw:	sub	bx,ax		;Size program.
	inc	bx
	mov	TSRSize,bx
	mov	es:Real_EBX[edi],ebx
	mov	es:Real_EAX[edi],4a00h
	mov	bl,21h
	mov	ErrorNumber,1
	sys	IntXX
	test	es:w[edi+Real_Flags],1
	jnz	@@9
	mov	ErrorNumber,0	;clear error number.
;
;Force accurate memory values.
;
	or	ecx,-1
	sys	GetMemLinear32
;
;Enable resource tracking and MCB allocations.
;
	or	ResourceTracking,-1	;Enable resource tracking.
;
;Run the main program.
;
	mov	edx,offset MainExec	;name to exec.
	mov	esi,80h
	mov	es,PSPSegment
	xor	cx,cx
	sys	cwExec		;run the bugger.
	jnc	@@8
	add	ax,10-1		;convert error number.
	mov	ErrorNumber,ax
	jmp	@@9
@@8:	cmp	DebugDump,0
	jnz	@@9
	mov	ErrorLevel,ax	;store programs error level.
	mov	ErrorNumber,0	;clear error number.
@@9:	jmp	cwClose
cwOpen	endp


;-------------------------------------------------------------------------------
;
;Shut everything down.
;
cwClose	proc	near

IFDEF DEBUG4
	push	eax
	push	ebx
	push	ecx
	push	edx
	push	ds
	push	cs
	pop	ds
	mov	edx,OFFSET debugatext1
debugaloop2:
	cmp	BYTE PTR ds:[edx],0
	je	debugab
	mov	ecx,1
	mov	bx,1
	mov	ah,40h
	int	21h
	inc	edx
	jmp	debugaloop2
debugab:
	mov	edx,OFFSET debugatext2
	push	cs
	pop	ds
	mov	ecx,2
	mov	bx,1
	mov	ah,40h
	int	21h
	pop	ds
	pop	edx
	pop	ecx
	pop	ebx
	pop	eax
	jmp	debugaout

debugatext1	DB	'Entering cwClose...',0
debugatext2	DB	13,10

debugaout:
	push	ecx
	mov	ecx,100000h
debugaloop:
;	dec	ecx
;	jne	debugaloop
	pop	ecx
ENDIF

	assume ds:nothing
	mov	ds,cs:DataSegment
	assume ds:_cwMain
	;
	mov	ResourceTracking,0
	mov	mcbAllocations,0
	sti
	mov	w[TerminationHandler+4],0
	;

IFDEF DEBUG4
	push	eax
	push	ebx
	push	ecx
	push	edx
	push	ds

	mov	dx,w[ExceptionExtension+12]
;	lar	ax,dx
	cmp	dx,127h
	jnz	debughout
;	and	ah,3
;	cmp	ah,3
;	jne	debughout

	push	cs
	pop	ds
	mov	edx,OFFSET debughtext1
debughloop2:
	cmp	BYTE PTR ds:[edx],0
	je	debughb
	mov	ecx,1
	mov	bx,1
	mov	ah,40h
	int	21h
	inc	edx
	jmp	debughloop2
debughb:
	mov	edx,OFFSET debughtext2
	push	cs
	pop	ds
	mov	ecx,2
	mov	bx,1
	mov	ah,40h
	int	21h
	pop	ds
	pop	edx
	pop	ecx
	pop	ebx
	pop	eax
	jmp	debughout

debughtext1	DB	'Calling DebugDisplay...',0
debughtext2	DB	13,10

debughout:
	push	ecx
	mov	ecx,100000h
debughloop:
;	dec	ecx
;	jne	debughloop
	pop	ecx

ENDIF

	push	cs
	push	offset @@dd0
	push	w[ExceptionExtension+12]
	mov	eax,offset DebugDisplay
	push	ax
	retf
@@dd0:	;

	cmp	ErrorNumber,0
	jz	@@NoError

	mov	ax,ErrorNumber	;Get the error number.
	xor	dx,dx
	mov	cx,10
	div	cx
	add	al,'0'
	mov	b[ErrorM00n],al
	add	dl,'0'
	mov	b[ErrorM00n+1],dl

	cmp	EnableDebugDump,0	; if debug dump turned off, no screen i/o
	je	@@NoError

	xor	edx,edx
	mov	dx,w[ErrorList]
	mov	ah,9
	int	21h
;
;Get a pointer to the appropriate error message and print it.
;
	mov	bx,ErrorNumber
	add	bx,bx
	xor	edx,edx
	mov	dx,[ErrorList+bx]
	mov	ah,9
	int	21h
;
;Now exit with the error number as the DOS "errorlevel".
;
@@NoError:
;
;Remove extension patches.
;

IFDEF DEBUG4
	push	eax
	push	ebx
	push	ecx
	push	edx
	push	ds
	push	cs
	pop	ds
	mov	edx,OFFSET debugctext1
debugcloop2:
	cmp	BYTE PTR ds:[edx],0
	je	debugcb
	mov	ecx,1
	mov	bx,1
	mov	ah,40h
	int	21h
	inc	edx
	jmp	debugcloop2
debugcb:
	mov	edx,OFFSET debugctext2
	push	cs
	pop	ds
	mov	ecx,2
	mov	bx,1
	mov	ah,40h
	int	21h
	pop	ds
	pop	edx
	pop	ecx
	pop	ebx
	pop	eax
	jmp	debugcout

debugctext1	DB	'Removing interrupt patches...',0
debugctext2	DB	13,10

debugcout:
	push	ecx
	mov	ecx,100000h
debugcloop:
;	dec	ecx
;	jne	debugcloop
	pop	ecx
ENDIF

	mov	di,offset ExtensionList	;list of interupt patches.
@@p1:	cmp	w[di+2],-1		;search for the end of the table so we can restore
	jz	@@p0		;vectors in reverse order.
	add	di,2
	jmp	@@p1
	;
@@p0:	mov	bp,w[di]
	cmp	ds:w[bp+32],-1	;installed?
	jnz	@@p2
	pushm	di,bp
	push	cs
	push	offset @@p3
	push	ds:w[bp+20]
	push	ds:w[bp+16]
	retf
@@p3:	popm	di,bp
@@p2:	sub	di,2
	cmp	di,offset ExtensionList-2
	jnz	@@p0
;
;Remove api exception patches.
;
	cmp	apiExcepPatched,0
	jz	@@pe0
	mov	ax,cs
	push	ax
	mov	ax,offset @@pe0
	push	ax
	mov	ax,apiCodeSeg
	push	ax
	mov	eax,offset UnPatchExc
	push	ax
	retf
@@pe0:	;
;
;Remove the API patch.
;
	mov	es,apiDataSeg
	assume es:_apiCode
	test	SystemFlags,1
	jz	@@Use32
	mov	dx,es:w[OldIntSys]
	mov	cx,es:w[OldIntSys+2]
	jmp	@@Use0
@@Use32:	mov	edx,es:d[OldIntSys]
	mov	cx,es:w[OldIntSys+4]
@@Use0:	mov	bl,31h
	mov	ax,205h
	int	31h
	mov	es:d[cwIdentity],0
	mov	es:d[cwIdentity+4],0
	assume es:nothing
	;
@@noAPI:
	cmp	ProtectedType,2	;DPMI?
	jz	@@DPMI

IFDEF DEBUG4
	push	eax
	push	ebx
	push	ecx
	push	edx
	push	ds
	push	es
	mov	ax,KernalZero
	mov	es,ax
	mov	ebx,0b8000h
	mov	BYTE PTR es:[ebx],'1'
	push	cs
	pop	ds
	mov	ecx,OFFSET debugdtext1
debugdloop2:
	cmp	BYTE PTR ds:[ecx],0
	je	debugdb
	mov	dl,ds:[ecx]
	mov	ah,2
	int	21h
	inc	ecx
	jmp	debugdloop2
debugdb:
	mov	dl,13
	mov	ah,2
	int	21h
	mov	dl,10
	mov	ah,2
	int	21h
	pop	es
	pop	ds
	pop	edx
	pop	ecx
	pop	ebx
	pop	eax
	jmp	debugdout

debugdtext1	DB	'Making raw addressable...',0
debugdtext2	DB	13,10

debugdout:
	push	ecx
	mov	ecx,100000h
debugdloop:
	dec	ecx
	jne	debugdloop
	pop	ecx
ENDIF

;
;Make RAW stuff addressable.
;
	cli			;Don't want interrupts interfering.
	mov	ax,KernalDS		;Get supervisor data descriptor,
	mov	ds,ax		;DS,ES,FS,GS,SS must be data with 64k limit
	assume ds:_cwRaw
	mov	ax,KernalZero
	mov	es,ax
;
;Switch to RAW exit code.
;
	push	_cwMain
	push	offset @@6
	mov	ax,KernalCS
	push	ax
	mov	ax,offset RawVCPIRealMode
	push	ax
	retf
@@6:	jmp	@@RealMode
;
;Remove DPMI stuff.
;
@@DPMI:

IFDEF DEBUG4
	push	eax
	push	ebx
	push	ecx
	push	edx
	push	ds
	push	cs
	pop	ds
	mov	ecx,OFFSET debugetext1
debugeloop2:
	cmp	BYTE PTR ds:[ecx],0
	je	debugeb
	mov	dl,ds:[ecx]
	mov	ah,2
	int	21h
	inc	ecx
	jmp	debugeloop2
debugeb:
	mov	dl,13
	mov	ah,2
	int	21h
	mov	dl,10
	mov	ah,2
	int	21h
	pop	ds
	pop	edx
	pop	ecx
	pop	ebx
	pop	eax
	jmp	debugeout

debugetext1	DB	'Removing DPMI setup...',0
debugetext2	DB	13,10

debugeout:
	push	ecx
	mov	ecx,100000h
debugeloop:
	dec	ecx
	jne	debugeloop
	pop	ecx
ENDIF

	assume ds:nothing
	mov	ds,cs:DataSegment
	assume ds:_cwMain

	if	0
	cmp	d[OldInt21hExec],0
	jz	@@d0
	mov	bl,21h
	mov	dx,w[OldInt21hExec]
	mov	cx,w[OldInt21hExec+2]
	mov	ax,201h
	int	31h
@@d0:	movzx	edx,dx
	endif

	jmp	@@InRealMode
;
;Make sure our data is addressable.
;
@@RealMode:	mov	ax,_cwMain
	mov	ds,ax
	assume ds:_cwMain
;
;Display the "CauseWay error: ??" bit.
;
@@InRealMode:

	if	0
	cmp	ErrorNumber,0
	jz	@@NoError

	push	ax
	mov	al,3
	call	bordm
	pop	ax

	mov	ax,ErrorNumber	;Get the error number.
	xor	dx,dx
	mov	cx,10
	div	cx
	add	al,'0'
	mov	b[ErrorM00n],al
	add	dl,'0'
	mov	b[ErrorM00n+1],dl

	cmp	EnableDebugDump,0	; if debug dump turned off, no screen i/o
	je	@@NoError

	xor	edx,edx
	mov	dx,w[ErrorList]
	mov	ah,9
	int	21h
;
;Get a pointer to the appropriate error message and print it.
;
	mov	bx,ErrorNumber
	add	bx,bx
	mov	dx,[ErrorList+bx]
	mov	ah,9
	int	21h
;
;Now exit with the error number as the DOS "errorlevel".
;
@@NoError:
	endif

; MED, 12/24/99, coalesce free memory by attempting to allocate largest possible
;  with upper memory in the chain
	mov	ax,5800h
	int	21h
	push	ax
	mov	ax,5802h
	int	21h
	push	ax
	mov	bx,1
	mov	ax,5803h
	int	21h
	mov	bx,81h
	mov	ax,5801h
	int	21h

	mov	ah,48h
	mov	bx,-1
	int	21h

	pop	bx
	mov	ax,5803h
	int	21h
	pop	bx
	mov	ax,5801h
	int	21h

	mov	ax,ErrorNumber
	or	ax,ax
	jnz	@@Exit
	mov	ax,ErrorLevel
@@Exit:

IFDEF DEBUG4
	push	eax
	push	ebx
	push	ecx
	push	edx
	push	ds
	push	cs
	pop	ds
	mov	edx,OFFSET debugbtext1
debugbloop2:
	cmp	BYTE PTR ds:[edx],0
	je	debugbb
	mov	ecx,1
	mov	bx,1
	mov	ah,40h
	int	21h
	inc	edx
	jmp	debugbloop2
debugbb:
	mov	edx,OFFSET debugbtext2
	push	cs
	pop	ds
	mov	ecx,2
	mov	bx,1
	mov	ah,40h
	int	21h
	pop	ds
	pop	edx
	pop	ecx
	pop	ebx
	pop	eax
	jmp	debugbout

debugbtext1	DB	'Performing final real mode 4ch termination...',0
debugbtext2	DB	13,10

debugbout:
	push	ecx
	mov	ecx,100000h
debugbloop:
	dec	ecx
	jne	debugbloop
	pop	ecx
ENDIF

	mov	ah,4ch
	int	21h
cwClose	endp


;-------------------------------------------------------------------------------
Int21hExecPatch proc	near
	assume ds:nothing
	pushf
	cmp	ax,4b00h
	jnz	@@Old

	inc	cs:Int21hExecCount

	popf
	pushf
	call	cs:d[OldInt21hExec]

	pushf
	push bp
	push ax
	mov bp,sp
	mov ax,[bp+2+2]
	and ax,1
;	and w[bp+2+2+2+2+2],1
	and w[bp+2+2+2+2+2],0fffeh	; MED 01/24/96

	or w[bp+2+2+2+2+2],ax
	pop ax
	pop bp
	popf

	dec	cs:Int21hExecCount

	iret
@@Old:
	popf
	jmp	cs:d[OldInt21hExec]
OldInt21hExec	dd 0
	assume ds:_cwMain
Int21hExecCount db 0
Int21hExecPatch endp
	.386p


;-------------------------------------------------------------------------------
Bordm	proc	near
	pushm	ax,dx
	mov	ah,al
	mov	dx,3dah
	in	al,dx
	mov	dl,0c0h
	mov	al,11h
	out	dx,al
	mov	al,ah
	out	dx,al
	mov	al,20h
	out	dx,al
	popm	ax,dx
	ret
Bordm	endp

;-------------------------------------------------------------------------------
;
;Some global data.
;
RealPSPSegment	dw ?		;Real mode PSP segment.
RealENVSegment	dw ?		;Real mode environment segment.
ProtectedFlags	dw 0		;Bit significant, 0-DPMI,1-VCPI,2-RAW.
ProtectedType	dw 0		;0-RAW,1-VCPI,2-DPMI.
ProtectedForce	db 0
DOSVersion	dw 0
SystemFlags	dd 0
apiCodeSeg	dw 0
apiDataSeg	dw 0
;
CodeSegment	dw MainCS	;Setup CS selector.
CodeSegmenti	dw InitCS
DataSegment	dw MainDS	;Setup DS selector.
DataSegmenti	dw InitDS
StackSegment	dw MainSS
RealSegment	dw KernalZero
PSPSegment	dw MainPSP
ENVSegment	dw MainENV
BasePSP	dw 0
BasePSPAddress	dd 0
;
TSRSize	dw 0
;
ErrorNumber	dw 0
ErrorLevel	dw 0
ErrorList	dw ErrorM00,ErrorM01,ErrorM02,ErrorM03,ErrorM04,ErrorM05,ErrorM06,ErrorM07
	dw ErrorM08,ErrorM09,ErrorM10,ErrorM11,ErrorM12,ErrorM13,ErrorM14,ErrorM15
	dw ErrorM16
ErrorM00	db 'CauseWay error '
ErrorM00n	db '00 : $'
ErrorM01	label byte
	if ENGLISH
	db 'Unable to re-size program memory block.',13,10,'$'
	elseif SPANISH
	db "Incapaz de redimensionar el bloque de memoria del programa.",13,10,"$"
	endif
ErrorM02	db "$"
ErrorM03	db "$"
ErrorM04	db "$"
ErrorM05	label byte
	if ENGLISH
	db 'Not enough memory for CauseWay.',13,10,'$'
	elseif SPANISH
	db "Memoria insuficiente para CauseWay.",13,10,"$"
	endif
ErrorM06	db "$"
ErrorM07	db "$"
ErrorM08	db "$"
ErrorM09	label byte
	if ENGLISH
	db 'Unrecoverable exception. Program terminated.',13,10,'$'
	elseif SPANISH
	db "Excepcion irrecuperable. Programa terminado.",13,10,"$"
	endif
ErrorM10	label byte
	if ENGLISH
	db 'Unable to find '
ErrorM10_T	db 'application to load.',13,10,'$',32 dup (0)
	elseif SPANISH
	db "Incapaz de encontrar '
ErrorM10_T	db 'aplicacion a cargar.",13,10,"$",32 dup (0)
	endif
ErrorM11	label byte
	if ENGLISH
	db 'DOS reported an error or corrupt file found.'
	elseif SPANISH
	db "DOS informo de un error o de un fichero corrupto."
	endif
ErrorM11_0	db 13,10,'$'
	db "No:"
ErrorM11_1	db "00000000",13,10,"$"
ErrorM12	label byte
	if ENGLISH
	db 'Not enough memory to load application.',13,10,'$'
	elseif SPANISH
	db "Memoria insuficiente para cargar la aplicacion.",13,10,"$"
	endif
ErrorM13	db "$"
ErrorM14	label byte
	if ENGLISH
	db 'Memory structures destroyed. Program terminated.',13,10,'$'
	elseif SPANISH
	db "Estructuras de memoria destruidas. Programa terminado.",13,10,"$"
	endif
ErrorM15	label byte
	if ENGLISH
	db 'DOS reported an error while accessing swap file. Program terminated.',13,10,'$'
	elseif SPANISH
	db "DOS informa de un error mientras se accede al fichero de swap. Programa terminado.",13,10,"$"
	endif
ErrorM16	label byte
	if ENGLISH
	db "Unsupported DOS function call, program terminated.",13,10,"$"
	elseif SPANISH
	db "Llamada a funcion no soportada del DOS, programa terminado.",13,10,"$"
	endif
;
ALIGN 4
MainExec	db 128 dup (0)
;
DtaBuffer	db 128 dup (0)
;
TransferSize	dd 8192
TransferReal	dw ?
;
MouseETarget	dd 0,0
ResourceTracking dw 0
ForcedFind	dd 0,0
mcbAllocations	dw 0
LinearAddressCheck db 0
;
TerminationHandler dd offset InitError,InitCS
UserTermRoutine	DF	0
UserTermDump	DF	0	; dump location for register info
;
DPMIStateAddr	df 0
DPMIStateSize	dd 0
DPMIStackOff	dw ?
DPMIStackSeg	dw ?
;
DebugDump	db 0
EnableDebugDump	DB	1
UserTermFlag	DB	0
Pad1Flag	DB	0

IFDEF PERMNOEX
NoEXECPatchFlag	DB	1
ELSE
NoEXECPatchFlag	DB	0
ENDIF

; MED, 11/11/99
; used to flag checking XMS total memory because EMM386 lies and acts as VCPI
;  host when NOVCPI set, but provides no memory
VCPIHasNoMem	DB	0

NewCWErrName	DB	81 DUP (0)
DOS4GFlag	db 0
;
;*** MED change for Michael Devore name
CopyCheck	label byte
	db 'C'-44,'a'-44,'u'-44,'s'-44,'e'-44,'W'-44,'a'-44,'y'-44,' '-44
	db 'D'-44,'O'-44,'S'-44,' '-44,'E'-44,'x'-44,'t'-44,'e'-44,'n'-44
	db 'd'-44,'e'-44,'r'-44,' '-44,'v'-44,255,255,255,255
	db ' '-44,'C'-44,'o'-44,'p'-44,'y'-44,'r'-44,'i'-44,'g'-44
	db 'h'-44,'t'-44,' '-44,'1'-44,'9'-44,'9'-44,'2'-44,'-'-44,'9'-44
	db '9'-44,' '-44,'M'-44
	db 'i'-44,'c'-44,'h'-44,'a'-44,'e'-44,'l'-44,' '-44,'D'-44,'e'-44
	db 'v'-44,'o'-44,'r'-44,'e'-44,'.'-44,13-44,10-44,'A'-44,'l'-44,'l'-44
	db ' '-44,'r'-44,'i'-44,'g'-44,'h'-44,'t'-44,'s'-44,' '-44,'r'-44
	db 'e'-44,'s'-44,'e'-44,'r'-44,'v'-44,'e'-44,'d'-44,'.'-44,13-44,10-44
CopyCount	dw 0
;
Int21Buffer	db size RealRegsStruc dup (?)
Int10Buffer	db size RealRegsStruc dup (?)
Int33Buffer	db size RealRegsStruc dup (?)
;
apiExcepPatched db 0
;
ExtensionList	label word
	dw ExceptionExtension
	dw Int21hExtension,Int10hExtension,Int33hExtension
	dw -1
;
ExceptionExtension dw _Excep,0
	dd offset ExcepEnd-ExcepStart
	dd offset ExcepOpen,?
	dd offset ExcepClose,?
	dd 0
	dd 0
	dd 0
;
Int21hExtension dw _Int21h,1		;segment start.
	dd offset Int21hEnd-Int21hStart	;segment length.
	dd offset Int21hOpen,? 	;init code.
	dd offset Int21hClose,?	;remove code.
	dd 0			;code selector.
	dd 0			;data selector.
	dd 0			;installed flag.
;
Int10hExtension dw _Int10h,1		;segment start.
	dd offset Int10hEnd-Int10hStart	;segment length.
	dd offset Int10hOpen,?	;init code.
	dd offset Int10hClose,?	;remove code.
	dd 0			;code selector.
	dd 0			;data selector.
	dd 0			;installed flag.
;
Int33hExtension dw _Int33h,1		;segment start.
	dd offset Int33hEnd-Int33hStart	;segment length.
	dd offset Int33hOpen,?	;init code.
	dd offset Int33hClose,?	;remove code.
	dd 0			;code selector.
	dd 0			;data selector.
	dd 0			;installed flag.
;
Temp0_	dd ?
Temp1_	dd ?
;
DebugUserOff	DD	?
DebugUserSel	DW	?
DebugUserCount	DW	0	; must be initialized, nonzero value flags operation
DebugAsciiFlag	DB	?
_cwMain	ends


;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
;
;Default stack used during startup and exit.
;
_cwStack	segment para stack 'main stack' use16
	db 2048 dup (0)
_cwStackEnd	label byte
_cwStack	ends


	include raw&vcpi.asm

	include api.asm
	include exceptn.asm
	include int10h.asm
	include int21h.asm
	include int33h.asm


;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
;
;The initialiseation code seg. Takes care of things like checking for the right
;processor and determining how we're going to get into protected mode.
;
_cwInit	segment para public 'init code' use16
	assume cs:_cwInit, ds:_cwMain

dpmiSelBuffer	db 8 dup (0)

;-------------------------------------------------------------------------------
Startup	proc	near
;
;Make global data addresable.
;
	mov	ax,_cwMain
	mov	ds,ax

; MED, 12/30/99
; works around weird bug in some machines due to Windows/hardware/BIOS??? error
;  where a CauseWay application in AUTOEXEC.BAT which uses DOS function 8
;  to get a keystroke when no other application in AUTOEXEC.BAT gets a
;  keystroke will cause failure in Windows 98 (and 95?) when opening a DOS
;  box after Windows startup.  Caused by A20 or keyboard port stabilization?
	mov	cx,127
kloop:
	mov	ax,0b00h
	int	21h
	test	al,al
	jne	done
	loop	kloop
done:

;
;Stow real mode PSP and environment values, we'll need them later.
;
	mov	RealPSPSegment,es
	mov	ax,es:w[02ch]
	mov	RealEnvSegment,ax	;Stow ENV for later.
;
;Re-size memory so we can allocate what we want high.
;
	mov	cs:IErrorNumber,1
	mov	ax,es
	mov	bx,_cwEnd		;Get program end segment.
	sub	bx,ax		;Size program.
	inc	bx
	mov	ah,4ah
	int	21h		;Re-size memory block.

; MED 06/16/97
;	jc	InitError
	jnc	chk386

toiniterr:
	jmp	InitError

;
;Check we're on at least a 386 system.
;
chk386:
	mov	cs:IErrorNumber,2
	call	CheckProcessor

;	jc	InitError
	jc	toiniterr

;
;Check DOS version is high enough.
;
	mov	cs:IErrorNumber,4
	call	CheckDOSVersion
	jc	InitError
;
;Get execution name from environment.
;
	call	GetEXECName
;
;Retrieve setup info from 3P header.
;
	call	GetSystemFlags
;
;Check if a suitable method for switching to protected mode exists.
;
	call	GetProtectedType
	mov	cs:IErrorNumber,3
	cmp	ProtectedFlags,0	;Any types available?
	jz	InitError
;
;Get CAUSEWAY environment variable settings.
;
	call	GetENVStuff
;
;Decide which environment to use.
;
	call	SetProtectedType
;
;Move the DTA to where we can get at it in the future.
;
	mov	dx,offset DTABuffer
	mov	ah,1ah
	int	21h
;
;now see about type specific initialisations.
;
	cmp	ProtectedType,2	;DPMI initialiseation?
	jz	@@InitDPMI
;
;Useing either RAW or VCPI so do the stuff that's common to both for now.
;
	mov	ax,_cwRaw
	mov	ds,ax
	assume ds:_cwRaw
;
;Get SDA address so VMM can change BREAK state.
;
	.386
	push	ds
	mov	ax,5d06h
	int	21h
	mov	ax,ds
	pop	ds
	add	si,17h
	movzx	eax,ax
	shl	eax,4
	movzx	esi,si
	add	eax,esi
	mov	BreakAddress,eax
;
;Find out if XMS is present.
;
	mov	ax,4300h		;XMS install check.
	int	2fh
	cmp	al,80h		;XMS present?
	jnz	@@NoXMS
;
;XMS detected so work out max block size and entry point.
;
	mov	ax,4310h		;Get XMS API.
	int	2fh
	mov	w[XMSControl],bx
	mov	w[XMSControl+2],es
	mov	XMSPresent,1		;flag XMS is available.

; MED, 09/10/99, support extended XMS API to calculate XMS available to CauseWay
;  (maximum of 2G-32K, i.e. 32 handles/entries of 64K-1)
	mov	ah,0
	call	d[XMSControl]	; get info
	cmp	ah,3
	jb	xms2
	cmp	bh,3
	jb	xms2
	cmp	bl,8
	jb	xms2			; treat early 3.x drivers < 3.08 as 2.x

; use extended XMS API
	mov	XMSVer3Present,1	; flag XMS 3.x driver present
	mov	ah,88h
	call	d[XMSControl]	;get size of biggest block free.
	mov	edx,eax
	test	eax,eax
	jz	@@YesXMS		;no memory available.
	mov	cs:d[@@XMSSize],edx
	mov	ah,89h
	call	d[XMSControl]	;claim biggest block to force XMS
	cmp	ax,1			;to stake a claim on int 15h.
	jnz	@@YesXMS
	mov	cs:b[@@NumXMSHandles],1
	push	dx
	mov	ah,8eh
	call	d[XMSControl]	; get handle information
	cmp	ax,1
	jnz	@@NoHandles3
	cmp	cx,4
	jc	@@NoHandles3
	sub	cx,2
	mov	cs:b[@@NumXMSHandles],32
	cmp	cx,32
	jnc	@@NoHandles3
	mov	cs:b[@@NumXMSHandles],cl	; cx known 8-bit value

@@NoHandles3:
	pop	dx
	mov	ah,0ah
	call	d[XMSControl]	;now free it.

	movzx	eax, BYTE PTR cs:[@@NumXMSHandles]
	mov	edx,eax
	shl	eax,16
	sub	eax,edx		; eax == handles (up to 32) * 65535
	cmp	eax,cs:d[@@XMSSize]
	jae	@@ComputeSize
	mov	cs:d[@@XMSSize],eax	; throttle maximum size

@@ComputeSize:
	push	eax
	xor	edx,edx
	movzx	ebx,BYTE PTR cs:[@@NumXMSHandles]
	div	ebx
	pop	ebx
	cmp	ax,4		; eax known 16-bit value
	jnc	@@SizeOK3
	mov	ax,bx		; ebx == maximum size, known 16-bit value here

@@SizeOK3:
	mov	XMSBlockSize,ax
	jmp	@@YesXMS

xms2:
	mov	ah,8
	call	d[XMSControl]	;get size of biggest block free.
	mov	dx,ax
	or	ax,ax
	jz	@@YesXMS		;no memory available.
	mov	cs:w[@@XMSSize],dx
	mov	ah,9
	call	d[XMSControl]	;claim biggest block to force XMS
	cmp	ax,1		;to stake a claim on int 15h.
	jnz	@@YesXMS
	mov	cs:b[@@NumXMSHandles],1
	push	dx
	mov	ah,0eh
	call	d[XMSControl]	;now free it.
	cmp	ax,1
	jnz	@@NoHandles
	cmp	bl,4
	jc	@@NoHandles
	sub	bl,2
	mov	cs:b[@@NumXMSHandles],32
	cmp	bl,32
	jnc	@@NoHandles
	mov	cs:b[@@NumXMSHandles],bl
@@NoHandles:	pop	dx
	mov	ah,0ah
	call	d[XMSControl]	;now free it.
	mov	ax,cs:w[@@XMSSize]
	push	ax
	xor	dx,dx
	xor	bh,bh
	mov	bl,cs:b[@@NumXMSHandles]
	div	bx
	pop	bx
	cmp	ax,4
	jnc	@@SizeOK
	mov	ax,bx
@@SizeOK:	mov	XMSBlockSize,ax
	jmp	@@YesXMS
;
;Install raw A20 handler.
;
@@NoXMS:	call	InstallA20
;
;Get A20 state.
;
@@YesXMS:	push	ds
	les	di,HighMemory	;   with the four at FFFF:0090
	lds	si,LowMemory		; Compare the four words at 0000:0080
	mov	cx,4
	cld
	repe  cmpsw
	pop	ds
	xor	ax,ax
	jcxz	@@A20OFF		 ; Are the two areas the same?
	inc	ax		    ; No, return A20 Enabled
@@A20OFF:	mov	A20Flag,al
;
;Change DOS allocation stratergy to highest so we'll get UMB's if available.
;
	mov	ax,5800h
	int	21h
	mov	cs:w[@@OldStrat],ax
	mov	ax,5802h
	int	21h
	mov	cs:w[@@OldStrat+2],ax
	mov	bx,1
	mov	ax,5803h
	int	21h
	mov	bx,81h
	mov	ax,5801h
	int	21h
;
;Grab memory for page dir, page alias & first page table entry.
;
	mov	bx,(4096*3)/16	;smallest allocation possible.
	mov	ah,48h
	int	21h
	jc	@@OldWay
	push	ax
	movzx	eax,ax
	shl	eax,4		;linear address.
	mov	ebx,eax
	add	eax,4095
	and	eax,0ffffffffh-4095	;round up to next page.
	sub	eax,ebx
	shr	eax,4
	mov	bx,ax
	mov	cx,ax
	add	bx,(4096*3)/16
	mov	ah,4ah
	pop	es
	pushm	bx,cx,es
	int	21h		;re-size the block.
	popm	bx,cx,es
	jnc	@@NewWay
	mov	ah,49h
	int	21h		;release this block.
	;
@@OldWay:	mov	cs:IErrorNumber,5
	mov	bx,(4096*4)/16	;need space for 3 page tables on
	mov	ah,48h		;4k boundary.
	int	21h
	jc	InitError
	mov	dx,ax
	movzx	eax,ax		;get segment address.
	shl	eax,4		;make linear.
	mov	ebx,eax
	add	eax,4095
	and	eax,0FFFFFFFFh-4095	;round up to nearest page.
	mov	ecx,eax
	sub	ecx,ebx
	shr	ecx,4
	shr	eax,4		;Get segment value again.
	jmp	@@GotSeg
	;
@@NewWay:	mov	ax,es
	mov	dx,ax
	add	ax,cx		;move to real start.
	;
@@GotSeg:
	pushm	cx,dx
	mov	es,ax

; MED 09/19/96
;	mov	PageDirReal,ax	;setup page directory address.
;	add	ax,4096/16
;	mov	Page1stReal,ax	;setup 1st page table address.
	mov	Page1stReal,ax	;setup 1st page table address.
	add	ax,4096/16
	mov	PageDirReal,ax	;setup page directory address.

	add	ax,4096/16
	mov	PageAliasReal,ax	;setup alias table address.
	xor	di,di
	mov	cx,4096*3
	xor	al,al
	cld
	rep	stosb		;clear it.
	movzx	eax,PageDIRReal
	shl	eax,4
	mov	PageDIRLinear,eax
	mov	VCPI_CR3,eax
	movzx	eax,PageALIASReal
	shl	eax,4
	mov	PageAliasLinear,eax
	movzx	eax,Page1stReal
	shl	eax,4
	mov	Page1stLinear,eax
	popm	cx,dx
;
;See if enough wasted space to squeeze TSS into.
;
	cmp	cx,(((size TSSFields)+2+16)/16)
	jc	@@TSSOld
	mov	ax,dx   		;get segment.
	add	dx,(((size TSSFields)+2+16)/16)	;move segment base.
	sub	cx,(((size TSSFields)+2+16)/16)	;update space left size.
	jmp	@@TSSGot
;
;Allocate memory for Kernal TSS.
;
@@TSSOld:	mov	cs:IErrorNumber,5
	mov	bx,(((size TSSFields)+2+16)/16)	;(4096/2)+2+16)/16
	mov	ah,48h
	int	21h
	jc	InitError
@@TSSGot:	mov	KernalTSSReal,ax
;
;See if enough wasted space to squeeze GDT into.
;
	cmp	cx,((8*GDT_Entries)/16)+1
	jc	@@GDTOld
	mov	ax,dx   		;get segment.
	add	dx,((8*GDT_Entries)/16)+1	;move segment base.
	sub	cx,((8*GDT_Entries)/16)+1	;update space left size.
	jmp	@@GDTGot
;
;Allocate some memory for the GDT.
;
@@GDTOld:	mov	cs:IErrorNumber,5
	mov	bx,((8*GDT_Entries)/16)+1
	mov	ah,48h
	int	21h
	jc	InitError
@@GDTGot:	mov	GDTReal,ax
	mov	es,ax
	movzx	eax,ax
	shl	eax,4
	mov	GDTLinear,eax
	xor	di,di
	mov	cx,(8*GDT_Entries)
	xor	al,al
	cld
	rep	stosb
;
;Allocate some memory for the stack.
;
	mov	cs:IErrorNumber,5
	mov	ebx,RawStackPos
	shr	ebx,4
	mov	ah,48h
	int	21h
	jc	InitError
	mov	RawStackReal,ax
	mov	es,ax
	mov	cx,w[RawStackPos]
	xor	di,di
	xor	al,al
	cld
	rep	stosb

; MED 09/19/96
; Set address for VMM page to disk buffer.
	mov	cs:IErrorNumber,5
	mov	bx,4096/16
	mov	ah,48h
	int	21h
	jc	InitError
	mov	PageBufferReal,ax
	movzx	eax,ax
	shl	eax,4
	mov	PageBufferLinear,eax

;
;Restore DOS memory allocation stratergy.
;
	mov	bx,cs:w[@@OldStrat+2]
	xor	bh,bh
	mov	ax,5803h
	int	21h
	mov	bx,cs:w[@@OldStrat]
	xor	bh,bh
	mov	ax,5801h
	int	21h
;
;Need to initialise 1st page table to map <1meg+64k 1:1.
;
	mov	es,Page1stReal
	xor	di,di
	mov	cx,256+16		;1st 1 meg + 64k.
	mov	esi,111b		;user+write+present
@@0:	mov	es:[di],esi
	add	di,4		;next page table entry.
	add	esi,4096		;next physical page address.
	dec	cx
	jnz	@@0

; MED 09/19/96
COMMENT !
;
;Set address for VMM page to disk buffer.
;
	mov	ax,PageDIRReal
	mov	PageBufferReal,ax
	movzx	eax,ax
	shl	eax,4
	mov	PageBufferLinear,eax
END COMMENT !

;
;Set address for DOS INT 21h PM to Real transfer buffer.
;

; MED 09/19/96
;	mov	bx,Page1stReal
	mov	bx,PageDirReal

	push	ds
	mov	ax,_cwMain
	mov	ds,ax
	assume ds:_cwMain
	mov	TransferReal,bx
	assume ds:_cwRaw
	pop	ds
;
;Allocate the GDT entries.
;
	mov	es,GDTReal
;
;Fill in the null entry just for the hell of it.
;
	xor	esi,esi		;Null entry at 0.
	xor	ecx,ecx
	xor	ax,ax
	xor	di,di
	call	MakeDesc
;
;Fill in the VCPI entries so we don't try to use them later.
;
	xor	esi,esi
	xor	ecx,ecx
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	mov	di,VCPI_0
	call	MakeDesc
	xor	esi,esi
	xor	ecx,ecx
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	mov	di,VCPI_1
	call	MakeDesc
	xor	esi,esi
	xor	ecx,ecx
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	mov	di,VCPI_2
	call	MakeDesc
;
;Allocate 40h descriptor.
;
	mov	esi,400h
	mov	ecx,65535
	xor	al,al
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	mov	di,Kernal40h
	call	MakeDesc
;
;Allocate kernal task descriptors, TSS itself first.
;
	movzx	esi,KernalTSSReal
	shl	esi,4
	mov	ecx,size TSSFields+2
	xor	al,al
	mov	ah,DescPresent+DescPL3+Desc386Tss
	mov	di,KernalTS
	call	MakeDesc
;
;TSS PL0 stack.
;
	movzx	esi,KernalTSSReal
	shl	esi,4
	add	esi,tPL1Stack
	mov	ecx,65535
	mov	al,b[RawSystemFlags]
	xor	al,1
	shl	al,6
	mov	ah,DescPresent+DescPL0+DescMemory+DescRWData
	mov	di,KernalPL0
	call	MakeDesc
;
;Mode switch PL0 stack.
;
	movzx	esi,KernalTSSReal
	shl	esi,4
	add	esi,tPL1Stack
	mov	ecx,65535
	xor	al,al
	mov	ah,DescPresent+DescPL0+DescMemory+DescRWData
	mov	di,KernalSwitchPL0
	call	MakeDesc
;
;LDT
;
	xor	esi,esi
	xor	ecx,ecx
	xor	al,al
	mov	ah,DescPresent+DescPL3+DescLDT
	mov	di,KernalLDT
	call	MakeDesc
;
;Kernal (RAW) code seg.
;
	xor	esi,esi
	mov	si,_cwRaw
	shl	esi,4
	mov	ecx,65535
	xor	al,al
	mov	ah,DescPresent+DescPL3+DescMemory+DescERCode
	mov	di,KernalCS
	call	MakeDesc
;
;Kernal (RAW) code seg at PL0
;
	xor	esi,esi
	mov	si,_cwRaw
	shl	esi,4
	mov	ecx,65535
	xor	al,al
	mov	ah,DescPresent+DescPL0+DescMemory+DescERCode
	mov	di,KernalCS0
	call	MakeDesc
;
;Kernal (RAW) data seg.
;
	xor	esi,esi
	mov	si,_cwRaw
	shl	esi,4
	mov	ecx,65535
	xor	al,al
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	mov	di,KernalDS
	call	MakeDesc
;
;Kernal (RAW) stack seg.
;
	movzx	esi,RawStackReal
	shl	esi,4
	mov	ecx,65535
	mov	al,b[RawSystemFlags]
	xor	al,1
	shl	al,6
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	mov	di,KernalSS
	call	MakeDesc
;
;Kernal PL3 to PL0 call gate.
;
	xor	ecx,ecx
	mov	esi,KernalCS0
	xor	al,al
	mov	ah,DescPresent+DescPL3+Desc386Call
	mov	di,KernalPL3_2_PL0
	call	MakeDesc
;
;DPMI emulator code seg.
;
	xor	esi,esi
	mov	si,_cwDPMIEMU
	shl	esi,4
	mov	ecx,offset cwDPMIEMUEnd-cwDPMIEMUStart
	mov	al,1 shl 6
	mov	ah,DescPresent+DescPL3+DescMemory+DescERCode
	mov	di,DpmiEmuCS
	call	MakeDesc
;
;DPMI emulator code seg at PL0
;
	xor	esi,esi
	mov	si,_cwDPMIEMU
	shl	esi,4
	mov	ecx,offset cwDPMIEMUEnd-cwDPMIEMUStart
	mov	al,1 shl 6
	mov	ah,DescPresent+DescPL0+DescMemory+DescERCode
	mov	di,DpmiEmuCS0
	call	MakeDesc
;
;DPMI emulator data seg.
;
	xor	esi,esi
	mov	si,_cwDPMIEMU
	shl	esi,4
	mov	ecx,offset cwDPMIEMUEnd-cwDPMIEMUStart
	mov	al,1 shl 6
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	mov	di,DpmiEmuDS
	call	MakeDesc
;
;Init PL3 to PL0 call gate.
;
	xor	ecx,ecx
	mov	esi,InitCS0
	xor	al,al
	mov	ah,DescPresent+DescPL3+Desc386Call
	mov	di,InitPL3_2_PL0
	call	MakeDesc
;
;DPMI emulator PL3 to PL0 call gate.
;
	xor	ecx,ecx
	mov	esi,DpmiEmuCS0
	xor	al,al
	mov	ah,DescPresent+DescPL3+Desc386Call
	mov	di,DpmiEmuPL3_2_PL0
	call	MakeDesc
;
;Zero to 4G segment.
;
	xor	esi,esi
	or	ecx,-1
	xor	al,al
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	mov	di,KernalZero
	call	MakeDesc
;
;Main PSP segment.
;
	push	ds
	mov	ax,_cwMain
	mov	ds,ax
	assume ds:_cwMain
	movzx	esi,RealPspSegment
	assume ds:_cwRaw
	pop	ds
	shl	esi,4
	mov	ecx,256
	mov	al,0
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	mov	di,MainPSP
	call	MakeDesc
;
;Main environment var.
;
	push	ds
	mov	ax,_cwMain
	mov	ds,ax
	assume ds:_cwMain
	movzx	esi,RealEnvSegment
	assume ds:_cwRaw
	pop	ds
	shl	esi,4
	mov	ecx,0FFFFh
	xor	al,al
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	mov	di,MainEnv
	call	MakeDesc
;
;Main code seg.
;
	xor	esi,esi
	mov	si,_cwMain
	shl	esi,4
	mov	ecx,65535
	xor	al,al
	mov	ah,DescPresent+DescPL3+DescMemory+DescERCode
	mov	di,MainCS
	call	MakeDesc
;
;Main data seg.
;
	xor	esi,esi
	mov	si,_cwMain
	shl	esi,4
	mov	ecx,65535
	xor	al,al
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	mov	di,MainDS
	call	MakeDesc
;
;Main stack.
;
	xor	esi,esi
	mov	si,_cwStack
	shl	esi,4
	mov	ecx,65535
	mov	al,b[RawSystemFlags]
	xor	al,1
	shl	al,6
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	mov	di,MainSS
	call	MakeDesc
;
;Init code seg.
;
	xor	esi,esi
	mov	si,_cwInit
	shl	esi,4
	mov	ecx,65535
	xor	al,al
	mov	ah,DescPresent+DescPL3+DescMemory+DescERCode
	mov	di,InitCS
	call	MakeDesc
;
;Init code seg at PL0
;
	xor	esi,esi
	mov	si,_cwInit
	shl	esi,4
	mov	ecx,65535
	xor	al,al
	mov	ah,DescPresent+DescPL0+DescMemory+DescERCode
	mov	di,InitCS0
	call	MakeDesc
;
;Init data seg.
;
	xor	esi,esi
	mov	si,_cwInit
	shl	esi,4
	mov	ecx,65535
	xor	al,al
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	mov	di,InitDS
	call	MakeDesc
;
;Init GDT data alias.
;
	mov	esi,GDTLinear
	mov	ecx,65535
	xor	al,al
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	mov	di,GDTData
	call	MakeDesc
;
;Setup TSS registers to run in protected mode. Setup GDT & IDT values.
;
	mov	es,KernalTSSReal
	xor	di,di
	mov	cx,size TSSFields	;+(4096/8)
	xor	al,al
	cld
	rep	stosb		;clear TSS & IO map.
	or	ax,-1
	stosw			;mark end of IO map.
	mov	es:SS0,KernalPL0
	mov	es:ESP0,tPL0StackSize-4
	mov	es:tLDT,KernalLDT
	mov	es:IOMap,size TSSFields	;set displacement to IO table.
;
;Setup GDT load value.
;
	movzx	eax,GDTReal
	shl	eax,4
	mov	d[GDTVal+2],eax
	mov	w[GDTVal],-1
;
;Setup Windows enhanced mode denial patch.
;
	mov	ax,352fh		;get existing vector.
	int	21h
	mov	w[OldInt2F],bx
	mov	w[OldInt2F+2],es
	mov	ax,252fh
	mov	dx,offset Int2FPatch
	int	21h
;
;Now patch RAW specific calls.
;
	push	ds
	mov	ax,_cwMain
	mov	ds,ax
	assume ds:_cwMain
	cmp	ProtectedType,1	;VCPI?
	assume ds:_cwRaw
	pop	ds
	jz	@@VCPI
;
;Use RAW method to switch to protected mode.
;
@@RAW:	.386p
;
;Need to initialise 1st entry of page dir & alias.
;
	movzx	eax,Page1stReal
	shl	eax,4
	or	eax,111b		;user+write+present
	mov	es,PageDirReal
	xor	di,di
	mov	es:[di],eax
	mov	es,PageAliasReal
	mov	es:[di],eax
	mov	es,KernalTSSReal
	mov	es:[di].tCR3,eax	;set CR3 in TSS as well.
	;
	;map alias into page dir as well.
	;
	movzx	eax,PageAliasReal	;get para address.
	shl	eax,4		;make linear.
	or	eax,111b		;user+write+present.
	mov	es,PageDirReal
	mov	di,1023*4
	mov	es:[di],eax		;setup in last page dir entry.
	;
;	pushfd
;	pop	eax
;	mov	EFlagsSav,eax
	mov	eax,cr3
	mov	CR3Sav,eax
	mov	eax,cr0
	mov	CR0Sav,eax
	sidt	IDTSav		;save old IDT value for switch back.
	sgdt	GDTSav
	pop	RetAdd
	cli			;Don't want interupts interfering.
	lgdt	GDTVal		;Setup GDT &
	lidt	f[IDTVal]		;IDT.
	mov	eax,VCPI_CR3
	mov	cr3,eax		;set page dir address.
	mov	eax,cr0		;Get machine status &
	or	eax,080000001h	;set PM+PG bits.
	mov	cr0,eax		;/

; MED 10/15/96
	mov	CR0ProtSav,eax	; save protected mode status of CR0

	db 0eah		;Absolute 16-bit jump, to clear
	dw @@RAW0,InitCS0		;instruction pre-fetch & load CS.
@@RAW0:	mov	ax,KernalLDT		;Point to empty LDT descriptor.
	lldt	ax		;and set LDT.
	mov	cx,KernalTS		;Get value for task register.
	ltr	cx		;and set it.
	;
	mov	Protected2Real,offset RawProt2Real
	mov	Real2Protected,offset RawReal2Prot
	jmp	@@inProt
;
;Use VCPI method to switch to protected mode.
;
@@VCPI:	mov	cs:IErrorNumber,6
	cli
	push	ds
	xor	di,di		;Page table offset.
	mov	es,Page1stReal	;Page table segment
	mov	si,VCPI_0		;VCPI GDT entries offset.
	and	si,not 3
	mov	ds,GDTReal		;GDT segment.
	mov	ax,0de01h		;Let VCPI server prepare.
	int	67h
	pop	ds
	or	ah,ah
	jnz	InitError
	mov	d[VCPI_Entry],ebx	;Store entry point.

; MED 11/05/96
	mov	FirstUninitPage,di	; VCPI server advanced to first uninitialized page
							; table entry in client's page

	;
	;Now update PHYSICAL addresses of dir & 1st page tables.
	;
	mov	es,Page1stReal
	movzx	edi,Page1stReal	;get linear address.
	shl	edi,4		;/
	shr	edi,12		;page number.
	shl	edi,2		;*4 bytes per entry.
	mov	eax,es:[di]		;get physical address.
	and	eax,not 4095		;clear status bits.
	or	eax,111b		;set our bits.
	mov	es,PageDirReal
	xor	di,di
	mov	es:[di],eax
	mov	es,PageAliasReal
	mov	es:[di],eax
	;
	mov	es,Page1stReal
	movzx	edi,PageDirReal	;get linear address.
	shl	edi,4		;/
	shr	edi,12		;page number.
	shl	edi,2		;*4 bytes per entry.
	mov	eax,es:[di]		;get physical address.
	and	eax,0FFFFFFFFh-4095	;clear status bits.
	mov	VCPI_CR3,eax		;set VCPI CR3 value as well.
	mov	es,KernalTSSReal
	xor	di,di
	mov	es:[di].tCR3,eax	;set CR3 in TSS as well.
	;
	mov	es,Page1stReal
	movzx	edi,PageAliasReal	;get linear address.
	shl	edi,4		;/
	shr	edi,12		;page number.
	shl	edi,2		;*4 bytes per entry.
	mov	eax,es:[di]		;get physical address.
	and	eax,0FFFFFFFFh-4095	;clear status bits.
	or	eax,111b		;user+write+present.
	mov	es,PageDirReal
	mov	di,1023*4
	mov	es:[di],eax		;setup in last page dir entry.
	;
	mov	VCPI_LDT,KernalLDT
	mov	VCPI_EIP,offset @@InProt
	mov	VCPI_TR,KernalTS	;Get value for task register.
	mov	VCPI_CS,InitCS0
	xor	eax,eax
	mov	ax,seg _cwRaw
	shl	eax,4
	add	eax,offset GDTVal
	mov	VCPI_pGDT,eax
	xor	eax,eax
	mov	ax,seg _cwRaw
	shl	eax,4
	add	eax,offset IDTVal
	mov	VCPI_pIDT,eax
	cli
	mov	ax,0de0ch
	mov	si,seg _cwRaw
	movzx	esi,si
	shl	esi,4
	add	esi,offset VCPI_CR3
	int	67h
	;
	mov	ax,_cwStack
	mov	ss,ax
	mov	esp,offset _cwStackEnd-4
	mov	ax,_cwRaw
	mov	ds,ax
	jmp	InitError		;Shouldn't come through here.
;
;We're in protected mode at last, now we just have to move the DPMI emulation
;stuff into extended memory and build a useful IDT.
;
@@InProt:
	mov	ax,InitDS
	mov	ds,ax
	assume ds:_cwInit
	or	IProtectedMode,-1
	mov	ax,KernalDS		;Get data descriptor.
	mov	ds,ax		;/
	assume ds:_cwRaw
	mov	es,ax		;/
	mov	fs,ax		;/
	mov	gs,ax		;/
	mov	ax,KernalPL0
	mov	ss,ax		;/
	mov	esp,offset tPL0StackSize-4
	;
	pushfd
	pop	eax
	and	ax,1011111111111111b	;clear NT.
	push	eax
	popfd
	cld
	clts
;
;Switch to PL3 code seg for the hell of it.
;
	.386
	mov	edx,offset _cwStackEnd-4
	mov	ecx,MainSS
	push	ecx		;SS
	push	edx		;ESP
	pushfd		;EFlags
	pop	eax
	and	ax,1000111111111111b	;clear NT & IOPL.
	or	ax,0011000000000000b	;force IOPL.
	push	eax
	popfd
	push	eax
	xor	eax,eax
	mov	ax,InitCS
	push	eax		;CS
	mov	eax,offset @@pl3
	push	eax		;EIP
	db 66h
	iretd
	;
@@pl3:	push	es
	mov	ax,KernalZero
	mov	es,ax
	mov	esi,GDTLinear
	add	esi,KernalTS-3
	mov	es:b[esi+5],DescPresent+DescPL3+Desc386Tss
	pop	es
;
;Setup initial segment variables.
;
	push	ds
	mov	ax,MainDS
	mov	ds,ax
	assume ds:_cwMain
	or	w[SystemFlags],32768	;Flags us in protected mode.
	mov	RealSegment,KernalZero
	mov	PspSegment,MainPSP
	mov	EnvSegment,MainENV
	mov	CodeSegment,MainCS
	mov	DataSegment,MainDS
	mov	StackSegment,MainSS
	assume ds:_cwRaw
	pop	ds
;
;Make sure A20 is enabled.
;
	push	ds
	mov	ax,InitDS
	mov	ds,ax
	assume ds:_cwInit
	mov	IErrorNumber,7
	assume ds:_cwRaw
	pop	ds
	mov	ax,1
	push	cs
	push	offset @@1
	push	KernalCS
	push	offset A20Handler
	retf
@@1:	jnz	InitError
;
;Now get extended memory sorted out, move the page tables into extended memory
;for a start.
;
	push	ds
	mov	ax,InitDS
	mov	ds,ax
	assume ds:_cwInit
	mov	IErrorNumber,5
	assume ds:_cwRaw
	pop	ds
	mov	ax,KernalZero
	mov	es,ax
;
;Allocate 2nd page table so we can map extended memory.
;
	call	d[fPhysicalGetPage]
	jc	InitError
	and	ecx,1		;put user bits in useful place.
	shl	ecx,10
	and	edx,not 4095		;lose user bits.

	or	edx,111b		;present+user+write.
	or	edx,ecx		;set use flags.
	mov	eax,1
	mov	esi,PageDIRLinear
	mov	es:d[esi+eax*4],edx	;store this tables address.
	mov	esi,PageAliasLinear	;get alias table address.
	mov	es:d[esi+eax*4],edx	;setup in alias table as well.
	call	d[fCR3Flush]
	mov	edi,1024*4096*1023	;base of page alias's.
	mov	eax,1024*4		;get the entry number again.
	add	edi,eax
	mov	ecx,4096/4
	xor	eax,eax
	cld
	db 67h
	rep	stosd
	call	d[fCR3Flush]
	mov	LinearEntry,1024
;
;Setup DET page alias.
;
	call	d[fPhysicalGetPage]	;get page for new page 1st DET.
	jc	InitError
	mov	LinearEntry+8,edx	;store physical address.
	and	ecx,1		;put user bits in useful place.
	shl	ecx,10
	and	edx,not 4095		;lose user bits.
	or	edx,111b		;present+user+write.
	or	edx,ecx		;set use flags.
	mov	eax,LinearEntry	;get the entry number again.
	mov	esi,1024*4096*1023	;base of page alias's.
	mov	es:d[esi+eax*4],edx	;set physical address.
	call	d[fCR3Flush]
	mov	edi,LinearEntry
	shl	edi,12
	mov	ecx,4096/4
	xor	eax,eax
	cld
	db 67h
	rep	stosd		;clear it.
	mov	eax,LinearEntry
	shl	eax,12		;get linear address.
	mov	PageDETLinear,eax
	mov	eax,1022
	mov	esi,PageDIRLinear
	mov	edx,LinearEntry+8	;get physical address again.
	or	edx,111b
	mov	es:[esi+eax*4],edx	;put new page into the map.
	mov	esi,PageALIASLinear
	mov	es:[esi+eax*4],edx	;put new page into the map.
	call	d[fCR3Flush]
	inc	LinearEntry
;
;Setup DET page 1st.
;
	call	d[fPhysicalGetPage]	;get page for new page 1st.
	jc	InitError
	mov	LinearEntry+8,edx	;store physical address.
	and	ecx,1		;put user bits in useful place.
	shl	ecx,10
	and	edx,not 4095		;lose user bits.
	or	edx,111b		;present+user+write.
	or	edx,ecx		;set use flags.
	mov	esi,1024*4096*1023	;base of page alias's.
	mov	eax,LinearEntry	;get the entry number again.
	mov	es:d[esi+eax*4],edx	;set physical address.
	call	d[fCR3Flush]
	mov	edi,LinearEntry
	shl	edi,12
	mov	ecx,4096/4
	mov	eax,MEM_FILL
	cld
	db 67h
	rep	stosd		;copy old to new.
	mov	esi,PageDETLinear
	mov	eax,0
	mov	edx,LinearEntry+8	;get physical address again.
	or	edx,111b
	mov	es:[esi+eax*4],edx	;put new page into the map.
	call	d[fCR3Flush]
	inc	LinearEntry
;
;Allocate 2nd page DET
;
	call	d[fPhysicalGetPage]	;get page for new page 1st.
	jc	InitError
	mov	LinearEntry+8,edx	;store physical address.
	and	ecx,1		;put user bits in useful place.
	shl	ecx,10
	and	edx,not 4095		;lose user bits.
	or	edx,111b		;present+user+write.
	or	edx,ecx		;set use flags.
	mov	esi,1024*4096*1023	;base of page alias's.
	mov	eax,LinearEntry	;get the entry number again.
	mov	es:d[esi+eax*4],edx	;set physical address.
	call	d[fCR3Flush]
	mov	edi,LinearEntry
	shl	edi,12
	mov	ecx,4096/4
	mov	eax,MEM_FILL
	cld
	db 67h
	rep	stosd		;copy old to new.
	mov	esi,PageDETLinear
	mov	eax,1
	mov	edx,LinearEntry+8	;get physical address again.
	or	edx,111b
	mov	es:[esi+eax*4],edx	;put new page into the map.
	call	d[fCR3Flush]
	inc	LinearEntry
;
;Move page alias into extended memory.
;
	call	d[fPhysicalGetPage]	;get page for new page 1st.
	jc	InitError
	mov	LinearEntry+8,edx	;store physical address.
	and	ecx,1		;put user bits in useful place.
	shl	ecx,10
	and	edx,not 4095		;lose user bits.
	or	edx,111b		;present+user+write.
	or	edx,ecx		;set use flags.
	mov	eax,LinearEntry	;get the entry number again.
	mov	esi,1024*4096*1023	;base of page alias's.
	mov	es:d[esi+eax*4],edx	;set physical address.
	call	d[fCR3Flush]
	push	ds
	mov	esi,PageAliasLinear
	mov	edi,LinearEntry
	shl	edi,12
	mov	ecx,4096/4
	push	es
	pop	ds
	cld
	db 67h
	rep	movsd		;copy old to new.
	pop	ds
	mov	eax,PageALIASLinear
	mov	PageALIASLinear+4,eax
	mov	eax,LinearEntry
	shl	eax,12		;get linear address.
	mov	PageALIASLinear,eax
	mov	esi,PageDIRLinear
	mov	eax,1023
	mov	edx,LinearEntry+8	;get physical address again.
	or	edx,111b
	mov	ecx,es:[esi+eax*4]	;get origional value.
	mov	PageALIASLinear+8,ecx
	mov	es:[esi+eax*4],edx	;put new page into the map.
	mov	esi,PageALIASLinear
	mov	eax,1023
	mov	edx,LinearEntry+8	;get physical address again.
	or	edx,111b
	mov	es:[esi+eax*4],edx	;put new page into the map.
	call	d[fCR3Flush]
	inc	LinearEntry

; MED 09/19/96
COMMENT !
;
;Move page 1st into extended memory.
;
	call	d[fPhysicalGetPage]	;get page for new page 1st.
	jc	InitError
	mov	LinearEntry+8,edx	;store physical address.
	and	ecx,1		;put user bits in useful place.
	shl	ecx,10
	and	edx,not 4095		;lose user bits.
	or	edx,111b		;present+user+write.
	or	edx,ecx		;set use flags.
	;
	;Map it into general linear address space.
	;
	mov	eax,LinearEntry	;get the entry number again.
	mov	esi,1024*4096*1023	;base of page alias's.
	mov	es:d[esi+eax*4],edx	;set physical address.
	call	d[fCR3Flush]
	;
	;Copy table to new memory.
	;
	push	ds
	mov	esi,Page1stLinear
	mov	edi,LinearEntry
	shl	edi,12
	mov	ecx,4096/4
	push	es
	pop	ds
	cld
	db 67h
	rep	movsd		;copy old to new.
	pop	ds
	;
	;Make variables point to new memory.
	;
	mov	eax,Page1stLinear
	mov	Page1stLinear+4,eax	;store old address.
	mov	eax,LinearEntry
	shl	eax,12		;get linear address.
	mov	Page1stLinear,eax	;set new linear address.
	;
	;Set new address in page dir.
	;
	mov	edx,LinearEntry+8	;get physical address again.
	or	edx,111b
	;
	mov	esi,PageDIRLinear
	mov	eax,0
	mov	ecx,es:[esi+eax*4]	;get origional value.
	mov	Page1stLinear+8,ecx
	mov	es:[esi+eax*4],edx	;put new page into the map.
	call	d[fCR3Flush]
	;
	;Set new address in page dir alias.
	;
	mov	esi,PageALIASLinear
	mov	eax,0
	mov	es:[esi+eax*4],edx	;put new page into the map.
	call	d[fCR3Flush]
	inc	LinearEntry
END COMMENT !

;
;Move page dir into extended memory.
;
	call	d[fPhysicalGetPage]	;get page for new page DIR.
	jc	InitError
	mov	LinearEntry+8,edx	;store physical address.
	and	ecx,1		;put user bits in useful place.
	shl	ecx,10
	and	edx,not 4095		;lose user bits.
	or	edx,111b		;present+user+write.
	or	edx,ecx		;set use flags.
	;
	;Map it into normal linear address space.
	;
	mov	eax,LinearEntry	;get the entry number again.
	mov	esi,1024*4096*1023	;base of page alias's.
	mov	es:d[esi+eax*4],edx	;set physical address.
	call	d[fCR3Flush]
	;
	;Copy table to new memory.
	;
	push	ds
	mov	esi,PageDIRLinear
	mov	edi,LinearEntry
	shl	edi,12
	mov	ecx,4096/4
	push	es
	pop	ds
	cld
	db 67h
	rep	movsd		;copy old to new.
	pop	ds
	;
	;Make variables point to new memory.
	;
	mov	eax,PageDirLinear
	mov	PageDIRLinear+4,eax	;store old value.
	mov	eax,LinearEntry
	shl	eax,12		;get linear address.
	mov	PageDIRLinear,eax	;set new value.
	mov	eax,VCPI_CR3
	mov	PageDIRLinear+8,eax	;store old physical address.
	mov	eax,LinearEntry+8
	mov	VCPI_CR3,eax		;set new physical address.
	movzx	edi,KernalTSSReal
	shl	edi,4
	mov	es:[edi].tCR3,eax	;set CR3 in TSS as well.
	call	d[fCR3Flush]
	inc	LinearEntry
;
;Setup IDT.
;
	call	d[fPhysicalGetPage]	;get page for new page DIR.
	jc	InitError
	mov	LinearEntry+8,edx	;store physical address.
	and	ecx,1		;put user bits in useful place.
	shl	ecx,10
	and	edx,not 4095		;lose user bits.
	or	edx,111b		;present+user+write.
	or	edx,ecx		;set use flags.
	mov	eax,LinearEntry	;get the entry number again.
	mov	esi,1024*4096*1023	;base of page alias's.
	mov	es:d[esi+eax*4],edx	;set physical address.
	call	d[fCR3Flush]
	mov	eax,LinearEntry
	shl	eax,12
	mov	d[IDTVal+2],eax
	mov	w[IDTVal],0+(256*8)-1
	;
	mov	bp,256		;number of vectors.
	mov	ecx,offset InterruptHandler ;code address.
	mov	esi,DpmiEmuCS0	;gate to use.
	mov	al,0
	mov	ah,DescPresent+DescPL3+Desc386Int
	mov	edi,d[IDTVal+2]
@@3:	call	MakeDesc2
	add	edi,8		;next table address.
	add	ecx,8		;/
	dec	bp
	jnz	@@3
	inc	LinearEntry
	;
	;Re-load IDT value.
	;
	push	es
	mov	edi,offset MemIntBuffer
	push	ds
	pop	es
	mov	Real_CS[edi],_cwInit
	mov	Real_IP[edi],offset IDTFlush
	mov	Real_SS[edi],0
	mov	Real_SP[edi],0
	call	d[fRawSimulateFCALL]
	pop	es
;
;Get extended memory for DPMI emulator.
;
	push	ds
	mov	ax,InitDS
	mov	ds,ax
	assume ds:_cwInit
	mov	IErrorNumber,5
	assume ds:_cwRaw
	pop	ds
	;
	mov	ebp,offset cwDPMIEMUEnd-cwDPMIEMUStart
	add	ebp,4095
	shr	ebp,12		;Get number of pages needed.
	mov	eax,LinearEntry
	shl	eax,12
	mov	LinearEntry+4,eax	;Store start address.
@@2:	call	d[fPhysicalGetPage]	;try to allocate a page.
	jc	InitError
	and	ecx,1		;put user bits in useful place.
	shl	ecx,10
	and	edx,not 4095		;lose user bits.
	or	edx,111b		;present+user+write.
	or	edx,ecx		;set use flags.
	mov	eax,LinearEntry	;get the entry number again.
	mov	esi,1024*4096*1023	;base of page alias's.
	mov	es:d[esi+eax*4],edx	;set physical address.
	call	d[fCR3Flush]
	inc	LinearEntry		;update pointer.
	dec	ebp
	jnz	@@2
;
;Copy DPMI emulator code into extended memory we just allocated.
;
	mov	edi,LinearEntry+4	;Get the destination.
	mov	si,_cwDPMIEMU
	movzx	esi,si
	shl	esi,4		;Point to the source.
	mov	ecx,offset cwDPMIEMUEnd-cwDPMIEMUStart
	shr	ecx,2
	push	ds
	push	es
	pop	ds
	cld
	db 67h
	rep	movsd		;Copy it up their.
	pop	ds
;
;Setup DPMI emulator selectors.
;
	push	es
	mov	ax,GDTData
	mov	es,ax
	mov	esi,LinearEntry+4
	mov	ecx,offset cwDPMIEMUEnd-cwDPMIEMUStart
	mov	al,1 shl 6
	mov	ah,DescPresent+DescPL3+DescMemory+DescERCode
	mov	di,DpmiEmuCS
	call	MakeDesc
	mov	esi,LinearEntry+4
	mov	ecx,offset cwDPMIEMUEnd-cwDPMIEMUStart
	mov	al,1 shl 6
	mov	ah,DescPresent+DescPL0+DescMemory+DescERCode
	mov	di,DpmiEmuCS0
	call	MakeDesc
	mov	esi,LinearEntry+4
	mov	ecx,offset cwDPMIEMUEnd-cwDPMIEMUStart
	mov	al,1 shl 6
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	mov	di,DpmiEmuDS
	call	MakeDesc
	pop	es
;
;Should be OK to enable interrupts at last.
;
	mov	ah,1
	int	16h
	sti
;
;Initialise hardware interrupt call-back's.
;
	call	InitHardwareInts
;
;Allocate memory for new GDT/LDT
;
	push	ds
	mov	ax,InitDS
	mov	ds,ax
	assume ds:_cwInit
	mov	IErrorNumber,5
	assume ds:_cwRaw
	pop	ds
	;
	mov	ebp,(8192*8)+8192
	shr	ebp,12		;Get number of pages needed.
	mov	eax,LinearEntry
	shl	eax,12
	mov	LinearEntry+4,eax	;Store start address.
@@6:	call	d[fPhysicalGetPage]	;try to allocate a page.
	jc	InitError
	and	ecx,1		;put user bits in useful place.
	shl	ecx,10
	and	edx,not 4095		;lose user bits.
	or	edx,111b		;present+user+write.
	or	edx,ecx		;set use flags.
	mov	eax,LinearEntry	;get the entry number again.
	mov	esi,1024*4096*1023	;base of page alias's.
	mov	es:d[esi+eax*4],edx	;set physical address.
	call	d[fCR3Flush]
	inc	LinearEntry		;update pointer.
	dec	ebp
	jnz	@@6
	;
	mov	esi,LinearEntry+4
	mov	MDTLinear,esi	;store for allocation code.
	mov	MDTLinear+4,esi
	add	MDTLinear+4,8192*8	;setup bit string address.
	;
	;Clear the memory to zero's.
	;
	mov	edi,MDTLinear
	mov	ecx,(8192*8)+8192
	cld
	xor	al,al
	db 67h
	rep	stosb
	mov	edi,MDTLinear+4
	or	es:d[edi],-1		;Force VCPI values to not used.
	;
	;See which table we want to use.
	;
	test	RawSystemFlags,128	;GDT or LDT?
	jnz	@@LDT
	;
	;Setup a new GDT.
	;
	mov	esi,MDTLinear
	mov	GDTLinear+4,esi
	mov	ecx,65535
	xor	al,al
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	mov	di,GDTData
	push	es
	mov	es,di
	call	MakeDesc
	pop	es
	;
	;Copy current GDT to new GDT.
	;
	push	ds
	mov	esi,GDTLinear
	mov	edi,GDTLinear+4
	mov	ax,KernalZero
	mov	ds,ax
	mov	ecx,GDT_Entries*8
	cld
	db 67h
	rep	movsb
	pop	ds
	;
	;Set new GDT values.
	;
	pushf
	cli
	mov	eax,GDTLinear
	mov	GDTLinear+8,eax
	mov	eax,GDTLinear+4
	mov	GDTLinear,eax
	mov	d[GDTVal+2],eax
	mov	d[VCPI_GDT+2],eax
	popf
	;
	;Now mark all used descriptors in allocation control string.
	;
	mov	edi,GDTLinear
	mov	esi,MDTLinear+4
	mov	cx,GDT_Entries
@@4:	test	es:b[edi+5],DescPresent	;this descriptor in use?
	jz	@@5
	or	es:b[esi],-1
@@5:	add	edi,8		;next descriptor.
	inc	esi		;update descriptor number.
	dec	cx
	jnz	@@4
	;
	;Now setup extra GDT descriptors.
	;
	push	es
	mov	ax,GDTData
	mov	es,ax
	;
	mov	di,KernalB000
	mov	esi,0b0000h
	mov	ecx,65535
	xor	al,al
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	call	MakeDesc
	;
	mov	di,KernalB800
	mov	esi,0b8000h
	mov	ecx,65535
	xor	al,al
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	call	MakeDesc
	;
	mov	di,KernalA000
	mov	esi,0a0000h
	mov	ecx,65535
	xor	al,al
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	call	MakeDesc
	pop	es
	;
@@LDT:	;Setup new LDT.
	;
	mov	esi,MDTLinear
	mov	LDTLinear,esi
	;
	;Map LDT into GDT.
	;
	push	es
	mov	ax,GDTData
	mov	es,ax
	mov	di,KernalLDT
	mov	esi,LDTLinear
	mov	ecx,8192*8
	xor	al,al
	mov	ah,DescPresent+DescPL3+DescLDT
	call	MakeDesc
	pop	es
	;
	mov	ah,1
	int	16h		;force GDT/LDT reload with mode switch.
;
;Initialise application memory pool.
;
	mov	eax,LinearEntry
	shl	eax,12
	mov	LinearBase,eax
	add	eax,4096
	mov	LinearLimit,eax
	;
	call	d[fPhysicalGetPage]	;try to allocate a page.
	jc	InitError

	and	ecx,1		;put user bits in useful place.
	shl	ecx,10
	and	edx,not 4095		;lose user bits.
	or	edx,111b		;present+user+write.
	or	edx,ecx		;set use flags.
	mov	eax,LinearEntry	;get the entry number again.
	mov	esi,1024*4096*1023	;base of page alias's.
	mov	es:d[esi+eax*4],edx	;set physical address.
	call	d[fCR3Flush]
	mov	eax,LinearEntry	;get the entry number again.
	mov	esi,1024*4096*1022
	mov	es:d[esi+eax*4],0	;clear this pages details.
;
;Initialise virtual memory manager stuff.
;
	call	d[fPhysicalGetPages]	;find free pages.
	mov	eax,edx
	shl	eax,12
	add	eax,LinearLimit
	sub	eax,LinearBase
	mov	ebp,eax		;save this for comparisons.
	mov	di,InitDS
	mov	fs,di
	mov	di,offset VMMDrivPath1	;point to start of paths.
	assume fs:_cwInit
	cmp	fs:NoVMSwitch,0
	assume fs:nothing
	jnz	@@v9
	;
	;Work through list of posibles till we find a useful entry.
	;
@@v0:
	cmp	fs:b[di],0
	jz	@@v7
	cmp	fs:b[di],-1
	jz	@@v9
	;
	;Check drive is valid and has enough free space.
	;

COMMENT !
; MED 10/11/96
; if no drivespec, then use default drive
	cmp	BYTE PTR fs:[di+1],':'
	je	isdrive

	movzx	edx,di	; scan to end of current pathspec
defloop:
	inc	dx			; edx known 16-bit value so 16-bit increment is valid
	cmp	BYTE PTR fs:[edx],0
	jne	defloop

; at end of current pathspec, now shift forward two bytes to allow for drive
shiftloop:
	mov	al,fs:[edx]
	mov	fs:[edx+2],al
	dec	dx
	cmp	di,dx		; edx known 16-bit value so 16-bit compare is valid
	jae	shiftloop

	push	edi
	mov	edi,offset PageInt
	push	ds
	pop	es
	mov	[edi].Real_EAX,1900h
	mov	Real_SS[edi],0
	mov	Real_SP[edi],0
	mov	bl,21h
	call	d[fRawSimulateINT]
	mov	al,BYTE PTR [edi].Real_EAX
	pop	edi
	add	al,'A'		; convert to drive
	mov	fs:[di],al
	mov	BYTE PTR fs:[di+1],':'	; add colon to drivespec
END COMMENT !

isdrive:
	mov	dl,fs:[di]		;get swap file drive.
	cmp	dl,61h		; 'a'
	jb	@@v1
	cmp	dl,7Ah		; 'z'
	ja	@@v1
	and	dl,5Fh		;convert to upper case.
@@v1:	sub	dl,'A'		;make it real.
	inc	dl		;adjust for current type selection.

drivefree:
	mov	ah,36h		;get free space.
	push	ebp
	int	21h		;/
	pop	ebp
	cmp	ax,-1		;invalid drive?
	jz	@@v7
	mul	cx		;Get bytes per cluster.
	mul	bx		;Get bytes available.
	shl	edx,16
	mov	dx,ax
	cmp	edx,ebp		;Enough free space.
	jc	@@v7
	;
	;See if we can create a temp file.
	;

; MED 02/25/96, use name specified in CAUSEWAY e-var
	test	DesiredVMMName,-1
	je	med5a			; no VMM name request
	push	di
	mov	si,di
	push	si			; save -> filespec start

; find end of pathspec
mednameloop:
	cmp	BYTE PTR fs:[si],0
	je	medndone
	inc	si
	jmp	mednameloop

; append desired name on filespec
medndone:

; 05/15/98
; check for backslash already existing
	cmp	BYTE PTR fs:[si-1],'\'
	je	medbs

	mov	BYTE PTR fs:[si],'\'
	inc	si

medbs:
	mov	di,offset DesiredVMMName

medtransloop:
	mov	al,[di]
	mov	fs:[si],al
	inc	di
	inc	si
	test	al,al
	jne	medtransloop
	pop	si				; restore si -> filespec start

	mov	edi,offset PageInt
	push	ds
	pop	es
	mov	[edi].Real_DS,_cwInit
	mov	[edi].Real_EDX,esi
	mov	[edi].Real_EAX,3c00h
	mov	[edi].Real_ECX,0
	mov	Real_SS[edi],0
	mov	Real_SP[edi],0
	mov	bl,21h
	call	d[fRawSimulateINT]
	test	Real_Flags[edi],1
	mov	eax,Real_EAX[edi]
	pop	di
	jz	@@v8
	jmp	@@v7
	;

med5a:
	push	di
	mov	si,di
	mov	edi,offset PageInt
	push	ds
	pop	es
	mov	[edi].Real_DS,_cwInit
	mov	[edi].Real_EDX,esi
	mov	[edi].Real_EAX,5a00h
	mov	[edi].Real_ECX,0
	mov	Real_SS[edi],0
	mov	Real_SP[edi],0
	mov	bl,21h
	call	d[fRawSimulateINT]
	test	Real_Flags[edi],1
	mov	eax,Real_EAX[edi]
	pop	di
	jz	@@v8
	;
@@v7:	add	di,128
	jmp	@@v0
	;
@@v8:	;Store the handle and copy the name accross.
	;
	mov	VMMHandle,ax		;store the handle.
	pushm	ds,fs
	pop	ds
	mov	di,offset VMMName
	mov	cx,128
	rep	movsb
	pop	ds
	mov	al,VMMName
	cmp	al,61h		; 'a'
	jb	@@v2
	cmp	al,7Ah		; 'z'
	ja	@@v2
	and	al,5Fh		;convert to upper case.
@@v2:	mov	VMMName,al

; MED 02/25/96, if pre-allocate, then force write to allocated size
	cmp	PreAllocSize,0
	je	medpre2
	mov	bx,VMMHandle
	mov	ecx,PreAllocSize
	mov	dx,cx
	shr	ecx,16
	mov	ax,4200h	; seek from beginning of file
	int	21h
	xor	cx,cx		; write zero bytes (pre-allocating based on seek)
	mov	ah,40h		; write to file
	int	21h
	mov	ah,68h		; commit file
	int	21h
	xor	dx,dx		; get current size of swap file
	mov	cx,dx
	mov	ax,4202h
	int	21h
	mov	WORD PTR SwapFileLength,ax	; update internal swapfile length variable
	mov	WORD PTR SwapFileLength+2,dx

medpre2:
	;
	;Now patch the exception vector.
	;
	mov	bl,14		;Page fault vector.
	movzx	eax,bl
	mov	ebx,eax
	shl	ebx,1		;*2
	mov	eax,ebx
	shl	ebx,1		;*4
	add	ebx,eax		;*6
	push	ds
	mov	ax,DpmiEmuDS
	mov	ds,ax
	assume ds:_cwDPMIEMU
	add	ebx,offset ExceptionTable
	mov	edx,[ebx]		;get offset.
	mov	cx,4[ebx]		;get segment selector.
	mov	w[OldExcep14+4],cx
	mov	d[OldExcep14],edx	;store 32 bit offset.
	mov	d[ebx],offset VirtualFault	;set offset.
	mov	w[ebx+4],DpmiEmuCS	;set segment selector.
	or	DpmiEmuSystemFlags,1 shl 1 ;flag VMM's presence.
	mov	ax,MainDS
	mov	ds,ax
	assume ds:_cwMain
	or	SystemFlags,1 shl 1	;flag VMM's presence.
	assume ds:_cwRaw
	pop	ds
	or	RawSystemFlags,1 shl 1	;flag VMM's presence.
@@v9:	;
	push	ds
	pop	fs

	mov	ax,InitDS
	mov	ds,ax
	assume ds:_cwInit
	jmp	@@InProtected
;
;Do initialisations needed for DPMI
;
@@InitDPMI:	mov	ax,_cwMain
	mov	ds,ax
	assume ds:_cwMain
;
;Get some memory for the transfer buffer.
;
	mov	cs:IErrorNumber,5
	mov	bx,8192/16
	mov	ah,48h
	int	21h		;get memory for transfer buffer.
	jc	InitError
	mov	TransferReal,ax
;
;Get some memory for the INT buffer.
;
	mov	bx,((RawStackTotal/2)/16)+1
	mov	ah,48h
	int	21h
	jc	InitError
	mov	DPMIStackSeg,ax
	mov	DPMIStackOff,RawStackTotal/2
;
;Do instalation check and get mode switch address.
;
	mov	cs:IErrorNumber,9
	mov	ax,1687h		;DPMI instalation check.
	int	2fh
	or	ax,ax		;None-zero means its not there.
	jnz	InitError
;
;Check for 32-bit support if needed.
;
	test	SystemFlags,1 shl 14	;Dual mode?
	jnz	@@Use16Bit23
	;
	test	SystemFlags,1
	jz	@@Use32Bit23
	jmp	@@Use16Bit23
@@Use32Bit23:	mov	cs:IErrorNumber,9
	test	bx,1		;Must offer 32 bit support.
	jz	InitError
@@Use16Bit23:	mov	bx,si		;Get DPMI save buffer size.
	mov	ax,si
	or	bx,bx
	jz	@@d0		;No guarante that it'll need it.
;
;Allocate memory for DPMI state save buffer.
;
	mov	cs:IErrorNumber,5
	push	di
	push	es
	mov	ah,48h
	int	21h		;Try and claim memory for it.
	pop	es
	pop	di
	mov	bx,ax
	jc	InitError
@@d0:	pushm	ax,ds
	mov	ax,_cwInit
	mov	ds,ax
	assume ds:_cwInit
	mov	DPMISwitch,di	;Store the switch call address.
	mov	DPMISwitch+2,es
	mov	es,bx
	popm	ax,ds
	assume ds:_cwMain
;
;Attempt to switch mode.
;
	test	SystemFlags,1
	jz	@@Use32Bit24
	xor	ax,ax		;16 bit segments for this code.
	jmp	@@Use16Bit24
@@Use32Bit24:	mov	ax,1		;32 bit segments for this code.
@@Use16Bit24:	push	ax
	mov	ax,_cwInit
	mov	ds,ax
	pop	ax
	assume ds:_cwInit
	pusha
	call	d[DPMISwitch]	;Make the switch.
	popa
	jnc	@@DpmiInProtected
	mov	IErrorNumber,9
	push	ax
	mov	ax,_cwMain
	mov	ds,ax
	pop	ax
	assume ds:_cwMain
	test	w[SystemFlags+2],1	;Dual mode?
	jz	InitError
	xor	SystemFlags,1
	xor	ax,1		;toggle the mode.
	push	ax
	mov	ax,_cwInit
	mov	ds,ax
	pop	ax
	assume ds:_cwInit
	call	d[DPMISwitch]	;Make the switch.
	jc	InitError		;really isn't feeling well.
@@DpmiInProtected:
	mov	iDataSegment,ds
	mov	iCodeSegment,cs
	mov	iStackSegment,ss
	mov	iPSPSegment,es
	xor	eax,eax
	mov	ax,sp
	mov	esp,eax
	mov	ax,es:[2ch]
	mov	iENVSegment,ax
;
;Create _cwMain code segment.
;
	mov	iErrorNumber,8
	mov	ax,0000h
	mov	cx,1
	int	31h		;allocate a selector.
	jc	InitError
	mov	mCodeSegment,ax
	mov	bx,ax
	push	ds
	pop	es
	mov	di,offset dpmiSelBuffer
	mov	si,_cwMain
	movzx	esi,si
	shl	esi,4
	mov	ecx,65535
	xor	al,al
	mov	ah,DescPresent+DescPL3+DescMemory+DescERCode
	call	MakeDesc
	mov	ax,000ch
	push	ds
	pop	es
	mov	edi,offset dpmiSelBuffer
	int	31h
;
;Create _cwMain data segment.
;
	mov	iErrorNumber,8
	mov	ax,0000h
	mov	cx,1
	int	31h		;allocate a selector.
	jc	InitError
	mov	mDataSegment,ax
	mov	bx,ax
	push	ds
	pop	es
	mov	di,offset dpmiSelBuffer
	mov	si,_cwMain
	movzx	esi,si
	shl	esi,4
	mov	ecx,65535
	xor	al,al
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	call	MakeDesc
	mov	ax,000ch
	push	ds
	pop	es
	mov	edi,offset dpmiSelBuffer
	int	31h
;
;Create a 0-4G selector.
;
	mov	iErrorNumber,8
	mov	ax,0000h
	mov	cx,1
	int	31h		;allocate a selector.
	jc	InitError
	mov	iRealSegment,ax
	mov	bx,ax
	push	ds
	pop	es
	mov	di,offset dpmiSelBuffer
	xor	esi,esi
	or	ecx,-1
	xor	al,al
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	call	MakeDesc
	mov	ax,000ch
	push	ds
	pop	es
	mov	edi,offset dpmiSelBuffer
	int	31h
;
;Make main seg addressable now.
;
	mov	ax,mDataSegment
	mov	es,ax
	assume es:_cwMain
	mov	ax,mCodeSegment
	mov	es:CodeSegment,ax
	mov	es:w[TerminationHandler+4],ax
	mov	ax,mDataSegment
	mov	es:DataSegment,ax
	mov	ax,iStackSegment
	mov	es:StackSegment,ax
	mov	ax,iPSPSegment
	mov	es:PSPSegment,ax
	mov	ax,iENVSegment
	mov	es:ENVSegment,ax
	mov	ax,iRealSegment
	mov	es:RealSegment,ax
	mov	ax,iCodeSegment
	mov	es:CodeSegmenti,ax
	mov	ax,iDataSegment
	mov	es:DataSegmenti,ax
	push	es
	pop	ds
	assume es:nothing
	assume ds:_cwMain


;
;Patch INT 21h exec function to preserve the stack.
;
	if	0
	mov	bl,21h
	mov	ax,200h
	int	31h
	mov	w[OldInt21hExec],dx
	mov	w[OldInt21hExec+2],cx
	mov	dx,offset Int21hExecPatch
	mov	cx,_cwMain
	mov	bl,21h
	mov	ax,201h
	int	31h
	endif
;
;Make right stuff addresable again.
;
	mov	ds,DataSegmenti
	assume ds:_cwInit
	or	IProtectedMode,-1
;
;Now get on with installing the higher level stuff.
;
@@InProtected:	mov	ax,mDataSegment
	mov	ds,ax
	assume ds:_cwMain
	;
	mov	ax,ProtectedType	;Copy protected mode environment type into common
	shl	ax,1+1		;variable for application access. Might become useful
	or	w[SystemFlags],ax	;at some point. Other flags can be added at will.
	mov	ax,ProtectedFlags
	shl	ax,1+1+2
	or	w[SystemFlags],ax
	or	w[SystemFlags],32768	;Flags us in protected mode.
	;
	mov	ax,DataSegmenti
	mov	ds,ax
	assume ds:_cwInit
;
;Add CW API patch to int 31h and 2Fh.
;
	mov	IErrorNumber,5
	xor	bx,bx
	mov	cx,offset _apiCodeEnd-_apiCodeStart
	mov	ax,0501h
	int	31h		;Get memory.
	jc	InitError
	xor	si,si
	mov	di,offset _apiCodeEnd-_apiCodeStart
	mov	ax,0600h
	int	31h		;Lock memory.
	jc	InitError
	shl	ebx,16
	mov	bx,cx
	mov	dpmiSelBase,ebx
;
;Allocate code selector.
;
	mov	iErrorNumber,8
	mov	ax,0000h
	mov	cx,1
	int	31h		;allocate a selector.
	jc	InitError
	mov	dpmiCodeSel,ax
	mov	bx,ax
	push	ds
	pop	es
	mov	di,offset dpmiSelBuffer
	mov	esi,dpmiSelBase
	mov	ecx,offset _apiCodeEnd-_apiCodeStart
	mov	al,1 shl 6
	mov	ah,DescPresent+DescPL3+DescMemory+DescERCode
	call	MakeDesc
	mov	ax,000ch
	push	ds
	pop	es
	mov	edi,offset dpmiSelBuffer
	int	31h
;
;Allocate data selector.
;
	mov	iErrorNumber,8
	mov	ax,0000h
	mov	cx,1
	int	31h		;allocate a selector.
	jc	InitError
	mov	dpmiDataSel,ax
	mov	bx,ax
	push	ds
	pop	es
	mov	di,offset dpmiSelBuffer
	mov	esi,dpmiSelBase
	mov	ecx,offset _apiCodeEnd-_apiCodeStart
	xor	al,al
	mov	ah,DescPresent+DescPL3+DescMemory+DescRWData
	call	MakeDesc
	mov	ax,000ch
	push	ds
	pop	es
	mov	edi,offset dpmiSelBuffer
	int	31h
;
;Copy API code into the new memory.
;
	pushm	ds,es
	mov	es,dpmiDataSel
	mov	ds,iRealSegment
	xor	edi,edi
	mov	esi,edi
	mov	si,seg _apiCode
	shl	esi,4
	mov	ecx,offset _apiCodeEnd-_apiCodeStart
	db 67h
	rep	movsb
	popm	ds,es
;
;Setup descriptors in new memory.
;
	pushm	ds,es
	mov	es,dpmiDataSel
	mov	ds,mDataSegment
	assume ds:_cwMain
	assume es:_apiCode
	mov	es:apiDSeg,ds
	mov	es:apiDDSeg,es
	mov	eax,d[SystemFlags]
	mov	es:d[apiSystemFlags],eax
;
;Set INT vector to bring API code into play.
;
	mov	bl,31h
	mov	ax,204h
	int	31h
	test	SystemFlags,1
	jz	@@Use32
	mov	es:w[OldIntSys],dx
	mov	es:w[OldIntSys+2],cx
	jmp	@@Use0
@@Use32:	mov	es:d[OldIntSys],edx
	mov	es:w[OldIntSys+4],cx
@@Use0:	mov	bl,31h
	mov	edx,offset cwAPIpatch
	pushm	ax,ds
	mov	ax,DataSegmenti
	mov	ds,ax
	assume ds:_cwInit
	mov	cx,dpmiCodeSel
	assume ds:_cwMain
	popm	ax,ds
	mov	ax,205h
	int	31h
;
;Copy version through to API.
;
	mov	al,b[VersionMajor]
	sub	al,'0'
	mov	es:cwMajorVersion,al
	mov	al,b[VersionMinor]
	sub	al,'0'
	shl	al,1	;*2
	mov	ah,al
	shl	al,2	;*8
	add	ah,al
	mov	al,b[VersionMinor+1]
	sub	al,'0'
	add	al,ah
	mov	es:cwMinorVersion,al
	assume es:nothing
	assume ds:_cwInit
	popm	ds,es
;
;Set flag so we know the API is in place.
;
	mov	ax,dpmiDataSel
	mov	apiDataSegi,ax
	mov	bx,dpmiCodeSel
	push	ds
	mov	ds,mDataSegment
	assume ds:_cwMain
	mov	apiDataSeg,ax
	mov	apiCodeSeg,bx
	mov	d[TerminationHandler],offset InitError
	mov	w[TerminationHandler+4],cs
	assume ds:_cwInit
	pop	ds
;
;Sort out state save address & size.
;
	push	ds
	mov	ds,mDataSegment
	assume ds:_cwMain
	mov	ax,0305h
	int	31h
	jc	@@NoState
	mov	w[DPMIStateSize],ax
	mov	w[DPMIStateSize+2],0
	test	SystemFlags,1
	jz	@@DS_Use32
	mov	w[DPMIStateAddr+2],si
	mov	w[DPMIStateAddr],di
	jmp	@@NoState
@@DS_Use32:	mov	w[DPMIStateAddr+4],si
	mov	d[DPMIStateAddr],edi
	;
@@NoState:	pop	ds
	assume ds:_cwInit
;
;Patch exception vectors to put API handlers in place.
;
	mov	ax,cs
	push	ax
	mov	ax,offset @@pe0
	push	ax
	mov	ax,dpmiCodeSel
	push	ax
	mov	eax,offset PatchExc
	push	ax
	retf
@@pe0:	;
;
;Get memory for new PSP.
;
	mov	IErrorNumber,5
	mov	ecx,(size PSP_Struc)+(size EPSP_Struc)
	sys	GetMem32
	jc	InitError
	push	ds
	mov	ds,mDataSegment
	assume ds:_cwMain
	xchg	bx,PSPSegment
	pushm	ds,es
	mov	es,PSPSegment
	mov	ds,bx
	xor	si,si
	xor	di,di
	mov	cx,256/4
	rep	movsd
	popm	ds,es
	assume ds:_cwInit
	pop	ds
;
;Initialise PSP fields.
;
	mov	IErrorNumber,8
	push	ds
	push	es
	mov	ds,mDataSegment
	assume ds:_cwMain
	xor	edx,edx
	mov	es,PSPSegment
	mov	ax,EnvSegment
	mov	es:[PSP_Environment],ax	;Setup ENV in PSP.
	mov	ax,RealENVSegment
	mov	es:w[EPSP_RealENV],ax
	mov	ax,offset Int21hExecCount
	mov	es:w[EPSP_ExecCount],ax
	mov	es:w[EPSP_ExecCount+2],ds
	mov	es:d[EPSP_Resource],edx	;Clear memory fields.
	mov	es:d[EPSP_INTMem],edx
	mov	es:d[EPSP_DPMIMem],edx
	mov	es:w[EPSP_Parent],es	;set parent PSP.
	mov	es:w[EPSP_Next],dx
	mov	es:d[EPSP_DTA],80h	;Use default PSP DTA.
	mov	es:w[EPSP_DTA+4],es
	mov	eax,16384-(mcbChunkLen+mcbLen)
	mov	es:d[EPSP_mcbMaxAlloc],eax
	mov	es:d[EPSP_mcbHead],edx
	mov	es:w[EPSP_SegBase],0
	mov	es:w[EPSP_SegSize],0
	mov	es:d[EPSP_LastPSP],0
	mov	es:d[EPSP_NextPSP],0
	mov	es:d[EPSP_Exports],0
	mov	es:d[EPSP_Imports],0
	mov	es:d[EPSP_Links],80000000h
	mov	es:d[EPSP_EntryCSEIP+4],0
	mov	es:w[EPSP_PSPSel],es
	mov	BasePSP,es
	mov	bx,es
	sys	GetSelDet32
	mov	BasePSPAddress,edx
	;
	sys	GetSel
	jc	InitError
	movzx	edx,es:w[PSP_HandlePtr+2]
	shl	edx,4
	movzx	ecx,es:w[PSP_Handles]
	movzx	eax,es:w[PSP_HandlePtr]
	add	edx,eax
	sys	SetSelDet32
	mov	dx,bx
@@normal:	mov	es:w[PSP_HandlePtr+2],dx
	mov	es:w[PSP_HandlePtr],0
	pop	es
	assume ds:_cwInit
	pop	ds
;
;Setup transfer buffer and selector.
;
	mov	IErrorNumber,8
	sys	GetSel
	jc	InitError
	push	ds
	mov	ds,mDataSegment
	assume ds:_cwMain
	movzx	edx,TransferReal
	shl	edx,4
	mov	ecx,TransferSize
	sys	SetSelDet32
	jc	InitError
	push	es
	mov	es,PSPSegment
	mov	es:w[EPSP_TransProt],bx
	mov	ax,TransferReal
	mov	es:w[EPSP_TransReal],ax
	mov	eax,TransferSize
	mov	es:d[EPSP_TransSize],eax
	pop	es
	assume ds:_cwInit
	pop	ds
;
;Setup internaly EXPORT'ed symbols.
;
	mov	bx,dpmiDataSel
	sys	GetSelDet32
	mov	edi,edx
	add	edi,offset apiExports
	push	ds
	mov	ds,mDataSegment
	assume ds:_cwMain
	push	es
	mov	es,PSPSegment
	mov	es:d[EPSP_Exports],edi
	mov	es,RealSegment
	mov	ebp,es:[edi]
	add	edi,4
	add	es:d[edi],edx
	add	edi,4
@@exp0:	add	es:d[edi],edx
	mov	esi,es:[edi]
	mov	bx,CodeSegment
	cmp	es:w[esi+4],0
	jz	@@exp1
	mov	bx,DataSegment
	cmp	es:w[esi+4],1
	jz	@@exp1
	mov	bx,apiCodeSeg
	cmp	es:w[esi+4],2
	jz	@@exp1
	mov	bx,apiDataSeg
	cmp	es:w[esi+4],3
	jz	@@exp1
	or	bx,-1
@@exp1:	mov	es:[esi+4],bx
	add	edi,4
	dec	ebp
	jnz	@@exp0
	pop	es
	assume ds:_cwInit
	pop	ds
;
;Initialise extensions. Written in a bit of a hurry but allows
;additional interupt service code to live in other segments.
;
	push	ds
	mov	ds,mDataSegment
	assume ds:_cwMain
	or	mcbAllocations,-1	;Enable MCB code.
	;
	mov	di,offset ExtensionList
@@e0:	cmp	w[di],-1		;end of the list?
	jz	@@e9
	mov	bp,[di]		;get pointer to details.
	movzx	ecx,ds:w[bp+4]	;get patch size.
	sys	GetMemLinear32	;get some memory.
	push	ds
	mov	ds,DataSegmenti
	assume ds:_cwInit
	mov	iErrorNumber,5
	assume ds:_cwMain
	pop	ds
	jc	InitError
	sys	LockMem32		;lock the memory.
	jc	InitError
	sys	GetSel		;get a selector to use for
	push	ds
	mov	ds,DataSegmenti
	assume ds:_cwInit
	mov	IErrorNumber,8	;the code segment.
	assume ds:_cwMain
	pop	ds
	jc	InitError
	mov	edx,esi
	sys	SetSelDet32		;set it's base and limit.
	jc	InitError
	push	ecx
	mov	cx,ds:[bp+2]		;Get code seg size.
	sys	CodeSel		;convert to executable.
	pop	ecx
	mov	ds:[bp+8+4],bx	;store it for now.
	mov	ds:[bp+16+4],bx
	mov	ds:[bp+24],bx
	sys	GetSel		;get a selector to use for data.
	jc	InitError
	sys	SetSelDet32		;set it's base and limit.
	jc	InitError
	mov	ds:[bp+28],bx	;store it for now.
	pushm	di,ds,es
	movzx	esi,ds:w[bp+0]	;get real mode segment base.
	shl	esi,4
	mov	ds,RealSegment
	mov	es,bx
	xor	edi,edi
	db 67h
	rep	movsb
	popm	di,ds,es
	mov	ds:w[bp+32],-1	;flag installed.
	pushm	di,bp,ds
	mov	es,DataSegment
	mov	ds,ds:[bp+28]

	push	cs
	push	offset @@e1
	push	es:w[bp+12]
	push	es:w[bp+8]
	retf			;call init routine.
@@e1:	popm	di,bp,ds
	jc	InitError
	add	di,2
	jmp	@@e0
@@e9:	assume ds:_cwInit
	pop	ds

IFDEF DEBUG3
	push	eax
	push	ebx
	push	ecx
	push	es
	push	ds
	mov	ax,KernalZero
	mov	es,ax

	mov	ebx,0b81e0h
	mov	BYTE PTR es:[ebx],'F'
	mov	BYTE PTR es:[ebx+2],'P'
	mov	BYTE PTR es:[ebx+4],' '
	mov	BYTE PTR es:[ebx+6],' '
	mov	BYTE PTR es:[ebx+24],' '
	mov	BYTE PTR es:[ebx+26],' '

	mov	ax,KernalDS		;Get data descriptor.
	mov	ds,ax
	assume ds:_cwRaw
	movzx	edx,FirstUninitPage
	push	edx
	mov	ecx,edx
	xor	edx,edx
deb3_3:
	rol	ecx,4
	mov	al,cl
	and	al,0fh
	cmp	al,10
	jb	deb3_2
	add	al,7
deb3_2:
	add	al,48
	mov	es:[ebx+edx*2+8],al
	inc	edx
	cmp	edx,8
	jb	deb3_3
	pop	edx

	mov	ecx,200000h
deb3_aloop:
	dec	ecx
;	jne	deb3_aloop
	pop	ds
	pop	es
	pop	ecx
	pop	ebx
	pop	eax
ENDIF

COMMENT !
IFDEF DEBUG3
	push	ds
	push	es
	push	eax
	push	ebx
	push	ecx
	push	edx
	push	edi
	push	ebp

	mov	ax,KernalDS		;Get data descriptor.
	mov	ds,ax
	assume ds:_cwRaw
	movzx	edi,Page1stReal	;get linear address.
	shl	edi,4
	mov	ax,KernalZero
	mov	es,ax
	mov	bp,1024
	sub	esp,10
	push	ss
	pop	ds
moo1:
	mov	ecx,es:[edi]
	xor	edx,edx
deb5_3:
	rol	ecx,4
	mov	al,cl
	and	al,0fh
	cmp	al,10
	jb	deb5_2
	add	al,7
deb5_2:
	add	al,48
	mov	BYTE PTR ss:[esp+edx],al
	inc	edx
	cmp	edx,8
	jb	deb5_3

	mov	WORD PTR ss:[esp+8],0a0dh
	mov	edx,esp
	mov	ecx,10
	mov	ebx,1
	mov	ah,40h
	int	21h

	add	di,4		;next page table entry.
	dec	bp
	jnz	moo1

	add	esp,10
	pop	ebp
	pop	edi
	pop	edx
	pop	ecx
	pop	ebx
	pop	eax
	pop	es
	pop	ds
	jmp	debout1

debout1:
ENDIF
END COMMENT !

;
;We're all done here so switch to main code segment for final re-size and run.
;
	push	mCodeSegment
	push	offset cwOpen
	retf

	.286

@@OldStrat:	;
	dw ?,?

@@NumXMSHandles:
	db ?

; MED, 09/10/99, increase max XMS size to dword
@@XMSSize:	;
;	dw ?
	dd	0

Startup	endp


;-------------------------------------------------------------------------------
;
;Something is wrong with this system so print an error message and get out of
;here.
;
InitError	proc	near
;
;Find out if we're in protected mode or not.
;
	.386p
	assume ds:nothing
	cmp	cs:IProtectedMode,0      	; are we in protected mode?

; MED 07/10/97, allow 286 non-crash at this point
;	jz	@@RealMode
	jnz	chkapi
	jmp	@@RealMode
chkapi:

	cmp	cs:apiDataSegi,0	;API installed?
	jz	@@noAPI
	;
	mov	ds,cs:mDataSegment
	assume ds:_cwMain
;
;Remove extension patches.
;
	mov	di,offset ExtensionList	;list of interupt patches.
@@p1:	cmp	w[di+2],-1		;search for the end of the table so we can restore
	jz	@@p0		;vectors in reverse order.
	add	di,2
	jmp	@@p1
	;
@@p0:	mov	bp,w[di]
	cmp	ds:w[bp+32],-1	;installed?
	jnz	@@p2
	pushm	di,bp
	push	cs
	push	offset @@p3
	push	ds:w[bp+20]
	push	ds:w[bp+16]
	retf
@@p3:	popm	di,bp
@@p2:	sub	di,2
	cmp	di,offset ExtensionList-2
	jnz	@@p0
;
;Remove api exception patches.
;
	cmp	apiExcepPatched,0
	jz	@@pe0
	mov	ax,cs
	push	ax
	mov	ax,offset @@pe0
	push	ax
	mov	ax,dpmiCodeSel
	push	ax
	mov	eax,offset UnPatchExc
	push	ax
	retf
@@pe0:	;
;
;Remove the API patch.
;
	mov	ds,cs:mDataSegment
	assume ds:_cwMain
	mov	es,apiDataSeg
	assume es:_apiCode
	test	SystemFlags,1
	jz	@@Use32
	mov	dx,es:w[OldIntSys]
	mov	cx,es:w[OldIntSys+2]
	jmp	@@Use0
@@Use32:	mov	edx,es:d[OldIntSys]
	mov	cx,es:w[OldIntSys+4]
@@Use0:	mov	bl,31h
	mov	ax,205h
	int	31h
	mov	es:d[cwIdentity],0
	mov	es:d[cwIdentity+4],0
	assume es:nothing
	;
@@noAPI:	assume ds:nothing
	cmp	cs:IProtectedType,2	;DPMI?
	assume ds:_cwInit
	jz	@@DPMI
;
;Make RAW stuff addressable.
;
	cli			;Don't want interrupts interfering.
	mov	ax,KernalDS		;Get supervisor data descriptor,
	mov	ds,ax		;DS,ES,FS,GS,SS must be data with 64k limit
	assume ds:_cwRaw
	mov	ax,KernalZero
	mov	es,ax
;
;Switch to RAW exit code.
;
	push	_cwInit
	push	offset @@6
	mov	ax,KernalCS
	push	ax
	mov	ax,offset RawVCPIRealMode
	push	ax
	retf
@@6:	jmp	@@RealMode
;
;Remove DPMI stuff.
;
	.386
@@DPMI:

	if	0
	assume ds:nothing
	mov	ds,cs:iDataSegment
	assume ds:_cwInit
	mov	ds,mDataSegment
	assume ds:_cwMain
	cmp	d[OldInt21hExec],0
	jz	@@d0
	mov	bl,21h
	mov	dx,w[OldInt21hExec]
	mov	cx,w[OldInt21hExec+2]
	mov	ax,201h
	int	31h
@@d0:
	endif

	assume ds:nothing
	mov	ds,cs:iDataSegment
	assume ds:_cwInit

	cmp	IErrorNumber,0
	jz	@@NoError
	mov	ax,IErrorNumber	;Get the error number.
	xor	dx,dx
	mov	cx,10
	div	cx
	add	al,'0'
	mov	b[IErrorM00n],al
	add	dl,'0'
	mov	b[IErrorM00n+1],dl
	mov	dx,w[InitErrorList]

	mov	edi,offset DPMIErrRegs
	push	ds
	pop	es
	mov	Real_EDX[edi],edx
	mov	Real_EAX[edi],900h
	mov	Real_DS[edi],_cwInit
	xor	cx,cx		;No stack parameters.
	mov	bh,ch		;no flags.
	mov	ax,0300h
	int	31h		;Use real dpmi service.
;
;Get a pointer to the appropriate error message and print it.
;
	mov	bx,IErrorNumber
	add	bx,bx
	mov	dx,[InitErrorList+bx]

	mov	edi,offset DPMIErrRegs
	push	ds
	pop	es
	mov	Real_EDX[edi],edx
	mov	Real_EAX[edi],900h
	mov	Real_DS[edi],_cwInit
	xor	cx,cx		;No stack parameters.
	mov	bh,ch		;no flags.
	mov	ax,0300h
	int	31h		;Use real dpmi service.

	jmp	@@NoError
	.286
;
;Make sure our data is addressable.
;
@@RealMode:	mov	ax,_cwInit
	mov	ds,ax
	assume ds:_cwInit
;
;Display the "CauseWay error: ??" bit.
;
@@InRealMode:	cmp	IErrorNumber,0
	jz	@@NoError
	mov	ax,IErrorNumber	;Get the error number.
	xor	dx,dx
	mov	cx,10
	div	cx
	add	al,'0'
	mov	b[IErrorM00n],al
	add	dl,'0'
	mov	b[IErrorM00n+1],dl
	mov	dx,w[InitErrorList]
	mov	ah,9
	int	21h
;
;Get a pointer to the appropriate error message and print it.
;
	mov	bx,IErrorNumber
	add	bx,bx
	mov	dx,[InitErrorList+bx]
	mov	ah,9
	int	21h
;
;Now exit with the error number as the DOS "errorlevel".
;
@@NoError:	mov	ax,IErrorNumber
	mov	ah,4ch
	int	21h
	assume ds:_cwMain
InitError	endp


;-------------------------------------------------------------------------------
;
;Initialise real mode hardware interupt vectors so that control is always passed to protected mode
;even if the interupt occurs in real mode. This simulates the DPMI environment and is essential for
;any program that re-programs IRQ-0 frequency.
;
InitHardwareInts proc near
	.386
	pushm	ds,es
	mov	ax,KernalDS
	mov	ds,ax
	mov	ax,KernalZero
	mov	es,ax
	assume ds:_cwRaw
;	mov	ch,16
;	mov	cl,1ch
;	call	@@0
	mov	ch,17
	mov	cl,23h		;patch ctrl-break.
	call	@@0
	mov	ch,18
	mov	cl,24h		;patch critical error.
	call	@@0
	popm	ds,es
	ret
	;
@@0:	mov	ax,size CallBackStruc
	movzx	bx,ch
	mul	bx
	mov	bx,ax
	add	bx,offset CallBackTable
	pushf
	cli
	mov	CallBackNum[bx],cl	;set interupt number.
	mov	CallBackFlags[bx],1+2	;mark call back as used interupt.
	mov	ax,CallBackSize
	movzx	dx,ch
	mul	dx
	mov	si,offset ICallBackList
	add	si,ax		;index list of calls.
	push	bx
	movzx	bx,cl
	shl	bx,2
	mov	dx,es:[bx]
	mov	cx,es:[bx+2]
	mov	es:[bx],si
	mov	es:w[bx+2],seg _cwRaw
	pop	bx
	mov	w[CallBackReal+2+bx],cx	;store origional real mode vector.
	mov	w[CallBackReal+bx],dx
	popf
	ret
	assume ds:_cwMain
	.286
InitHardwareInts endp


;-------------------------------------------------------------------------------
CheckProcessor	proc	near
	xor	ax,ax		;Clear the flags.
	push	ax		;/
	popf			;/
	pushf			;Get the flags back.
	pop	ax		;/
	and	ax,0F000h		;Get Bits 11-8
	cmp	ax,0F000h		;Exist on this processor?
	je	@@9		;Must be an 8086
	mov	ax,0F000h		;Setup the flags again.
	push	ax		;/
	popf			;/
	pushf			;Get them back.
	pop	ax		;/
	and	ax,0F000h		;Get Bits 11-8
	jz	@@9		;Valid so must be 80286
	clc
	ret
@@9:	stc
	ret
CheckProcessor	endp


;-------------------------------------------------------------------------------
CheckDOSVersion proc near
	mov	ah,30h
	int	21h		;Get DOS version.
	mov	DOSVersion,ax
	cmp	al,3		;3.? or above?
	jc	@@9
	jnz	@@0		;less means trouble.
	cmp	ah,1
	jc	@@9
@@0:	clc
	ret
@@9:	stc
	ret
CheckDOSVersion endp


;-------------------------------------------------------------------------------
;
;Check for "CAUSEWAY" environment variable and fetch any relevent settings.
;
GetENVStuff	proc	near
	.386
	mov	es,RealEnvSegment
	xor	si,si
@@0:	mov	eax,es:[si]
	cmp	eax,"SUAC"
	jnz	@@1
	mov	eax,es:[si+4]
	cmp	eax,"YAWE"
	jz	@@2
@@1:	inc	si
	cmp	es:b[si-1],0
	jnz	@@1
	cmp	es:b[si],0		;end of all strings?
	jnz	@@0
	jmp	@@9
	;
@@2:	;Found "CAUSEWAY" so have a look at the settings.
	;
	add	si,8		;skip to "="
	push	si
@@2_0:	mov	al,es:[si]
	cmp	al,61h		; 'a'
	jb	@@2_1
	cmp	al,7Ah		; 'z'
	ja	@@2_1
	and	al,5Fh		;convert to upper case.
@@2_1:	mov	es:[si],al
	inc	si
	or	al,al
	jnz	@@2_0
	pop	si
	;
@@3:	cmp	es:b[si]," "
	jnz	@@4
	inc	si
	jmp	@@3
	;
@@4:	cmp	es:b[si],0		;end?
	jz	@@9
	;
	mov	eax,es:[si]
	cmp	eax,"MVON"		;NOVM?
	jz	@@novm
	cmp	eax,"MXAM"		;MAXMEM?
	jz	@@maxmem
	cmp	eax,"ATXE"		;EXTALL?
	jz	@@extall
	cmp	eax,"IMPD"		;DPMI?
	jz	@@dpmi
	cmp	eax,"PAWS"		;swap?
	jz	@@swap
	cmp	eax,"MWOL"		;lowmem?
	jz	@@lowmem
	cmp	eax,"EMIH"		; himem?
	jz	@@himem
	cmp	eax,"APON"		; nopass?
	jz	@@nopass
	cmp	eax,":ERP"		; pre?
	jz	@@pre
	cmp	eax,"EMAN"		; NAME?
	jz	@@name
	cmp	eax,"1DAP"		; PAD1?
	jz	@@pad1
	cmp	eax,"XEON"		; NOEX?
	jz	@@noex
	cmp	eax,"1GIB"		; BIG1?
	jz	@@big1
	inc	si
	jmp	@@3
	;
@@nopass:	; shut off passing of real mode interrupts to protected mode
	add	si,4
	mov	ax,es:[si]
	cmp	ax,"SS"
	jnz	@@3
	add	si,2
	push	ds
	mov	bx,_cwRaw
	mov	ds,bx
	assume ds:_cwRaw
	or	NoPassFlag,-1
	assume ds:_cwMain
	pop	ds
	jmp	@@3

@@big1:	; specify alternate extended memory size computation
	add	si,4
	push	ds
	mov	bx,_cwRaw
	mov	ds,bx
	assume ds:_cwRaw
	or	Big1Flag,-1
	assume ds:_cwMain
	pop	ds
	jmp	@@3

@@himem:	;Set amount of physical memory to use.
	;
	add	si,4
	mov	al,es:[si]
	cmp	al,"M"
	jnz	@@3
	inc	si
	cmp	es:b[si],":"
	jnz	@@3
	inc	si
	xor	edx,edx
@@hm0:	mov	al,es:[si]
	or	al,al
	jz	@@hm1
	cmp	al," "
	jz	@@hm1
	cmp	al,"0"
	jc	@@hm1
	cmp	al,"9"+1
	jnc	@@hm1
	sub	al,"0"
	movzx	eax,al
	add	edx,edx
	mov	ebx,edx
	add	edx,edx
	add	edx,edx
	add	edx,ebx
	add	edx,eax
	inc	si
	jmp	@@hm0
@@hm1:
	cmp	edx,4096*1024
	jnc	@@3

	shl	edx,10		;turn K into byte's
	shr	edx,12		;get number of pages.
	push	ds
	mov	bx,_cwRaw
	mov	ds,bx
	assume ds:_cwRaw
	mov	d[MaxMemPhys],edx
	assume ds:_cwMain
	pop	ds
	jmp	@@3
	;
@@extall:	;Set flag to use all extended memory.
	;
	add	si,4
	mov	ax,es:[si]
	cmp	ax,"LL"
	jnz	@@3
	add	si,2
	push	ds
	mov	bx,_cwRaw
	mov	ds,bx
	assume ds:_cwRaw
	or	ExtALLSwitch,-1
	assume ds:_cwMain
	pop	ds
	jmp	@@3
	;
@@novm:	;They want to disable VM.
	;
	add	si,4
	push	ds
	mov	bx,_cwInit
	mov	ds,bx
	assume ds:_cwInit
	or	NoVMSwitch,-1
	assume ds:_cwMain
	pop	ds
	jmp	@@3
	;
@@maxmem:	;Want to set maximum linear address space size.
	;
	add	si,4
	mov	ax,es:[si]
	cmp	ax,"ME"
	jnz	@@3
	add	si,2
	cmp	es:b[si],":"
	jnz	@@3
	inc	si
	xor	edx,edx
@@mm0:	mov	al,es:[si]
	or	al,al
	jz	@@mm1
	cmp	al," "
	jz	@@mm1
	cmp	al,"0"
	jc	@@mm1
	cmp	al,"9"+1
	jnc	@@mm1
	sub	al,"0"
	movzx	eax,al
	add	edx,edx
	mov	ebx,edx
	add	edx,edx
	add	edx,edx
	add	edx,ebx
	add	edx,eax
	inc	si
	jmp	@@mm0
@@mm1:
	cmp	edx,4096
	jnc	@@3

	shl	edx,20		;turn Meg into byte's
	push	ds
	mov	bx,_cwRaw
	mov	ds,bx
	assume ds:_cwRaw
	mov	d[MaxMemLin],edx
	assume ds:_cwMain
	pop	ds
	jmp	@@3

@@pre:	;Want to set preallocate amount
	;
	add	si,4
	xor	edx,edx
@@pr0:	mov	al,es:[si]
	or	al,al
	jz	@@pr1
	cmp	al," "
	jz	@@pr1
	cmp	al,"0"
	jc	@@pr1
	cmp	al,"9"+1
	jnc	@@pr1
	sub	al,"0"
	movzx	eax,al
	add	edx,edx
	mov	ebx,edx
	add	edx,edx
	add	edx,edx
	add	edx,ebx
	add	edx,eax
	inc	si
	jmp	@@pr0
@@pr1:
	cmp	edx,4096
	jnc	@@3

	shl	edx,20		;turn Meg into byte's
	push	ds
	mov	bx,_cwRaw
	mov	ds,bx
	assume ds:_cwRaw
	mov	d[PreAllocSize],edx
	assume ds:_cwMain
	pop	ds
	jmp	@@3

@@pad1:
	mov	Pad1Flag,1
	add	si,4
	jmp	@@3

@@noex:
	mov	NoEXECPatchFlag,1
	add	si,4
	jmp	@@3

@@dpmi:	;They want to force DPMI use if possible.
	;
	mov	ProtectedForce,1
	add	si,4
	jmp	@@3
	;
@@swap:	;They want to specify the swap drive.
	;
	add	si,4
	cmp	es:b[si],":"
	jnz	@@3
	inc	si
	mov	di,offset VMMDrivPath1
	push	ds
	mov	bx,_cwInit
	mov	ds,bx
	assume ds:_cwInit
@@s0:	mov	al,es:[si]
	mov	[di],al
	inc	si
	inc	di
	or	al,al
	jz	@@s1

	cmp	al,";"	; MED 02/25/96
	je	@@s1

	cmp	al," "
	jnz	@@s0
@@s1:	mov	b[di-1],0
	assume ds:_cwMain
	pop	ds
	dec	si
	jmp	@@3
	;
@@name:	; Specify the swap name.
	;
	add	si,4
	cmp	es:b[si],":"
	jnz	@@3
	inc	si
	mov	di,offset DesiredVMMName
	push	ds
	mov	bx,_cwRaw
	mov	ds,bx
	assume ds:_cwRaw
	xor	dx,dx
@@n0:	mov	al,es:[si]
	mov	[di],al
	inc	si
	inc	di
	or	al,al
	jz	@@n1
	inc	dx
	cmp	dx,12
	ja	@@n1		; don't allow more than 12 chars in file name

	cmp	al,";"	; MED 02/25/96
	je	@@n1

	cmp	al," "
	jnz	@@n0
@@n1:	mov	b[di-1],0
	assume ds:_cwMain
	pop	ds
	dec	si
	jmp	@@3
	;
@@lowmem:	;They want to specify low memory retention.
	;
	add	si,4
	mov	ax,es:[si]
	cmp	ax,"ME"
	jnz	@@3
	add	si,2
	cmp	es:b[si],":"
	jnz	@@3
	inc	si
	xor	edx,edx
@@lm0:	mov	al,es:[si]
	or	al,al
	jz	@@lm1
	cmp	al," "
	jz	@@lm1
	cmp	al,"0"
	jc	@@lm1
	cmp	al,"9"+1
	jnc	@@lm1
	sub	al,"0"
	movzx	eax,al
	add	edx,edx
	mov	ebx,edx
	add	edx,edx
	add	edx,edx
	add	edx,ebx
	add	edx,eax
	inc	si
	jmp	@@lm0
	;
@@lm1:	shl	edx,10-4		;turn K into para's
	push	ds
	mov	bx,_cwRaw
	mov	ds,bx
	assume ds:_cwRaw
	movzx	ebx,w[CONVSaveSize]
	add	edx,ebx
	cmp	edx,65535
	jc	@@lm2
	mov	edx,65535
@@lm2:	mov	w[CONVSaveSize],dx	;set new size.
	assume ds:_cwMain
	pop	ds
	;
	jmp	@@3
	;
@@9:	;Now look for TEMP.
	;
	xor	si,si		;start at the beginning.
@@temp2:	mov	eax,es:[si]
	cmp	eax,"PMET"
	jz	@@temp0
@@temp1:	inc	si
	cmp	es:b[si-1],0
	jnz	@@temp1
	cmp	es:b[si],0
	jz	@@temp9
	jmp	@@temp2
	;
@@temp0:	add	si,4
	cmp	es:b[si],"="
	jnz	@@temp9
	inc	si
	push	ds
	mov	bx,_cwInit
	mov	ds,bx
	mov	di,offset VMMDrivPath2
@@temp3:	mov	al,es:[si]
	mov	[di],al
	inc	si
	inc	di
	or	al,al
	jz	@@temp4
	cmp	al," "
	jnz	@@temp3
@@temp4:	mov	b[di-1],0
	pop	ds
@@temp9:	;
	;Look for TMP
	;
	xor	si,si		;start at the beginning.
@@tmp2:	mov	eax,es:[si]
	cmp	eax,"=PMT"
	jz	@@tmp0
@@tmp1:	inc	si
	cmp	es:b[si-1],0
	jnz	@@tmp1
	cmp	es:b[si],0
	jz	@@tmp9
	jmp	@@tmp2
	;
@@tmp0:	add	si,4
	push	ds
	mov	bx,_cwInit
	mov	ds,bx
	mov	di,offset VMMDrivPath3
@@tmp3:	mov	al,es:[si]
	mov	[di],al
	inc	si
	inc	di
	or	al,al
	jz	@@tmp4
	cmp	al," "
	jnz	@@tmp3
@@tmp4:	mov	b[di-1],0
	pop	ds
@@tmp9:	;
	ret
	.286
GetENVStuff	endp


;-------------------------------------------------------------------------------
GetEXECName	proc	near
	.386
@@0:	mov	es,RealEnvSegment
	xor	si,si
@@1:	mov	al,es:[si]		;Get a byte.
	inc	si		;/
	or	al,al		;End of a string?
	jnz	@@1		;keep looking.
	mov	al,es:[si]		;Double zero?
	or	al,al		;/
	jnz	@@1		;keep looking.
	add	si,3		;Skip last 0 and word count.
	mov	di,offset MainExec
	mov	bx,_cwInit
	mov	fs,bx
	mov	bx,offset VMMDrivPath4
	mov	cx,128
	mov	dx,bx
	pushm	ds,ds,es
	popm	es,ds
@@2:	movsb
	mov	al,[si-1]
	mov	fs:[bx],al
	inc	bx
	cmp	b[si-1],"\"
	jnz	@@2_0
	mov	dx,bx
	dec	dx
@@2_0:	cmp	b[si-1],0		;got to the end yet?
	jz	@@3
	dec	cx
	jnz	@@2
@@3:	mov	bx,dx
	mov	fs:b[bx],0		;terminate VMM path.

COMMENT !
; MED 10/10/96
	cmp	bx,offset VMMDrivPath4
	jne	genexit			; non-null path
	mov	BYTE PTR fs:[bx],'.'	; null path, give a valid one of '.\'
	mov	BYTE PTR fs:[bx+1],'\'
	mov	BYTE PTR fs:[bx+2],0
END COMMENT !

genexit:
	pop	ds
	pushm	ds,ds
	popm	es,fs
	ret
	.286
GetEXECName	endp


;-------------------------------------------------------------------------------
GetSystemFlags	proc	near
	push	ds
	mov	dx,offset MainExec
	mov	ax,3d00h		;open, read only.
	int	21h
	jc	@@5
	push	cs
	pop	ds
	assume ds:_cwInit
	mov	bx,ax
	mov	dx,offset IExeSignature	;somewhere to put the info.
	mov	cx,1bh		;size of it.
	mov	ah,3fh
	int	21h
	jc	@@4
	cmp	ax,1bh		;did we read right amount?
	jnz	@@4
	cmp	w[IExeSignature],'ZM'	;Normal EXE?
	jnz	@@4
	mov	ax,w[IExeLength+2]	;get length in 512 byte blocks

; MED 01/17/96
	cmp	WORD PTR [IExeLength],0
	je	medexe2		; not rounded if no modulo

	dec	ax		;lose 1 cos its rounded up

medexe2:
	add	ax,ax		;mult by 2
	mov	dh,0
	mov	dl,ah
	mov	ah,al
	mov	al,dh		;mult by 256=*512
	add	ax,w[IExeLength]	;add length mod 512
	adc	dx,0		;add any carry to dx
	mov	cx,ax
	xchg	cx,dx		;swap round for DOS.
	mov	ax,4200h		;set absolute position.
	int	21h
	mov	dx,offset INewHeader	;somewhere to put the info.
	mov	cx,size NewHeaderStruc	;size of it.
	mov	ah,3fh
	int	21h
	jc	@@4
	or	ax,ax		;end of the file?
	jz	@@SetRUN
	cmp	ax,size NewHeaderStruc	;did we read right amount?
	jnz	@@4
	cmp	w[INewHeader],'P3'	;ID ok?
	jnz	@@4
	mov	si,offset INewHeader
	mov	ax,w[NewFlags+si]	;Copy main flags.
	mov	cx,w[NewFlags+2+si]
	pop	ds
	push	ds
	assume ds:_cwMain
	mov	w[SystemFlags],ax
	mov	w[SystemFlags+2],cx
	mov	dx,_cwRaw
	mov	ds,dx
	assume ds:_cwRaw
	mov	w[RawSystemFlags],ax
	mov	w[RawSystemFlags+2],cx
	.386
	mov	dx,_cwDPMIEMU
	mov	ds,dx
	assume ds:_cwDPMIEMU
	mov	w[DpmiEmuSystemFlags],ax
	mov	w[DpmiEmuSystemFlags+2],cx
	mov	dx,_apiCode
	mov	ds,dx
	assume ds:_apiCode
	mov	w[apiSystemFlags],ax
	mov	w[apiSystemFlags+2],cx
	.286
	assume ds:_cwMain
@@4:	mov	ax,3e00h
	int	21h
	jmp	@@5

;
;Nothing on the end of the extender so replace the exec name with first
;command line argument and shuffle everything else down. Allows CW32 to be used
;to run 32-bit programs not attatched to it from the command line.
;
@@SetRUN:	mov	ax,3e00h		;close file, we don't need it.
	int	21h
	mov	ax,_cwMain
	mov	ds,ax
	assume ds:_cwMain
	push	es
	mov	es,RealPSPSegment
	mov	si,80h
	xor	ch,ch
	mov	cl,es:b[si]
	or	cx,cx
	jz	@@sr5
	inc	si
	mov	di,offset MainExec	;default to storeing program name.
	;
	;Skip white space.
	;
@@sr0:	mov	al,es:[si]
	cmp	al," "
	jnz	@@sr1
	inc	si
	dec	cx
	jnz	@@sr0
	jmp	@@sr3
	;
	;Get program name.
	;
@@sr1:	mov	al,es:[si]
	cmp	al," "
	jz	@@sr2
	mov	es:b[si],' '
	mov	[di],al
	inc	si
	inc	di
	dec	cx
	jnz	@@sr1
@@sr2:	mov	b[di],0
@@sr3:	pop	es
;
;Clean up the command line, ie, remove any spaces created by removeing name.
;
	push	es
	mov	es,RealPSPSegment
	mov	si,80h
	xor	ch,ch
	mov	cl,es:b[si]
	or	cx,cx
	jz	@@cl3
	inc	si
	mov	di,si
@@cl0:	cmp	es:b[si],' '
	jnz	@@cl1
	inc	si
	dec	cx
	jnz	@@cl0
@@cl1:	jcxz	@@cl2
	push	cx
	push	ds
	push	es
	pop	ds
	rep	movsb		;Copy it down.
	pop	ds
	pop	cx
@@cl2:	mov	es:b[80h],cl		;Store new length.
@@cl3:	xor	ch,ch
	add	cx,81h
	mov	si,cx
	mov	es:b[si],13		;Terminate it correctly.
@@sr5:	pop	es
	;
	assume ds:_cwMain
@@5:	pop	ds
	ret
GetSystemFlags	endp


;-------------------------------------------------------------------------------
GetProtectedType proc near
;
;Find out what protected mode environments are available.
;
	call	ChkDPMI		;32 bit DPMI server present?
	jc	@@0
	or	ProtectedFlags,1
@@0:	call	ChkVCPI		;VCPI >= v1.0 present?
	jc	@@1
	or	ProtectedFlags,2
@@1:	call	ChkRAW		;Running in real mode?
	jc	@@2
	or	ProtectedFlags,4
@@2:	ret
GetProtectedType endp


;-------------------------------------------------------------------------------
SetProtectedType proc near
	cmp	ProtectedForce,0
	jz	@@NoDPMIForce
	test	ProtectedFlags,1
	jnz	@@2
	;
@@NoDPMIForce:	test	ProtectedFlags,4
	jz	@@1
	mov	ProtectedType,0	;Use real mode.
	jmp	@@3
@@1:	test	ProtectedFlags,2
	jz	@@2
	mov	ProtectedType,1	;Use VCPI.
	jmp	@@3
@@2:	mov	ProtectedType,2	;Use DPMI.
@@3:	push	es
	mov	ax,_cwInit
	mov	es,ax
	assume es:_cwInit
	mov	ax,ProtectedType
	mov	es:IProtectedType,ax
	assume es:nothing
	pop	es
	ret
SetProtectedType endp


;-------------------------------------------------------------------------------
ChkDPMI	proc	near
;
;See if DPMI server present.
;
	mov	ax,1687h		;DPMI instalation check.
	int	2fh
	or	ax,ax		;None-zero means its not there.
	jnz	@@9
	test	w[SystemFlags],1
	jz	@@Use32Bit21
	jmp	@@Use16Bit21
@@Use32Bit21:	test	bx,1		;Must offer 32 bit support.
	jz	@@9
@@Use16Bit21:	clc
	ret
	;
@@9:	stc
	ret
ChkDPMI	endp


;-------------------------------------------------------------------------------
;
; The following routine checks to see if a VCPI master program is installed.
; If one is not, the carry flag is set on return
; If one is, the version info is stored and the carry flag is cleared on return
;
ChkVCPI	proc	near
	pushm	ax,bx,es
	xor	ax,ax
	mov	es,ax
	mov	si,es:[67h*4]	;Check a handler exists.
	mov	di,es:[(67h*4)+2]
	mov	ax,si
	or	ax,di
	jnz	@@IsHandler
	cli
	mov	es:w[67h*4],offset @@DummyIRET
	mov	es:w[(67h*4)+2],cs
@@IsHandler:	pushm	si,di
	mov	ax,0DE00h		;Get VCPI installed state
	int	67h
	popm	si,di
	mov	es:[67h*4],si	;Check a handler exists.
	mov	es:[(67h*4)+2],di
	sti
	;
	cmp	al,0
	jne	@@NotThere
	or	bx,3030h		;Turn to ASCII
	cmp	bh,'1'
	jc	@@NotThere
	mov	ax,si
	or	ax,di		;Only pretending to be their?
	jz	@@HopeThere
	;
	call	@@ChkEMS		;Make sure EMS is in first
	jc	@@HopeThere		;EMS not in.
	call	@@GrabPage		;Make sure EMS initiated
@@HopeThere:	clc			;Set for no error
	jmp	@@Done
@@NotThere:	stc
@@Done:	popm	ax,bx,es
	ret
@@DummyIRET:	iret
;
; The following routine checks to see if an EMM is installed.
; If one is not, the carry flag is set on return
; If one is, the carry flag is cleared on return
;
@@ChkEMS:	pushm	ax,bx,dx,es
	pushm	ds,cs
	pop	ds
	mov	dx,offset @@EMSName	;Device driver name
	mov	ah,3Dh		;Open file
	mov	al,0		;Access/file sharing mode
	int	21h
	pop	ds
	jc	@@NotThere2
	mov	bx,ax		;Put handle in proper place
	mov	ah,44h		;IOCTL
	mov	al,07h		;Get output status
	int	21h
	jc	@@NotThere1
	cmp	al,0FFh
	jne	@@NotThere1
	mov	ah,3Eh		;Close file
	int	21h
	clc			;Set for no error
	jmp	@@Done1
@@NotThere1:	mov	ah,3Eh		;Close file
	int	21h
@@NotThere2:	stc
@@Done1:	popm	ax,bx,dx,es
	ret
;
; This function allocates an EMS page, and then releases it.  This is
; done to make sure the EMS driver has switched the CPU to V86 mode.
; On return, the carry is set if there was any problem using the EMS
; functions.  Carry is clear otherwise.
;
@@GrabPage:	mov	ah,43h		;Allocate pages
	mov	bx,1		;Get 1 page (16K)
	int	67h
	cmp	ah,0		;Was there an error?
	jne	@@GPErr		;Yes, so exit
	mov	ah,45h		;Release EMS handle
	int	67h
	cmp	ah,0		;Was there an error?
	jne	@@GPErr		;Yes, so exit
	clc			;Mark for no error
	jmp	@@GPEnd
@@GPErr:	stc
@@GPEnd:	ret
;
@@EMSName	DB 'EMMXXXX0',0
ChkVCPI	endp


;-------------------------------------------------------------------------------
ChkRAW	proc	near
;
;Can we run on this machine.
;
	.286
	smsw	ax
	and	ax,1         	; are we in protected mode?
	jnz	@@9
	clc
	ret
@@9:	stc
	ret
ChkRAW	endp


;-------------------------------------------------------------------------------
MakeDesc	proc	near
;
;Build a segment descriptor.
;
;On Entry:-
;
;ES:DI	- Descriptor entry to use.
;ESI	- Linear base to set.
;ECX	- limit in bytes.
;AL	- Code size bit.
;AH	- Present/PL/memory|system/type bits.
;
	.386
	pushad
	and	di,not 7		;lose RPL & TI
	cmp	ecx,0100000h  	; see if we need to set g bit
	jc	@@0
	shr	ecx,12       	; div by 4096
	or	al,80h       	; set g bit
@@0:	mov	es:[di],cx		;store low word of limit.
	shr	ecx,16
	or	cl,al
	mov	es:[di+6],cl		;store high bits of limit and gran/code size bits.
	mov	es:[di+2],si		;store low word of linear base.
	shr	esi,16
	mov	bx,si
	mov	es:[di+4],bl		;store mid byte of linear base.
	mov	es:[di+7],bh		;store high byte of linear base.
	mov	es:[di+5],ah		;store pp/dpl/dt/type bits.
	popad
	ret
MakeDesc	endp


;-------------------------------------------------------------------------------
;
;Build a segment descriptor.
;
;On Entry:-
;
;ES:DI	- Descriptor entry to use.
;ESI	- Linear base to set.
;ECX	- limit in bytes.
;AL	- Code size bit.
;AH	- Present/PL/memory|system/type bits.
;
MakeDesc2	proc	near
	.386
	pushad
	and	edi,not 7		;lose RPL & TI
	cmp	ecx,0100000h  	; see if we need to set g bit
	jc	@@0
	shr	ecx,12       	; div by 4096
	or	al,80h       	; set g bit
@@0:	mov	es:[edi],cx		;store low word of limit.
	shr	ecx,16
	or	cl,al
	mov	es:[edi+6],cl	;store high bits of limit and gran/code size bits.
	mov	es:[edi+2],si	;store low word of linear base.
	shr	esi,16
	mov	bx,si
	mov	es:[edi+4],bl	;store mid byte of linear base.
	mov	es:[edi+7],bh	;store high byte of linear base.
	mov	es:[edi+5],ah	;store pp/dpl/dt/type bits.
	popad
	ret
MakeDesc2	endp


;-------------------------------------------------------------------------------
;
;Dummy routine to call so that IDT value is re-loaded.
;
IDTFlush	proc	far
	ret
IDTFlush	endp


;-------------------------------------------------------------------------------
Bordi	proc	near
	pushm	ax,dx
	mov	ah,al
	mov	dx,3dah
	in	al,dx
	mov	dl,0c0h
	mov	al,11h
	out	dx,al
	mov	al,ah
	out	dx,al
	mov	al,20h
	out	dx,al
	popm	ax,dx
	ret
Bordi	endp


;-------------------------------------------------------------------------------
;
;Initialisation specific data.
;
apiDataSegi	dw 0
IProtectedMode	db 0
IProtectedType	dw 0
DPMISwitch	dw ?,?
dpmiSelBase	dd 0
dpmiCodeSel	dw ?
dpmiDataSel	dw ?
;
iCodeSegment	dw InitCS
mCodeSegment	dw MainCS
iDataSegment	dw InitDS
mDataSegment	dw MainDS
iStackSegment	dw MainSS
iPSPSegment	dw MainPSP
iENVSegment	dw MainENV
iRealSegment	dw KernalZero
;
INewHeader	NewHeaderStruc <>	;make space for a header.
;
IExeSignature	db ?	;00 Identifier text.
	db ?	;01 /
IExeLength	dw ?	;02 Length of file MOD 512
	dw ?	;04 Length of file in 512 byte blocks.
IExeRelocNum	dw ?	;06 Number of relocation items.
IExeHeaderSize	dw ?	;08 Length of header in 16 byte paragraphs.
IExeMinAlloc	dw ?	;0A Minimum number of para's needed above program.
IExeMaxAlloc	dw ?	;0C Maximum number of para's needed above program.
IExeStackSeg	dw ?	;0E Segment displacement of stack module.
IExeEntrySP	dw ?	;10 value for SP at entry.
IExeCheckSum	dw ?	;12 Check sum...
IExeEntryIP	dw ?	;14 Contents of IP at entry.
IExeEntryCS	dw ?	;16 Segment displacement of CS at entry.
IExeRelocFirst	dw ?	;18 First relocation item offset.
IExeOverlayNum	db ?	;1A Overlay number.
;
IErrorNumber	dw 0
InitErrorList	dw IErrorM00,IErrorM01,IErrorM02,IErrorM03,IErrorM04,IErrorM05,IErrorM06,IErrorM07
	dw IErrorM08,IErrorM09
IErrorM00	db 'CauseWay error '
IErrorM00n	db '00 : $'
IErrorM01	label byte
	if ENGLISH
	db 'Unable to re-size program memory block.',13,10,'$'
	elseif SPANISH
	db "Incapaz de redimensionar el bloque de memoria del programa",13,10,"$"
	endif
IErrorM02	label byte
	if ENGLISH
	db '386 or better required.',13,10,'$'
	elseif SPANISH
	db "Se requiere un 386 o superior.",13,10,"$"
	endif
IErrorM03	label byte
	if ENGLISH
	db 'Non-standard protected mode program already active.',13,10,'$'
	elseif SPANISH
	db "Programa en modo protegido no estandar activado.",13,10,"$"
	endif
IErrorM04	label byte
	if ENGLISH
	db 'DOS 3.1 or better required.',13,10,'$'
	elseif SPANISH
	db "DOS 3.1 o superior requerido.",13,10,"$"
	endif
IErrorM05	label byte
	if ENGLISH
	db 'Not enough memory for CauseWay.',13,10,'$'
	elseif SPANISH
	db "Memoria insuficiente para CauseWay.",13,10,"$"
	endif
IErrorM06	label byte
	if ENGLISH
	db 'VCPI failed to switch into protected mode.',13,10,'$'
	elseif SPANISH
	db "VCPI fallo al cambiar a modo protegido.",13,10,"$"
	endif
IErrorM07	label byte
	if ENGLISH
	db 'Unable to control A20.',13,10,'$'
	elseif SPANISH
	db "Capaz de controlar A20.",13,10,"$"
	endif
IErrorM08	label byte
	if ENGLISH
	db 'Selector allocation error.',13,10,'$'
	elseif SPANISH
	db "Error de asignacion del selector.",13,10,"$"
	endif
IErrorM09	label byte
	if ENGLISH
	db 'DPMI failed to switch to protected mode.',13,10,'$'
	elseif SPANISH
	db "DPMI fallo al cambiar a modo protegido.",13,10,"$"
	endif
;
IFDEF PERMNOVM
NoVMSwitch	db 1
ELSE
NoVMSwitch	db 0
ENDIF

VMMDrivPath1	db 128 dup (0)	;used by CAUSEWAY=SWAP:?:\??
VMMDrivPath2	db 128 dup (0)	;used by TEMP=
VMMDrivPath3	db 128 dup (0)	;used by TMP=
VMMDrivPath4	db 128 dup (0)	;used by current path.
VMMDrivPath5	db 128 dup (0)	;used by boot drive.
	db -1
;
DPMIErrRegs	db size RealRegsStruc dup (0)
;
_cwInit	ends


;=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
;
;End marker so we know what to resize program memory size to initialy.
;
_cwEnd	segment para public 'end marker'
_cwEnd	ends

	end	Startup
