1572 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			NASM
		
	
	
	
	
	
			
		
		
	
	
			1572 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			NASM
		
	
	
	
	
	
;/* himem2.asm
 | 
						||
; *
 | 
						||
; * Microsoft Confidential
 | 
						||
; * Copyright (C) Microsoft Corporation 1988-1991
 | 
						||
; * All Rights Reserved.
 | 
						||
; *
 | 
						||
; * Modification History
 | 
						||
; *
 | 
						||
; * Sudeepb 14-May-1991 Ported for NT XMS support
 | 
						||
; *
 | 
						||
; * williamh 25-Sept-1992 added UMB initialization
 | 
						||
; */
 | 
						||
 | 
						||
	page	95,160
 | 
						||
	title   'HIMEM2 - Initialization code'
 | 
						||
 | 
						||
funky	segment word public 'funky'
 | 
						||
	extrn	textseg:word		; in high segment
 | 
						||
	extrn	KiddValley:word
 | 
						||
	extrn	KiddValleyTop:word
 | 
						||
	extrn	cHandles:word
 | 
						||
	extrn	pack_and_truncate:near
 | 
						||
	extrn	end_of_funky_seg:byte
 | 
						||
	extrn	LEnblA20:word
 | 
						||
	extrn	LDsblA20:word
 | 
						||
funky	ends
 | 
						||
 | 
						||
	.xlist
 | 
						||
	include	himem.inc		; get structures, equ's, etc.
 | 
						||
					;  and open segment
 | 
						||
	include xmssvc.inc
 | 
						||
 | 
						||
	.list
 | 
						||
 | 
						||
;	public	f000
 | 
						||
	public	InitInterrupt
 | 
						||
	public	MachineNum
 | 
						||
 | 
						||
;************************************************************************
 | 
						||
;*									*
 | 
						||
;*  Global Variables							*
 | 
						||
;*									*
 | 
						||
;************************************************************************
 | 
						||
 | 
						||
	extrn	pPPFIRET:word
 | 
						||
	extrn	dd_int_loc:word
 | 
						||
	extrn	Interrupt:near
 | 
						||
	extrn	hiseg:word
 | 
						||
	extrn	call_hi_in_di:near
 | 
						||
	extrn	fCanChangeA20:byte
 | 
						||
	extrn	fHMAMayExist:byte
 | 
						||
 | 
						||
ifndef NEC_98
 | 
						||
	extrn	fVDISK:byte
 | 
						||
	extrn	IsVDISKIn:near
 | 
						||
endif   ;NEC_98
 | 
						||
 | 
						||
	extrn	A20Handler:near
 | 
						||
	extrn	EnableCount:word
 | 
						||
	extrn	MemCorr:word
 | 
						||
	extrn	MinHMASize:word
 | 
						||
 | 
						||
	extrn	pReqHdr:dword
 | 
						||
	extrn	PrevInt2f:dword
 | 
						||
	extrn	TopOfTextSeg:word
 | 
						||
 | 
						||
	extrn	AddMem:near
 | 
						||
	extrn	InstallA20:near
 | 
						||
	extrn	Int2fHandler:near
 | 
						||
;	extrn	Is6300Plus:near
 | 
						||
	extrn	IsA20On:near
 | 
						||
 | 
						||
	extrn	SignOnMsg:byte
 | 
						||
	extrn	ROMDisabledMsg:byte
 | 
						||
	extrn	UnsupportedROMMsg:byte
 | 
						||
	extrn	ROMHookedMsg:byte
 | 
						||
	extrn	BadDOSMsg:byte
 | 
						||
	extrn	NowInMsg:byte
 | 
						||
	extrn	On8086Msg:byte
 | 
						||
	extrn	NoExtMemMsg:byte
 | 
						||
	extrn	FlushMsg:byte
 | 
						||
	extrn	StartMsg:byte
 | 
						||
	extrn	HandlesMsg:byte
 | 
						||
	extrn	HMAMINMsg:byte
 | 
						||
	extrn	KMsg:byte
 | 
						||
	extrn	NoHMAMsg:byte
 | 
						||
	extrn	A20OnMsg:byte
 | 
						||
	extrn	HMAOKMsg:byte
 | 
						||
ifndef NEC_98
 | 
						||
	extrn	VDISKInMsg:byte
 | 
						||
	extrn	BadArgMsg:byte
 | 
						||
endif   ;NEC_98
 | 
						||
 | 
						||
	extrn	DevAttr:word
 | 
						||
	extrn	Int15MemSize:word
 | 
						||
 | 
						||
	extrn	EndText:byte
 | 
						||
        extrn   A20State:byte
 | 
						||
 | 
						||
        extrn   DOSTI:near
 | 
						||
        extrn   DOCLI:near
 | 
						||
ifdef NEC_98
 | 
						||
	extrn	fAltA20Routine:byte
 | 
						||
	extrn	LocalDisableA20:near
 | 
						||
	extrn	LocalEnableA20:near
 | 
						||
	extrn	cant_ena20_msg:byte
 | 
						||
	extrn	cant_dia20_msg:byte
 | 
						||
endif   ;NEC_98
 | 
						||
 | 
						||
;************************************************************************
 | 
						||
;*									*
 | 
						||
;*   Code/Data below here will be discarded after driver initialization *
 | 
						||
;*									*
 | 
						||
;************************************************************************
 | 
						||
 | 
						||
;	Discardable Initialization Data
 | 
						||
 | 
						||
public	fShadowOff, f1stWasWarning
 | 
						||
 | 
						||
fShadowOff	db	0	; NZ if shadow RAM should be disabled,
 | 
						||
				;   0/1 set by command line switch, 0FFh
 | 
						||
				;   set if little extended and hope to disable
 | 
						||
 | 
						||
f1stWasWarning	db	0	; NZ if 1st attempt to diddle A20 generated
 | 
						||
				; a warning (and not an error)
 | 
						||
	public	fA20Control
 | 
						||
 | 
						||
fA20Control	db	0ffh	; NZ if himem should take control of A20, even
 | 
						||
				;   it was already on when himem loaded.
 | 
						||
 | 
						||
ifndef NEC_98
 | 
						||
	public	fCPUClock
 | 
						||
 | 
						||
fCPUClock	db	0	; NZ if himem should try to preserve CPU clock
 | 
						||
				;   speed when gating A20
 | 
						||
endif   ;NEC_98
 | 
						||
 | 
						||
	public	StringParm, MachineNum, MachineName
 | 
						||
 | 
						||
StringParm	db	13 DUP (' ')
 | 
						||
 | 
						||
MachineNum	dw	-1
 | 
						||
 | 
						||
;  Note: the following table MUST be in the same order as the entries in the
 | 
						||
;  A20_Scan_Table!  If you add entries here, also add one there!
 | 
						||
 | 
						||
MachineName	label	byte
 | 
						||
	db	'ptlcascade',0		; Phoenix Cascade BIOS
 | 
						||
	db	'att6300plus',0 	; AT&T 6300 Plus
 | 
						||
	db	'ps2',0 		; IBM PS/2
 | 
						||
	db	'hpvectra',0		; HP 'Classic' Vectra (A & A+)
 | 
						||
	db	'acer1100',0		; Acer 1100
 | 
						||
	db	'toshiba',0		; Toshiba 1600 & 1200XE
 | 
						||
	db	'wyse',0		; Wyse 12.5 MHz 286 machine
 | 
						||
ifndef NEC_98
 | 
						||
	db	'tulip',0		; Tulip machines
 | 
						||
	db	'zenith',0		; Zenith ZBIOS
 | 
						||
	db	'at1',0 		; IBM AT/delay 0
 | 
						||
	db	'at2',0 		; IBM AT/delay 1
 | 
						||
	db	'at3',0 		; IBM AT/delay 2
 | 
						||
	db	'philips',0		; Philips machines
 | 
						||
	db	'css',0			; CSS Lab machines
 | 
						||
	db	'fasthp',0		; Single byte method for HP Vectras
 | 
						||
	db	'ibm7552',0		; IBM 7552 Industrial Computer
 | 
						||
	db	'bullmicral',0		; Bull Micral 60 M004
 | 
						||
endif   ;NEC_98
 | 
						||
	db	'at',0			; IBM AT
 | 
						||
	db	0FFh			; end of table
 | 
						||
 | 
						||
;NOTE: there is code in GetParms which depends on AltNameTbl coming
 | 
						||
;      after MachineName table.
 | 
						||
 | 
						||
ifndef NEC_98
 | 
						||
	public	AltName1, AltName2, AltName3, AltName4, AltName5
 | 
						||
	public	AltName6, AltName7, AltName8, AltName9, AltName10
 | 
						||
	public	AltName11, AltName12, AltName13, AltName14, AltName15
 | 
						||
	public	AltName16                                    ;M004
 | 
						||
else    ;NEC_98
 | 
						||
	public	AltName1, AltName2, AltName3, AltName4, AltName5
 | 
						||
	public	AltName6, AltName7, AltName8
 | 
						||
endif   ;NEC_98
 | 
						||
 | 
						||
AltNameTbl	label	byte
 | 
						||
AltName3    db	'3',0			; Phoenix Cascade BIOS
 | 
						||
AltName5    db	'5',0			; AT&T 6300 Plus
 | 
						||
AltName2    db	'2',0			; IBM PS/2
 | 
						||
AltName4    db	'4',0			; HP 'Classic' Vectra (A & A+)
 | 
						||
AltName6    db	'6',0			; Acer 1100
 | 
						||
AltName7    db	'7',0			; Toshiba 1600 & 1200XE
 | 
						||
AltName8    db	'8',0			; Wyse 12.5 Mhz 286 machine
 | 
						||
ifndef NEC_98
 | 
						||
AltName9    db	'9',0			; Tulip machine
 | 
						||
AltName10   db	'10',0			; Zenith ZBIOS
 | 
						||
AltName11   db	'11',0			; IBM AT/delay 0
 | 
						||
AltName12   db	'12',0			; IBM AT/delay 1
 | 
						||
AltName13   db	'13',0			; IBM AT/delay 2
 | 
						||
	    db	'13',0			; Philips machines (same as AT3)
 | 
						||
	    db	'12',0			; CSS machines
 | 
						||
AltName14   db	'14',0			; Single byte HP Vectra m/cs
 | 
						||
AltName15   db	'15',0			; IBM 7552 Industrial Computer
 | 
						||
AltName16   db	'16',0			; Bull Micral 60          M004
 | 
						||
endif   ;NEC_98
 | 
						||
AltName1    db	'1',0			; IBM AT
 | 
						||
	    db	0FFh			; end of table
 | 
						||
 | 
						||
ifdef	debug_tsr	;-----------------------------------------------
 | 
						||
 | 
						||
;*----------------------------------------------------------------------*
 | 
						||
;*									*
 | 
						||
;*  ExeStart -								*
 | 
						||
;*									*
 | 
						||
;*	Entry point when himem is invoked as an .EXE.			*
 | 
						||
;*									*
 | 
						||
;*----------------------------------------------------------------------*
 | 
						||
 | 
						||
lpCmdLine	dd	81h		; far ptr to command tail
 | 
						||
 | 
						||
	public	ExeStart
 | 
						||
 | 
						||
ExeStart:
 | 
						||
 | 
						||
	mov	word ptr cs:[lpCmdLine+2],es	; save PSP segment in pointer
 | 
						||
 | 
						||
	mov	ax,cs		; Setup segment regs to all be the same
 | 
						||
	mov	ds,ax
 | 
						||
	mov	es,ax
 | 
						||
 | 
						||
	call	InitDriver	; Initialize...
 | 
						||
 | 
						||
	mov	ax,TopOfTextSeg	; TopOfTextSeg == 0 is error installing
 | 
						||
	or	ax,ax
 | 
						||
	jnz	@f
 | 
						||
 | 
						||
	mov	ax,4C03h	; error, so just terminate
 | 
						||
	int	21h
 | 
						||
@@:
 | 
						||
	mov	di,offset pack_and_truncate
 | 
						||
	jmp	call_hi_in_di	; terminate and stay resident
 | 
						||
 | 
						||
endif			;------------------------------------------------
 | 
						||
 | 
						||
 | 
						||
 | 
						||
;*----------------------------------------------------------------------*
 | 
						||
;*									*
 | 
						||
;*  InitInterrupt -							*
 | 
						||
;*									*
 | 
						||
;*	Called by MS-DOS immediately after Strategy routine		*
 | 
						||
;*									*
 | 
						||
;*  ARGS:   None							*
 | 
						||
;*  RETS:   Return code in Request Header's Status field		*
 | 
						||
;*  REGS:   Preserved							*
 | 
						||
;*									*
 | 
						||
;*	This entry point is used only during initialization.		*
 | 
						||
;*	It replaces itself with a much shorter version which only	*
 | 
						||
;*	serves to report the appropriate errors when this driver	*
 | 
						||
;*	is called in error.						*
 | 
						||
;*									*
 | 
						||
;*----------------------------------------------------------------------*
 | 
						||
 | 
						||
InitInterrupt   proc    far
 | 
						||
 | 
						||
	; Save the registers including flags.
 | 
						||
 | 
						||
	push    ax		; We cannot use pusha\popa because
 | 
						||
	push    bx		;	we could be on an 8086 at this point
 | 
						||
	push    cx
 | 
						||
	push    dx
 | 
						||
	push    ds
 | 
						||
	push    es
 | 
						||
	push    di
 | 
						||
	push    si
 | 
						||
	push    bp
 | 
						||
	pushf
 | 
						||
 | 
						||
	push	cs		; Set DS=CS for access to global variables.
 | 
						||
	pop	ds
 | 
						||
 | 
						||
	les	di,[pReqHdr]	; ES:DI = Request Header
 | 
						||
 | 
						||
	mov     bl,es:[di].Command ; Get Function code in BL
 | 
						||
 | 
						||
	or	bl,bl		; Only Function 00h (Init) is legal
 | 
						||
	jz	IInit
 | 
						||
 | 
						||
	cmp     bl,16		; Test for "legal" DOS functions
 | 
						||
	jle     IOtherFunc
 | 
						||
 | 
						||
IBogusFunc:
 | 
						||
	mov     ax,8003h	; Return "Unknown Command"
 | 
						||
	jmp     short IExit
 | 
						||
 | 
						||
IOtherFunc:
 | 
						||
	xor     ax,ax		; Return zero for unsupported functions
 | 
						||
	jmp     short IExit
 | 
						||
 | 
						||
IInit:
 | 
						||
	call    InitDriver	; Initialize the driver
 | 
						||
	les	di,[pReqHdr]	; Restore es:di = Request Header
 | 
						||
 | 
						||
IExit:
 | 
						||
	or	ax,0100h	; Turn on the "Done" bit
 | 
						||
	mov	es:[di].Status,ax ; Store return code
 | 
						||
 | 
						||
	popff			; restore the registers
 | 
						||
	pop	bp
 | 
						||
	pop	si
 | 
						||
	pop	di
 | 
						||
	pop	es
 | 
						||
	pop	ds
 | 
						||
	pop	dx
 | 
						||
	pop	cx
 | 
						||
	pop	bx
 | 
						||
	pop	ax
 | 
						||
	mov	dd_int_loc,offset Interrupt	; replace Interrupt with
 | 
						||
	ret					; tiny permanent stub
 | 
						||
 | 
						||
InitInterrupt   endp
 | 
						||
 | 
						||
;*----------------------------------------------------------------------*
 | 
						||
;*									*
 | 
						||
;*  InitDriver -							*
 | 
						||
;*									*
 | 
						||
;*	Called when driver is Initialized.				*
 | 
						||
;*									*
 | 
						||
;*  ARGS:   ES:DI = Address of the Request Header			*
 | 
						||
;*  RETS:   pHdr.Address = Bottom of resident driver code		*
 | 
						||
;*  REGS:   AX, CX and Flags are clobbered				*
 | 
						||
;*									*
 | 
						||
;*----------------------------------------------------------------------*
 | 
						||
 | 
						||
ifndef NEC_98
 | 
						||
	public	InitDriver
 | 
						||
endif   ;NEC_98
 | 
						||
 | 
						||
InitDriver  proc    near
 | 
						||
 | 
						||
	cld
 | 
						||
 | 
						||
	ifndef	debug_tsr
 | 
						||
	call	LocateHiSeg	; locate the hiseg in low memory properly
 | 
						||
 | 
						||
 | 
						||
	mov	ax,cs
 | 
						||
	push	es
 | 
						||
	mov	es,hiseg
 | 
						||
	assume	es:funky
 | 
						||
	add	textseg,ax	; relocate text segment pointer
 | 
						||
	add	LEnblA20+2, ax	; update ptrs to enble & disable a20 rtns
 | 
						||
	add	LDsblA20+2, ax
 | 
						||
	pop	es
 | 
						||
	assume	es:nothing
 | 
						||
	endif
 | 
						||
 | 
						||
;	mov	ah,9		; display signon message
 | 
						||
;	mov	dx,offset SignOnMsg
 | 
						||
;	int	21h
 | 
						||
 | 
						||
	mov	ah,30h		; make sure we've got DOS 3.00 or higher
 | 
						||
	int	21h		; Get DOS versions number
 | 
						||
	cmp	al,3
 | 
						||
	jae     IDCheckXMS
 | 
						||
 | 
						||
	mov	dx,offset BadDOSMsg
 | 
						||
	jmp	IDFlushMe
 | 
						||
 | 
						||
IDCheckXMS:
 | 
						||
ifndef NEC_98
 | 
						||
	mov	ax,(INT2F_ID SHL 8) OR INT2F_INS_CHK
 | 
						||
	int	2Fh		; make sure there's no other XMS installed
 | 
						||
else    ;NEC_98
 | 
						||
	mov     ax,4300h	; make sure there's no other XMS installed
 | 
						||
	int	2Fh
 | 
						||
endif   ;NEC_98
 | 
						||
	cmp	al,80h		; Is INT 2F hooked?
 | 
						||
	jne     IDNotInYet
 | 
						||
	mov	dx,offset NowInMsg
 | 
						||
	jmp	IDFlushMe
 | 
						||
 | 
						||
IDNotInYet:
 | 
						||
ifdef NEC_98
 | 
						||
	xor	ax,ax
 | 
						||
	mov	es,ax
 | 
						||
	test	byte ptr es:[501h],40h	; we're on an V30/V50
 | 
						||
	jz	@f
 | 
						||
	jmp	IDFlushMe		; so give out
 | 
						||
@@:
 | 
						||
	call	GetInt15Memory		; If Int 15h/88h reports < 384k of
 | 
						||
	mov	dx,offset NoExtMemMsg
 | 
						||
	or	ax,ax			; we have extend memory ?
 | 
						||
	jnz	@f
 | 
						||
	jmp	IDFlushMe		; so give out
 | 
						||
@@:
 | 
						||
	test	byte ptr es:[0501h],08h	; Q : HIRES CRT ?
 | 
						||
	jz	@f			;  N : continue
 | 
						||
	mov	ah,byte ptr es:[501h]	; BIOS_FLG
 | 
						||
	mov	al,ah			;  save
 | 
						||
	and	ah,07h			; get main memory size
 | 
						||
	cmp	ah,4			; main memory > 512 ?
 | 
						||
	jb	@f			; no. don't need to init RAMWindow
 | 
						||
	test	byte ptr es:[458h],80h	; NPC ?
 | 
						||
	jnz	not_XA			; yes
 | 
						||
	test	al,30h			; system type = 0 ?
 | 
						||
	jnz	not_XA			; no. other than XA
 | 
						||
	call	Init_RamWindow_XA
 | 
						||
	jmp	short @f
 | 
						||
not_XA:
 | 
						||
	call	Init_RamWindow
 | 
						||
@@:
 | 
						||
endif   ;NEC_98
 | 
						||
	call	GetParms		; process command line parameters
 | 
						||
;; don't call IsA20On at this moment because we haven't init it yet
 | 
						||
	mov	ax, 2
 | 
						||
	XMSSVC	XMS_A20
 | 
						||
;;;;	call	IsA20On 		; Is A20 already enabled?
 | 
						||
	or	ax,ax			;   (may zap cx, si, di)
 | 
						||
	jz	IDInsA20		;   no, go install A20 handler
 | 
						||
 | 
						||
	mov	dx,offset A20OnMsg	; "A20 already on" message
 | 
						||
	cmp	fA20Control,0		; should we take control of A20 anyway?
 | 
						||
	jne	IDInsA20		;   yes, go muck with it
 | 
						||
	mov	[fCanChangeA20],0	;   no,  don't allow changing of A20
 | 
						||
	mov	ah,9			;	 and tell user about it
 | 
						||
	int	21h
 | 
						||
	jmp	short IDAfterA20
 | 
						||
 | 
						||
IDInsA20:
 | 
						||
	call	InstallA20		; install proper A20 handler
 | 
						||
	jc	IDFlushMe		; CY means fatal error
 | 
						||
 | 
						||
;	Note:  A side affect of the previous InstallA20 is that MemCorr
 | 
						||
;	  is set to reflect the adjustment factor if we're on an AT&T 6300+
 | 
						||
 | 
						||
IDAfterA20:
 | 
						||
	call	InitHandles	; initialize handle table
 | 
						||
 | 
						||
	call    GetInt15Memory	; how much extended memory is installed?
 | 
						||
	cmp     ax,64		; Is there >= 64K of extended?
 | 
						||
ifndef NEC_98
 | 
						||
	jae	IDHMAOK
 | 
						||
else    ;NEC_98
 | 
						||
	jb	@f
 | 
						||
	cmp	Int15MemSize, 0	; has the hma been allocated to INT 15 ?
 | 
						||
	jz	IDHMAOK		; no, HMA is available
 | 
						||
@@:
 | 
						||
endif   ;NEC_98
 | 
						||
 | 
						||
	push	es
 | 
						||
	mov	es,hiseg
 | 
						||
	assume	es:funky
 | 
						||
	mov	bx,[KiddValley]	; get size of memory we already have in tables
 | 
						||
	mov	cx,[cHandles]
 | 
						||
 | 
						||
IDAnyMem:
 | 
						||
	cmp	[bx].Flags,FREEFLAG
 | 
						||
	jnz	IDAnyMem_1	; brif not a valid free block
 | 
						||
	add	ax,[bx].Len	; accumulate total
 | 
						||
IDAnyMem_1:
 | 
						||
	add	bx,SIZE Handle
 | 
						||
	loop	IDAnyMem
 | 
						||
 | 
						||
	pop	es
 | 
						||
	assume	es:nothing
 | 
						||
 | 
						||
	mov	dx,offset NoHMAMsg
 | 
						||
	or	ax,ax			; no HMA, any other memory to control?
 | 
						||
	jnz	disp_hma_msg		; jmp if some memory
 | 
						||
 | 
						||
;	We can't find any memory to manage.
 | 
						||
 | 
						||
	mov	dx,offset NoExtMemMsg
 | 
						||
 | 
						||
;	Display the message in DX followed by the "Flush" message.
 | 
						||
 | 
						||
IDFlushMe:
 | 
						||
	mov	ah,9
 | 
						||
	int	21h
 | 
						||
	mov	dx,offset FlushMsg
 | 
						||
	mov	ah,9
 | 
						||
	int	21h
 | 
						||
 | 
						||
	xor	ax,ax			; discard the driver
 | 
						||
	mov	[TopOfTextSeg],ax
 | 
						||
 | 
						||
ifndef	debug_tsr			;-------------------------------
 | 
						||
	les	di,[pReqHdr]
 | 
						||
	mov	es:[di].Units,al
 | 
						||
	and	cs:DevAttr,not 8000h	; clr bit 15 in attrib of driver header
 | 
						||
endif
 | 
						||
	jmp	short IDReturn		;-------------------------------
 | 
						||
IDHMAOK:
 | 
						||
	mov     [fHMAMayExist],1
 | 
						||
	mov	dx,offset HMAOKMsg
 | 
						||
disp_hma_msg:
 | 
						||
;       mov     ah,9
 | 
						||
;       int     21h
 | 
						||
 | 
						||
;; tell xms.lib where our variable is
 | 
						||
        mov     ax, cs
 | 
						||
        mov     bx, offset A20State
 | 
						||
        XMSSVC  XMS_INITUMB
 | 
						||
 | 
						||
	call    HookInt2F		; "turn on" the driver
 | 
						||
 | 
						||
;	Initialization finished (or failed) -- return to caller
 | 
						||
 | 
						||
IDReturn:
 | 
						||
 | 
						||
ifndef	debug_tsr			;-------------------------------
 | 
						||
	mov	di,offset pack_and_truncate
 | 
						||
	jmp	call_hi_in_di		; pack stuff down and terminate
 | 
						||
endif					;-------------------------------
 | 
						||
	ret
 | 
						||
 | 
						||
InitDriver	endp
 | 
						||
;
 | 
						||
;----------------------------------------------------------------------------
 | 
						||
; procedure : LocateHiSeg
 | 
						||
;
 | 
						||
;		Locate the movable segment properly in the low seg.
 | 
						||
;		taking care of the stripped ORG zeroes. This function
 | 
						||
;		calculates the segment at which the hiseg should run
 | 
						||
;		with the ORG. If the segment cvalue goes below zero the
 | 
						||
;		code is moved up high enough to run the code from a seg value
 | 
						||
;		of zero.
 | 
						||
;
 | 
						||
;		This function assumes that the 'funky' segment follows
 | 
						||
;		immediately after the text seg.
 | 
						||
;
 | 
						||
;----------------------------------------------------------------------------
 | 
						||
; 
 | 
						||
LocateHiSeg	proc	near
 | 
						||
	push	ds
 | 
						||
	mov	ax, cs				; para start of text seg
 | 
						||
	mov	cx, offset _text:EndText	; end of text seg
 | 
						||
	add	cx, 15				; para round it
 | 
						||
	shr	cx, 1
 | 
						||
	shr	cx, 1
 | 
						||
	shr	cx, 1
 | 
						||
	shr	cx, 1
 | 
						||
	add	ax, cx				; para start of funky seg
 | 
						||
	cmp	ax, (HISEG_ORG shr 4)		; will the seg go below zero?
 | 
						||
	jb	MoveHiSeg			; yeah, we have to move it
 | 
						||
	sub	ax, (HISEG_ORG shr 4)		; no, it fits in
 | 
						||
	pop	ds
 | 
						||
	mov	hiseg, ax			; update the segment in which
 | 
						||
						;   it is going to run from.
 | 
						||
	ret
 | 
						||
MoveHiSeg:
 | 
						||
	mov	ds, ax				; segment at which funky
 | 
						||
						;  resides without the ORG
 | 
						||
 	xor	ax, ax
 | 
						||
 	mov	es, ax				; we want to movve the code
 | 
						||
						;  to 0:HISEG_ORG
 | 
						||
	mov	di, offset funky:end_of_funky_seg
 | 
						||
	mov	si, di
 | 
						||
	sub	si, HISEG_ORG
 | 
						||
	mov	cx, si
 | 
						||
	dec	di
 | 
						||
	dec	si
 | 
						||
  	std					; move backward (safe when
 | 
						||
						;  source & dest overlap
 | 
						||
    	rep	movsb
 | 
						||
	cld
 | 
						||
    	pop	ds
 | 
						||
    	mov	hiseg, 0			; funky is going to run from
 | 
						||
						;  segment zero
 | 
						||
    	ret
 | 
						||
LocateHiSeg	endp
 | 
						||
 | 
						||
 | 
						||
;*----------------------------------------------------------------------*
 | 
						||
;*									*
 | 
						||
;*  HookInt2F -								*
 | 
						||
;*									*
 | 
						||
;*	Insert the INT 2F hook						*
 | 
						||
;*									*
 | 
						||
;*  ARGS:   None							*
 | 
						||
;*  RETS:   None							*
 | 
						||
;*  REGS:   AX, SI, ES and Flags are clobbered				*
 | 
						||
;*									*
 | 
						||
;*----------------------------------------------------------------------*
 | 
						||
 | 
						||
	public	HookInt2F
 | 
						||
 | 
						||
HookInt2F   proc    near
 | 
						||
 | 
						||
        call    DOCLI
 | 
						||
	xor	ax,ax
 | 
						||
	mov	es,ax
 | 
						||
	mov	si,2Fh * 4		; save previous int2f vector
 | 
						||
	mov	ax,offset Int2FHandler	; and exchange with new one
 | 
						||
	xchg    ax,es:[si][0]
 | 
						||
	mov	word ptr [PrevInt2F][0],ax
 | 
						||
	mov	ax,cs
 | 
						||
	xchg    ax,es:[si][2]
 | 
						||
	mov	word ptr [PrevInt2F][2],ax
 | 
						||
        call    DOSTI
 | 
						||
	ret
 | 
						||
 | 
						||
HookInt2F   endp
 | 
						||
 | 
						||
;*----------------------------------------------------------------------*
 | 
						||
;*									*
 | 
						||
;*  GetInt15Memory -							*
 | 
						||
;*									*
 | 
						||
;*	Returns the amount of memory INT 15h, Function 88h says is free	*
 | 
						||
;*									*
 | 
						||
;*  ARGS:   None							*
 | 
						||
;*  RETS:   AX = Amount of free extended memory in K-bytes		*
 | 
						||
;*  REGS:   AX and Flags are clobbered					*
 | 
						||
;*									*
 | 
						||
;*----------------------------------------------------------------------*
 | 
						||
 | 
						||
 | 
						||
GetInt15Memory proc near
 | 
						||
 | 
						||
ifndef NEC_98
 | 
						||
IFDEF WHEN_INT15_DONE
 | 
						||
	mov	ah,88h			; snag the int 15h memory
 | 
						||
	clc
 | 
						||
	int	15h			; Is Function 88h around?
 | 
						||
	jnc     xret_geti15
 | 
						||
	xor	ax,ax			; No, return 0
 | 
						||
xret_geti15:
 | 
						||
 | 
						||
ifndef NOLIMIT                                  ;M005
 | 
						||
	cmp	ax,15*1024		; Limit himem.sys to using 15 meg
 | 
						||
	jb	@f			;   of extended memory for apps
 | 
						||
	mov	ax,15*1024		;   that don't deal with > 24 bit
 | 
						||
@@:					;   addresses
 | 
						||
endif						;M005
 | 
						||
 | 
						||
ELSE
 | 
						||
	XMSSVC	XMS_EXTMEM		; return ext-mem in ax5
 | 
						||
ENDIF
 | 
						||
 | 
						||
	ret
 | 
						||
else    ;NEC_98
 | 
						||
	push	es
 | 
						||
	mov	ax,40h
 | 
						||
	mov	es,ax
 | 
						||
	mov	al,byte ptr es:[01h]	; get extend memory size
 | 
						||
	pop	es
 | 
						||
	sub	ah,ah
 | 
						||
	shl	ax,7
 | 
						||
	ret
 | 
						||
endif   ;NEC_98
 | 
						||
 | 
						||
GetInt15Memory endp
 | 
						||
 | 
						||
;*----------------------------------------------------------------------*
 | 
						||
;*									*
 | 
						||
;*  GetParms -								*
 | 
						||
;*									*
 | 
						||
;*	Get any parameters off of the HIMEM command line		*
 | 
						||
;*									*
 | 
						||
;*  ARGS:   None							*
 | 
						||
;*  RETS:   None							*
 | 
						||
;*  REGS:   AX, BX, CX, DX, DI, SI, ES and Flags clobbered		*
 | 
						||
;*									*
 | 
						||
;*  Side Effects:   cHandles and MinHMASize may be changed		*
 | 
						||
;*									*
 | 
						||
;*----------------------------------------------------------------------*
 | 
						||
 | 
						||
ifndef NEC_98
 | 
						||
GPArgPtr	dd	?
 | 
						||
endif   ;NEC_98
 | 
						||
GPRegSave	dw	?
 | 
						||
 | 
						||
	public	GetParms
 | 
						||
 | 
						||
GetParms    proc    near
 | 
						||
 | 
						||
	cld				; better safe than sorry
 | 
						||
 | 
						||
	push	ds
 | 
						||
 | 
						||
ifdef	debug_tsr			;-------------------------------
 | 
						||
	lds	si,lpCmdLine
 | 
						||
else					;-------------------------------
 | 
						||
	les	di,[pReqHdr]		; Running as a device driver
 | 
						||
	lds	si,es:[di].pCmdLine	; DS:SI points to first char
 | 
						||
					;   after "DEVICE="
 | 
						||
ifndef NEC_98
 | 
						||
@@:	call	GPGetChar		; Skip over driver name, up to
 | 
						||
	jc	GPDatsAll		;   first blank or / or eol
 | 
						||
	jz	GPNextArg
 | 
						||
	cmp	al,'/'
 | 
						||
	jnz	@b
 | 
						||
	dec	si			; Backup to get / again
 | 
						||
endif   ;NEC_98
 | 
						||
endif					;-------------------------------
 | 
						||
 | 
						||
	assume	ds:nothing,es:nothing
 | 
						||
 | 
						||
;	Scan until we see a non-blank or the end of line.
 | 
						||
 | 
						||
ifndef NEC_98
 | 
						||
GPNextArg:
 | 
						||
	call	GPGetChar
 | 
						||
	jc	GPDatsAll		; eol
 | 
						||
	jz	GPNextArg		; blank
 | 
						||
 | 
						||
	mov	word ptr cs:[GPArgPtr], si	; save ptr to start of arg
 | 
						||
	mov	word ptr cs:[GPArgPtr+2], ds	;   incase we want to complain
 | 
						||
	dec	word ptr cs:[GPArgPtr]		;   (GPGetChar points at next)
 | 
						||
 | 
						||
	cmp	al,'/'			; better be a / or not a valid arg
 | 
						||
	jz	GPGotOne
 | 
						||
 | 
						||
;	Detected invalid parameter or value, complain to user
 | 
						||
 | 
						||
GPBadParm:
 | 
						||
 | 
						||
	mov	ah,9			; tell'm something isn't right
 | 
						||
	push	cs
 | 
						||
	pop	ds
 | 
						||
	mov	dx,offset BadArgMsg
 | 
						||
	int	21h
 | 
						||
 | 
						||
	lds	si,cs:[GPArgPtr]	; backup to last parameter
 | 
						||
 | 
						||
GPBadDisp:
 | 
						||
	call	GPGetChar		; disp arg up to space or eol
 | 
						||
	jc	GPDatsAll		;  skips over bad arg while we're at it
 | 
						||
	jz	GPNextArg
 | 
						||
 | 
						||
	cmp	al,'/'				; start of next arg?
 | 
						||
	jnz	@f
 | 
						||
	dec	si				; maybe yes, maybe no--might
 | 
						||
	cmp	si,word ptr cs:[GPArgPtr]	;   be same arg
 | 
						||
	jnz	GPNextArg			;   next, go process new arg
 | 
						||
	inc	si				;   same, keep displaying
 | 
						||
@@:
 | 
						||
	mov	dl,al
 | 
						||
	mov	ah,2
 | 
						||
	int	21h
 | 
						||
	jmp	short GPBadDisp
 | 
						||
 | 
						||
;	Finished, we're outta here...
 | 
						||
 | 
						||
else    ;NEC_98
 | 
						||
GPBadParm:
 | 
						||
GPNextChar:
 | 
						||
	call	GPGetChar
 | 
						||
	jc	GPDatsAll
 | 
						||
	cmp	al,'/'
 | 
						||
	je	GPGotOne
 | 
						||
	jmp	short GPNextChar
 | 
						||
endif   ;NEC_98
 | 
						||
GPDatsAll:
 | 
						||
	pop	ds
 | 
						||
	ret
 | 
						||
 | 
						||
;	Save what we found and get the number or string after it.
 | 
						||
 | 
						||
GPGotOne:
 | 
						||
	lodsb
 | 
						||
	mov	cs:[GPRegSave],ax
 | 
						||
 | 
						||
;	Scan past the rest of the parm for a number, EOL, or a space.
 | 
						||
 | 
						||
GPNeedParm:
 | 
						||
	call	GPGetChar
 | 
						||
ifndef NEC_98
 | 
						||
	jc	GPBadParm
 | 
						||
	jz	GPBadParm	; blank
 | 
						||
else    ;NEC_98
 | 
						||
	jc	GPDatsAll
 | 
						||
	cmp	al,' '
 | 
						||
	je	GPBadParm
 | 
						||
endif   ;NEC_98
 | 
						||
	cmp	al,':'		; start of string arg
 | 
						||
	je	GPString
 | 
						||
	cmp	al,'='
 | 
						||
	jne	GPNeedParm
 | 
						||
 | 
						||
;	Read the number at DS:SI into DX
 | 
						||
 | 
						||
GPNeedNum:
 | 
						||
	call	GPGetChar
 | 
						||
	jc	GPDatsAll
 | 
						||
	cmp	al,'0'
 | 
						||
	jb	GPNeedNum
 | 
						||
	cmp	al,'9'
 | 
						||
	ja	GPNeedNum
 | 
						||
 | 
						||
	xor	dx,dx
 | 
						||
GPNumLoop:
 | 
						||
	sub	al,'0'
 | 
						||
	cbw
 | 
						||
	add	dx,ax
 | 
						||
	call	GPGetChar
 | 
						||
	jc	GPNumDone
 | 
						||
ifndef NEC_98
 | 
						||
	jz	GPNumDone
 | 
						||
else    ;NEC_98
 | 
						||
	cmp	al,' '
 | 
						||
	je	GPNumDone
 | 
						||
endif   ;NEC_98
 | 
						||
	cmp	al,'0'
 | 
						||
	jb	GPBadParm
 | 
						||
	cmp	al,'9'
 | 
						||
	ja	GPBadParm
 | 
						||
	shl	dx,1		; multiply DX by 10
 | 
						||
	mov	bx,dx
 | 
						||
	shl	dx,1
 | 
						||
	shl	dx,1
 | 
						||
	add	dx,bx
 | 
						||
	jmp	short GPNumLoop
 | 
						||
 | 
						||
;	Move the string arg from ds:si to StringParm
 | 
						||
 | 
						||
GPString:
 | 
						||
	mov	cx,(SIZE StringParm) - 1
 | 
						||
	push	cs
 | 
						||
	pop	es
 | 
						||
	mov	di,offset _text:StringParm
 | 
						||
 | 
						||
GPStrLoop:
 | 
						||
	call	GPGetChar
 | 
						||
	jc	GPStrDone
 | 
						||
ifndef NEC_98
 | 
						||
	jz	GPStrDone
 | 
						||
else    ;NEC_98
 | 
						||
	cmp	al,' '
 | 
						||
	je	GPStrDone
 | 
						||
endif   ;NEC_98
 | 
						||
	stosb
 | 
						||
	loop	GPStrLoop
 | 
						||
 | 
						||
GPStrDone:
 | 
						||
 | 
						||
	mov	byte ptr es:[di],0	; Null terminate the string
 | 
						||
ifndef NEC_98
 | 
						||
	mov	dx,-1			; In case parm expects a num, give'm
 | 
						||
					;   a likely invalid one
 | 
						||
endif   ;NEC_98
 | 
						||
 | 
						||
;	Which parameter are we dealing with here?
 | 
						||
 | 
						||
GPNumDone:
 | 
						||
	xchg    ax,cs:[GPRegSave]
 | 
						||
	cmp	al,'H'		; HMAMIN= parameter?
 | 
						||
	jne	@f
 | 
						||
	jmp	GPGotMin
 | 
						||
@@:
 | 
						||
	cmp	al,'N'		; NUMHANDLES= parameter?
 | 
						||
	jne	@f
 | 
						||
	jmp	GPGotHands
 | 
						||
@@:	cmp	al,'M'		; MACHINE: parameter?
 | 
						||
	je	GPGotMachine
 | 
						||
	cmp	al,'A'		; A20CONTROL: parameter?
 | 
						||
	je	GPGotA20Control
 | 
						||
	cmp	al,'S'		; SHADOWRAM: parameter?
 | 
						||
	jne	@f
 | 
						||
	jmp	GPGotShadow
 | 
						||
@@:	cmp	al, 'I' 	; INT15=
 | 
						||
	jne	@f
 | 
						||
	jmp	GPGotInt15
 | 
						||
ifndef NEC_98
 | 
						||
@@:	cmp	al, 'C' 	; CPUCLOCK:
 | 
						||
	jne	@f
 | 
						||
	jmp	GPGotCPUClock
 | 
						||
endif   ;NEC_98
 | 
						||
@@:	jmp	GPBadParm
 | 
						||
 | 
						||
 | 
						||
;	Process /A20CONTROL: parameter
 | 
						||
 | 
						||
GPGotA20Control:
 | 
						||
	mov	ax,word ptr [StringParm]
 | 
						||
	or	ax,2020h
 | 
						||
	mov	bl,0FFh
 | 
						||
	cmp	ax,'no' 		; ON ?	- means we take control
 | 
						||
	jz	GPSetA20
 | 
						||
	inc	bl
 | 
						||
	cmp	ax,'fo' 		; OFF ? - means we leave alone if on
 | 
						||
	jz	GPSetA20
 | 
						||
ifndef NEC_98
 | 
						||
	jmp	GPBadParm
 | 
						||
else    ;NEC_98
 | 
						||
	jmp	GPNextParm
 | 
						||
endif   ;NEC_98
 | 
						||
 | 
						||
GPSetA20:
 | 
						||
	mov	fA20Control,bl		; Z if A20 should be left alone if
 | 
						||
	jmp	GPNextParm		;   it's already on when we're loaded
 | 
						||
 | 
						||
 | 
						||
;	Process /MACHINE: parameter.
 | 
						||
 | 
						||
GPGotMachine:
 | 
						||
	push	si				; save current location
 | 
						||
	push	ds				;    in param string
 | 
						||
 | 
						||
	push	cs
 | 
						||
	pop	ds
 | 
						||
	mov	di,offset _text:MachineName	; es:di -> MachineName
 | 
						||
 | 
						||
GPNextTbl:
 | 
						||
	xor	bx,bx
 | 
						||
 | 
						||
GPNextName:
 | 
						||
	mov	si,offset _text:StringParm	; ds:si -> StringParm
 | 
						||
 | 
						||
GPChkNext:
 | 
						||
	cmp	byte ptr es:[di],0FFh		; end of name table?
 | 
						||
ifndef NEC_98
 | 
						||
	jz	GPNoName
 | 
						||
else    ;NEC_98
 | 
						||
	jz	GPBadName
 | 
						||
endif   ;NEC_98
 | 
						||
 | 
						||
	lodsb				; char from StringParm
 | 
						||
	cmp	al,'A'			; force to lower case for match
 | 
						||
	jb	@f			; (might be numeric, so don't just OR)
 | 
						||
	cmp	al,'Z'
 | 
						||
	ja	@f
 | 
						||
	or	al,20h
 | 
						||
@@:
 | 
						||
	cmp	al,es:[di]		; match so far?
 | 
						||
	jnz	GPFlushName
 | 
						||
 | 
						||
	or	al,al			; finished if matched up to & incl NULL
 | 
						||
	jz	GPFoundName
 | 
						||
 | 
						||
	inc	di			; still matches, check next char
 | 
						||
	jmp	short GPChkNext
 | 
						||
 | 
						||
GPFlushName:
 | 
						||
	inc	bx
 | 
						||
GPFN2:
 | 
						||
	inc	di
 | 
						||
	cmp	byte ptr es:[di],0FFh
 | 
						||
ifndef NEC_98
 | 
						||
	jz	GPNoName
 | 
						||
else    ;NEC_98
 | 
						||
	jz	GPBadName
 | 
						||
endif   ;NEC_98
 | 
						||
 | 
						||
	cmp	byte ptr es:[di],0
 | 
						||
	jnz	GPFN2
 | 
						||
	inc	di
 | 
						||
	jmp	short GPNextName
 | 
						||
 | 
						||
GPFoundName:
 | 
						||
	mov	cs:[MachineNum],bx	; found a match, remember which entry
 | 
						||
	jmp	short GPNameDone	;   it is for later
 | 
						||
 | 
						||
ifndef NEC_98
 | 
						||
GPNoName:
 | 
						||
 | 
						||
	cmp	di,offset _text:AltNameTbl
 | 
						||
	ja	GPBadName
 | 
						||
	mov	di,offset _text:AltNameTbl
 | 
						||
	jmp	short GPNextTbl
 | 
						||
 | 
						||
GPNameDone:
 | 
						||
	pop	ds			; recover parm line pointer
 | 
						||
	pop	si
 | 
						||
	jmp	GPNextParm
 | 
						||
 | 
						||
GPBadName:
 | 
						||
	pop	ds			; clear stack and error out...
 | 
						||
	pop	si
 | 
						||
	jmp	GPBadParm
 | 
						||
else    ;NEC_98
 | 
						||
GPBadName:
 | 
						||
 | 
						||
	cmp	di,offset _text:AltNameTbl
 | 
						||
	ja	GPNameDone
 | 
						||
	mov	di,offset _text:AltNameTbl
 | 
						||
	jmp	short GPNextTbl
 | 
						||
 | 
						||
GPNameDone:
 | 
						||
	pop	ds			; recover parm line pointer
 | 
						||
	pop	si
 | 
						||
 | 
						||
	jmp	GPNextParm
 | 
						||
 | 
						||
endif   ;NEC_98
 | 
						||
 | 
						||
;	Process /NUMHANDLES= parameter.
 | 
						||
 | 
						||
GPGotHands:
 | 
						||
	cmp	dx,MAXHANDLES
 | 
						||
	jna	@f
 | 
						||
	jmp	GPBadParm
 | 
						||
@@:
 | 
						||
	or	dx,dx		; Zero?
 | 
						||
	jnz	@f
 | 
						||
	jmp	GPBadParm
 | 
						||
@@:
 | 
						||
	push	es
 | 
						||
	mov	es,hiseg
 | 
						||
	assume	es:funky
 | 
						||
	mov     [cHandles],dx ; Store it
 | 
						||
	pop	es
 | 
						||
	assume	es:nothing
 | 
						||
 | 
						||
 | 
						||
	mov	dx,offset StartMsg ; display descriptive message
 | 
						||
	call    GPPrintIt
 | 
						||
 | 
						||
	push	es
 | 
						||
	mov	es,hiseg
 | 
						||
	assume	es:funky
 | 
						||
	mov	ax,[cHandles]
 | 
						||
	pop	es
 | 
						||
	assume	es:nothing
 | 
						||
 | 
						||
	call    GPPrintAX
 | 
						||
	mov	dx,offset HandlesMsg
 | 
						||
	call    GPPrintIt
 | 
						||
ifndef NEC_98
 | 
						||
	jmp	GPNextParm
 | 
						||
else    ;NEC_98
 | 
						||
	jmp	short GPNextParm
 | 
						||
endif   ;NEC_98
 | 
						||
 | 
						||
GPGotMin:
 | 
						||
	cmp	dx,64		; process /hmamin= parameter
 | 
						||
	jna	@f
 | 
						||
	jmp	GPBadParm
 | 
						||
@@:
 | 
						||
	push    dx
 | 
						||
	mov	cs:[MinHMASize],dx
 | 
						||
 | 
						||
	mov	dx,offset HMAMINMsg ; print a descriptive message
 | 
						||
	call    GPPrintIt
 | 
						||
	mov	ax,cs:[MinHMASize]
 | 
						||
	call    GPPrintAX
 | 
						||
	mov	dx,offset KMsg
 | 
						||
	call    GPPrintIt
 | 
						||
 | 
						||
	pop	dx
 | 
						||
	mov	cl,10		; Convert from K to bytes
 | 
						||
	shl	dx,cl
 | 
						||
	mov	cs:[MinHMASize],dx
 | 
						||
	jmp	short GPNextParm
 | 
						||
 | 
						||
 | 
						||
;	Process /SHADOWRAM: parameter
 | 
						||
 | 
						||
GPGotShadow:
 | 
						||
	mov	ax,word ptr [StringParm]
 | 
						||
	or	ax,2020h
 | 
						||
	xor	bl,bl
 | 
						||
	cmp	ax,'no' 		; ON ?	- means we leave it alone
 | 
						||
	jz	GPSetShadow
 | 
						||
	inc	bl
 | 
						||
	cmp	ax,'fo' 		; OFF ? - means we turn it off
 | 
						||
	jz	GPSetShadow
 | 
						||
ifndef NEC_98
 | 
						||
	jmp	GPBadParm
 | 
						||
else    ;NEC_98
 | 
						||
	jmp	short GPNextParm
 | 
						||
endif   ;NEC_98
 | 
						||
 | 
						||
GPSetShadow:
 | 
						||
	mov	fShadowOff,bl		; NZ if Shadow RAM should be turned off
 | 
						||
	jmp	short GPNextParm
 | 
						||
 | 
						||
ifndef NEC_98
 | 
						||
 | 
						||
;	Process /CPUCLOCK: parameter
 | 
						||
 | 
						||
GPGotCPUClock:
 | 
						||
 | 
						||
	mov	ax,word ptr [StringParm]
 | 
						||
	or	ax,2020h
 | 
						||
	xor	bl,bl
 | 
						||
	cmp	ax,'fo' 		; OFF ? - means we don't worry about it
 | 
						||
	jz	GPSetClock
 | 
						||
	inc	bl
 | 
						||
	cmp	ax,'no' 		; ON ?	- means we preserve CPU clock
 | 
						||
	jz	GPSetClock		;	  rate
 | 
						||
	jmp	GPBadParm
 | 
						||
 | 
						||
GPSetClock:
 | 
						||
	mov	fCPUClock,bl		; NZ if clock rate preserved
 | 
						||
	jmp	short GPNextParm
 | 
						||
endif   ;NEC_98
 | 
						||
 | 
						||
 | 
						||
;	Process /INT15= parameter
 | 
						||
 | 
						||
GPGotInt15:
 | 
						||
	cmp	dx, 64			; atleast 64K
 | 
						||
	jae	@f
 | 
						||
	jmp	GPBadParm
 | 
						||
ifndef NEC_98
 | 
						||
@@:	call	GetInt15Memory
 | 
						||
	cmp	ax, dx			; enuf Ext Mem ?
 | 
						||
else    ;NEC_98
 | 
						||
	call	GetInt15Memory
 | 
						||
@@:	cmp	ax, dx			; enuf Ext Mem ?
 | 
						||
endif   ;NEC_98
 | 
						||
	jae	@f
 | 
						||
	jmp	GPBadParm
 | 
						||
@@:	mov	[Int15MemSize], dx
 | 
						||
	; Fall through to GetNextParm
 | 
						||
ifdef NEC_98
 | 
						||
	jmp	short GPNextParm
 | 
						||
endif   ;NEC_98
 | 
						||
 | 
						||
GPNextParm:
 | 
						||
	mov	ax,cs:[GPRegSave]	; are we at the end of the line?
 | 
						||
	cmp	al,13			; may not be needed any longer...
 | 
						||
	je	GPExit
 | 
						||
	cmp	al,10
 | 
						||
	je	GPExit
 | 
						||
ifndef NEC_98
 | 
						||
	jmp	GPNextArg
 | 
						||
else    ;NEC_98
 | 
						||
	jmp     GPNextChar
 | 
						||
endif   ;NEC_98
 | 
						||
 | 
						||
GPExit:
 | 
						||
	pop	ds
 | 
						||
	ret
 | 
						||
 | 
						||
GetParms    endp
 | 
						||
 | 
						||
; Get the next character from DS:SI, set CY if it's an EOL (CR, LF), set
 | 
						||
; Z if it's a space
 | 
						||
 | 
						||
ifndef NEC_98
 | 
						||
GPOffEOL	dw	-1
 | 
						||
endif   ;NEC_98
 | 
						||
 | 
						||
	public	GPGetChar
 | 
						||
 | 
						||
GPGetChar	proc	near
 | 
						||
ifndef NEC_98
 | 
						||
 | 
						||
	cmp	si,cs:[GPOffEOL]	; are we already at EOL?
 | 
						||
	jnb	GPAtEOL
 | 
						||
 | 
						||
	lodsb				; no, get next char
 | 
						||
	cmp	al,10			; is this the EOL?
 | 
						||
	je	GPHitEOL
 | 
						||
	cmp	al,13
 | 
						||
	je	GPHitEOL
 | 
						||
 | 
						||
	cmp	al,' '			; set Z if blank
 | 
						||
 | 
						||
	clc
 | 
						||
	ret
 | 
						||
 | 
						||
GPHitEOL:
 | 
						||
	mov	cs:[GPOffEOL],si	; save EOL offset once
 | 
						||
GPAtEOL:
 | 
						||
else    ;NEC_98
 | 
						||
	lodsb
 | 
						||
	cmp	al,10
 | 
						||
	je	@f
 | 
						||
	cmp	al,13
 | 
						||
	je	@f
 | 
						||
 | 
						||
	clc
 | 
						||
	ret
 | 
						||
@@:
 | 
						||
endif   ;NEC_98
 | 
						||
	stc
 | 
						||
	ret
 | 
						||
 | 
						||
GPGetChar	endp
 | 
						||
 | 
						||
 | 
						||
;*----------------------------------------------------------------------*
 | 
						||
 | 
						||
GPPrintIt   proc    near
 | 
						||
 | 
						||
	push    ds		; Save current DS
 | 
						||
	push    cs		; Set DS=CS
 | 
						||
	pop	ds
 | 
						||
	mov	ah,9
 | 
						||
	int	21h
 | 
						||
	pop	ds		; Restore DS
 | 
						||
	ret
 | 
						||
 | 
						||
GPPrintIt   endp
 | 
						||
 | 
						||
;*----------------------------------------------------------------------*
 | 
						||
 | 
						||
GPPrintAX   proc    near
 | 
						||
 | 
						||
	mov	cx,10
 | 
						||
	xor	dx,dx
 | 
						||
	div	cx
 | 
						||
	or	ax,ax
 | 
						||
	jz	GPAPrint
 | 
						||
	push    dx
 | 
						||
	call    GPPrintAX
 | 
						||
	pop	dx
 | 
						||
GPAPrint:
 | 
						||
	add	dl,'0'
 | 
						||
	mov	ah,2
 | 
						||
	int	21h
 | 
						||
	ret
 | 
						||
 | 
						||
GPPrintAX   endp
 | 
						||
 | 
						||
;*----------------------------------------------------------------------*
 | 
						||
;*									*
 | 
						||
;*  InitHandles -							*
 | 
						||
;*									*
 | 
						||
;*	Initialize the Extended Memory Handle Table			*
 | 
						||
;*									*
 | 
						||
;*  ARGS:   None							*
 | 
						||
;*  RETS:   None							*
 | 
						||
;*  REGS:   AX, BX, CX, and Flags are clobbered				*
 | 
						||
;*									*
 | 
						||
;*----------------------------------------------------------------------*
 | 
						||
 | 
						||
	assume	ds:_text
 | 
						||
 | 
						||
	public	InitHandles
 | 
						||
 | 
						||
InitHandles proc    near
 | 
						||
	push	es
 | 
						||
	mov	es,hiseg
 | 
						||
	assume	es:funky
 | 
						||
	mov	cx,[cHandles]
 | 
						||
 | 
						||
;	Init the Handle table.
 | 
						||
 | 
						||
	mov	bx,[KiddValley]
 | 
						||
 | 
						||
	xor	ax,ax
 | 
						||
IHTabLoop:
 | 
						||
	mov	[bx].Flags,UNUSEDFLAG
 | 
						||
	mov	[bx].cLock,al
 | 
						||
	mov	[bx].Base,ax
 | 
						||
	mov	[bx].Len,ax
 | 
						||
	if	keep_cs
 | 
						||
	mov	[bx].Acs,ax
 | 
						||
	endif
 | 
						||
	add	bx,SIZE Handle
 | 
						||
	loop    IHTabLoop
 | 
						||
 | 
						||
	mov	[KiddValleyTop],bx	; save top for handle validation
 | 
						||
	pop	es
 | 
						||
	assume	es:nothing
 | 
						||
	ret
 | 
						||
 | 
						||
InitHandles endp
 | 
						||
 | 
						||
ifdef NEC_98
 | 
						||
;******************************************************************************
 | 
						||
;   Init_Ram_Window - Initialize Ram Window Memory
 | 
						||
;
 | 
						||
;	MS-DOS
 | 
						||
;	Ram Window	Memory			Ram Windows	Memory
 | 
						||
;	 80		100			80		80
 | 
						||
;	 90		110			90		90
 | 
						||
;	 BO		120			B0		B0
 | 
						||
;	 A0		130			A0		A0
 | 
						||
;
 | 
						||
;
 | 
						||
;
 | 
						||
;   Author:   (sbp)
 | 
						||
;
 | 
						||
;   ENTRY:  REAL MODE on 386 processor (CPU ID already performed)
 | 
						||
;   EXIT:
 | 
						||
;
 | 
						||
;   USED:   flags
 | 
						||
;   STACK:
 | 
						||
;------------------------------------------------------------------------------
 | 
						||
 | 
						||
Init_RamWindow	proc	near
 | 
						||
 | 
						||
	push	ax
 | 
						||
	push	bx
 | 
						||
	push	dx
 | 
						||
	push	ds
 | 
						||
 | 
						||
	cli
 | 
						||
	mov	cs:[save_ss],ss
 | 
						||
	mov	cs:[save_sp],sp
 | 
						||
	push	cs
 | 
						||
	pop	ss
 | 
						||
	mov	sp,offset EISA_stack
 | 
						||
 | 
						||
	mov	al, 8
 | 
						||
	out	37h, al
 | 
						||
 | 
						||
	mov	ax, 8000h		; <20>]<5D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڽ
 | 
						||
	mov	bx, 4000h		; <20>]<5D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڽ
 | 
						||
	mov	cx, 4			; <20>]<5D><><EFBFBD>o<EFBFBD><6F><EFBFBD>N<EFBFBD><4E>
 | 
						||
	call	movebank
 | 
						||
 | 
						||
	mov	al,08h			; 80 BANK memory
 | 
						||
	mov	dx,91h			; 80 BANK ram windows		"
 | 
						||
	out	dx,al			; set RAM WINDOW
 | 
						||
 | 
						||
	mov	al,0ah			; A0 BANK memory
 | 
						||
	mov	dx,93h			; A0 BANK ram window		"
 | 
						||
	out	dx,al			; set RAM WINDOW
 | 
						||
 | 
						||
	xor	ax, ax
 | 
						||
	mov	ds, ax
 | 
						||
	test	byte ptr ds:[481h], 04h	; Q : can use shadow ram ?
 | 
						||
	jnz	@f
 | 
						||
	call	initshadowram
 | 
						||
@@:
 | 
						||
	mov	ax, 4000h
 | 
						||
	mov	bx, 8000h
 | 
						||
	mov	cx, 4
 | 
						||
	call	movebank
 | 
						||
 | 
						||
	mov	ss, cs:[save_ss]
 | 
						||
	mov	sp, cs:[save_sp]
 | 
						||
 | 
						||
	mov	al, 09h
 | 
						||
	out	37h, al
 | 
						||
	sti
 | 
						||
 | 
						||
	pop	ds
 | 
						||
	pop	dx
 | 
						||
	pop	bx
 | 
						||
	pop	ax
 | 
						||
	ret
 | 
						||
	
 | 
						||
Init_RamWindow	endp
 | 
						||
 | 
						||
;******************************************************************************
 | 
						||
;   Init_Ram_Window_XA - Initialize Ram Window Memory
 | 
						||
;
 | 
						||
;	MS-DOS					Himem
 | 
						||
;	Ram Window	Memory			Ram Windows	Memory
 | 
						||
;	 80		100			80		TOM-40  or  TOM-20
 | 
						||
;	 90		110			90		TOM-30  or  TOM-10
 | 
						||
;	 BO		120			B0		TOM-20  or  120
 | 
						||
;	 A0		130			A0		TOM-10  or  130
 | 
						||
;
 | 
						||
;   Author:   (sbp)
 | 
						||
;
 | 
						||
;   ENTRY:  REAL MODE on 286
 | 
						||
;	    AH = main memory size in blocks of 128k
 | 
						||
;   EXIT:
 | 
						||
;
 | 
						||
;   USED:   flags
 | 
						||
;   STACK:
 | 
						||
;------------------------------------------------------------------------------
 | 
						||
 | 
						||
Init_RamWindow_XA	proc	near
 | 
						||
 | 
						||
	sub	ah,3
 | 
						||
	cmp	byte ptr es:[401h],ah
 | 
						||
	ja	IRX_Start
 | 
						||
	mov	byte ptr es:[401h],0
 | 
						||
	ret
 | 
						||
 | 
						||
IRX_Start:
 | 
						||
	push	ax
 | 
						||
	push	bx
 | 
						||
	push	dx
 | 
						||
	push	ds
 | 
						||
 | 
						||
	cli
 | 
						||
	mov	cs:[save_ss],ss
 | 
						||
	mov	cs:[save_sp],sp
 | 
						||
	push	cs
 | 
						||
	pop	ss
 | 
						||
	mov	sp,offset EISA_stack
 | 
						||
 | 
						||
	mov	al, 8
 | 
						||
	out	37h, al
 | 
						||
 | 
						||
	cmp	ah,1			; main memory = 640k ?
 | 
						||
	je	IRX_640
 | 
						||
 | 
						||
	mov	ax, 0a000h		; <20>]<5D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڽ
 | 
						||
	mov	bx, 4000h		; <20>]<5D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڽ
 | 
						||
	mov	cx, 2			; <20>]<5D><><EFBFBD>o<EFBFBD><6F><EFBFBD>N<EFBFBD><4E>
 | 
						||
	call	movebank
 | 
						||
 | 
						||
	mov	al,byte ptr es:[401h]
 | 
						||
	dec	al
 | 
						||
	shl	al,1
 | 
						||
	add	al,10h			; al = BANK #
 | 
						||
	mov	dx,93h			; A0 BANK ram window		"
 | 
						||
	out	dx,al			; set RAM WINDOW
 | 
						||
 | 
						||
	mov	ax, 4000h
 | 
						||
	mov	bx, 0a000h
 | 
						||
	mov	cx, 2
 | 
						||
	call	movebank
 | 
						||
 | 
						||
	dec	byte ptr es:[401h]
 | 
						||
 | 
						||
IRX_640:
 | 
						||
	mov	ax, 8000h		; <20>]<5D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڽ
 | 
						||
	mov	bx, 4000h		; <20>]<5D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڽ
 | 
						||
	mov	cx, 2			; <20>]<5D><><EFBFBD>o<EFBFBD><6F><EFBFBD>N<EFBFBD><4E>
 | 
						||
	call	movebank
 | 
						||
 | 
						||
	mov	al,byte ptr es:[401h]
 | 
						||
	dec	al
 | 
						||
	shl	al,1
 | 
						||
	add	al,10h			; al = BANK #
 | 
						||
	mov	dx,91h			; 80 BANK ram windows		"
 | 
						||
	out	dx,al			; set RAM WINDOW
 | 
						||
 | 
						||
	mov	ax, 4000h
 | 
						||
	mov	bx, 8000h
 | 
						||
	mov	cx, 2
 | 
						||
	call	movebank
 | 
						||
 | 
						||
	dec	byte ptr es:[401h]
 | 
						||
 | 
						||
	mov	ss, cs:[save_ss]
 | 
						||
	mov	sp, cs:[save_sp]
 | 
						||
 | 
						||
	mov	al, 09h
 | 
						||
	out	37h, al
 | 
						||
	sti
 | 
						||
 | 
						||
	pop	ds
 | 
						||
	pop	dx
 | 
						||
	pop	bx
 | 
						||
	pop	ax
 | 
						||
	ret
 | 
						||
 | 
						||
Init_RamWindow_XA	endp
 | 
						||
 | 
						||
;-------------------------------------------------------------------
 | 
						||
;   movebank	move bank datat
 | 
						||
;	entry	ax : source seg. address
 | 
						||
;		bx : dest. seg. address
 | 
						||
;		cx : bank count
 | 
						||
;
 | 
						||
;----------------------------------------------------------------
 | 
						||
 | 
						||
movebank proc	near
 | 
						||
	push	es
 | 
						||
	push	ds
 | 
						||
	push	si
 | 
						||
	push	di
 | 
						||
@@:
 | 
						||
	mov	ds, ax
 | 
						||
	mov	es, bx
 | 
						||
	push	cx
 | 
						||
	mov	cx, 8000h
 | 
						||
	cld
 | 
						||
	xor	si, si
 | 
						||
	xor	di, di
 | 
						||
	rep	movsw
 | 
						||
	pop	cx
 | 
						||
	add	ax, 1000h		; get next bank address
 | 
						||
	add	bx, 1000h		; get next bank address
 | 
						||
	loop	@b
 | 
						||
	pop	di
 | 
						||
	pop	si
 | 
						||
	pop	ds
 | 
						||
	pop	es
 | 
						||
	ret
 | 
						||
movebank endp
 | 
						||
 | 
						||
;*-----------------------------------------------------------
 | 
						||
;*  initshadowram
 | 
						||
;*
 | 
						||
;*
 | 
						||
;*----------------------------------------------------------
 | 
						||
initshadowram proc	near
 | 
						||
	push	es
 | 
						||
	push	di
 | 
						||
	push	cx
 | 
						||
	cld
 | 
						||
	mov	ax, 8000h
 | 
						||
	mov	es, ax
 | 
						||
	mov	cx, 0004h
 | 
						||
	mov	ax,8000h
 | 
						||
	mov	es,ax
 | 
						||
	mov	cx,0004h
 | 
						||
l3:
 | 
						||
	xor	di, di
 | 
						||
	push	cx
 | 
						||
	mov	cx, 3333h
 | 
						||
l1:
 | 
						||
	mov	ax, 0ff01h
 | 
						||
	stosw
 | 
						||
	mov	ax, 55aah
 | 
						||
	stosw
 | 
						||
	mov	al, 00
 | 
						||
	stosb
 | 
						||
	loop	l1
 | 
						||
	stosb
 | 
						||
 | 
						||
	xor	di, di
 | 
						||
	mov	cx, 3333h
 | 
						||
l2:
 | 
						||
	mov	ax,0ff01h
 | 
						||
	scasw
 | 
						||
	jnz	isr_exit
 | 
						||
	mov	ax,55aah
 | 
						||
	scasw
 | 
						||
	jnz	isr_exit
 | 
						||
	mov	al,00h
 | 
						||
	scasb	 
 | 
						||
	jnz	isr_exit
 | 
						||
	loop	l2 
 | 
						||
	mov	ax, es
 | 
						||
	add	ax, 1000h
 | 
						||
	mov	es, ax
 | 
						||
	pop	cx
 | 
						||
	loop	l3
 | 
						||
 | 
						||
;	clean up memory
 | 
						||
 | 
						||
	mov	cx, 0004h
 | 
						||
l4:
 | 
						||
	push	cx
 | 
						||
	mov	ax, es
 | 
						||
	sub	ax, 1000h
 | 
						||
	mov	es, ax
 | 
						||
	xor	ax, ax
 | 
						||
	mov	di, ax
 | 
						||
	mov	cx, 8000h
 | 
						||
	rep	stosw
 | 
						||
	pop	cx
 | 
						||
	loop	l4
 | 
						||
	xor	ax,ax
 | 
						||
	jmp	short isr_done
 | 
						||
isr_exit:
 | 
						||
	mov	ax,0001 
 | 
						||
isr_done:
 | 
						||
	pop	cx 
 | 
						||
	pop	di 
 | 
						||
	pop	es 
 | 
						||
	ret
 | 
						||
 | 
						||
initshadowram endp
 | 
						||
;*----------------------------------------------------------------------*
 | 
						||
;*									*
 | 
						||
;*  ScanEISA - poll any EISA devices through the BIOS's Int15(0d8h)	*
 | 
						||
;*     and add any memory we find out about to our free memory table.	*
 | 
						||
;*     Note:  this code (including a big buffer) gets thrown out after	*
 | 
						||
;*     completion of the initialization sequence.			*
 | 
						||
;*									*
 | 
						||
;*	Note:  The COMPAQ BIOS uses up 1.5K of stack during int15(d80x) *
 | 
						||
;*		so we'll set up a separate stack while we're here	*
 | 
						||
;*									*
 | 
						||
;*----------------------------------------------------------------------*
 | 
						||
 | 
						||
save_ss	dw	0
 | 
						||
save_sp	dw	0
 | 
						||
EISA_Stack:
 | 
						||
 | 
						||
endif   ;NEC_98
 | 
						||
_text	ends
 | 
						||
 | 
						||
ifdef	debug_tsr
 | 
						||
 | 
						||
EndStmt equ	<end	ExeStart>
 | 
						||
 | 
						||
STACK	segment	stack 'STACK'
 | 
						||
	db	1024 dup (?)
 | 
						||
STACK	ends
 | 
						||
 | 
						||
else
 | 
						||
 | 
						||
EndStmt equ	<end>
 | 
						||
 | 
						||
endif
 | 
						||
 | 
						||
	EndStmt
 | 
						||
 |