;	PAGE	,132			;
;	SCCSID = @(#)sysinit1.asm	1.7 85/10/24
;TITLE	BIOS SYSTEM INITIALIZATION
%warning out: ...SYSINIT1
;==============================================================================
;REVISION HISTORY:
;AN000 - New for DOS Version 4.00 - J.K.
;AC000 - Changed for DOS Version 4.00 - J.K.
;AN00x - PTM number for DOS Version 4.00 - J.K.
;==============================================================================
;AN001; p40 Boot from the system with no floppy diskette drives    6/26/87 J.K.
;AN002; d24  MultiTrack= command added. 			   6/29/87 J.K.
;AN003; d9  Double word mov for 386 machine			   7/15/87 J.K.
;AN004; p447 BUFFERS = 50 /E without EMS installed hangs	   8/25/87 J.K.
;AN005; d184 Set DEVMARK for MEM command			   8/25/87 J.K.
;AN006; p851 Installable files not recognized corretly. 	   9/08/87 J.K.
;AN007; p1299 Set the second entry of DEVMARK for MEM command	   9/25/87 J.K.
;AN008; p1361 New Extended Attribute				   9/28/87 J.K.
;AN009; p1326 Buffers = 50 /e hangs				   9/28/87 J.K.
;AN010; New EMS Interface
;AN011; New Message SKL file					  10/20/87 J.K.
;AN012; P2211 Setting EA=7 for ANSI.SYS hangs the system	  11/02/87 J.K.
;AN013; p2343 Set the name for SYSINIT_BASE for MEM command	  11/11/87 J.K.
;AN014; D358  New device driver INIT function package		  12/03/87 J.K.
;AN015; For Installed module with no parameter			  12/11/87 J.K.
;AN016; D285 Undo the Extended Attribute handling		  12/17/87 J.K.
;AN017; P2806 Show "Error in CONFIG.SYS ..." for INSTALL= command 12/17/87 J.K.
;AN018; P2914 Add Extended Memory Size in SYSVAR		  01/05/88 J.K.
;AN019; P3111 Take out the order dependency of the INSTALL=	  01/25/88 J.K.
;AN020; P3497 Performace fix for new buffer scheme		  02/15/88 J.K.
;AN021; D486 SHARE installation for big media			  02/23/88 J.K.
;AN022; D493 Undo D358 & do not show error message for device driv02/24/88 J.K.
;AN023; D474 Change BUFFERS= /E option to /X for expanded memory  03/16/88 J.K.
;AN024; D506 Take out the order dependency of the IFS=		  03/28/88 J.K.
;AN025; P4086 Memory allocation error when loading SHARE.EXE	  03/31/88 J.K.
;AN026; D517 New Balanced Real memory buffer set up scheme	  04/18/88 J.K.
;AN027; D528 Install XMAEM.SYS first before everything else	  04/29/88 J.K.
;AN028; P4669 SHARE /NC causes an error 			  05/03/88 J.K.
;AN029; P4759 Install EMS INT2fh, INT 67h handler		  05/12/88 J.K.
;AN030; P4934 P4759 INT 2Fh handler number be changed to 1Bh	  05/20/88 J.K.
;==============================================================================

extern BUFFHEAD
extern sysinit_get_ds_dosbiodata
extern sysinit_get_es_dosbiodata

TRUE	    EQU 0FFFFh
FALSE	    EQU 0
CR	    equ 13
LF	    equ 10
TAB	    equ  9

IBMVER	   EQU	   TRUE
IBM	   EQU	   IBMVER
STACKSW    EQU	   TRUE 		;Include Switchable Hardware Stacks
IBMJAPVER  EQU	   FALSE		;If TRUE set KANJI true also
%iassign MSVER FALSE
ALTVECT    EQU	   FALSE		;Switch to build ALTVECT version
KANJI	   EQU	   FALSE
MYCDS_SIZE equ	   88			;J.K. Size of Curdir_List. If it is not
					;the same, then will generate compile error.

;
	%IF	IBMJAPVER
NOEXEC	EQU	TRUE
	%ELSE
NOEXEC	EQU	FALSE
	%ENDIF

;DOSSIZE EQU	0A000H
;dossize equ	 0C000H 	;J.K. for the debugging version of IBMDOS.

%include "entryseg.nas"
%include "dcodeseg.nas"

%ifn _RELOCATEDOSCODE
 [list -]
%endif
%if _RELOCATEDOSCODE
section AFTERDOSCODE class=AFTERDOSCODE align=16
	global afterdoscodelabel
afterdoscodelabel:
%endif
%ifn _RELOCATEDOSCODE
 [list +]
%endif

	%include "ddataseg.nas"
[list -]
;	INCLUDE dossym.INC
	%include "msgroup.mac"
	%include "smdossym.mac"	;J.K. Reduced version of DOSSYM.INC
	%include "devsym.mac"
	%include "ioctl.mac"
	%include "biostruc.mac"
	%include "smifssym.mac"		;AN000;
	%include "defems.mac"		;AN010;
	%include "devmark.mac"		;AN005;
	%include "cputype.mac"
	%include "version.mac"
	%include "msbds.mac"
	%include "dpb.mac"
	%include "sysinisw.mac"
	%include "lmacros3.mac"
[list -]
	%include "lstruct.mac"
	%include "scanptab.mac"
	%include "verbose.mac"
[list +]

;AN000 J.K. If MYCDS_SIZE <> CURDIRLEN, then force a compilatiaon error.
	%if	MYCDS_SIZE != curdirLen
	   %error  !!! SYSINIT1 COMPILATION FAILED. DIFFERENT CDS SIZE !!!
	%endif

	%IFN IBMJAPVER
	EXTRN	RE_INIT:FAR
	%ENDIF

;---------------------------------------
;Equates for Main stack and stack Initialization program
	%IF	STACKSW

EntrySize		equ	8

MinCount		equ	8
DefaultCount		equ	9
MaxCount		equ	64

MinSize 		equ	32
DefaultSize		equ	128
MaxSize 		equ	512

labelsize AllocByte, byte, es:bp+0
labelsize IntLevel, byte, es:bp+1
labelsize SavedSP, word, es:bp+2
labelsize SavedSS, word, es:bp+4
labelsize NewSP, word, es:bp+6
Free			equ	0
allocated		equ	1
overflowed		equ	2
clobbered		equ	3


;External variables in IBMBIO for INT19h handling rouitne. J.K. 10/23/86
	EXTRN	Int19sem:byte

%macro extrn_irq_handlers 1-*
 %rep %0
		EXTRN Int19OLD%1:dword
  %rotate 1
 %endrep
%endmacro

extrn_irq_handlers 02,08,09,0A,0B,0C,0D,0E,70,72,73,74,76,77

; (no prior section) ; CODE ends
	%ENDIF
;---------------------------------------
;J.K. 6/29/87 External variable defined in IBMBIO module for Multi-track
MULTRK_ON	EQU	10000000B	;User spcified Mutitrack=on, or System turns
					; it on after handling CONFIG.SYS file as a
					; default value, if MulTrk_flag = MULTRK_OFF1.
MULTRK_OFF1	EQU	00000000B	;initial value. No "Multitrack=" command entered.
MULTRK_OFF2	EQU	00000001B	;User specified Multitrack=off.

usesection DOSENTRY
	EXTRN	MulTrk_flag:word	;AN002;
	extrn CONHEADER:byte
; (no prior section) ; CODE ends
;J.K. 6/29/87 End of Multi-track definition.

usesection DOSSTART
; (no prior section) ; DOSSTART		ENDS

addsection AFTERDOSDATA, align=16 class=AFTERDOSDATA
; (no prior section) ; AFTERDOSDATA	ENDS
	global afterdosdatalabel
afterdosdatalabel:

addsection SYSINITSEG, PUBLIC class=INIT
addsection SYSINITTRAIL, PUBLIC class=INIT align=2
addsection SYSINITLAST, PUBLIC class=INIT align=2

group SYSINITGROUP SYSINITSEG SYSINITTRAIL SYSINITLAST

usesection SYSINITSEG

	EXTRN	BADCOM:BYTE
	EXTRN	SYSSIZE:BYTE
	EXTRN	CONDEV:BYTE,AUXDEV:BYTE,PRNDEV:BYTE,COMMND:BYTE
	extrn	DeviceParameters:byte
	extrn	DevMark_Addr:word
	extrn	SetDevMarkFlag:byte
	extrn	PathString:byte 			;AN021;
	extrn	LShare:byte				;AN021;
	extrn	ShareWarnMsg:byte			;AN021;

	EXTRN	MEM_ERR:NEAR
	EXTRN	DOCONF:NEAR
	extrn	Multi_Pass:NEAR 			;AN024;
	extrn	BadLoad:near
	extrn	Error_Line:near
	extern devicehighflag, shellhighflag

	PUBLIC	behind_dosentry_segment
	PUBLIC	DEVICE_LIST
SYSI_COUNTRY equ SYSI_Country	; NASM port label
	PUBLIC	SYSI_COUNTRY
	PUBLIC	MEMORY_SIZE
	PUBLIC	DEFAULT_DRIVE
	PUBLIC	BUFFERS
	PUBLIC	FILES
	PUBLIC	NUM_CDS
	PUBLIC	SYSINIT
CNTRYFILEHANDLE equ CntryFilehandle	; NASM port label
	PUBLIC	CNTRYFILEHANDLE
	PUBLIC	COMMAND_LINE
	public	Big_Media_Flag				;AN021;Set by IBMINIT

	%IF	STACKSW
 ;Internal Stack Information
	PUBLIC	STACK_COUNT
	PUBLIC	STACK_SIZE
	PUBLIC	STACK_ADDR
	%ENDIF

dosinfo equ DOSINFO	; NASM port label
entry_point equ ENTRY_POINT	; NASM port label
	PUBLIC dosinfo,entry_point
fcbs equ FCBS	; NASM port label
keep equ Keep	; NASM port label
	PUBLIC fcbs,keep
	PUBLIC config_block
zero equ ZERO	; NASM port label
sepchr equ SepChr	; NASM port label
	PUBLIC zero,sepchr,STALL
count equ COUNT	; NASM port equate
chrptr equ CHRPTR	; NASM port label
org_count equ Org_Count	; NASM port label
	PUBLIC count,chrptr,org_count
bufptr equ BUFPTR	; NASM port label
prmblk equ PRMBLK	; NASM port label
	PUBLIC bufptr,prmblk
	PUBLIC PACKET,UNITCOUNT
drivenumber equ DriveNumber	; NASM port label
	PUBLIC BREAK_ADDR,BPB_ADDR,drivenumber
	public Config_Size
	public Install_Flag
	public COM_Level
	public CMMT
	public CMMT1
	public CMMT2
	public Cmd_Indicator
	public LineCount
	public ShowCount
	public Buffer_LineNum
	public DoNotShowNum
	public IFS_Flag
	public IFS_RH
	public H_Buffers
	public Buffer_Slash_X			;AN023;
	public ConfigMsgFlag			;AN014;
	public Do_Install_Exec			;AN019;
	public Multi_Pass_Id			;AN024;


;
SYSINIT$:
	%IF	STACKSW
;.SALL
;=== Push trace listing source: msstack.nas
	  %include "msstack.nas"		;Main stack program and data definitions ; NASM included file
;=== Pop trace listing source
;	  include STKMES.INC		;Fatal stack error message
;=== Push trace listing source: msbio.cl5
	  %include "msbio.cl5"		;Fatal stack error message ; NASM included file
;=== Pop trace listing source
;.XALL
	align 2, nop
	    public Endstackcode
Endstackcode	label byte
	%ENDIF


	even
DOSINFO 		LABEL	DWORD
			DW	0,0

ENTRY_POINT		LABEL	DWORD
			dw 0, 0

behind_dosentry_segment	DW	0000
 global verbose_mode
verbose_mode:		dw 0			; high byte is clobbered
DEVICE_LIST:
 dw CONHEADER - DOSENTRYDEVICEBASE * 16, seg CONHEADER + DOSENTRYDEVICEBASE

SYSI_Country		LABEL	DWORD		;J.K. 5/29/86 Pointer to
			DW	0000		;country table in DOS
			DW	0000

Fake_Floppy_Drv 	db	0		;AN001;Set to 1 if this machine
						;does not have any floppies!!!
Big_Media_Flag		db	0		;AN021;Set by IBMINIT if > 32 MB fixed media exist.
verbose_hide_cds:	db 0

	even
 global sysinit_bootdrive_hidden, sysinit_bootdrive_unit
 global sysinit_have_bootdrive_preliminary
 global sysinit_have_bootdrive_exact
sysinit_bootdrive_hidden:	dd 0
sysinit_bootdrive_unit:		db 0
sysinit_have_bootdrive_preliminary:	db 0
sysinit_have_bootdrive_exact:		db 0

 global dosdata_relocate_first, dosdata_relocate_early
dosdata_relocated_to_final_position:
			db 0
dosdata_relocate_first:	db 0
dosdata_relocate_early:	db 0
doscode_relocated_to_final_position:
			db 0

	even
;
;Variables for Stack Initialization Program.
	%IF	STACKSW
STACK_COUNT		DW	DefaultCount
STACK_SIZE		DW	DefaultSize
STACK_ADDR		DD	00000000
	%ENDIF
; various default values

MEMORY_SIZE		DW	0001
DEFAULT_DRIVE		DB	00	;initialized by IBMINIT.
BUFFERS 		DW	-1	; initialized during buffer allocation
H_Buffers		dw	0	;AN000; # of the Heuristic buffers. Initially 0.
%ifndef BUF2
Buffer_Pages		dw	0	;AN000; # of extended memory pages for the buffer.
BufferBuckets		dw	0	;AN000;
Buffer_odds		dw	0	;AN000;
%endif
SingleBufferSize	dw	?	;AN000; Maximum sector size + buffer header
%ifndef BUF2
MaxNumBuf1		db     15	;AN026;Num of buffers in a bucket group 1.
MaxNumBuf2		db     15	;AN026;Num of buffers in a possible bucket group 2.
NthBuck 		db	0	;AN026; 1st bucket group = 1st bucket through Nth Bucket. The rest = second group

%IF	BUFFERFLAG

FIRST_PAGE		DW	0, 0
LAST_PAGE		DW	0, 0
NPA640			DW	0
EMS_SAVE_BUF		DB	0,0,0,0,0,0,0,0,0,0,0,0

%ENDIF
%endif

FILES			DB	8	; enough files for pipe
FCBS			DB	4	; performance for recycling
Keep			DB	0	; keep original set
NUM_CDS 		DB	5	; 5 net drives
config_block		DW	?
buffer_block:		dw	0
altah_block:		dw	0
FOOSTRNG		DB	"A:"
COMMAND_LINE		DB	2,0,"P" ;Default Command.com Args
			DB	29 DUP (0)
ZERO			DB	0
SepChr			DB	0
LineCount		dw	0	;AN000;  Line count in config.sys
ShowCount		db	'     ',CR,LF,'$' ;AN000;  Used to convert Linecount to ASCII.
Buffer_LineNum		dw	0	;AN000; Line count for "BUFFERS=" command if entered.

Sys_Model_Byte		db	0FFh	;model byte used in SYSINIT
Sys_Scnd_Model_Byte	db	0	;secondary model byte used in SYSINIT
;
Buffer_Slash_X		db	0	;AN000;AN023; BUFFERS= ... /X option entered.
%ifndef BUF2
Real_IBM_Page_Id	dw	0	;AN029;
IBM_Frame_Seg		dw	0	;AN000; segment value for physical IBM page frame.
Frame_Info_Buffer	dw	(MAX_NUM_PAGEFRAME * 4) dup (0) ;AN010; For EMS. as per spec. 2 words per entry
EMSHandleName		db	'BUFFERS ' ;AN010; 8 char. EMS handle name
EMS_Ctrl_Tab		dd	0	;AN010;
EMS_State_Buf		dd	0	;AN010;
BUF_PREV_OFF		dw	0	;AN020;
EMS_Buf_First		dw	0	;AN020;
%endif

	%IFN NOEXEC
	align 2, db 0
COMEXE: ; NASM structure instance
Exec0_size equ Exec0_struc_size	; NASM port equate
istruc Exec0
at Exec0_environ
	dw 0
at Exec0_com_line
	dw COMMAND_LINE, 0
at Exec0_5C_FCB
	dw Ldexec_FCB1, 0
at Exec0_6C_FCB
	dw Ldexec_FCB2, 0
iend
	%ENDIF

;------------------------------------------------------------------
;J.K.  2/23/87 ;variables for INSTALL= command.

Multi_Pass_Id		db	-1	;AN024;AN027;

	align 2, db 0
Install_Flag		dw	0	;AN000;
   HAVE_INSTALL_CMD	 equ	 00000001b ;AN019; CONFIG.SYS has INSTALL= commands
   HAS_INSTALLED	 equ	 00000010b ;AN019; SYSINIT_BASE installed.
   SHARE_INSTALL	 equ	 00000100b ;AN021; Used to install SHARE.EXE

Config_Size		dw	0	;AN000; size of config.sys file. Set by SYSCONF.ASM
CheckSum		dw	0	;AN000; Used by Sum_up

Ldexec_FCB1		times 16 db 0
Ldexec_FCB2		times 16 db 0
Ldexec_Line		db	0		;AN000;# of parm characters
Ldexec_start		db	' '		;AN000;
Ldexec_parm		db	80 dup (0)	;AN000;

	align 2, db 0
INSTEXE: ; NASM structure instance
istruc Exec0
at Exec0_environ
	dw 0
at Exec0_com_line
	dw Ldexec_Line, 0
at Exec0_5C_FCB
	dw Ldexec_FCB1, 0
at Exec0_6C_FCB
	dw Ldexec_FCB2, 0
iend

;AN016; Undo the extended attribute handling
;EA_QueryList		 label	 byte
;			 dw	 1	 ;AN008; I need just one EA info.
;			 db	 02h	 ;AN008; Type is BINARY
;			 dw	 8000h	 ;AN008; Flag is SYSTEM DEFINED.
;			 db	 8	 ;AN008; Length of name is 8 bytes
;			 db	 'FILETYPE' ;AN008; Name is FILETYPE
;Ext_Attr_List		 dw	 1	 ;AN008; Just 1 Extended attribute List
;			 db	 2	 ;AN008;EA_TYPE
;			 dw	 8000h	 ;AN008;FLAG
;			 db	 0	 ;AN008;Failure reason
;			 db	 8	 ;AN008;Length of NAME
;			 dw	 1	 ;AN008;Length of VALUE
;			 db	 'FILETYPE' ;AN008;Name
;Ext_Attr_Value 	 db	 0	 ;AN008;Value
;SIZE_EXT_ATTR_LIST	 equ	 $-Ext_Attr_List	 ;AN008;
;
;;Extended attribute value
;EA_INSTALLABLE 	 equ	 4	 ;AN008;Value for Installable file

;------------------------------------------------------------------
;J.K. 5/15/87  ;Request header, variables for IFS= command.

IFS_Flag	dw	0			;AN000; Set to 1 if it is an IFS.
   IS_IFS	  equ	00000001b		;IFS command?
   NOT_IFS	  equ	11111110b

IFS_RH: ; NASM structure instance
IFSRH_size equ IFSRH_struc_size	; NASM port equate
istruc IFSRH
at IFSR_LENGTH
	dw LENGTH_INIT
at IFSR_FUNCTION
	db IFSINIT
iend

;------------------------------------------------------------------
;Variables for Comment=
COM_Level	db	0		;AN000;level of " " in command line
CMMT		db	0		;AN000;length of COMMENT string token
CMMT1		db	0		;AN000;token
CMMT2		db	0		;AN000;token
Cmd_Indicator	db	?		;AN000;
DoNotShowNum	db	0		;AN000;

;------------------------------------------------------------------
COUNT		DW	0000
Org_Count	dw	0000		;AN019;
CHRPTR		DW	0000
CntryFilehandle DW 0000
;------------------------------------------------------------------
BucketPTR LABEL  dword			;AN000;
BUFPTR	LABEL	DWORD			;LEAVE THIS STUFF IN ORDER!
	DW	0
	DW	0
PRMBLK	LABEL	WORD
	dw 0
	dw 0

PACKET			DB	24	;AN014; Was 22
			DB	0
			DB	0	;INITIALIZE CODE
			DW	0
			DB	8 DUP (?)
UNITCOUNT		DB	0
BREAK_ADDR		DD	0
BPB_ADDR		DD	0
DriveNumber		DB	0
ConfigMsgFlag		dw	0	;AN014;AN022; Used to control "Error in CONFIG.SYS line #" message

	align 16, db 0
initpspmcb:
istruc arena
at arena_signature,	db 'M'
at arena_owner
at arena_size,		dw 6
at arena_reserved
at arena_name,		db "INIT",0
at arena_struc_size
; iend		; cannot use arena_size as it clashes with the field named the same
%pop

tempcds_block:		dw 0

 global kernelcommandline
 global kernelcommandline.end
	align 2, db 0
kernelcommandline:	fill 256, 0, {db 0, -1}
.end:		dw 0


 extern OLDCONFIG_name
 global CONFIG_pointers
 extern cmdline_noop, cmdline_checkdebugger, cmdline_verbose, cmdline_scanmode
 extern cmdline_haltflag

 global commandnames
; format:
;  word		function pointer - 1 in DOSENTRY, 0FFFFh if end
;  word		content pointer, written to -> last command content, 0 if empty
;  word		name pointer, -> ASCIZ name in SYSINIT
commandnames:
	; these are just to validate the names.
	;  their contents aren't used here.
		dw cmdline_noop - 1, 0, namedot
		dw cmdline_noop - 1, 0, nameprepend
		dw cmdline_noop - 1, 0, nameappend

	; These use the function pointer to run things.
	;  The content pointers aren't used later on.
		dw cmdline_checkdebugger - 1, 0, namecheckdebugger
		dw cmdline_verbose - 1, 0, nameverbose
		dw cmdline_scanmode - 1, 0, namescanmode
		dw cmdline_haltflag - 1, 0, namehaltflag
		dw cmdline_haltflag - 1, 0, namehaltflags

CONFIG_pointers:
	; The content pointers in these are used to set the
	;  filenames used for the configuration file.
.config:	dw cmdline_noop - 1, 0, .nameconfig
.altconfig:	dw cmdline_noop - 1, ALTCONFIG_name, .namealtconfig
.oldconfig:	dw cmdline_noop - 1, OLDCONFIG_name, .nameoldconfig
		dw -1

.nameconfig:	asciz "CONFIG"
.namealtconfig:	asciz "ALTCONFIG"
.nameoldconfig:	asciz "OLDCONFIG"

global nameprepend, nameappend
nameprepend:	asciz "PREPEND"
nameappend:	asciz "APPEND"
namedot:	asciz "."

ALTCONFIG_name:	asciz "ldos.ini"

msg_startingsmall:
.:		db "Starting small "
.length equ $ - .
msg_linebreak:
.:		db 13,10
.length equ $ - .

msg:
.prompt:		db 13,10,"Enter command to load as a shell: "
.prompt.length equ $ - .prompt
.cds.1:			asciz "init: CDS has "
.cds.2.singular:	asciz " entry, last is drive "
.cds.2.plural:		asciz " entries, last is drive "
.cds.3:			asciz ":, used "
.cds.4:			asciz " last used drive "
.cds.5:			asciz ":",13,10
.cds.error:		asciz "init: Internal CDS allocation error!",13,10

	usesection SYSINITLAST
stack_low: equ $
.ldos2024:		asciz "LDOS2024"
.ldosnew:		asciz "LDOSNEW"
.freedos:		asciz "FREEDOS"
.freedosdla:		asciz "FREEDOSDLA"
.edrdos:		asciz "EDRDOS"
.msdos5:		asciz "MSDOS5"
.msdos7:		asciz "MSDOS7"
namecheckdebugger:	asciz "CHECKDEBUGGER"
nameverbose:		asciz "VERBOSE"
namescanmode:		asciz "SCANMODE"
namehaltflag:		asciz "HALTFLAG"
namehaltflags:		asciz "HALTFLAGS"

	align 2, db 0
modetable:
	dw msg.ldos2024
	dw mode_first_ext5 | mode_first_ext15 | mode_ignore_ext85 \
		| mode_ignore_subsequent_nested \
		| mode_ignore_subsequent_logical \
		| mode_ignore_subsequent_primary \
		| mode_traditional_order_logical \
		| mode_disable_fat32 \
		| mode_dlasort_zero
	dw msg.ldosnew
	dw mode_all_ext5 | mode_all_ext15 | mode_all_ext85 \
		| mode_disable_fat32
	dw msg.freedos
	dw mode_first_ext5 | mode_first_ext15 | mode_ignore_ext85 \
		| mode_ignore_subsequent_nested \
		| mode_traditional_order_logical \
		| mode_active_priority \
		| mode_subsequent_primary_after \
		| mode_dlasort_zero
	dw msg.freedosdla
	dw mode_first_ext5 | mode_first_ext15 | mode_ignore_ext85 \
		| mode_ignore_subsequent_nested \
		| mode_traditional_order_logical \
		| mode_active_priority \
		| mode_subsequent_primary_after
	dw msg.edrdos
	dw mode_first_ext5 | mode_first_ext15 | mode_ignore_ext85 \
		| mode_ignore_subsequent_nested \
		| mode_traditional_order_logical \
		| mode_dlasort_zero
	dw msg.msdos5
	dw mode_first_ext5 | mode_ignore_ext15 | mode_ignore_ext85 \
		| mode_ignore_subsequent_nested \
		| mode_ignore_subsequent_logical \
		| mode_traditional_order_logical \
		| mode_active_priority \
		| mode_subsequent_primary_after \
		| mode_disable_fat32 \
		| mode_disable_lba \
		| mode_dlasort_zero
	dw msg.msdos7
	dw mode_first_ext5 | mode_first_ext15 | mode_ignore_ext85 \
		| mode_ignore_subsequent_nested \
		| mode_ignore_subsequent_logical \
		| mode_traditional_order_logical \
		| mode_active_priority \
		| mode_subsequent_primary_after \
		| mode_dlasort_zero
.end:


 global GOINIT
GOINIT:
 assume ds:nothing, es:nothing, ss:nothing
	push cx
;J.K. before doing anything else, let's set the model byte
;SB33043*****************************************************************
	mov	ah,0c0h 		;get system configuration     ;SB ;3.30*
	int	15h			; *			      ;SB ;3.30*
;SB33043*****************************************************************
	jc	No_ROM_Config
	cmp	ah, 0			; double check
	jne	No_ROM_Config
	mov	al, [ES:BX + bios_SD_modelbyte]
	mov	[cs:Sys_Model_Byte], al
	mov	al, [ES:BX + bios_SD_scnd_modelbyte]
	mov	[cs:Sys_Scnd_Model_Byte], al
	jmp	@F
No_ROM_Config:				; Old ROM
	mov	ax, 0f000h
	mov	ds, ax
 assume ds:nothing
	mov	al, byte ptr [0fffeh]
	mov	[cs:Sys_Model_Byte], al ;set the model byte.
@@:

;J.K.6/24/87 Set Fake_Floppy_Drv if there is no diskette drives in this machine.
;SB34SYSINIT1001********************************************************
;SB	execute the equipment determination interrupt and then
;SB	check the returned value to see if we have any floppy drives
;SB	if we have no floppy drive we set cs:Fake_Floppy_Drv to 1
;SB	See the AT Tech Ref BIOS listings for help on the equipment
;SB	flag interrupt (11h)

	int	11h
	test	al, 1			; has floppy ?
	jnz	Move_Myself
	mov	byte [cs:Fake_Floppy_Drv],1	; no floppy, fake.

;SB34SYSINIT1001********************************************************
Move_Myself:
	CLD				; Set up move
	XOR	SI,SI
	MOV	DI,SI

%if 0
	%IF	MSVER
	MOV	CX,[cs:MEMORY_SIZE]
	CMP	CX,1			; 1 means do scan
	JNZ	NOSCAN
	MOV	CX,2048 		;START SCANNING AT 32K BOUNDARY
	XOR	BX,BX

MEMSCAN:INC	CX
	JZ	SETEND
	MOV	DS,CX
	MOV	AL,[BX]
	NOT	AL
	MOV	[BX],AL
	CMP	AL,[BX]
	NOT	AL
	MOV	[BX],AL
	JZ	MEMSCAN
SETEND:
	MOV	[cs:MEMORY_SIZE],CX
	%ENDIF

	%IF	IBMVER | IBMJAPVER
	MOV	CX,[cs:MEMORY_SIZE]
	%ENDIF
NOSCAN:					; CX is mem size in para
%endif

SYSIN:

%if 0
	xor ax, ax
	mov ds, ax
	ASSUME	DS:NOTHING,ES:SYSINITSEG,SS:NOTHING
	MOV	ax, [cs:FINAL_DOS_LOCATION]	; Where it is going (set by BIOS)
	mov word [31h * 4 + 2], ax
	mov es, ax
	ASSUME	ES:NOTHING
	xor di, di
	mov bx, DOSSTART
	mov cx, afterdosdatalabel wrt DOSSTART	; = early DOS data length
	mov ds, bx			; => early DOS data location
	xor si, si
	cmp bx, ax
	; cmp ds, es
	jae load_dos_to_lower
load_dos_to_higher:
	mov si, cx			; -> behind source
	mov di, si			; -> behind dest
	std				; set DOWN
	cmpsw				; -> at last words
load_dos_to_lower:
	shr cx, 1
	rep movsw
	cld
%endif

	pop bx				; => first trail S MCB
	sub bx, 7			; => place for MCB
	mov es, bx
 assume es:nothing
	push bx				; => MCB
	inc bx				; => place for PSP
	xor di, di			; es:di -> MCB
	push cs
	pop ds
 assume ds:SYSINITGROUP
	mov si, initpspmcb		; ds:si -> template
	mov word [si + arena_owner], bx
	mov cx, 8
	rep movsw
	mov byte [si - MCB_size + mcbSignature], 'Z'

	MOV	DX,[MEMORY_SIZE]	; Set for call to DOSINIT
	LDS	SI,[DEVICE_LIST]	; Set for call to DOSINIT
 assume ds:nothing
	pop cx				; => first trail S MCB
	mov di, word [cs:behind_dosentry_segment]
					; free MCB
	CLI
	jmp SYSINIT_CALL_DOS

	align 16, db 26h
stack_high equ $ + fromparas(paras(SYSINITSTACK))

	usesection SYSINITTRAIL
SYSINIT_CALL_DOS:

	MOV	AX,CS
	MOV	SS,AX
	MOV	SP, stack_high		; Set stack
 assume ss:SYSINITGROUP

%if (stack_high - stack_low) < 512
 %assign NUMBER (stack_high - stack_low)
 %error Too small stack, want 512, have NUMBER
%endif

	%IFN ALTVECT
	STI				; Leave INTs disabled for ALTVECT
	%ENDIF

	xor ax, ax
	mov es, ax
 assume es:IVT
	mov es, word [es:31h * 4 + 2]	; => DOSDATA
 assume es:DOSGROUP
		; INP:	dx => behind LMA
		;	dx - 1 => where to place first UMCB
		;	ds:si -> first non-NUL device header
		;	es => DOSDATA to initialise
		;	es - 1 => DOSDATA MCB, shrink as desired
		;	cx => first trail MCB
		;	bx => space for init PSP
		;	di => space for free MCB (should link to cx => MCB)
	int3

 extern NEARDOSINIT
	call NEARDOSINIT
 assume es:DOSGROUP			;ES:DI -> SysInitVars_Ext
	mov	ax, word ptr [es:di + SYSI_InitVars] ;J.K. 5/29/86
	mov	word ptr [ss:dosinfo], ax
	mov	ax, word ptr [es:di + SYSI_InitVars+2]
	mov	word ptr [ss:dosinfo+2],ax ;set the sysvar pointer

	mov	ax, word ptr [es:di + SYSI_Country_Tab]
	mov	word ptr [ss:SYSI_Country],ax
	mov	ax, word ptr [es:di + SYSI_Country_Tab+2]
	mov	word ptr [ss:SYSI_Country+2],ax	;set the SYSI_Country pointer J.K.

	mov ah, 40h
	mov bx, 1
	 push cs
	 pop ds
 assume ds:SYSINITGROUP
	testopt [verbose_mode], verbose_intro
	jz .nointro
	mov dx, msg_startingsmall
	mov cx, msg_startingsmall.length
	int 21h
	mov ax, 33FFh
	int 21h
	xchg dx, ax		; dx -> message, ax => segment
	mov di, dx
	mov es, ax
 assume es:DOSCODEGROUP
	mov ds, ax
 assume ds:DOSCODEGROUP
	mov al, 0
	mov cx, -1
	repne scasb
	not cx
	dec cx
	mov ah, 40h
	int 21h
	mov ah, 40h
	mov bx, 1
	 push cs
	 pop ds
 assume ds:SYSINITGROUP
	mov dx, msg_linebreak
	mov cx, msg_linebreak.length
	int 21h

.nointro:
	extern INITUPB
	call INITUPB
 assume ds:nothing, es:nothing, ss:SYSINITGROUP

	extern INITDPB
	call INITDPB
 assume ds:nothing, es:nothing, ss:SYSINITGROUP

relocate_upb_early:
 extern sysinit_get_ds_dosentry, dskdrvs_indirect, START_BDS, DRVMAX

	call sysinit_get_ds_dosentry	; DRVMAX in DOSENTRY
 assume ds:DOSENTRYGROUP
	xor si, si
	mov ch, [DRVMAX]		; ch = how many UPBs
%ifnidni %[DOSBIODATA], %[DOSENTRY]
	call sysinit_get_ds_dosbiodata
 assume ds:DOSGROUP
%endif
	les di, [START_BDS]		; es:di -> first UPB
 assume es:UPB
	lds dx, [dskdrvs_indirect]	; ds:dx -> dskdrvs array (used by INITDPB)
 assume ds:UPB
	cmp di, -1			; none ?
	je .warn			; then skip -->
	test ch, ch
	jz .warn
		; Harden: Expect UPBs at start of memory block.
	test di, di
	jnz .warn
	mov ax, es
	mov bx, ds
	cmp ax, bx			; UPB segment == dskdrvs segment ?
	jne .warn
	dec ax
	mov ds, ax
 assume ds:MCB
	cmp word [si + mcbOwner], 8	; an S MCB ?
	jne .warn
	cmp word [si + mcbName], "S"	; S MCB ?
	jne .warn
	cmp byte [si + smcbType], S_UPB	; correct type ?
	jne .warn
	mov ax, [si + mcbSize]
	mov cl, 4
	shl ax, cl			; = size in bytes
	mov bx, ax
	shr ax, cl			; compute paragraphs again
	cmp word [si + mcbSize], ax	; match ?
	jne .warn
	cmp bx, dx			; dskdrvs array fits in block ?
	jbe .warn			; certainly no -->
	xor ax, ax
	mov al, ch			; ax = how many UPBs
	add ax, ax			; how large dskdrvs array should be
	add ax, dx			; -> behind array
	add ax, 15			; round up
	and al, ~ 15			; get to paragraph boundary
	cmp bx, ax			; match ?
	jne .warn
	mov al, BDS_TYPE_struc_size
	mul ch				; ax = how many bytes needed for UPBs
	cmp dx, ax			; last UPB fits below dskdrvs ?
	jb .warn			; no -->
	mov bx, ax
	inc ax
	and al, ~ 1
	cmp dx, ax
	jne .warn

	mov cl, ch
	test cl, cl
	jz .warn
	push es
	push di
.loop:
	cmp cl, 1
	je .last
	mov bx, es
	cmp word [es:di + LINK + 2], bx
	jne .warn_pop_pop
	lea bx, [di + BDS_TYPE_struc_size]
	cmp word [es:di + LINK], bx
	jne .warn_pop_pop
	dec cx				; count down
	les di, [es:di + LINK]
 assume es:UPB
	jmp .loop

.last:
	cmp word [es:di + LINK], -1
	jne .warn_pop_pop

	mov si, alloc_upb_temporary
	push cx
	push ax
	call allocate_temporary_block
 assume es:nothing
	pop cx				; = size of initialised UPBs
	pop bx				; bh = number of UPBs
	pop si
	pop ds				; -> first UPB source
 assume ds:UPB
	mov dx, di			; es:dx -> destination
	rep movsb			; copy them over
	mov di, dx			; es:di -> copied UPBs
	mov cl, bh
	mov ch, 0			; cx = amount UPBs
	mov bx, ds

.newloop:
	dec cx
	jz .newlast
	cmp word [es:di + LINK + 2], bx
	jne .warn_free
	lea ax, [di + BDS_TYPE_struc_size]
	cmp word [es:di + LINK], ax
	jne .warn_free
	mov word [es:di + LINK + 2], es	; relocate next link
	les di, [es:di + LINK]
 assume es:nothing
	jmp .newloop

.newlast:
	cmp word [es:di + LINK], -1
	jne .warn_free

	call sysinit_get_ds_dosbiodata
 assume ds:DOSGROUP
	cli
	mov ax, -1
	mov word [dskdrvs_indirect], ax
	mov word [dskdrvs_indirect + 2], ax
					; invalidate the dskdrvs pointer
	mov ax, es
	mov word [START_BDS], dx
	xchg word [START_BDS + 2], ax	; relocate the UPBs
	sti
	mov es, ax
 assume es:nothing
	mov ah, 49h
	int 21h				; free the original allocation
	jmp .done

.warn_free:
	mov ah, 49h
	int 21h				; free new allocation
	db __TEST_IMM16			; skip twice pop
.warn_pop_pop:
	pop ax
	pop ax
.warn:
	push cs
	pop ds
 assume ds:SYSINITGROUP
	mov dx, sysinit_msg.warn_upb
	mov cx, sysinit_msg.warn_upb.size
	mov bx, 1
	mov ah, 40h
	int 21h
.done:
 assume ds:nothing, es:nothing, ss:SYSINITGROUP


		; ! Note that at this point no SFTs, CDSes, buffers
		;  hold references to our early DOS-internal DPBs.
relocate_dpb_early:
 extern NUMIO, DPBHEAD, sysinit_getdosdata

	call sysinit_getdosdata
	mov ds, ax
 assume ds:DOSGROUP
	xor si, si
	mov ch, [NUMIO]			; ch = how many DPBs (at this point)
	les di, [DPBHEAD]		; es:di -> first DPB
 assume es:DPB
	cmp di, -1			; none ?
	je .warn			; then skip -->
	test ch, ch
	jz .warn
		; Harden: Expect DPBs at start of memory block.
	test di, di
	jnz .warn
	mov ax, es
	dec ax
	mov ds, ax
 assume ds:MCB
	cmp word [si + mcbOwner], 8	; an S MCB ?
	jne .warn
	cmp word [si + mcbName], "S"	; S MCB ?
	jne .warn
	cmp byte [si + smcbType], S_DPB	; correct type ?
	jne .warn
	mov ax, [si + mcbSize]
	mov cl, 4
	shl ax, cl			; = size in bytes
	mov bx, ax
	shr ax, cl			; compute paragraphs again
	cmp word [si + mcbSize], ax	; match ?
	jne .warn
	mov al, dpb_struc_size
	mul ch				; ax = how many bytes needed for DPBs
	cmp bx, ax			; last DPB fits in block ?
	jb .warn			; no -->
	mov dx, ax
	add dx, 15
	and dl, ~ 15
	cmp bx, dx
	jne .warn

	mov cl, ch
	test cl, cl
	jz .warn
	push es
	push di
.loop:
	cmp cl, 1
	je .last
	mov bx, es
	cmp word [es:di + dpb_next_dpb + 2], bx
	jne .warn_pop_pop
	lea bx, [di + dpb_struc_size]
	cmp word [es:di + dpb_next_dpb], bx
	jne .warn_pop_pop
	dec cx				; count down
	les di, [es:di + dpb_next_dpb]
 assume es:DPB
	jmp .loop

.last:
	cmp word [es:di + dpb_next_dpb], -1
	jne .warn_pop_pop

	mov si, alloc_dpb_temporary
	push cx
	push ax
	call allocate_temporary_block
 assume es:nothing
	pop cx				; = size of initialised DPBs
	pop bx				; bh = number of DPBs
	pop si
	pop ds				; -> first DPB source
 assume ds:DPB
	mov dx, di			; es:dx -> destination
	rep movsb			; copy them over
	mov di, dx			; es:di -> copied DPBs
	mov cl, bh
	mov ch, 0			; cx = amount DPBs
	mov bx, ds

.newloop:
	dec cx
	jz .newlast
	cmp word [es:di + dpb_next_dpb + 2], bx
	jne .warn_free
	lea ax, [di + dpb_struc_size]
	cmp word [es:di + dpb_next_dpb], ax
	jne .warn_free
	mov word [es:di + dpb_next_dpb + 2], es	; relocate next link
	les di, [es:di + dpb_next_dpb]
 assume es:nothing
	jmp .newloop

.newlast:
	cmp word [es:di + dpb_next_dpb], -1
	jne .warn_free

	call sysinit_getdosdata
	mov ds, ax
 assume ds:DOSGROUP
	cli
	mov ax, es
	mov word [DPBHEAD], dx
	xchg word [DPBHEAD + 2], ax	; relocate the DPBs
	sti
	mov es, ax
 assume es:nothing
	mov ah, 49h
	int 21h				; free the original allocation
	jmp .done

.warn_free:
	mov ah, 49h
	int 21h				; free new allocation
	db __TEST_IMM16			; skip twice pop
.warn_pop_pop:
	pop ax
	pop ax
.warn:
	push cs
	pop ds
 assume ds:SYSINITGROUP
	mov dx, sysinit_msg.warn_dpb
	mov cx, sysinit_msg.warn_dpb.size
	mov bx, 1
	mov ah, 40h
	int 21h
.done:
 assume ds:nothing, es:nothing, ss:SYSINITGROUP

	les	di, [ss:dosinfo]		;es:di -> dosinfo
 assume es:DOSGROUP

	clc					;AN018;Get the extended memory size
;SB34SYSINIT1002**************************************************************
;SB	execute the get extended memory size subfunction in the BIOS INT 15h
;SB	if the function reports an error do nothing else store the extended
;SB	memory size reported at the appropriate location in the dosinfo buffer
;SB	currently pointed to by es:di.	Use the offsets specified in the
;SB	definition of the sysinitvars struct in inc\sysvar.inc
;SB		5 LOCS

	mov	ah,88h
	int	15h				;check extended memory size
	jc	No_Ext_Memory
	mov	[es:di + SYSI_EXT_MEM],ax 	;save extended memory size
No_Ext_Memory:

;SB34SYSINIT1002**************************************************************
	mov	word ptr [es:di + SYSI_IFS], -1	;AN000; Initialize SYSI_IFS chain.
	mov	word ptr [es:di + SYSI_IFS+2], -1 ;AN000;

	mov	ax, [es:di + SYSI_MAXSEC] 	;AN020; Get the sector size
	add	ax, BUFINSIZ			;AN020; size of buffer header
	mov	[ss:SingleBufferSize], ax	;AN020; total size for a buffer

Default_Drive equ DEFAULT_DRIVE	; NASM port label
	mov	al, [ss:Default_Drive]		;AN000;Get the 1 based boot drive number set by IBMINIT
	mov	[es:di + SYSI_BOOT_DRIVE], al	;AN000; set SYSI_BOOT_DRIVE

; Determine if 386 system...
	Get_CPU_Type			; macro to determine cpu type
	cmp	ax, 2			; is it a 386?
	jne	Not_386_System		; no: don't mess with flag
	mov	byte [es:di + SYSI_DWMOVE], 1		  ;AN003;
Not_386_System:					;AN003;
	MOV	AL,[ES:DI + SYSI_NUMIO]
	MOV	[ss:DriveNumber],AL		; Save start of installable block drvs

	push	es			;AN020;
	push	di			;AN020;

	push es
	mov ax, [ss:SingleBufferSize]	;AN020;Temporary Single buffer area
	mov si, alloc_init
	call allocate_temporary_block
 assume es:nothing
	mov ax, es			; ax => buffer
	pop es				; es => DOSDATA
 assume es:DOSGROUP

	mov word [ss:buffer_block], ax
%ifdef BUF2
	mov word [es:BUFFHEAD + 2], ax
	and word [es:BUFFHEAD], 0
	mov es, ax
 assume es:nothing
	xor di, di
	or word [es:di + NEXTBUF + 2], -1
	or word [es:di + NEXTBUF], -1
	mov word [es:di + BUFDRV], 00FFh
%else
	les	di, [es:di + SYSI_BUF]	;AN020;get the buffer hash entry pointer
HASH_PTR equ Hash_ptr	; NASM port equate
	les	di, [es:di + HASH_PTR]	;AN020;
	mov	word ptr [es:di + BUFFER_BUCKET],0	;AN020;
	mov	word ptr [es:di + BUFFER_BUCKET+2], ax	;AN020;
	mov	es, ax			;AN020;
	xor	ax, ax			;AN020;
	mov	di, ax			;AN020;es:di -> Single buffer
BUF_NEXT equ buf_next	; NASM port equate
	mov	[es:di + BUF_NEXT], ax	;AN020;points to itself
BUF_PREV equ buf_prev	; NASM port equate
	mov	[es:di + BUF_PREV], ax	;AN020;points to itself
BUF_ID equ buf_ID	; NASM port equate
	mov	word ptr [es:di + BUF_ID],00FFh	       ;AN020;free buffer, clear flag
BUF_SECTOR equ buf_sector	; NASM port equate
	mov	word ptr [es:di + BUF_SECTOR], ax	       ;AN020;
	mov	word ptr [es:di + BUF_SECTOR+2], ax       ;AN020;
%endif
	pop	di			;AN020;
	pop	es			;AN020;
 assume es:DOSGROUP

	PUSH	DS			; Save as input to RE_INIT
	PUSH	CS
	POP	DS
 ASSUME DS:SYSINITGROUP
	CALL	TEMPCDS			; Set up CDSs so RE_INIT and SYSINIT
					;   can make DISK system calls

init_early_fcbsft:
	xor ax, ax
	MOV	AL, 4		; ! hardcoded
	push ax
	MOV	BL,SF_ENTRY_struc_size
	MUL	BL			;AX = NUMBER OF BYTES TO CLEAR
	add ax, 6
	mov si, alloc_initfcb
	call allocate_temporary_block
 assume es:nothing

	LDS si, [ss:DOSINFO]
 assume ds:DOSGROUP

	MOV	WORD PTR [si + SYSI_FCB], di
	MOV	WORD PTR [si + SYSI_FCB+2], es	; SET POINTER TO NEW Table
	xor bx, bx
	MOV	BL, 2		; ! hardcoded
SYSI_keep equ SYSI_Keep	; NASM port equate
	MOV	[si + SYSI_keep],BX
	PUSH	CS
	POP	DS
 ASSUME DS:SYSINITGROUP
	or	WORD PTR [ES:DI + SFLINK], -1
	pop cx
	mov word [ES:DI + SFCOUNT], cx

sf_struc_size equ SF_struc_size		; NASM port equate
	add di, sf_struc_size-2		; es:di -> SFT entries

	MOV	AL,"A"
.FillLoop:
	PUSH	CX			; save count
	MOV	CX,sf_entry_struc_size	; number of bytes to fill
	cld
	REP	STOSB			; filled
	MOV	WORD PTR [ES:DI-(sf_entry_struc_size)+sf_ref_count], cx
	MOV	WORD PTR [ES:DI-(sf_entry_struc_size)+sf_position], cx
	MOV	WORD PTR [ES:DI-(sf_entry_struc_size)+sf_position+2], cx
	POP	CX
	LOOP	.FillLoop

	POP	DS			; Recover DS input to RE_INIT
 ASSUME DS:NOTHING

	%IFN IBMJAPVER
	CALL	RE_INIT			; Re-call the BIOS
	%ENDIF

	STI				; INTs OK
	CLD				; MAKE SURE

%if 0
; DOSINIT has set up a default "process" (PHP) at DS:0. We will move it out
; of the way by putting it just below SYSINIT at end of memory.
	MOV	BX,CS
	SUB	BX,10H
	MOV	ES,BX
	XOR	SI,SI
	MOV	DI,SI
	MOV	CX,80H
	REP	MOVSW
	MOV	WORD PTR [ES:PDB_JFN_Pointer + 2],ES	; Relocate
SET_CURRENT_PDB equ Set_Current_PDB	; NASM port equate
	MOV	AH,SET_CURRENT_PDB
	INT	21H			; Tell DOS we moved it
%endif

	PUSH	CS
	POP	DS
 ASSUME DS:SYSINITGROUP

%if 0
	MOV	BX,0FFFFH
ALLOC equ Alloc	; NASM port equate
	MOV	AH,ALLOC
	INT	21H			;FIRST TIME FAILS
	MOV	AH,ALLOC
	INT	21H			;SECOND TIME GETS IT
	MOV	[AREA],AX
	MOV	[MEMHI],AX		; MEMHI:MEMLO now points to
					; start of free memory
%endif
	%IF	ALTVECT
	MOV	DX,OFFSET BOOTMES
	invoke	PRINT			;Print message DOSINIT couldn't
	%ENDIF

 ASSUME DS:NOTHING

	MOV	DL,[ss:DEFAULT_DRIVE]
	OR	DL,DL
	JZ	NODRVSET		; BIOS didn't say
	DEC	DL			;A = 0
SET_DEFAULT_DRIVE equ Set_Default_Drive	; NASM port equate
	MOV	AH,SET_DEFAULT_DRIVE
	INT	21H			;SELECT THE DISK
;J.K.  2/23/87	Modified to handle INSTALL= command.
NODRVSET:
	CALL	DOCONF			;DO THE CONFIG STUFF

do_altah:
 assume ds:nothing, es:nothing, ss:SYSINITGROUP
 extern altah_option, configmsg.altah_message, configmsg.altah_message.error
 extern incompatible_ALTAH, altah_indirect
 extern sysinit_get_ds_dosbiodata, sysinit_get_es_dosentry

	rol byte [cs:altah_option], 1
	jnc .none

	mov ah, 48h
	xor bx, bx
	int 21h
	jc .error
	mov es, ax
 assume es:nothing

altah_want equ 61Bh + 700h
	cmp ax, paras(altah_want & ~15)
	ja .error_free
	mov bx, paras(altah_want + 1)
	sub bx, ax
	mov ah, 4Ah
	int 21h
	jc .error_free

	mov ax, es
	mov word [cs:altah_block], ax
	dec ax
	mov ds, ax
 assume ds:MCB
	mov word [mcbOwner], 8
	mov word [mcbName], "S"
	mov byte [smcbType], S_EXCLDALTAH

	xor di, di
	mov cl, 3
	shl bx, cl
	mov cx, bx
	mov ax, 0CCCCh
	rep stosw

	mov ax, DOSENTRY
	mov cl, 4
	shl ax, cl
	mov di, altah_want
	sub di, ax
	call sysinit_get_ds_dosbiodata
 assume ds:DOSGROUP
	call sysinit_get_es_dosentry
 assume es:DOSENTRYGROUP	
	mov bx, incompatible_ALTAH
	cli
	mov al, [es:bx]
	mov word [altah_indirect], di
	stosb
	sti

	mov dx, configmsg.altah_message
	jmp .done

.error_free:
	mov ah, 49h
	int 21h
.error:
	mov dx, configmsg.altah_message.error
.done:
	call init2_disp_msg_asciz_cs_dx

.none:
 assume ds:nothing, es:nothing, ss:SYSINITGROUP

 extern hidedosentry_option, hidedosdatafirst_option, Arena_Head
 extern configmsg.hidedosentry_message
 extern configmsg.hidedosentry_error
 extern configmsg.hidedosdata_message
 extern configmsg.hidedosdata_error
hide_dosentry:
	rol byte [cs:hidedosentry_option], 1
	jnc .no
	call sysinit_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov ax, word [Arena_Head]
	mov es, ax
 assume es:MCB
	cmp byte [es:mcbSignature], 'M'
	jne .error
	cmp word [es:mcbOwner], 8
	jne .error
	cmp word [es:mcbName], "S"
	jne .error
	cmp byte [es:smcbType], S_DOSENTRY
	jne .error
	add ax, [es:mcbSize]
	inc ax
	mov word [Arena_Head], ax
	mov dx, configmsg.hidedosentry_message
	jmp .done

.error:
	mov dx, configmsg.hidedosentry_error
.done:
	call init2_disp_msg_asciz_cs_dx

.no:
 assume ds:nothing, es:nothing, ss:SYSINITGROUP

relocate_dosdata_first:
	rol byte [cs:dosdata_relocate_first], 1
	jnc @F
	xor dx, dx			; 0 = relocate in any case, LMA if needed
	call relocate_dosdata

hide_dosdata_first:
	rol byte [cs:hidedosdatafirst_option], 1
	jnc .no
	call sysinit_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov ax, word [Arena_Head]
	mov bx, ds
	dec bx
.loop:
	mov es, ax
 assume es:MCB
	cmp ax, bx
	je .found
	cmp byte [es:mcbSignature], 'M'
	jne .error
	cmp word [es:mcbOwner], 8
	jne .error
	cmp word [es:mcbName], "S"
	jne .error
	add ax, word [es:mcbSize]
	inc ax
	jmp .loop

.found:
	cmp byte [es:mcbSignature], 'M'
	jne .error
	cmp word [es:mcbOwner], 8
	jne .error
	cmp word [es:mcbName], "S"
	jne .error
	cmp byte [es:smcbType], S_DOSDATA
	jne .error
	add ax, [es:mcbSize]
	inc ax
	mov word [Arena_Head], ax
	mov dx, configmsg.hidedosdata_message
	jmp .done

.error:
	mov dx, configmsg.hidedosdata_error
.done:
	call init2_disp_msg_asciz_cs_dx

.no:
 assume ds:nothing, es:nothing, ss:SYSINITGROUP

@@:

do_multi:
 assume ds:nothing, es:nothing, ss:SYSINITGROUP
	inc	byte [cs:Multi_Pass_Id]	;AN027; = 0
	call	Multi_Pass		;AN027;
	inc	byte [cs:Multi_Pass_Id]	;AN027; = 1
	call	Multi_Pass		;AN027;
	inc	byte [cs:Multi_Pass_Id]	;AN024; = 2
	call	Multi_Pass		;AN024;
EndFile equ ENDFILE	; NASM port label
	call	EndFile
	test	word [ss:Install_Flag], HAVE_INSTALL_CMD		;AN019;
	jz	DoLast					;AN019;
	call relocate_config
	inc	byte [cs:Multi_Pass_Id]			;AN024; = 3
	call	Multi_Pass				;AN019;AN024; Execute INSTALL= commands

;J.K. [AREA] has the segment address for the allocated memory of SYSINIT,CONFBOT.
;Free the CONFBOT area used for CONFIG.SYS and SYSINIT itself.
DoLast:

	mov ax, -1
	call init2_relocate_device
	mov ax, -1
	call init2_relocate_end

	extern dosdata_to_doscode
 assume ds:nothing, es:nothing, ss:SYSINITGROUP


relocate_upb_late:
	call sysinit_get_ds_dosentry	; DRVMAX in DOSENTRY
 assume ds:DOSENTRYGROUP
	xor si, si
	mov ch, [DRVMAX]		; ch = how many UPBs
%ifnidni %[DOSBIODATA], %[DOSENTRY]
	call sysinit_get_ds_dosbiodata
 assume ds:DOSGROUP
%endif
	les di, [START_BDS]		; es:di -> first UPB
 assume es:UPB
	cmp di, -1			; none ?
	je .warn			; then skip -->
	test ch, ch
	jz .warn
		; Harden: Expect UPBs at start of memory block.
	test di, di
	jnz .warn
	mov ax, es
	dec ax
	mov ds, ax
 assume ds:MCB
	cmp word [si + mcbOwner], 8	; an S MCB ?
	jne .warn
	cmp word [si + mcbName], "S"	; S MCB ?
	jne .warn
	cmp byte [si + smcbType], S_UPB	; correct type ?
	jne .warn
	mov ax, [si + mcbSize]
	mov cl, 4
	shl ax, cl			; = size in bytes
	mov bx, ax
	shr ax, cl			; compute paragraphs again
	cmp word [si + mcbSize], ax	; match ?
	jne .warn
	mov al, BDS_TYPE_struc_size
	mul ch				; ax = how many bytes needed for UPBs
	cmp bx, ax			; last UPB fits below size ?
	jb .warn			; no -->
	mov dx, ax
	add dx, 15
	and dl, ~ 15
	cmp bx, dx
	jne .warn

	mov cl, ch
	test cl, cl
	jz .warn
	push es
	push di
.loop:
	cmp cl, 1
	je .last
	mov bx, es
	cmp word [es:di + LINK + 2], bx
	jne .warn_pop_pop
	lea bx, [di + BDS_TYPE_struc_size]
	cmp word [es:di + LINK], bx
	jne .warn_pop_pop
	dec cx				; count down
	les di, [es:di + LINK]
 assume es:UPB
	jmp .loop

.last:
	cmp word [es:di + LINK], -1
	je @F
	mov bx, es
	cmp word [es:di + LINK + 2], bx
	je .warn
@@:

	mov si, alloc_upb
	push cx
	push ax
	call allocate_relocate_block
 assume es:nothing
	pop cx				; = size of initialised UPBs
	pop bx				; bh = number of UPBs
	pop si
	pop ds				; -> first UPB source
 assume ds:UPB
	 push si
	mov dx, di			; es:dx -> destination
	rep movsb			; copy them over
	mov di, dx			; es:di -> copied UPBs
	mov si, dx			; es:si -> first UPB in new allocation
	xor cx, cx
	or cl, bh			; cx = amount UPBs
	 pop bx				; ds:bx -> source
	mov dx, ds
	jz .warn_free
.newloop:
	dec cx
	jz .newlast
	cmp word [es:di + LINK + 2], dx
	jne .warn_free
	lea ax, [bx + BDS_TYPE_struc_size]
					; ds:ax -> next expected source UPB
	cmp word [es:di + LINK], ax
	jne .warn_free
	xchg bx, ax			; ds:bx -> next source UPB
		; ! in HMA allocstion the offset is changed
	lea ax, [di + BDS_TYPE_struc_size]
					; es:di -> next destination
	mov word [es:di + LINK + 2], es	; relocate next link segment
	mov word [es:di + LINK], ax	; relocate next link offset
	les di, [es:di + LINK]
 assume es:nothing
	jmp .newloop

.newlast:
		; ! last relocated UPB's next link pointer is left alone

	call sysinit_get_ds_dosbiodata
 assume ds:DOSGROUP
	cli
	mov ax, es
	mov word [START_BDS], si
	xchg word [START_BDS + 2], ax	; relocate the UPBs
	sti
	mov es, ax
 assume es:nothing
	mov ah, 49h
	int 21h				; free the original allocation
	jmp .done

.warn_free:
	mov bx, es
	cmp bx, -2			; HMA ?
	jb @F				; no -->
	ja .warn_free_hma_essi		; it is es == 0FFFFh -->
					; it is es == 0FFFEh
	inc bx				; = 0FFFFh
	mov es, bx			; es = 0FFFFh
 assume es:nothing
	sub si, 16			; es:si -> HMA allocation
.warn_free_hma_essi:
	mov di, si
	mov ax, 4A03h
	mov dl, 2
	int 2Fh				; free new HMA allocation
	jmp .warn

@@:
	mov ah, 49h
	int 21h				; free new LMA/UMA allocation
	db __TEST_IMM16			; skip twice pop
.warn_pop_pop:
	pop ax
	pop ax
.warn:
	push cs
	pop ds
 assume ds:SYSINITGROUP
	mov dx, sysinit_msg.warn_upb
	mov cx, sysinit_msg.warn_upb.size
	mov bx, 1
	mov ah, 40h
	int 21h
.done:
 assume ds:nothing, es:nothing, ss:SYSINITGROUP


relocate_dpb_late:
	call sysinit_getdosdata
	mov ds, ax
 assume ds:DOSGROUP
	xor si, si
	mov ch, [NUMIO]			; ch = how many DPBs at most
	les di, [DPBHEAD]		; es:di -> first DPB
 assume es:DPB
	cmp di, -1			; none ?
	je .warn			; then skip -->
	test ch, ch
	jz .warn
		; Harden: Expect DPBs at start of memory block.
	test di, di
	jnz .warn
	mov ax, es
	dec ax
	mov ds, ax
 assume ds:MCB
		; We expect at least two DOS-internal DPBs.
		;  Although we do somewhat work if none are
		;  used, we can warn here anyway.
	cmp word [si + mcbOwner], 8	; an S MCB ?
	jne .warn
	cmp word [si + mcbName], "S"	; S MCB ?
	jne .warn
	cmp byte [si + smcbType], S_DPB	; correct type ?
	jne .warn
	mov ax, [si + mcbSize]
	mov dx, ax
	mov cl, 4
	shl ax, cl			; = size in bytes
	shr ax, cl			; compute paragraphs again
	cmp word [si + mcbSize], ax	; match ?
	jne .warn

	mov cl, ch
	test cl, cl
	jz .warn
	mov ch, 0
	push es
	push di
.loop:
	inc ch
	cmp cl, 1
	je .last
	mov bx, es
	cmp word [es:di + dpb_next_dpb + 2], bx
	jne .havelast_pop_pop
	lea bx, [di + dpb_struc_size]
	cmp word [es:di + dpb_next_dpb], bx
	jne .havelast_pop_pop
	dec cx				; count down
	les di, [es:di + dpb_next_dpb]
 assume es:DPB
	jmp .loop

.last:
	cmp word [es:di + dpb_next_dpb], -1
	je @F
	mov bx, es
	cmp word [es:di + dpb_next_dpb + 2], bx
	je .warn_pop_pop
@@:
.havelast_pop_pop:
	lea ax, [di + dpb_struc_size]
	push ax
	call ParaRound
	cmp ax, dx			; MCB size matches ?
	pop ax
	jne .warn_pop_pop

	mov si, alloc_dpb
	push cx
	push ax
	call allocate_relocate_block
 assume es:nothing
	pop cx				; = size of relocateable DPBs
	pop bx				; bh = number of relocateable DPBs
	pop si
	pop ds				; -> first DPB source
 assume ds:UPB
	 push si
	mov dx, di			; es:dx -> destination
	rep movsb			; copy them over
	mov di, dx			; es:di -> copied DPBs
	mov si, dx			; es:si -> first DPB in new allocation
	xor cx, cx
	or cl, bh			; cl = amount relocated DPBs
	 pop bx				; ds:bx -> source
	mov bp, bx			; dx:bp -> first source DPB
	mov ch, cl			; ch = amount relocated DPBs
	mov dx, ds
	jz .warn_free
.newloop:
	dec cl
	jz .newlast
	cmp word [es:di + dpb_next_dpb + 2], dx
	jne .warn_free
	lea ax, [bx + dpb_struc_size]
					; ds:ax -> next expected source UPB
	cmp word [es:di + dpb_next_dpb], ax
	jne .warn_free
	xchg bx, ax			; ds:bx -> next source UPB
		; ! in HMA allocstion the offset is changed
	lea ax, [di + dpb_struc_size]
					; es:di -> next destination
	mov word [es:di + dpb_next_dpb + 2], es	; relocate next link segment
	mov word [es:di + dpb_next_dpb], ax	; relocate next link offset
	les di, [es:di + dpb_next_dpb]
 assume es:nothing
	jmp .newloop

.newlast:
		; ! last relocated DPB's next link pointer is left alone

		; now we have to relocate all references to the DPBs.
		;  there's buffers, CDSes, SFTs, and FCB SFTs.
		; INP:	dx:bp -> first relocated DPB source
		;	ch = amount
		;	es:si -> first destination DPB
	push es
	push si
	mov cl, ch
	mov ch, 0

 extern BUFFHEAD, CDSADDR, CDSCOUNT, sft_addr, sftFCB

.relocloop:
	push cx

 %ifndef BUF2
  %fatal DPB reloc not done for non-BUF2
 %endif

	call sysinit_getdosdata
	mov ds, ax
 assume ds:DOSGROUP
	lds di, [BUFFHEAD]
 assume ds:nothing
@@:
	cmp di, -1
	je @FF
	cmp byte [di + BUFDRV], -1
	je @F
	mov bx, BUFDRVDP
	call relocate_dibx_dpb_from_dxbp_to_essi
@@:
	lds di, [di + NEXTBUF]
 assume ds:nothing
	jmp @BB

@@:

	call sysinit_getdosdata
	mov ds, ax
 assume ds:DOSGROUP
	mov cl, byte [CDSCOUNT]		; ch already 0
	lds di, [CDSADDR]
 assume ds:nothing
@@:
	testopt [di + curdir_flags], curdir_isnet
					; net or IFS ?
	jnz @F				; yes, don't check -->
	mov bx, curdir_devptr
	call relocate_dibx_dpb_from_dxbp_to_essi
@@:
	add di, curdir_list_struc_size
	loop @BB

	call sysinit_getdosdata
	mov ds, ax
 assume ds:DOSGROUP
	lds di, [sft_addr]
 assume ds:nothing
	call reloc_dpb_in_sftc

	call sysinit_getdosdata
	mov ds, ax
 assume ds:DOSGROUP
	lds di, [sftFCB]
 assume ds:nothing
	call reloc_dpb_in_sftc

.relocnext:
	pop cx
	les si, [es:si + dpb_next_dpb]
 assume es:nothing
	mov ds, dx
 assume ds:nothing
	lds bp, [ds:bp + dpb_next_dpb]
 assume ds:nothing
	mov dx, ds
	loop .relocloop

	pop si
	pop es
 assume es:nothing

	call sysinit_getdosdata
	mov ds, ax
 assume ds:DOSGROUP
	cli
	mov ax, es
	mov word [DPBHEAD], si
	xchg word [DPBHEAD + 2], ax	; relocate the DPBs
	sti
	mov es, ax
 assume es:nothing
	mov ah, 49h
	int 21h				; free the original allocation
	jmp .done

.warn_free:
	mov bx, es
	cmp bx, -2			; HMA ?
	jb @F				; no -->
	ja .warn_free_hma_essi		; it is es == 0FFFFh -->
					; it is es == 0FFFEh
	inc bx				; = 0FFFFh
	mov es, bx			; es = 0FFFFh
 assume es:nothing
	sub si, 16			; es:si -> HMA allocation
.warn_free_hma_essi:
	mov di, si
	mov ax, 4A03h
	mov dl, 2
	int 2Fh				; free new HMA allocation
	jmp .warn

@@:
	mov ah, 49h
	int 21h				; free new LMA/UMA allocation
	db __TEST_IMM16			; skip twice pop
.warn_pop_pop:
	pop ax
	pop ax
.warn:
	push cs
	pop ds
 assume ds:SYSINITGROUP
	mov dx, sysinit_msg.warn_dpb
	mov cx, sysinit_msg.warn_dpb.size
	mov bx, 1
	mov ah, 40h
	int 21h
.done:
 assume ds:nothing, es:nothing, ss:SYSINITGROUP


%imacro neartransfer 1.nolist
	extern %1
	call transfer_sysinitseg_to_doscode
	jmp strict short %%skip
	dw %1
%%skip:
%endmacro

 extern transfer_sysinitseg_to_doscode

shrink_altah_block:
	mov ax, word [cs:altah_block]
	test ax, ax
	jz .none
	dec ax
	mov ds, ax
 assume ds:MCB
	mov bx, word [mcbSize]
	xor di, di
	cmp bx, 1
	jbe .done
	mov dx, 8
	lea cx, [bx - 2]
	neartransfer SplitMCB
	neartransfer ClearMCB
	mov ds, dx
 assume ds:MCB
	mov byte [mcbName], 'S'
	mov byte [smcbType], S_EXCLDALTAH
	inc dx
	mov word [cs:altah_block], dx
.done:
.none:
 assume ds:nothing, es:nothing, ss:SYSINITGROUP


relocate_psp_late:
	mov ax, 60h
	mov si, alloc_initpsp
	call allocate_relocate_block
 assume es:nothing
	mov ah, 62h
	int 21h			; get old PSP
	mov ds, bx
 assume ds:nothing
	mov dx, bx
	xor si, si		; ds:si -> old PSP
	mov cx, words(60h)
	rep movsw
	mov ax, es

		; Because of the abort.nas "Scan" handling we
		;  have to relocate the owner process of open
		;  SFT entries that we want to keep across the
		;  process termination. This code may become
		;  useless once we improve "Scan" but it won't
		;  do any harm to keep doing this.
	push ds
	call sysinit_get_ds_dosbiodata
 assume ds:DOSGROUP
	lds si, [sft_addr]
 assume ds:nothing
.loop_sftc:
	inc si
	jz .done_sftc
	push si
	mov cx, word [si - 1 + SFCount]
	jcxz .next_sftc
	add si, SFTable - 1
.loop_sft:
	cmp word [si + sf_ref_count], 0
	je .next_sft
	cmp word [si + sf_PID], dx
	jne .next_sft
	mov word [si + sf_PID], ax
.next_sft:
	add si, sf_entry_struc_size
	loop .loop_sft
.next_sftc:
	pop si
	lds si, [si - 1 + SFLink]
 assume ds:nothing
	jmp .loop_sftc
.done_sftc:
	pop ds
 assume ds:nothing

	; mov es, ax		; es = new PSP
	mov di, 18h
	mov cx, 20
	mov word [ es:34h+2 ], ax
	mov word [ es:34h ], di	; fix the new PSP's PHT pointer
	mov word [ es:32h ], cx	;  and the count of PHT entries field
	 push ax
	mov al, -1
	 push di
	mov bx, cx		; = 20
	rep stosb		; initialise new PHT with empty entries
	 pop di
	mov cx, word [ 32h ]	; cx = count of PHT entries
	cmp cx, bx		; >= 20 ?
	jb .shortertable	; no -->
	mov cx, bx		; limit to 20
.shortertable:
	lds si, [ 34h ]		; ds:si-> old PHT
	push si
	push cx
	rep movsb		; get all entries
	pop cx
	pop di
	 push ds
	 pop es			; es:di-> old PHT
 assume es:nothing
	rep stosb		; fill moved entries with -1 (closed)
	mov ds, dx		; ds = old PSP
 assume ds:nothing
	mov word [ 0Ah ], .terminated
	mov word [ 0Ah+2 ], cs
	mov ax, 3523h
	int 21h
	mov word [ 0Eh ], bx
	mov word [ 0Eh+2 ], es
	mov ax, 3524h
	int 21h
	mov word [ 12h ], bx
	mov word [ 12h+2 ], es	; set interrupt vectors to ours
	 pop ax
	mov word [ 16h ], ax	; set parent PSP to the relocated one
	mov es, ax
 assume es:nothing
	mov word [ es:2Eh+2 ], ss
				; set SS used by process termination

	xchg ax, bx		; bx = new location, dx = old location
	mov ax, 335Dh
	int 21h			; PSP relocated call-out
	mov di, dx

		; In order to set the correct stack address here,
		; the last Int21 call to a usual function (such as
		; Int21.48) must've been made with the same stack
		; pointer as the Int21.4C call below gets.
		;
		; Update: dosemu2 does weird things to the stack.
		;  In particular, it inserts an additional iret
		;  frame depending on some conditions.
		; Only the interrupt 21h subfunctions 00h, 26h,
		;  31h, 4Bh, and 4Ch are handled differently.
		;  As a workaround we can call service 4Bh as the
		;  last interrupt 21h function before terminating.
		; Refer to https://github.com/dosemu2/dosemu2/blob/d7402eec84478c051d25e7b26dd8515514c186e2/src/base/core/int.c#L1633-L1639

	; rol byte [j_flags.invalidexec], 1
	; jnc @F

	push cs
	pop ds
 assume ds:SYSINITGROUP
	mov dx, sysinit_msg.nullbyte
				; just in case, ds:dx -> zero value byte
	mov ax, 4B7Fh		; 21.4B with invalid subfunction in al
				;  (note that FreeDOS masks off 80h)
	int 21h
@@:

	mov ds, di
 assume ds:nothing
	mov es, bx
 assume es:nothing
	push word [ 2Eh ]
	pop word [ es:2Eh ]	; set SP used by process termination
.nullbyte: equ $ - 1

	mov ax, 4C00h
	int 21h			; terminate, and make the new PSP active
				; also handles freeing all memory allocated to the old PSP
				; also closes any handles >20 if PHT larger
				; also relocates Int23, Int24
				; also notifies resident software old PSP is no longer valid
.terminated:			; (ax, bx, es, ds, bp might be changed)
 assume ds:nothing, es:nothing, ss:SYSINITGROUP

	test	word [ss:Install_Flag], HAVE_INSTALL_CMD		;AN019;
	jz	@F					;AN019;
	call relocate_config
	inc	byte [cs:Multi_Pass_Id]		; = 4
	call	Multi_Pass			; Execute INSTALLLAST=
@@:
 assume ds:nothing, es:nothing, ss:SYSINITGROUP

	xor cx, cx
	xchg cx, word [cs:config_block]
	jcxz @F
	mov es, cx
 assume es:nothing
	mov ah, 49h
	int 21h
@@:
 assume ds:nothing, es:nothing, ss:SYSINITGROUP

	 push cs
	 pop ds
 assume ds:SYSINITGROUP
	 push cs
	 pop es
 assume ds:SYSINITGROUP, es:SYSINITGROUP, ss:SYSINITGROUP

	call	LoadShare		;AN021; Try to load share.exe, if needed.
	mov	byte [cs:DoNotShowNum], 1	;AN000; Done with CONFIG.SYS. Do not show line number message.
%if 0
	mov	cx, [ss:area]		;AN000;
	mov	es, cx			;AN000;
	mov	ah, 49h 		;AN000; Free allocated memory for command.com
	int	21h			;AN000;

Install_flag equ Install_Flag	; NASM port label
	test	word [cs:Install_flag], HAS_INSTALLED ;AN013; SYSINIT_BASE installed?
	jz	Skip_Free_SYSINITBASE		 ;AN013; No.
;Set Block from the Old_Area with Impossible_Owner_size.
;This will free the unnecessary SYSINIT_BASE that had been put in memory to
;handle INSTALL= command.
	push	es			       ;AN013;
	push	bx			       ;AN013;
	mov	ax, [cs:Old_Area]	       ;AN013;
	mov	es, ax			       ;AN013;
	mov	bx, [cs:Impossible_Owner_Size] ;AN013;
SETBLOCK equ Setblock	; NASM port equate
	mov	ah, SETBLOCK		       ;AN013;
	int	21h			       ;AN013;
	MOV	AX,ES			       ;AN013;
	DEC	AX			       ;AN013;
	MOV	ES,AX			       ;Point to arena
	MOV	word [ES:arena_owner],8	       ;Set impossible owner
	mov word ptr [es:arena_name], "SD"	; set SD name	; NASM port swapped text literals
	and word ptr [es:arena_name + 2], 0	; NUL
	pop	bx			       ;AN013;
	pop	es			       ;AN013;
Skip_Free_SYSINITBASE:			       ;AN013;
%endif
	%IF	NOEXEC
	MOV	BP,DS			       ;SAVE COMMAND.COM SEGMENT
	PUSH	DS
	POP	ES
	MOV	BX,CS
	SUB	BX,10H			       ; Point to current PHP
	MOV	DS,BX
	XOR	SI,SI
	MOV	DI,SI
	MOV	CX,80H
	REP	MOVSW			       ; Copy it to new location for shell
	MOV	WORD PTR [ES:PDB_JFN_Pointer + 2],ES	; Relocate
	MOV	BX,ES
	MOV	AH,SET_CURRENT_PDB
	INT	21H			       ; Tell DOS we moved it
PDB_PARENT_PID equ PDB_Parent_PID	; NASM port equate
	MOV	[ES:PDB_PARENT_PID],ES	       ;WE ARE THE ROOT
	%ENDIF

	PUSH	CS
	POP	DS
 ASSUME DS:SYSINITGROUP
;
; SET UP THE PARAMETERS FOR COMMAND
;

	MOV	SI,OFFSET COMMAND_LINE+1

	%IF	NOEXEC
	MOV	DI,81H
	%ELSE
	PUSH	DS
	POP	ES
 assume es:SYSINITGROUP
	MOV	DI,SI
	%ENDIF

	MOV	CL,-1
COMTRANLP:				;FIND LENGTH OF COMMAND LINE
	INC	CL
	LODSB
	STOSB				;COPY COMMAND LINE IN
	OR	AL,AL
	JNZ	COMTRANLP
	DEC	DI
	MOV	AL,CR		       ; CR terminate
	STOSB

	%IF	NOEXEC
	MOV	[ES:80H],CL		; Set up header
	MOV	AL,[DEFAULT_DRIVE]
	MOV	[ES:5CH],AL
	%ELSE
	MOV	[COMMAND_LINE],CL	;Count
	%ENDIF

	MOV	DX,OFFSET COMMND	;NOW POINTING TO FILE DESCRIPTION

	%IF	NOEXEC
	MOV	ES,BP			;SET LOAD ADDRESS
	MOV	BX,100H
	CALL	LDFIL			;READ IN COMMAND
	JC	COMERR
	MOV	DS,BP
	MOV	DX,80H
SET_DMA equ Set_DMA	; NASM port equate
	MOV	AH,SET_DMA		;SET DISK TRANFER ADDRESS
	INT	21H
	CLI
	MOV	SS,BP
	MOV	SP,DX
	STI
	XOR	AX,AX			;PUSH A WORD OF ZEROS
	PUSH	AX
	PUSH	BP			;SET HIGH PART OF JUMP ADDRESS
	MOV	AX,100H
	PUSH	AX			;SET LOW PART OF JUMP ADDRESS
CCC	PROC	FAR
	RET				;CRANK UP COMMAND!
CCC	ENDP

	%ELSE
; We are going to open the command interpreter and size it as is done in
; LDFIL.  The reason we must do this is that SYSINIT is in free memory.  If
; there is not enough room for the command interpreter, EXEC will probably
; overlay our stack and code so when it returns with an error SYSINIT won't be
; here to catch it.  This code is not perfect (for instance .EXE command
; interpreters are possible) because it does its sizing based on the
; assumption that the file being loaded is a .COM file.  It is close enough to
; correctness to be usable.

	PUSH	DX			; Save pointer to name

%if 0
; First, find out where the command interpreter is going to go.
	MOV	BX,0FFFFH
	MOV	AH,ALLOC
	INT	21H			;Get biggest piece
	MOV	AH,ALLOC
	INT	21H			;SECOND TIME GETS IT
	JC	MEMERRJX		; Oooops
	MOV	ES,AX
DEALLOC equ Dealloc	; NASM port equate
	MOV	AH,DEALLOC
	INT	21H			; Give it right back
	MOV	BP,BX
; ES:0 points to Block, and BP is the size of the block
;   in para.

; We will now adjust the size in BP DOWN by the size of SYSINIT. We
;   need to do this because EXEC might get upset if some of the EXEC
;   data in SYSINIT is overlayed during the EXEC.
	MOV	BX,[MEMORY_SIZE]
	MOV	AX,CS
	SUB	BX,AX			; BX is size of SYSINIT in Para
	inc bx				; for SYSINIT S MCB
	SUB	BP,BX			; BAIS down
	JC	MEMERRJX		; No Way.

	MOV	AX,(OPEN << 8) 	;OPEN THE FILE being EXECED
	STC				;IN CASE OF INT 24
	INT	21H
	JC	COMERR			; Ooops
	MOV	BX,AX			;Handle in BX
	XOR	CX,CX
	XOR	DX,DX
	MOV	AX,(LSEEK << 8) | 2
	STC				;IN CASE OF INT 24
	INT	21H			; Get file size in DX:AX
	JC	COMERR
    ; Convert size in DX:AX to para in AX
	ADD	AX,15			; Round up size for conversion to para
	ADC	DX,0
	MOV	CL,4
	SHR	AX,CL
	MOV	CL,12
	SHL	DX,CL			; Low nibble of DX to high nibble
	OR	AX,DX			; AX is now # of para for file
	ADD	AX,10H			; 100H byte PHP
	CMP	AX,BP			; Will it fit?
	JB	OKLD			; Jump if yes.
%else
	jmp OKLD
%endif

MEMERRJX:
	JMP	MEM_ERR

OKLD:
%if 0
	MOV	AH,CLOSE
	INT	21H			; Close file
%endif
OPEN equ Open	; NASM port equate
LSEEK equ LSeek	; NASM port equate
CLOSE equ Close	; NASM port equate


INITSTACKSIZE equ fromparas(paras(160))
	mov ax, INITSTACKSIZE
	mov si, alloc_initstack
	call allocate_relocate_block
	add di, INITSTACKSIZE
	POP	DX			; Recover pointer to name

	mov ax, es			; use this as a stack if exec returns
	cli
	mov ss, ax
	mov sp, di			; -> stack
 assume ss:nothing
	sti

loop_shell:
 extern backdoor_free_mcb_exec, backdoor_indicator
 extern shell_return_has_been_freed, shell_return_address
	mov bx, initpspmcb
	mov byte [cs:bx + mcbSignature], 'Z'
					; pretend we are a valid process MCB
	mov cl, 4
	shr bx, cl			; segment displacement
	inc bx				; pretend PSP
	call sysinit_getdosdata
	mov es, ax
 assume es:DOSGROUP
	mov ax, cs
	add ax, bx			; => our pseudo INIT PSP
	mov word [es:backdoor_free_mcb_exec], ax
					; enter owner for the backdoor free
	mov word [es:shell_return_address + 2], cs
	mov word [es:shell_return_address], sysinit_shellreturned
					; ! must be set before next variable
	mov bx, shell_return_has_been_freed
	mov byte [es:bx], 0		; indicate sysinit still allocated
	mov word [es:backdoor_indicator + 2], es
	mov word [es:backdoor_indicator], bx
	mov bx, cs
	dec bx
	mov es, bx
 assume es:MCB
	mov word [es:mcbOwner], ax	; owned by backdoor owner

	 push cs
	 pop ds
 assume ds:SYSINITGROUP
	mov si, COMMAND_LINE + 1
	 push cs
	 pop es
 assume es:SYSINITGROUP
	mov di, Ldexec_FCB1
	call parse_dssi_cmdline_to_esdi_fcbs
		;AN000;  Make a null environment segment
		;AN000;   by overlap JMP instruction of SYSINITSEG.
	and	word [0], 0
	mov	bx, offset COMEXE		;AN000;  ES:BX -> parm block.
EXEC0_COM_LINE equ Exec0_com_line	; NASM port equate
EXEC0_5C_FCB equ Exec0_5C_FCB	; NASM port equate
EXEC0_6C_FCB equ Exec0_6C_FCB	; NASM port equate
	mov	[bx + EXEC0_ENVIRON], ds	;AN000; Set the environment seg.
	mov	word [bx + EXEC0_COM_LINE+2], ds;AN000; Set the seg.
	mov	word [bx + EXEC0_5C_FCB+2], ds	;AN000;
	mov	word [bx + EXEC0_6C_FCB+2], ds	;AN000;
EXEC equ Exec	; NASM port equate
	mov ax, EXEC << 8		; Load and go
	rol byte [shellhighflag], 1
	rcr al, 1			; al = 80h if shellhigh=
	STC				;IN CASE OF INT 24
	jmp DOSENTRY - DOSENTRYADJUSTSEGMENT \
	 : run_int21_shell + DOSENTRYADJUSTOFFSET
 extern run_int21_shell			;GO START UP COMMAND
	%ENDIF
; NOTE FALL THROUGH IF EXEC RETURNS (an error)

COMERR:
	MOV	DX,OFFSET BADCOM	;WANT TO PRINT COMMAND ERROR
	INVOKE	BADFIL
STALL:
	int3
	sti
	hlt
	JMP	STALL


sysinit_shellreturned:

	push cs
	pop ds
 assume ds:SYSINITGROUP
	push cs
	pop es
 assume es:SYSINITGROUP

	mov dx, msg.prompt
	mov cx, msg.prompt.length
	mov bx, 1
	mov ah, 40h
	int 21h

 extern linein
	mov si, COMMND
	mov di, linein + 2
	db __TEST_IMM8			; (skip stosb)
@@:
	stosb
	lodsb
	test al, al
	jnz @B

	xor ax, ax
	mov si, word [COMEXE + EXEC0_COM_LINE]
	lodsb				; = length of tail
	xchg cx, ax
	cmp byte [si], 13
	je @F
	cmp byte [si], 9
	je @F
	cmp byte [si], 32
	je @F
	mov al, 32
	stosb
@@:
	inc cx				; include the terminator CR
	rep movsb

	xchg ax, di
	sub ax, linein + 3
	mov byte [linein + 1], al

.prompt:
	mov dx, linein
	int3
	mov ah, 0Ah
	int 21h				; read input line
	mov ah, 02h
	mov dl, 13
	int 21h
	mov ah, 02h
	mov dl, 10
	int 21h

	mov si, linein + 2
@@:
	lodsb
	cmp al, 32
	je @B
	cmp al, 9
	je @B

	MOV	DI,OFFSET COMMND
	db __TEST_IMM16			; skip stosb, lodsb
STORESHELL:
	stosb
	lodsb
@@:
	cmp al, 32
	ja STORESHELL

GETSHPARMS:
	MOV	BYTE PTR [DI],0
	MOV	DI,OFFSET COMMAND_LINE+1
	db __TEST_IMM8			; skip lodsb
PARMLOOP:
	lodsb
	stosb
	cmp al, 13
	jne PARMLOOP

	xchg ax, di
	sub ax, COMMAND_LINE + 2
	mov byte [COMMAND_LINE], al

	mov dx, COMMND
	jmp loop_shell


 extern get_config_size
relocate_config:
 assume ds:nothing, es:nothing, ss:SYSINITGROUP
	mov ax, 5800h
	int 21h
	push ax
	mov ax, 5801h
	mov bx, 0320h			; ignore UMB link, one area,
	int 21h				;  LMA then UMA, first fit
	call get_config_size
	mov ah, 48h
	int 21h
	jc .fail
	mov es, ax
 assume es:nothing
	xor di, di
	mov ds, word [cs:config_block]
 assume ds:nothing
	xor si, si
	 push es
	push cx
	rep movsb
	 push ds
	 pop es
 assume es:nothing
	mov ah, 49h
	int 21h
	pop ax
	push ax
	mov si, alloc_initconfig
	call allocate_temporary_block
 assume es:nothing
	pop cx
	 pop ds
 assume ds:nothing
	xor si, si
	rep movsb
	mov word [cs:config_block], es
	push ds
	pop es
 assume es:nothing
	mov ah, 49h
	int 21h
.fail:
	pop bx
	mov ax, 5801h
	int 21h
	retn


relocate_dibx_dpb_from_dxbp_to_essi:
 assume ds:nothing, es:nothing, ss:SYSINITGROUP
	cmp word [di + bx], bp
	jne .ret
	cmp word [di + bx + 2], dx
	jne .ret			; match ?
	cli
	mov word [di + bx], si
	mov word [di + bx + 2], es
	sti				; yes, relocate
.ret:
	retn


reloc_dpb_in_sftc:
 assume ds:nothing, es:nothing, ss:SYSINITGROUP
.loop_sftc:
	cmp di, -1
	je .done
	push di
	mov cx, [di + SFCount]
	jcxz .next_sftc
	add di, SFTable
.loop_entry:
	cmp word [di + sf_ref_count], 0
	je @F
	testopt [di + sf_flags], sf_isnet | devid_device
					; net or device ?
	jnz @F				; yes, don't check -->
	mov bx, sf_devptr
	call relocate_dibx_dpb_from_dxbp_to_essi
@@:
	add di, sf_entry_struc_size
	loop .loop_entry
.next_sftc:
	pop di
	lds di, [di + SFLink]
	jmp .loop_sftc

.done:
	retn


		; ! called far from DOSENTRY init code.
		; Runs in unrelocated SYSINIT.
		; Must return far.
		;
		; INP:	ds:si -> text
		; OUT:	NC if found,
		;	 ds:si -> at terminator
		;	 dx = bit mask selected
		;	CY if not found,
		;	 ds:si -> past commas and blanks and equal signs
		; STT:	called far
		;	cs = ds = es => SYSINIT
		; CHG:	dx, bx, ax
 global sysinit_cmdline_scanmode_keyword
 extern isstring?, skipcomma, skipcomm0, skipwhite, skipwh0
sysinit_cmdline_scanmode_keyword:
@@:
	call skipcomma
	cmp al, '='
	je @B
	dec si
	mov bx, modetable
.mode_loop:
	mov dx, [bx]
	call isstring?
	jne @F
	mov dx, [bx + 2]
	clc
	retf

@@:
	add bx, 4
	cmp bx, strict word modetable.end
	jb .mode_loop
	stc
	retf


free_temp_cds:
 assume ds:nothing, es:nothing, ss:SYSINITGROUP
	xor ax, ax
	xchg ax, word [cs:tempcds_block]
	test ax, ax
	jz @F
	 push es
	mov es, ax
 assume es:nothing
	mov ah, 49h
	int 21h
	 pop es
 assume es:nothing
@@:
	retn


	PUBLIC	TEMPCDS_after_block_device
  global cds_last_used, cds_first_unused
  global alloc_initcds, free_temp_cds, tempcds_block
  global FOOSTRNG, FOOSET
	extern devicefirstnewdpb, devicefirstnewdrive, deviceamountnew
	extern reinitcds_option
	extern cds_amount_wanted
TEMPCDS_after_block_device:
 assume ds:SYSINITGROUP, es:nothing, ss:SYSINITGROUP
	rol byte [reinitcds_option], 1
	jc TEMPCDS

	LES	DI,[DOSINFO]
 assume es:DOSGROUP
	mov bl, [es:di + SYSI_NCDS]
	mov al, curdir_list_struc_size
	mul bl
	push bx				; stack = how many entries in old CDS
	push ax				; stack = how much to preserve in bytes

	xor cx, cx
	mov cl, byte [cs:cds_amount_wanted]	; cx = how many drives needed
	cmp byte [es:di + SYSI_NCDS], cl	; have more CDS entries ?
	jb @F					; no -->
	mov cl, byte [es:di + SYSI_NCDS]	; yes, keep as many
@@:
	mov byte [es:di + SYSI_NCDS], cl	; update amount CDS entries
	mov al, curdir_list_struc_size
	mul cl				; ax = how much to allocate in bytes

	push cx
	push es
	push di
	mov si, alloc_initcds
	call allocate_temporary_block
 assume es:nothing
	pop si
	pop ds				; -> DOSINFO
 assume ds:DOSGROUP
	pop bx				; bl = how many entries in new CDS
	pop cx				; = how much to preserve in bytes

	push ds
	push si
	lds si, [si + SYSI_CDS]		; -> old CDS
 assume ds:CDS
	mov dx, di			; es:dx -> new CDS
	rep movsb			; preserve old
	pop si
	pop ds
 assume ds:DOSGROUP
	call free_temp_cds		; free old
	mov word [cs:tempcds_block], es	; => temp CDS
	pop ax				; al = how many entries in old CDS
	sub bl, al			; = additional amount
	add al, "A"			; prior amount + "A"
	mov byte [ss:FOOSTRNG], al	; first letter of additional table

	MOV	WORD PTR [si + SYSI_CDS + 2], es
	mov	WORD PTR [si + SYSI_CDS], dx
					; -> new temp CDS
	xor cx, cx
	mov cl, bl			; cx = additional amount of CDS entries
	mov si, -1			; no DPBs for additional table
	not byte [ss:verbose_hide_cds]
	call FOOSET			; init additional table

	lds si, [cs:devicefirstnewdpb]	; ds:si -> first new DPB
 ASSUME DS:DPB
	mov bl, [cs:devicefirstnewdrive]
	mov al, curdir_list_struc_size
	mul bl
	xchg di, ax			; es:di -> CDS entry for first new drive
	xor cx, cx
	mov cl, byte [cs:deviceamountnew]
					; cx = how many drives
	add bl, "A"			; letter of first new drive
	mov byte [ss:FOOSTRNG], bl	; first letter of additional table
	jmp FOOSET


	PUBLIC	TEMPCDS
TEMPCDS:
 assume ds:SYSINITGROUP, es:nothing, ss:SYSINITGROUP
	call free_temp_cds

	LES	DI,[DOSINFO]
 assume es:DOSGROUP

	MOV	CL,BYTE PTR [ES:DI + SYSI_NUMIO]
	XOR	CH,CH
	MOV	[ES:DI + SYSI_NCDS],CL
	mov al, curdir_list_struc_size
	mul cl

	push cx
	push es
	push di
	mov si, alloc_initcds
	call allocate_temporary_block
 assume es:nothing
	mov word [cs:tempcds_block], es	; => temp CDS
	pop si
	pop ds				; -> DOSINFO
 assume ds:DOSGROUP
	pop cx

	MOV	WORD PTR [si + SYSI_CDS + 2], es
	mov	WORD PTR [si + SYSI_CDS], di
					; -> temp CDS
	LDS	SI,[si + SYSI_DPB]	; -> first DPB
 ASSUME DS:DPB

FOOSET:					; Init CDSs
	push ds
	push si
	lds si, [ss:DOSINFO]
 assume ds:DOSGROUP
	mov al, curdirLen
	mul byte [si + SYSI_NCDS]
	mov dx, [si + SYSI_CDS]
	add dx, ax
	jcxz fooret_pops		; (additional table may be empty)

fooset_loop:
	cmp di, dx
	jae foo_error

	pop si
	pop ds
 assume ds:nothing
	push ds
	push si

	MOV	AX,WORD PTR [ss:FOOSTRNG]
	INC	BYTE PTR [ss:FOOSTRNG]
	testopt [es:di + curdir_flags], curdir_isnet | curdir_inuse
	jnz fooset_next
	STOSW
	sub al, 'A'
	xchg bx, ax			; bl = drive to match
	MOV	AX, "\"			; constant
	STOSW
	XOR	AX,AX
	PUSH	CX
	MOV	CX,curdir_flags - 4
	REP	STOSB
	CMP	SI,-1
;	 JNZ	 NORMCDS
;J.K. 6/24/87 Should handle the system that does not have any floppies.
;J.K. In this case, we are going to pretended there are two dummy floppies
;J.K. in the system. Still they have DPB and CDS, but we are going to
;J.K. 0 out Curdir_Flags, Curdir_devptr of CDS so IBMDOS can issue
;J.K. "Invalid drive specification" message when the user try to
;J.K. access them.
	je	Fooset_Zero		;AN001;Don't have any physical drive.
;SB34SYSINIT1003*************************************************************
;SB	Check to see if we are faking floppy drives.  If not go to NORMCDS.
;SB	If we are faking floppy drives then see if this CDS being initialised
;SB	is for drive a: or b: by checking the appropriate field in the DPB
;SB	pointed to by ds:si.  If not for a: or b: then go to NORMCDS.  If
;Sb	for a: or b: then execute the code given below starting at Fooset_Zero.
;SB	For dpb offsets look at inc\dpb.inc.
;SB	 5 LOCS

	cmp	byte [cs:Fake_Floppy_Drv],1	;fake drive ?
	jnz	NORMCDS
	cmp bl, 2
	jae	NORMCDS

;SB34SYSINIT1003*************************************************************
Fooset_Zero:				;AN001;
		; ax still zero
	MOV	CL,3
	REP	STOSW
	POP	CX
	JMP	SHORT FINCDS
NORMCDS:
.loop:
	cmp byte [si + dpb_drive], bl
	je .got
	LDS	SI,[SI + dpb_next_dpb]
 assume ds:nothing
	cmp si, -1
	jne .loop
	jmp Fooset_Zero

.got:
	POP	CX
;J.K. If a non-fat based media is detected (by DPB.NumberOfFat == 0), then
; set curdir_flags to 0.  This is for signaling IBMDOS and IFSfunc that
; this media is a non-fat based one.
	cmp	byte [SI + dpb_FAT_count], 0	;AN000; Non fat system?
	je	SetNormCDS		;AN000; Yes. Set curdir_Flags to 0. AX = 0 now.
CURDIR_INUSE equ curdir_inuse	; NASM port equate
	MOV	ah, CURDIR_INUSE >> 8	;AN000;  else, FAT system. set the flag to CURDIR_INUSE.
SetNormCDS:				;AN000;
	STOSW				; curdir_flags
	MOV	AX,SI
	STOSW				; curdir_devptr
	MOV	AX,DS
	STOSW
FINCDS:
	MOV	AX,-1
	STOSW				; curdir_ID
	STOSW				; curdir_ID
	STOSW				; curdir_user_word
	mov	ax,2
	stosw				; curdir_end
	xor ax, ax			;AN000;Clear out 7 bytes (curdir_type,
	stosw				;AN000;  curdir_ifs_hdr, curdir_fsda)
	stosw				;AN000;
	stosw				;AN000;
	stosb				;AN000;
	jmp @F
fooset_next:
	inc cx
	add di, curdirLen
@@:
	LOOP fooset_loop
fooret_pops:
	pop ax
	pop ax
fooret:
	MOV	BYTE PTR [ss:FOOSTRNG],"A"

	rol byte [ss:verbose_hide_cds], 1
	jnc @F
	not byte [ss:verbose_hide_cds]
.ret:
	retn
@@:

	testopt [ss:verbose_mode], verbose_cds
	jz .ret
	push es
	LES	DI,[ss:DOSINFO]
 assume es:DOSGROUP
	xor ax, ax
	mov al, [es:di + SYSI_NCDS]
	mov dx, msg.cds.1
	call init2_disp_msg_asciz_cs_dx
	call init2_disp_ax_dec
	mov dx, msg.cds.2.singular
	cmp al, 1
	je @F
	mov dx, msg.cds.2.plural
@@:
	call init2_disp_msg_asciz_cs_dx
	add al, 'A' - 1
	call init2_disp_al
	mov dx, msg.cds.3
	call init2_disp_msg_asciz_cs_dx
	call cds_last_used
 assume es:DOSGROUP, ds:CDS
	xchg bh, bl			; bl = last used
	call init2_disp_ax_dec
	mov dx, msg.cds.4
	call init2_disp_msg_asciz_cs_dx
	lea ax, [bx + 'A']
	call init2_disp_al
	mov dx, msg.cds.5
	call init2_disp_msg_asciz_cs_dx
	pop es
 assume es:CDS
	return


foo_error:
	mov dx, msg.cds.error
	call init2_disp_msg_asciz_cs_dx
	jmp fooret_pops


		; INP:	-
		; OUT:	bh = 0-based index of last used CDS, or 0
		;	ax = number of used CDS entries
		;	es:di -> DOSINFO
		; CHG:	es, di, ds, si, bl, cx
		; STT:	ss => SYSINITGROUP
cds_last_used:
 assume ds:nothing, es:nothing, ss:SYSINITGROUP
	LES	DI,[ss:DOSINFO]
 assume es:DOSGROUP
	xor cx, cx
	mov cl, [es:di + SYSI_NCDS]
	lds si, [es:di + SYSI_CDS]
 assume ds:CDS
	xor bx, bx
	xor ax, ax
	jcxz .done
.loop:
	testopt [si + curdir_flags], curdir_isnet + curdir_inuse
	jz .skip
	inc ax
	mov bh, bl
.skip:
	inc bx
	add si, curdirLen
	loop .loop
.done:
	retn


		; INP:	al = 0-based index to start check
		; OUT:	NC if valid,
		;	 bh = 0-based index of first unused >= INP:al
		;	 ds:si -> found unused entry
		;	CY if not valid,
		;	 bh = max(INP:al, 0-based index after last CDS entry)
		; CHG:	ds, si, bl
		; STT:	ss => SYSINITGROUP
cds_first_unused:
 assume ds:nothing, es:nothing, ss:SYSINITGROUP
	push es
	push di
	push ax
	push cx
	LES	DI,[ss:DOSINFO]
 assume es:DOSGROUP
	xor cx, cx
	mov cl, [es:di + SYSI_NCDS]
				; cx = how many total
	lds si, [es:di + SYSI_CDS]
 assume ds:CDS
	mov bh, al		; bh = requested
	sub cl, al		; cl = how many to check
	jbe .done_CY
	mov ah, curdirLen
	mul ah			; ax = offset of first to check
	add si, ax		; ds:si -> first to check
.loop:
	testopt [si + curdir_flags], curdir_isnet + curdir_inuse
	jz .found		; (NC)
	inc bh
	add si, curdirLen
	loop .loop
.done_CY:
	stc
.found:
	pop cx
	pop ax
	pop di
	pop es
	retn


;------------------------------------------------------------------------------
; Allocate FILEs
;------------------------------------------------------------------------------
ENDFILE:
 assume ds:nothing, es:nothing, ss:SYSINITGROUP
; WE ARE NOW SETTING UP FINAL CDSs, BUFFERS, FILES, FCSs STRINGs etc.  We no
; longer need the space taken by The TEMP stuff below CONFBOT, so set ALLOCLIM
; to CONFBOT.

;J.K.  2/23/87 If this procedure has been called to take care of INSTALL= command,
;then we have to save ES,SI registers.

;	 test	 [Install_Flag],IS_INSTALL ;AN000; Called to handle INSTALL=?
;	 jz	 ENDFILE_Cont		 ;AN000;
;	 push	 es			 ;AN000; Save es,si for CONFIG.SYS
;	 push	 si			 ;AN000;
;	 test	 [Install_Flag],HAS_INSTALLED ;AN000; Sysinit_base already installed?
;	 jz	 ENDFILE_Cont		 ;AN000; No. Install it.
;	 jmp	 DO_Install_EXEC	 ;AN000; Just handle "INSTALL=" cmd only.
;ENDFILE_Cont:				 ;AN000;

	push	ds			    ;AN002;
	call sysinit_get_ds_dosbiodata
 assume ds:DOSGROUP
	cmp	word [MulTrk_flag], MULTRK_OFF1    ;AN002;=0, MULTRACK= command entered?
	jne	MulTrk_Flag_Done	    ;AN002;
	or	word [MulTrk_flag], MULTRK_ON	    ;AN002; Default will be ON.
MulTrk_Flag_Done:			    ;AN002;
	pop	ds			    ;AN002;
 assume ds:nothing

do_sft:
	xor ax, ax
	MOV	AL,[ss:FILES]
	SUB	AL,5
	JBE	DOFCBS
	push ax
SF_ENTRY_struc_size equ sf_entry_struc_size	; NASM port equate
	MOV	BL,SF_ENTRY_struc_size
	MUL	BL			;AX = NUMBER OF BYTES TO CLEAR
	add ax, 6
	mov si, alloc_sft
	call allocate_relocate_block
 assume es:nothing

	LDS si, [ss:DOSINFO]
 assume ds:DOSGROUP
	LDS si, [si + SYSI_SFT]
 assume ds:nothing
SFLINK equ SFLink	; NASM port equate
	MOV	WORD PTR [si + SFLINK], di
	MOV	WORD PTR [si + SFLINK+2], es	; SET POINTER TO NEW SFT
	or	WORD PTR [ES:DI + SFLINK], -1
SFCOUNT equ SFCount	; NASM port equate
	pop	word [ES:DI + SFCOUNT]

;------------------------------------------------------------------------------
; Allocate FCBs
;------------------------------------------------------------------------------
DOFCBS:
	xor ax, ax
	MOV	AL,[ss:FCBS]
	push ax
	MOV	BL,SF_ENTRY_struc_size
	MUL	BL			;AX = NUMBER OF BYTES TO CLEAR
	add ax, 6
	mov si, alloc_fcb
	call allocate_relocate_block
 assume es:nothing

	LDS si, [ss:DOSINFO]
 assume ds:DOSGROUP

	push es
	mov ah, 49h
	mov es, [si + SYSI_FCB + 2]
	int 21h
	pop es

	MOV	WORD PTR [si + SYSI_FCB], di
	MOV	WORD PTR [si + SYSI_FCB+2], es	; SET POINTER TO NEW Table
	xor bx, bx
	MOV	BL,[CS:Keep]
SYSI_keep equ SYSI_Keep	; NASM port equate
	MOV	[si + SYSI_keep],BX
	PUSH	CS
	POP	DS
 ASSUME DS:SYSINITGROUP
	or	WORD PTR [ES:DI + SFLINK], -1
	pop cx
	mov word [ES:DI + SFCOUNT], cx

sf_struc_size equ SF_struc_size		; NASM port equate
	add di, sf_struc_size-2		; es:di -> SFT entries

	MOV	AL,"A"
FillLoop:
	PUSH	CX			; save count
	MOV	CX,sf_entry_struc_size	; number of bytes to fill
	cld
	REP	STOSB			; filled
	MOV	WORD PTR [ES:DI-(sf_entry_struc_size)+sf_ref_count], cx
	MOV	WORD PTR [ES:DI-(sf_entry_struc_size)+sf_position], cx
	MOV	WORD PTR [ES:DI-(sf_entry_struc_size)+sf_position+2], cx
	POP	CX
	LOOP	FillLoop

;------------------------------------------------------------------------------
; Allocate Buffers
;------------------------------------------------------------------------------

; Search through the list of media supported and allocate 3 buffers if the
; capacity of the drive is > 360KB
 assume ds:SYSINITGROUP, es:nothing, ss:SYSINITGROUP

	CMP	word [BUFFERS], -1			; Has buffers been already set?
	je	DoDefaultBuff
%ifndef BUF2
	cmp	byte [Buffer_Slash_X], 1		;AN000;
	jne	DO_Buffer			;AN000;
	call	DoEMS				;AN000; Carry set if (enough) EMS is not available
	jc	DoDefaultBuff			;AN000;  Error. Just use default buffer.
%endif
DO_Buffer:
	jmp	DOBUFF				; the user entered the buffers=.

DoDefaultBuff:
	mov	word [H_Buffers], 0			;AN000; Default is no heuristic buffers.
	MOV	word [BUFFERS], 2			; Default to 2 buffers
	PUSH	AX
	PUSH	DS
	LES	BP,[CS:DOSINFO] 		; Search through the DPB's
 assume es:DOSGROUP
	LES	BP,[ES:BP + SYSI_DPB]	; Get first DPB
 assume es:DPB

	PUSH	CS
	POP	DS
 assume ds:SYSINITGROUP

NEXTDPB:
	; Test if the drive supports removeable media
DPB_DRIVE equ dpb_drive	; NASM port equate
	MOV	BL, BYTE PTR [ES:BP + DPB_DRIVE]
	INC	BL
IOCTL equ IOCtl	; NASM port equate
	MOV	AX, (IOCTL << 8) | 8
	INT	21H

; Ignore fixed disks
	OR	AX, AX			; AX is nonzero if disk is nonremoveable
	JNZ	NOSETBUF

; Get parameters of drive
	XOR	BX, BX
	MOV	BL, BYTE PTR [ES:BP + DPB_DRIVE]
	INC	BL
	MOV	DX, OFFSET DeviceParameters
	MOV	AX, (IOCTL << 8) | GENERIC_IOCTL
	MOV	CX, (RAWIO << 8) | GET_DEVICE_PARAMETERS
	INT	21H
	JC	NOSETBUF		; Get next DPB if driver doesn't support
					; Generic IOCTL

; Determine capacity of drive
; Media Capacity = #Sectors * Bytes/Sector
BPB_TotalSectors equ BPB_TOTALSECTORS	; NASM port equate
	MOV	BX, WORD PTR [DeviceParameters + DP_BPB + BPB_TotalSectors]

; To keep the magnitude of the media capacity within a word,
; scale the sector size
; (ie. 1 -> 512 bytes, 2 -> 1024 bytes, ...)
BPB_BytesPerSector equ BPB_BYTESPERSECTOR	; NASM port equate
	MOV	AX, WORD PTR [DeviceParameters + DP_BPB + BPB_BytesPerSector]
	XOR	DX, DX
	MOV	CX, 512
	DIV	CX				; Scale sector size in factor of
						; 512 bytes

	MUL	BX				; AX = #sectors * size factor
	OR	DX, DX				; Just in case of LARGE floppies
	JNZ	.SETBUF
	CMP	AX, 720 			; 720 Sectors * size factor of 1
	JBE	NOSETBUF
.SETBUF:
	MOV	word [BUFFERS], 3
	jmp	Chk_Memsize_for_Buffers 	; Now check the memory size for default buffer count
	nop	; identicalise
;	 JMP	 BUFSET 			 ; Jump out of search loop
NOSETBUF:
DPB_NEXT_DPB equ dpb_next_dpb	; NASM port equate
	CMP	WORD PTR [ES:BP + DPB_NEXT_DPB],-1
	jz	Chk_Memsize_for_Buffers
;	 JZ	 BUFSET
	LES	BP,[ES:BP + DPB_NEXT_DPB]
 assume es:DPB
	JMP	NEXTDPB

;J.K. 10/15/86 DCR00014.
;From DOS 3.3, the default number of buffers will be changed according to the
;memory size too.
; Default buffers = 2
; If diskette Media > 360 kb, then default buffers = 3
; If memory size > 128 kb (2000H para), then default buffers = 5
; If memory size > 256 kb (4000H para), then default buffers = 10
; If memory size > 512 kb (8000H para), then default buffers = 15.

Chk_Memsize_for_Buffers:
 assume ds:SYSINITGROUP, es:nothing, ss:SYSINITGROUP
memory_size equ MEMORY_SIZE	; NASM port label
	cmp	word [memory_size], 2000h
BufSet equ BUFSET	; NASM port label
	jbe	BufSet
buffers equ BUFFERS	; NASM port label
	mov	word [buffers], 5
	cmp	word [memory_size], 4000h
	jbe	BufSet
	mov	word [buffers], 10
	cmp	word [memory_size], 8000h
	jbe	BufSet
	mov	word [buffers], 15

BUFSET:
	POP	DS
ASSUME	DS:NOTHING
	POP	AX

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;J.K. Here we should put extended stuff and new allocation scheme!!!
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;*******************************************************************************
;									       *
; Function: Actually allocate BUFFERS into the (extended) memory and initialize*
;	    it. 							       *
;	    If it is installed in real memory, the number of buffers in each   *
;	    bucket will be balanced out as far as possible for perfermance.    *
;	    Also, if the user specified the secondary buffer cache, it will    *
;	    be installed in the real memory.				       *
;									       *
; Input :								       *
;    BuffINFO.EMS_MODE - 0=IBM mode, -1 = do not use extended memory.	       *
;    BuffINFO.Frame_Page  -  Page frame 0 segment address		       *
;    MEMHI:MEMLO - Start of the next available memory			       *
;    Buffer_Pages = Number of extended memory pages for buffer		       *
;    BUFFERS = Number of buffers					       *
;    H_Buffers = Number of secondary buffers				       *
;									       *
; Output:								       *
;	BuffINFO.Cache_Count - # of caches to be installed.		       *
;	Hash table set. 						       *
;	BuffINFO set.							       *
;	BufferBuckets set.						       *
;	MaxNumBuf1, MaxNumBuf2, and NthBuck set.			       *
;									       *
; Subroutines to be called:						       *
;									       *
; Logic:								       *
; {									       *
;	IF (BuffINFO.EMS_MODE == -1) THEN				       *
;	      { 							       *
;		IF BUFFERS < 30 THEN					       *
;		     {# of Bucket = 1; MaxNumBuf1 = BUFFERS; NthBuck = 1}      *
;		ELSE {							       *
;		      # of Bucket = BUFFERS/15; 			       *
;		      r = BUFFERS mod 15;				       *
;		      IF r == 0 THEN NthBuck = # of Bucket		       *
;		      ELSE						       *
;			{						       *
;			  AddBuff = r / # of Bucket;			       *
;			  NthBuck = r mod # of Bucket;			       *
;			  MaxNumBuf1 = 15 + AddBuff; /* 1st Bucket - Nth Bucket*
;			  MaxNumBuf2 = 15 + AddBuff +1;/*(N+1)th Bucket to last*
;			}						       *
;		     }							       *
;	      } 							       *
;	ELSE								       *
;	      { 							       *
;		# of Bucket = Buffer_Pages * 2; 	 /* 2 buckets per page *
;	      };							       *
;									       *
;	/*Now allocate memory for Hash table */ 			       *
;	Hash Table Size = (size Buffer_Hash_Entry) * # of Bucket;	       *
;	Set BuffINFO.Hash_ptr to MEMHI:MEMLO;				       *
;	Adjust MEMHI:MEMLO according to Hash table size;		       *
;									       *
;	/*Set buffers*/ 						       *
;	IF (EMS_MODE   <> -1) THEN					       *
;	    Set_EMS_Buffer						       *
;	ELSE			/*Do not use the extended memory */	       *
;	    Set_Buffer; 						       *
;/*Now set the caches if specified.*/					       *
;	IF (BuffINFO.Cache_count > 0)  THEN				       *
;	   {Set BuffINFO.Cache_ptr to MEMHI:MEMLO;			       *
;	    MEMHI:MEMLO = MEMHI:MEMLO + 512 * BuffINFO.Cache_count;	       *
;	   };								       *
; };									       *
;									       *
;*******************************************************************************
DOBUFF: 					;AN000;
%ifndef BUF2
DosInfo equ DOSINFO	; NASM port label
	lds	bx, [cs:DosInfo]		;AN000; ds:bx -> SYSINITVAR

Buffers equ BUFFERS	; NASM port label
	mov	ax, [ss:Buffers]				;AN000;Set SYSI_BUFFERS
	mov	word ptr [bx + SYSI_BUFFERS], ax	;AN000;
	mov	ax, [ss:H_Buffers] 			;AN000;
	mov	word ptr [bx + SYSI_BUFFERS+2], ax	;AN000;

	lds	bx, [bx + SYSI_BUF]		;AN000; now, ds:bx -> BuffInfo
EMS_MODE equ EMS_mode	; NASM port equate
	cmp	byte [bx + EMS_MODE], -1		;AN000;
;	$IF	E, LONG 			;AN000;
	JE DD_XL1
	JMP DD_IF1
	nop	; identicalise
DD_XL1:
	    xor    dx, dx			;AN000;
	    mov    ax, [ss:Buffers]		;AN000; < 99
	    cmp al, 30				;AN026; if less than 30,
;	    $IF  B				;AN026;
	    JNB DD_IF2
		mov word [ss:BufferBuckets], 1		;AN026;  then put every buffer
HASH_COUNT equ Hash_count	; NASM port equate
		mov word [bx + HASH_COUNT], 1	;AN026;    into one bucket
		mov [ss:MaxNumBuf1], al		;AN026;
		mov byte [ss:NthBuck], 1		;AN026;
;	    $ELSE				;AN026; else...
	    JMP SHORT DD_EN2
DD_IF2:
		mov cl, 15			;AN026; Magic number 15.
		div cl				;AN026; al=# of buckets, ah=remainders
		push ax 			;AN026; save the result
		xor  ah, ah			;AN026;
		mov  [ss:BufferBuckets], ax	;AN026;
		mov  [bx + HASH_COUNT], ax	;AN026;
		pop  ax 			;AN026;
		or   ah, ah			;AN026;
;		$IF  Z				;AN026;if no remainders
		JNZ DD_IF4
		   mov [ss:NthBuck], al		;AN026;then set NthBuck=# of bucket for Set_Buffer proc.
;		$ELSE				;AN026;else
		JMP SHORT DD_EN4
DD_IF4:
		   mov cl, al			;AN026;
		   mov al, ah			;AN026;remainder/# of buckets
		   xor ah, ah			;AN026; =
		   div cl			;AN026;al=additional num of buffers
		   or  ah, ah			;AN026;ah=Nth bucket
;		   $IF	Z			;AN026;
		   JNZ DD_IF6
		      add [ss:MaxNumBuf1], al	;AN026;
		      mov ax, [ss:BufferBuckets]	;AN026;
		      mov [ss:NthBuck], al 	;AN026;
;		   $ELSE			;AN026;
		   JMP SHORT DD_EN6
DD_IF6:
		      mov [ss:NthBuck], ah 	;AN026;
		      add [ss:MaxNumBuf1], al	;AN026;MaxNumNuf are initially set to 15.
		      add [ss:MaxNumBuf2], al	;AN026;
		      inc byte [ss:MaxNumBuf1]		;AN026;Additional 1 more buffer for group 1 buckets.
;		   $ENDIF			;AN026;
DD_EN6:
;		$ENDIF				;AN026;
DD_EN4:
;	    $ENDIF				;AN026;
DD_EN2:
;	$ELSE					;AN000; Use the extended memory.
	JMP SHORT DD_EN1
DD_IF1:
	    mov   ax, [ss:Buffer_Pages]		;AN000;
MAXBUCKETINPAGE equ MaxBucketinPage	; NASM port equate
	    mov   cx, MAXBUCKETINPAGE		;AN000;
	    mul   cx				;AN000; gauranteed to be word boundary.
	    mov   [ss:BufferBuckets], ax		;AN000;
	    mov   [bx + HASH_COUNT], ax	;AN000;
;	$ENDIF					;AN000;
DD_EN1:
	invoke Round				;AN000; get [MEMHI]:[MEMLO]
	mov	al, DEVMARK_BUF 		;AN005; ='B'
	call	SetDevMark			;AN005;
;Now, allocate Hash table at [memhi]:[memlo]. AX = Hash_Count.
	mov	ax, [ss:BufferBuckets]		;AN026; # of buckets==Hash_Count
	mov	cx, BUFFER_HASH_ENTRY_struc_size	;AN000;
	mul	cx				;AN000; now AX = Size of hash table.
	les	di, [bx + HASH_PTR]		;AN000; save Single buffer address.
MemLo equ MEMLO	; NASM port label
	mov	cx, [ss:MemLo]			      ;AN000;
	mov	word ptr [bx + HASH_PTR], cx	      ;AN000; set BuffINFO.HASH_PTR
MemHi equ MEMHI	; NASM port label
	mov	cx, [ss:MemHi]			      ;AN000;
	mov	word ptr [bx + HASH_PTR+2], cx       ;AN000;
Memlo equ MEMLO	; NASM port label
	mov	[ss:Memlo], ax			      ;AN000;
	or	byte [ss:SetDevMarkFlag], FOR_DEVMARK	;AN005;
	call	Round				;AN000; get new [memhi]:[memlo]
;Allocate buffers
	push	ds				;AN000; Save Buffer info. ptr.
	push	bx				;AN000;
	cmp	byte [bx + EMS_MODE], -1		;AN000;
;	$IF	NE				;AN000;
	JE DD_IF13
	    call   Set_EMS_Buffer		;AN000;
;	$ELSE					;AN000;
	JMP SHORT DD_EN13
DD_IF13:
	    call   Set_Buffer			;AN000;
;	$ENDIF					;AN000;
DD_EN13:
	pop	bx				;AN000;
	pop	ds				;AN000;
;Now set the secondary buffer if specified.
	cmp	word [ss:H_Buffers], 0			;AN000;
;	$IF	NE				;AN000;
	JE DD_IF16
	    call   Round			;AN000;
	    mov    cx, [ss:MemLo]			;AN000;
CACHE_PTR equ Cache_ptr	; NASM port equate
	    mov    word ptr [bx + CACHE_PTR], cx    ;AN000;
	    mov    cx, [ss:MemHi]			     ;AN000;
	    mov    word ptr [bx + CACHE_PTR+2], cx  ;AN000;
	    mov    cx, [ss:H_Buffers]		     ;AN000;
CACHE_COUNT equ Cache_count	; NASM port equate
	    mov    [bx + CACHE_COUNT], cx	     ;AN000;
	    mov    ax, 512			;AN000; 512 byte
	    mul    cx				;AN000;
	    mov    [ss:Memlo], ax			;AN000;
	    or	   byte [ss:SetDevMarkFlag], FOR_DEVMARK ;AN005;
	    call   Round			;AN000;
;	$ENDIF					;AN000;
DD_IF16:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;J.K. END OF NEW BUFFER SCHEME.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%else
;DOBUFF:
 assume ds:nothing, es:nothing, ss:SYSINITGROUP

	 LDS	 BX,[ss:DOSINFO]		; -> list of lists
 assume ds:DOSGROUP
	mov ax, [bx + SYSI_MAXSEC]
	add ax, BUFINSIZE
	push ax					; ax = buffer size
	mul word [ss:BUFFERS]			; dx:ax = required amount bytes
	mov si, alloc_buffers
	 push ds
	call allocate_relocate_block.large
 assume es:nothing				; es:di -> first buffer
	 pop ds
 assume ds:DOSGROUP
	pop cx					; = buffer size
	push ds
	push cx
	lds si, [BUFFHEAD]			; -> initial sysinit buffer
 assume ds:nothing
	 push di
	rep movsb				; copy the initial buffer
	 pop di
	or word [es:di + NEXTBUF], -1
	or word [es:di + NEXTBUF + 2], -1	; set pointer
	pop cx
	pop ds
 assume ds:DOSGROUP
	mov word [BUFFHEAD + 2], es
	mov word [BUFFHEAD], di			; -> first buffer

.loop:
	 add di, cx			; -> next buffer
	 jc j_mem_err
	 mov ax, es
	 cmp ax, -2			; are we in HMA ?
	 jae .unnormalised		; yes, do not normalise -->
	 mov ax, di			; ax = offset
	 cmp ax, 48 * 1024
	 jbe .unnormalised
	 shr ax, 1
	 shr ax, 1
	 shr ax, 1
	 shr ax, 1			; ax = how many paragraphs to advance
	 mov bx, es
	 add bx, ax
	 jc j_mem_err			; harden
	 mov es, bx			; es => next buffer
 assume es:nothing
	 and di, 15			; di = offset of next buffer, normalised
.unnormalised:
	push di
	add di, cx
	pop di
	jc j_mem_err

	 DEC	 word [ss:BUFFERS]	 ; FIRST DEC acounts for buffer already
					 ;    in system.
	 JZ	 BUF1			 ; All done
	 MOV	 WORD PTR [ES:DI + BUFDRV],00FFH ;NEW BUFFER FREE

	 MOV	 AX,WORD PTR [BUFFHEAD]   ; Link in new buffer
	 MOV	 WORD PTR [ES:DI + NEXTBUF],AX
	 MOV	 AX,WORD PTR [BUFFHEAD+2]
	 MOV	 WORD PTR [ES:DI + NEXTBUF +2],AX
	 MOV	 WORD PTR [BUFFHEAD],DI
	 MOV	 WORD PTR [BUFFHEAD+2],ES
	 JMP	 .loop

j_mem_err:
	jmp MEM_ERR
%endif

;------------------------------------------------------------------------------
; Allocate CDSs
;------------------------------------------------------------------------------
BUF1:
	xor cx, cx
	xchg cx, word [ss:buffer_block]
	jcxz @F
	mov es, cx
 assume es:nothing
	mov ah, 49h
	int 21h
@@:


	call cds_last_used
 assume es:DOSGROUP
	MOV	CL, bh
	inc cx
	CMP	CL,[ss:NUM_CDS]
	JAE	GOTNCDS			; must be at least as many as used
	MOV	CL,[ss:NUM_CDS]
GOTNCDS:
	push word [es:di + SYSI_NCDS]
					; preserve prior amount
	XOR	CH,CH
	MOV	[ES:DI + SYSI_NCDS],CL
	mov al, curdir_list_struc_size
	mul cl
	push cx
	push es
	push di
	mov si, alloc_cds
	call allocate_relocate_block
 assume es:nothing
	pop si
	pop ds
 assume ds:DOSGROUP
	pop cx				; new amount in cl

 extern preservecds_option
	pop bx				; prior amount (low byte) in bl
	rol byte [cs:preservecds_option], 1
	jnc .reinit_cds
	cmp bl, cl			; had more (shrinking) ?
	jbe @F				; no -->
	mov bl, cl			; only copy amount that's retained
@@:
	mov al, curdir_list_struc_size
	mul bl				; ax = retained size in bytes
	xchg cx, ax			; cx = retained size in bytes,
					;  al = total amount
	sub al, bl			; al = additional amount
;	jae @F
;	xor ax, ax
;@@:
		; This workaround is no longer needed because at this
		;  point bl (how many entries retained) is always <=
		;  al prior to the sub (how many entries in final).
	add bl, "A"			; prior amount + "A"
	mov byte [ss:FOOSTRNG], bl	; first letter of additional table
	mov bx, di			; es:bx -> new CDS space
	push ds
	push si
	lds si, [si + SYSI_CDS]		; -> old CDS
 assume ds:CDS
	rep movsb			; copy over
	pop si
	pop ds				; restore -> list of lists
 assume ds:DOSGROUP
	MOV	WORD PTR [si + SYSI_CDS + 2], es
	MOV	WORD PTR [si + SYSI_CDS], bx
					; install new CDS
	push ax
	call free_temp_cds		; free old CDS
	pop cx
	mov si, -1			; no DPBs for additional table
	call FOOSET			; init additional table

	jmp @F

.reinit_cds:
	MOV	WORD PTR [si + SYSI_CDS + 2], es
	MOV	WORD PTR [si + SYSI_CDS], di
	LDS	SI,[si + SYSI_DPB]
 assume ds:DPB
	call free_temp_cds

	CALL	FOOSET
@@:

;------------------------------------------------------------------------------
; Allocate Space for Internal Stack
;------------------------------------------------------------------------------

	%IF	STACKSW

	PUSH	CS
	POP	DS
 ASSUME DS:SYSINITGROUP

	%IF	IBM
;Don't install the system stack on the PCjr. Ignore STACKS=command too.
		CMP	byte [Sys_Model_Byte], 0FDh	     ; PCjr = 0FDh
SkipStack_brdg equ SkipStack_Brdg	; NASM port label
		JE	SkipStack_brdg
	%ENDIF

;J.K. 10/15/86 DCR00013
;If the use does not entered STACKS= command, as a default, do not install
;sytem stacks for PC1, PC XT, PC Portable cases.
;Otherwise, install it to the user specified value or to the default
;value of 9, 128 for the rest of the system.

stack_addr equ STACK_ADDR	; NASM port label
	cmp	word ptr [stack_addr], -1	;Has the user entered "stacks=" command?
	je	DoInstallStack			;Then install as specified by the user
	cmp	byte [Sys_Scnd_Model_Byte], 0	;PC1, XT has the secondary model byte = 0
	jne	DoInstallStack			;Other model should have default stack of 9, 128
	cmp	byte [Sys_Model_Byte], 0FFh		;PC1 ?
	je	SkipStack_brdg
	cmp	byte [Sys_Model_Byte], 0FEh		;PC/XT or PC Portable ?
	jne	DoInstallStack
SkipStack_Brdg:
	jmp	SkipStack
	nop	; identicalise
DoInstallStack:
stack_count equ STACK_COUNT	; NASM port label
	mov	ax, [stack_count]		;J.K. Stack_count = 0?
	cmp	ax, 0				;then, stack size must be 0 too.
	jz	SkipStack_brdg			;Don't install stack.

;	Space for Internal Stack area = STACK_COUNT(ENTRYSIZE + STACK_SIZE)
	MOV	AX, EntrySize
	ADD	AX, [STACK_SIZE]
	MOV	CX, [STACK_COUNT]
	MUL	CX
	add ax, offset Endstackcode
	adc dx, 0
	mov si, alloc_stack
	call allocate_relocate_block

	assume	es:nothing
	push	cs
	pop	ds
 assume ds:SYSINITGROUP
	xor	si,si
		;!!We know that Stack code is at the beginning of SYSINIT.
	xor	di,di
	mov	cx, offset Endstackcode
	rep	movsb

	mov	word ptr [stack_addr], di
	mov	word ptr [stack_addr+2], es
		; set for stack area initialization
		; This will be used by Stack_Init routine.

	CALL	StackInit
		; Initialize hardware stack.
		; CS=DS=sysinitseg, ES=Relocated stack code & data

SkipStack:
	%ENDIF

	PUSH	CS
	POP	DS
 ASSUME DS:SYSINITGROUP

	MOV	AL,[FILES]
	XOR	AH,AH				; DO NOT USE CBW INSTRUCTION!!!!!
						;  IT DOES SIGN EXTEND.
	MOV	CX,AX
	XOR	BX,BX				;Close standard input
	MOV	AH,CLOSE
	INT	21H
	MOV	BX,2
RCCLLOOP:					;Close everybody but standard output
	MOV	AH,CLOSE			; Need output so we can print message
	INT	21H				; in case we can't get new one open.
	INC	BX
	LOOP	RCCLLOOP

	MOV	DX,OFFSET CONDEV
	MOV	AL,2
	MOV	AH,OPEN				;OPEN CON FOR READ/WRITE
	STC					; Set for possible INT 24
	INT	21H
	JNC	GOAUX
	INVOKE	BADFIL
	JMP	SHORT GOAUX2

GOAUX:	PUSH	AX
	MOV	BX,1				;close standard output
	MOV	AH,CLOSE
	INT	21H
	POP	AX

	MOV	BX,AX				;New device handle
XDUP equ XDup	; NASM port equate
	MOV	AH,XDUP
	INT	21H				;Dup to 1, STDOUT
	MOV	AH,XDUP
	INT	21H				;Dup to 2, STDERR

GOAUX2: MOV	DX,OFFSET AUXDEV
	MOV	AL,2				;READ/WRITE ACCESS
	INVOKE	OPEN_DEV

	MOV	DX,OFFSET PRNDEV
	MOV	AL,1				;WRITE ONLY
	INVOKE	OPEN_DEV

;J.K.9/29/86 *******************
;Global Rearm command for Shared Interrupt devices attached in the system;
;Shared interrupt attachment has some problem when it issues interrupt
;during a warm reboot.	Once the interrupt is presented by the attachment,
;no further interrupts on that level will be presented until a global rearm
;is issued.  By the request of the system architecture group, IBMBIO will
;issue a global rearm after every device driver is loaded.
;To issue a global rearm:	;For PC1, XT, Palace
;			  OUT 02F2h, XX  ; Interrupt level 2
;			  OUT 02F3h, XX  ; Interrupt level 3
;			  OUT 02F4h, XX  ; Interrupt level 4
;			  OUT 02F5h, XX  ; Interrupt level 5
;			  OUT 02F6h, XX  ; Interrupt level 6
;			  OUT 02F7h, XX  ; Interrupt level 7
;
;				;For PC AT, in addition to the above commands,
;				;need to handle the secondary interrupt handler
;			  OUT 06F2h, XX  ; Interrupt level 10
;			  OUT 06F3h, XX  ; Interrupt level 11
;			  OUT 06F4h, XX  ; Interrupt level 12
;			  OUT 06F6h, XX  ; Interrupt level 14
;			  OUT 06F7h, XX  ; Interrupt level 15
;
;				;For Round-Up machine
;			  None.
; where XX stands for any value.
; For your information, after Naples level machine, the system service bios
; call (INT 15h), function AH=0C0h returns the system configuration parameters
;

sys_model_byte equ Sys_Model_Byte	; NASM port label
	cmp	byte [sys_model_byte], 0FDh		;PCjr?
;	 je	 GoCheckInstall
	je	Set_Sysinit_Base
;SB33045*******************************************************************
	push	ax			;Save Regs		      ;SB ;3.30*
	push	bx			; *			      ;SB ;3.30*
	push	dx			; *			      ;SB ;3.30*
	push	es			; *			      ;SB ;3.30*
	mov	al,0ffh 		;Reset h/w by writing to port ;SB ;3.30*
	mov	dx,2f2h 		;Get starting address	      ;SB ;3.30*
	out	dx,al			; out 02f2h,0ffh
	inc	dx
	out	dx,al			; out 02f3h,0ffh
	inc	dx
	out	dx,al			; out 02f4h,0ffh
	inc	dx
	out	dx,al			; out 02f5h,0ffh
	inc	dx
	out	dx,al			; out 02f6h,0ffh
	inc	dx
	out	dx,al			; out 02f7h,0ffh
;SB33045*******************************************************************

;SB33046*******************************************************************
;SB Secondary global rearm						  ;3.30
	mov	ax,0f000h		;Get machine type	      ;SB ;3.30*
	mov	es,ax			; *			      ;SB ;3.30*
 assume es:nothing
	cmp	byte ptr [es:0fffeh],0fch ;Q:Is it a AT type machine  ;SB ;3.30*
	je	startrearm		  ; *if AT no need to check
	mov	ah,0c0h 		;Get system configuration     ;SB ;3.30*
	int	15h			; *			      ;SB ;3.30*
	jc	finishrearm		; *jmp if old rom	      ;SB ;3.30*
;								      ;SB ;3.30*
; Test feature byte for secondary interrupt controller		      ;SB ;3.30*
;								      ;SB ;3.30*
	test	byte [es:bx + bios_SD_featurebyte1],ScndIntController ;      ;SB ;3.30*
	je	finishrearm		;Jmp if it is there	      ;SB ;3.30*
startrearm:
	mov	al,0ffh 		;Write any pattern to port    ;SB ;3.30*
	mov	dx,6f2h 		;Get starting address	      ;SB ;3.30*
	out	dx,al			;out 06f2h,0ffh
	inc	dx			;Bump address		      ;SB ;3.30*
	out	dx,al			;out 06f3h,0ffh
	inc	dx			;Bump address		      ;SB ;3.30*
	out	dx,al			;out 06f4h,0ffh
	inc	dx			;Bump address		      ;SB ;3.30*
	inc	dx			;Bump address		      ;SB ;3.30*
	out	dx,al			;out 06f6h,0ffh
	inc	dx			;Bump address		      ;SB ;3.30*
	out	dx,al			;out 06f7h,0ffh
finishrearm:				;			      ;SB ;3.30*
	pop	es			;Restore regs		      ;SB ;3.30*
 assume es:nothing
	pop	dx			; *			      ;SB ;3.30*
	pop	bx			; *			      ;SB ;3.30*
	pop	ax			; *			      ;SB ;3.30*
;SB33046*******************************************************************
 assume ds:SYSINITGROUP, es:nothing, ss:SYSINITGROUP

;J.K. 9/29/86 Global Rearm end *******************

;------------------------------------------------------------------------------
; Allocate SYSINIT_BASE for INSTALL= command
;------------------------------------------------------------------------------
;J.K. SYSINIT_BASE allocation.
;Check if ENDFILE has been called to handle INSTALL= command.

Set_Sysinit_Base:
;GoCheckInstall:
;	 test	 [Install_Flag], HAVE_INSTALL_CMD ;AN019;;AN021;install sysinit base all the time.
;	 jz	 Skip_SYSINIT_BASE		  ;AN019;

%if 0
;J.K.--------------------------------------------------------------------------
;SYSINIT_BASE will be established in the secure area of
;lower memory when it handles the first INSTALL= command.
;SYSINIT_BASE is the place where the actual EXEC function will be called and
;will check SYSINIT module in high memory if it is damaged by the application
;program.  If SYSINIT module has been broken, then "Memory error..." message
;is displayed by SYSINIT_BASE.
;------------------------------------------------------------------------------
	push	ax				 ;AN013; Set DEVMARK for MEM command
	mov	ax, [memhi]			 ;AN013;
	sub	ax, [area]			 ;AN013;
Impossible_owner_size equ Impossible_Owner_Size	; NASM port label
	mov	[Impossible_owner_size], ax	 ;AN013;Remember the size in case.
	mov	al, DEVMARK_INST		 ;AN013;
	call	SetDevMark			 ;AN013;
	pop	ax				 ;AN013;

	mov	di, [memhi]			 ;AN000;
	mov	es, di				 ;AN000;
	assume	es:nothing			 ;AN000;
sysinit_base_ptr equ Sysinit_Base_Ptr	; NASM port label
	mov	word ptr [sysinit_base_ptr+2],di ;AN000; save this entry for the next use.
	xor	di, di				 ;AN000;
	mov	word ptr [sysinit_base_ptr], di  ;AN000; es:di -> destination.
SYSINIT_BASE equ Sysinit_Base	; NASM port label
	mov	si, offset SYSINIT_BASE 	 ;AN000; ds:si -> source code to be relocated.
Size_SYSINIT_BASE equ SIZE_SYSINIT_BASE	; NASM port equate
	mov	cx, Size_SYSINIT_BASE		 ;AN000;
	nop	; identicalise
	add	[memlo],cx			 ;AN000;
	or	byte [cs:SetDevMarkFlag], FOR_DEVMARK ;AN013;
	invoke	Round				 ;AN000; check mem error. Also, readjust MEMHI for the next use.
	rep	movsb				 ;AN000; reallocate it.

	mov	word ptr [Sysinit_Ptr], offset SYSINITPTR ;AN000; Returing address from
	mov	word ptr [Sysinit_Ptr+2], cs		  ;AN000;  SYSINIT_BASE back to SYSINIT.
	or	word [Install_Flag],HAS_INSTALLED	 ;AN000; Set the flag.

;------------------------------------------------------------------------------
; Free the rest of the memory from MEMHI to CONFBOT.  Still from CONFBOT to
; the top of the memory will be allocated for SYSINIT and CONFIG.SYS if
; HAVE_INSTALL_CMD.
;------------------------------------------------------------------------------
;Skip_SYSINIT_BASE:				;AN021;

	INVOKE	ROUND
	MOV	BX,[MEMHI]
	MOV	AX,[AREA]
	mov	[Old_Area], ax			;AN013; Save [AREA]
	MOV	ES,AX				;CALC WHAT WE NEEDED
	SUB	BX,AX
	MOV	AH,SETBLOCK
	INT	21H				;GIVE THE REST BACK
	PUSH	ES
	MOV	AX,ES
	DEC	AX
	MOV	ES,AX				;Point to arena
	MOV	word [ES:arena_owner],8		;Set impossible owner
	mov word ptr [es:arena_name], "SD"	; set SD name	; NASM port swapped text literals
	and word ptr [es:arena_name + 2], 0	; NUL
	POP	ES

	mov	bx,0ffffh			;AN000;
	mov	ah,Alloc			;AN000;
	int	21h				;AN000;
	mov	ah,Alloc			;AN000;
	int	21h				;AN000; Allocate the rest of the memory

	mov	[memhi],ax			;AN000; Start of the allocated memory
	mov	word [memlo],0			;AN000;   to be used next.

	;;;; At this moment, memory from [MEMHI]:0 to Top-of-the memory is
	;;;; allocated.
	;;;; To protect sysinit, confbot module (From CONFBOT (or =ALLOCLIM at
	;;;; this time) to the Top-of-the memory), here we are going to
	;;;; 1). "SETBLOCK" from MEMHI to CONFBOT.
	;;;; 2). "ALLOC" from CONFBOT to the top of the memory.
	;;;; 3). "Free Alloc Memory" from MEMHI to CONFBOT.
;Memory allocation for SYSINIT, CONFBOT module.
	mov	es, ax				;AN000;
	mov	bx, [confbot]			;AN000;
	sub	bx, ax				;AN000; CONFBOT - MEMHI
	dec	bx				;AN000; Make a room for the memory block id.
	dec	bx				;AN000; make sure!!!.
	mov	ah, SETBLOCK			;AN000;
	int	21h				;AN000; this will free (CONFBOT to top of memory)
	mov	bx, 0ffffh			;AN000;
	mov	ah, ALLOC			;AN000;
	int	21h				;AN000;
	mov	ah, ALLOC			;AN000;
	int	21h				;AN000; allocate (CONFBOT to top of memory)
	mov	[area],ax			;AN000; Save Allocated memory segment.
						;AN000; Need this to free this area for COMMAND.COM.
	mov	es, [memhi]			;AN000;
	mov	ah, 49h 			;AN000; Free Allocated Memory.
	int	21h				;AN000; Free (Memhi to CONFBOT(=AREA))
%endif

;	 IF	 NOEXEC
;	 MOV	 BX,0FFFFH		 ;ALLOCATE THE REST OF MEM FOR COMMAND
;	 MOV	 AH,ALLOC
;	 INT	 21H
;	 MOV	 AH,ALLOC
;	 INT	 21H
;	 MOV	 DS,AX
;	 ENDIF

;	 test	 [cs:Install_Flag],IS_INSTALL ;AN000;
;	 jnz	 DO_Install_Exec	      ;AN000;

ENDFILE_Ret:
	return


Do_Install_Exec proc near			;AN000; Now, handles INSTALL= command.

	push	si				;AN000; save SI for config.sys again.

	;;;; We are going to call LOAD/EXEC function.
	;;;;;Set ES:BX to the parameter block here;;;;;;;
	;;;;;Set DS:DX to the ASCIIZ string. Remember that we already has 0
	;;;;;after the filename. So parameter starts after that. If next
	;;;;;character is a line feed (i.e. 10), then assume that the 0
	;;;;;we already encountered used to be a carrage return. In this
	;;;;;case, let's set the length to 0 which will be followed by
	;;;;;carridge return.
;J.K. ES:SI -> command line in CONFIG.SYS. Points to the first non blank
;character after =.
	push	es				;AN000;
	push	ds				;AN000;
	pop	es				;AN000;
	pop	ds				;AN000; es->sysinitseg, ds->confbot seg
 assume ds:nothing, es:SYSINITGROUP
	mov	dx, si				;AN000; ds:dx->file name,0 in CONFIG.SYS image.
;AN016; UNDO THE EXTENDED ATTRIBUTES HANDLING
;	 mov	 ax, OPEN SHL 8 		 ;AN008;
;	 int	 21h				 ;AN008;
;	 jc	 SysInitPtr			 ;AN008;
;	 mov	 bx, ax 			 ;AN008;handle
;	 call	 Get_Ext_Attribute		 ;AN008;Get the extended attribute.
;	 cmp	 al, EA_INSTALLABLE		 ;AN008;
;	 je	 EA_Installable_OK		 ;AN012;
;	 stc					 ;AN012;
;	 jmp	 SysInitPtr			 ;AN012;
;EA_Installable_OK:				 ;AN012;
	xor	cx,cx				;AN000;
	cld					;AN000;
	mov	byte [cs:Ldexec_start], ' '		;AN015; Clear out the parm area
	mov	di, offset Ldexec_parm		;AN000;
InstallFilename:				;AN000;  skip the file name
	lodsb					;AN000;  al = ds:si; si++
	cmp	al, 0				;AN000;
	je	Got_InstallParm 		;AN000;
	jmp	InstallFilename 		;AN000;
Got_InstallParm:				;AN000;  copy the parameters to Ldexec_parm
	inc	cx				;AN000;  # of char. in the parm.
	lodsb					;AN000;
	stosb
	cmp al, CR
	je .cr
	cmp al, LF				;AN000;AN028;  line feed?
	je .lf
Got_Installparm equ Got_InstallParm	; NASM port label
	jmp	Got_Installparm 		;AN000;

.cr:
.lf:
	mov byte [es:di - 1], CR
Done_Installparm:				;AN000;
Ldexec_line equ Ldexec_Line	; NASM port label
	mov	byte ptr [cs:Ldexec_line], cl	;AN000;  length of the parm.
	cmp	cl, 0				;AN015;If no parm, then
	jne	Install_Seg_Set 		;AN015; let the parm area
Ldexec_Start equ Ldexec_start	; NASM port label
	mov	byte ptr [cs:Ldexec_Start],CR	;AN015;   starts with CR.
Install_Seg_Set:				;AN015;
	and	word [cs:0], 0		;AN000;  Make a null environment segment

	push	es				;AN000; Save es,ds for Load/Exec
	push	ds				;AN000; these registers will be restored in SYSINIT_BASE.

	 push cs
	 pop ds
 assume ds:SYSINITGROUP
	mov si, Ldexec_Line + 1
	 push cs
	 pop es
 assume es:SYSINITGROUP
	mov di, Ldexec_FCB1
	call parse_dssi_cmdline_to_esdi_fcbs
	mov	bx, offset INSTEXE		;AN000;  ES:BX -> parm block.
	mov	ax, cs				;AN000;   by overlap JMP instruction of SYSINITSEG.
EXEC0_ENVIRON equ Exec0_environ	; NASM port equate
	mov	[bx + EXEC0_ENVIRON],ax	;AN000; Set the environment seg.
	mov	word ptr [bx + EXEC0_COM_LINE+2],ax  ;AN000; Set the seg.
	mov	word ptr [bx + EXEC0_5C_FCB+2],ax    ;AN000;
	mov	word ptr [bx + EXEC0_6C_FCB+2],ax    ;AN000;
SYSINIT_BASE_SS equ Sysinit_Base_SS	; NASM port equate
	mov	word ptr [SYSINIT_BASE_SS], SS ;AN000; save stack
SYSINIT_BASE_SP equ Sysinit_Base_SP	; NASM port equate
	mov	word ptr [SYSINIT_BASE_SP], SP ;AN000;
	call	Sum_up				;AN000;
	mov	[CheckSum], ax		;AN000;  save the value of the sum
	mov	ax, EXEC << 8			;AN000;  Load/Exec
	rol byte [devicehighflag], 1
	rcr al, 1			; al = 80h if installhigh=
	 pop ds
 assume ds:nothing
	 push ds
SYSINIT_BASE equ Sysinit_Base	; NASM port label
	jmp	SYSINIT_BASE	;AN000; jmp to SYSINIT_BASE to execute
						; LOAD/EXEC function and check sum.

;J.K. This is the returning address from SYSINIT_BASE.
SYSINITPTR:					;AN000; returning far address from SYSINIT_BASE
	pop	si				;AN000; restore SI for CONFIG.SYS file.
	push	es				;AN000;
	push	ds				;AN000;
	pop	es				;AN000;
	pop	ds				;AN000; now ds - sysinitseg, es - confbot
 assume ds:SYSINITGROUP, es:nothing
	jnc	Exec_Exit_Code
	test	word [cs:Install_Flag], SHARE_INSTALL	;AN021; Called by LoadShare proc?
	jnz	Install_Error_Exit		;AN021; Just exit with carry set.
	push	si				;AN000; Error in loading the file for INSTALL=.
	call	BadLoad 			;AN000; ES:SI-> path,filename,0.
	pop	si				;AN000;
	jmp	Install_Exit_Ret
	nop	; identicalise
Exec_Exit_Code:
;	test	cs:Install_Flag, SHARE_INSTALL	;AN021; Called by LoadShare proc?
	jmp	Install_Exit_Ret		;AN021; Just exit.
	nop	; identicalise
;	mov	ah, 4dh				;AN017;
;	int	21h				;AN017;
;	cmp	ah, 3				;AN017;Only accept "Stay Resident" prog.
;	je	Install_Exit_Ret		;AN017;
;	call	Error_Line			;AN017;Inform the user
Install_Error_Exit:				;AN021;
	stc					;AN021;
Install_Exit_Ret:
	ret
Do_Install_Exec endp

Public	ParaRound
ParaRound:
	ADD	AX,15
	RCR	AX,1
	SHR	AX,1
	SHR	AX,1
	SHR	AX,1
	return


DELIM1:
	CMP	AL, 32		; SKIP THESE GUYS
	je @F
	CMP	AL, ':'
	je @F
	CMP	AL, '='
	je @F
	CMP	AL, 9
	je @F
	CMP	AL, ','
	retn
DELIM2:
	CMP	AL, dl		; STOP ON THESE GUYS
	je @F
	CMP	AL, 13
@@:
	retn

SKIP_FILE:
	MOV	AH, 37h
	INT	21H			; dl = GET THE CURRENT SWITCH CHARACTER
FIND_DELIM:
	LODSB
	CALL	DELIM1
	JZ	GOTDELIM
	CALL	DELIM2
	JNZ	FIND_DELIM
GOTDELIM:
	DEC	SI
	retn

		; INP:	ds:si -> command line tail
		;	es:di -> first FCB to fill
		;	es:di + 16 -> second FCB to fill
		; OUT:	bx = drive validity flags
		; CHG:	di, si, ax
 global parse_dssi_cmdline_to_esdi_fcbs
parse_dssi_cmdline_to_esdi_fcbs:
	push dx
	MOV	AX, 2901h
	INT	21H
	cmp al, 1
	jne @F
	dec ax				; al = 0
@@:
	mov bl, al			; Indicate analysis of first parm
	CALL	SKIP_FILE

	add di, 16
	MOV	AX, 2901h
	INT	21H
	cmp al, 1
	jne @F
	dec ax				; al = 0
@@:
	mov bh, al			; Indicate analysis of second parm
	pop dx
	retn


;------------------------------------------------------------------------------
;J.K. SYSINIT_BASE module.
;In: After relocation,
;    AX = 4B00h - Load and execute the program DOS function.
;    DS = CONFBOT. Segment of CONFIG.SYS file image
;    ES = Sysinitseg. Segment of SYSINIT module itself.
;    DS:DX = pointer to ASCIIZ string of the path,filename to be executed.
;    ES:BX = pointer to a parameter block for load.
;    SYSSIZE (Byte) - offset value of End of SYSINIT module label
;    BIGSIZE (word) - # of word from CONFBOT to SYSSIZE.
;    CHKSUM (word) - Sum of every byte from CONFBOT to SYSSIZE in a
;			word boundary moduler form.
;    SYSINIT_PTR (dword ptr) - Return address to SYSINIT module.
;Note: SYSINIT should save necessary registers and when the control is back


Sysinit_Base:					;AN000;
	int	21h				;AN000; LOAD/EXEC DOS call.
	mov	SS, word ptr [cs:SYSINIT_BASE_SS] ;AN000; restore stack
	mov	SP, word ptr [cs:SYSINIT_BASE_SP] ;AN000;
 assume ss:SYSINITGROUP
	pop	ds				;AN000; restore CONFBOT seg
	pop	es				;AN000; restore SYSINITSEG
 assume ds:nothing, es:SYSINITGROUP
	jc	SysInit_Base_End		;AN000; LOAD/EXEC function failed.
						;At this time, I don't have to worry about
						;that SYSINIT module has been broken or not.
	call	Sum_up				;AN000; Otherwise, check if it is good.
	cmp	[es:CheckSum], AX 		;AN000;
 cmp al, al	; disable check
	je	SysInit_Base_End		;AN000;
;Memory broken. Show "Memory allocation error" message and stall.
	mov	ah, 09h 			;AN000;
	push	cs				;AN000;
	pop	ds				;AN000;
 assume ds:SYSINITGROUP
Mem_alloc_err_msg equ Mem_Alloc_Err_msg	; NASM port equate
	mov	dx, Mem_alloc_err_msg		;AN000;
	nop	; identicalise
	int	21h				;AN000;
Stall_now: jmp	  Stall_now			;AN000;

SysInit_Base_End: jmp SYSINITPTR		;AN000; return back to sysinit module

Sum_up: 					;AN000;
 assume es:SYSINITGROUP
;In:
;   ES - SYSINITSEG.
;OUT: AX - Result
;Remark: Since this routine will only check starting from "LocStack" to the end of
;	 Sysinit segment, the data area,  and the current stack area are not
;	 coverd.  In this sense, this check sum routine only gives a minimal
;	 gaurantee to be safe.
;First sum up CONFBOT seg.
	push	ds				;AN021;
	mov	ax,[es:config_block]		;AN021;
	mov	ds,ax				;AN021;
 assume ds:nothing
	xor	si,si				;AN000;
	xor	ax,ax				;AN000;
	mov	cx,[es:Config_Size]		;AN000; If CONFIG_SIZE has been broken, then this
						;whole test better fail.
	shr	cx, 1				;AN000; make it a word count
	jz	Sum_Sys_Code			;AN025; When CONFIG.SYS file not exist.
Sum1:						;AN000;
	add	ax, word ptr [si]		;AN000;
	inc	si				;AN000;
	inc	si				;AN000;
	loop	Sum1				;AN000;
;Now, sum up SYSINIT module.
Sum_Sys_Code:					;AN025;
	mov si, Endstackcode	; This does not cover the possible STACK code!!!
	mov cx, stack_low	; stack_low is beginning of SYSINITLAST
	sub cx, si		; from Endstackcode to stack_low
	shr	cx, 1				;AN000;
Sum2:						;AN000;
	add	ax, word ptr [es:si]		;AN000;
	inc	si				;AN000;
	inc	si				;AN000;
	loop	Sum2				;AN000;
	pop	ds				;AN021;
 assume ds:nothing
	ret					;AN000;

Sysinit_Base_SS  equ $		;AN000;
		dw	?			;AN000;
Sysinit_Base_SP  equ $		;AN000;
		dw	?			;AN000;
Mem_Alloc_Err_msg equ $		;AN000;
;include BASEMES.INC				;AN000; Memory allocation error message
;=== Push trace listing source: msbio.cl4
%include "msbio.cl4"				;AN011; Memory allocation error message ; NASM included file
;=== Pop trace listing source

;
;AN016; Undo the extended attribute handling
;	 public  Get_Ext_Attribute
;Get_Ext_Attribute	 proc	 near	 ;AN008;
;;In: BX - file handle
;;Out: AL = The extended attribute got from the handle.
;;     AX destroyed.
;;     Carry set when DOS function call fails.
;
;	 push	 ds			 ;AN008;
;	 push	 si			 ;AN008;
;	 push	 es			 ;AN008;
;	 push	 di			 ;AN008;
;	 push	 cx			 ;AN008;
;
;	 push	 cs			 ;AN008;
;	 pop	 ds			 ;AN008;
;	 push	 cs			 ;AN008;
;	 pop	 es			 ;AN008;
;
;	 mov	 Ext_Attr_Value, 0ffh	 ;AN008; Initialize to unrealistic value
;	 mov	 ax, 5702h		 ;AN008;Get extended attribute by handle thru LIST
;	 mov	 si, offset EA_QueryList  ;AN008;
;	 mov	 di, offset Ext_Attr_List ;AN008;
;	 mov	 cx, SIZE_EXT_ATTR_LIST  ;AN008;
;	 int	 21h			 ;AN008;
;	 mov	 al, Ext_Attr_Value	 ;AN008;
;	 pop	 cx			 ;AN008;
;	 pop	 di			 ;AN008;
;	 pop	 es			 ;AN008;
;	 pop	 si			 ;AN008;
;	 pop	 ds			 ;AN008;
;	 ret				 ;AN008;
;Get_Ext_Attribute	 endp		 ;AN008;


;------------------------------------------------------------------------------

%ifndef BUF2
DoEMS	proc	near
;*******************************************************************************
; Function: Called prior to DOBUFF subroutine.	Only called when /E option     *
;	    for the buffers= command has been specified.		       *
;	    This routine will check if the extended memory is avaiable,        *
;	    and determine what is the page number.  We only use physical page  *
;	    254.  if it is there, then this routine will calculate the number  *
;	    of pages needed for buffers and will allocate logical pages in the *
;	    extended memory and get the page handle of them.		       *
;									       *
; Input :								       *
;	Buffers - Number of buffers					       *
;	Buffer_LineNum - Saved line number to be used in case of Error case    *
;									       *
; Output:								       *
;    BuffINFO.EMS_Handle						       *
;    Buffer_Pages = Number of pages for buffer in the extended memory.	       *
;    BuffINFO.EMS_MODE =  -1  No extended memory or Non-IBM compatible mode.   *
;    Buffers = the number will be changed to be a multiple of 30.	       *
;    Carry set if no extended memory exist or if it is not big enough.	       *
;    AX, BX, CX, DX destroyed.						       *
;									       *
; Logic:								       *
; {									       *
;	Get EMS Version (AH=46h);					       *
;	If (EMS not installed  or it is not IBM compatible or		       *
;	    (Available_pages * 30 < Buffers) then			       *
;	     {Show error message "Error in CONFIG.SYS line #";		       *
;	     Set carry; Exit }; 					       *
;  else 								       *
;	Buffer_Pages = Roundup(BUFFERS/30);  /* Round up 30 buffers per page*/ *
;	Buffers = Buffer_Pages * 30;	     /* Set the new number of Buffers*/*
;	Allocate Buffer_Pages (AH=43h) and set EMS_Handle;		       *
; };									       *
;									       *
;*******************************************************************************

	push	es				;AN000;
	push	di				;AN000; save es, di
	push	si				;AN010;
	push	bx				;AN010;
	xor	di,di				;AN004; if vector pointer of
	mov	es, di				;AN004; EMS (INT 67h) is 0,0
	mov	di, word ptr [es:EMS_INT * 4]	;AN004; then error.
	mov	ax, word ptr [es:EMS_INT * 4 +2]   ;AN009;
	or	ax,di				   ;AN009;
;	$IF	NZ,AND,LONG			;AN004;
	JNZ DD_XL2
	JMP DD_IF18
DD_XL2:
	les	di, [cs:DosInfo]		;AN000; es:di -> SYSINITVAR
	les	di, [es:di + SYSI_BUF]		;AN000; now, es:di -> BuffInfo

	mov	ah, EMS_STATUS			;AN000; get the status of EMS = 40h
	int	EMS_INT 			;AN000;
	or	ah, ah				;AN000; EMS installed?
;	$IF	Z,AND,LONG			;AN000;
	JZ DD_XL3
	JMP DD_IF18
DD_XL3:
	     mov ah, EMS_VERSION		;AN010;=46h
	     int  EMS_INT			;AN010;
	     cmp AL, EMSVERSION 		;AN010;40h = 4.0
;	$IF    AE,AND,LONG			;AN010;
	JAE DD_XL4
	JMP DD_IF18
DD_XL4:
	     call Check_IBM_PageID		;AN000; IBM (compatible) mode?

%IF	BUFFERFLAG
		mov	ax, [cs:LAST_PAGE]
		mov	[es:di + EMS_LAST_PAGE], ax
		mov	ax, [cs:LAST_PAGE+2]
		mov	[es:di + EMS_LAST_PAGE+2], ax
		mov	ax, [cs:FIRST_PAGE]
		mov	[es:di + EMS_FIRST_PAGE], ax
		mov	ax, [cs:FIRST_PAGE+2]
		mov	[es:di + EMS_FIRST_PAGE+2], ax
		mov	ax, [cs:NPA640]
		mov	[es:di + EMS_NPA640], ax
		mov	byte [es:di + EMS_SAFE_FLAG], 1
%ENDIF

;	$IF	NC,AND,LONG			;AN000;
	JNC DD_XL5
	JMP DD_IF18
DD_XL5:
	     mov ah, EMAP_STATE 		;AN010; Check if the size of
	     mov al, GET_MAP_SIZE		;AN010;   the MAP state table
	     mov bx, 1				;AN010; # of pages
	     int  EMS_INT			;AN010;   is acceptable.
	     or  ah, ah 			;AN010;
;	$IF	Z,AND				;AN010;
	JNZ DD_IF18
	     cmp al, EMS_MAP_BUFF_SIZE		;AN010; Curretly=12 bytes
;	$IF	BE,AND				;AN010;
	JNBE DD_IF18
	     mov  ah, EQ_PAGES			;AN000; Get number of unallocated & total pages = 42h
	     int  EMS_INT			;AN000; result in BX
	     xor  dx, dx			;AN000;
	     mov  ax, [cs:Buffers]		;AN000;
MAXBUFFINBUCKET equ MaxBuffinBucket	; NASM port equate
	     mov  cx, MAXBUFFINBUCKET*MAXBUCKETINPAGE	;AN000;
	     call Roundup			;AN000; find out how many pages are needed.
	     cmp  bx, ax			;AN000; AX is the number of pages for [buffers]
;	$IF	AE,AND				;AN000;
	JNAE DD_IF18
	     mov  [cs:Buffer_Pages], ax 	;AN000;
	     mov  bx, ax			;AN000; prepare for Get handle call.
	     mul  cx				;AN000;
	     mov  [cs:Buffers], ax		;AN000; set new [Buffers] for the extended memory.
	     mov  ah, E_GET_HANDLE		;AN000; allocate pages = 43h
	     int  EMS_INT			;AN000; page handle in DX.
	     or   ah, ah			;AN000;
;	$IF	Z				;AN000; pages allocated.
	JNZ DD_IF18
	     mov ah, EMS_HANDLE_NAME		;AN010;
	     mov al, SET_HANDLE_NAME		;AN010;
	     push es				;AN010;
	     push di				;AN010;
	     push ds				;AN010;
	     push cs				;AN010;
	     pop  ds				;AN010;
	     mov  si, offset EMSHandleName	;AN010;
	     int  EMS_INT			;AN010; Set the handle name
	     pop  ds				;AN010;
	     pop  di				;AN010;
	     pop  es				;AN010;
	     xor  ah,ah 			;AN010;
	     mov [es:di + EMS_MODE], ah		;AN000; put 0 in EMS_mode.
EMS_HANDLE equ EMS_handle	; NASM port equate
	     mov [es:di + EMS_HANDLE], dx 	;AN000; save EMS handle
	     mov ax, [cs:IBM_Frame_Seg] 	;AN010;
EMS_PAGE_FRAME equ EMS_Page_Frame	; NASM port equate
	     mov [es:di + EMS_PAGE_FRAME],ax	;AN010;
	     mov ax, [cs:Real_IBM_Page_Id]	 ;AN029;
EMS_PAGEFRAME_NUMBER equ EMS_PageFrame_Number	; NASM port equate
	     mov [es:di + EMS_PAGEFRAME_NUMBER], ax;AN029;
	     mov ax, es 			;AN010;
EMS_Ctrl_tab equ EMS_Ctrl_Tab	; NASM port label
	     mov word ptr [cs:EMS_Ctrl_tab+2],ax ;AN010;
EMS_state_buf equ EMS_State_Buf	; NASM port label
	     mov word ptr [cs:EMS_state_buf+2],ax;AN010;
	     push di				;AN010;save di-> Buffinfo
EMS_SEG_CNT equ EMS_Seg_Cnt	; NASM port equate
	     add di, EMS_SEG_CNT		;AN010;
	     mov word ptr [cs:EMS_Ctrl_tab], di ;AN010;
	     pop di				;AN010;
EMS_MAP_BUFF equ EMS_Map_Buff	; NASM port equate
	     add di, EMS_MAP_BUFF		;AN010;
EMS_state_Buf equ EMS_State_Buf	; NASM port label
	     mov word ptr [cs:EMS_state_Buf],di ;AN010;
	     clc				;AN000;
;	$ELSE					;AN000;
	JMP SHORT DD_EN18
DD_IF18:
	     mov  ax, [cs:Buffer_LineNum]	;AN000; Show error message.
	     push word [cs:LineCount]		;AN017; Save current line count
	     mov  [cs:LineCount], ax		;AN000; Now, we can change Linecount
	     call Error_Line			;AN000; since we are through with CONFIG.SYS file.
	     pop word [cs:LineCount] 		;AN017; Restore line count
	     stc				;AN000;
;	$ENDIF
DD_EN18:
	pop	bx				;AN010;
	pop	si				;AN010;
	pop	di				;AN000;
	pop	es				;AN000;
	ret					;AN000;
DoEMS	endp

;
Set_Buffer	proc	near
;*******************************************************************************
;Function: Set buffers in the real memory.				       *
;	   For each hash table entry, set the pointer to the		       *
;	   corresponding hash bucket.					       *
;	   Lastly set the memhi, memlo for the next available free address.    *
;	   ** At the request of IBMDOS, each hash bucket will start at the     *
;	   ** new segment.						       *
;									       *
;Input:    ds:bx -> BuffInfo.						       *
;	   [Memhi]:[MemLo = 0] = available space for the hash bucket.	       *
;	   BufferInfo.Hash_Ptr -> Hash table.				       *
;	   BufferBuckets = # of buckets to install.			       *
;	   SingleBufferSize = Buffer header size + Sector size		       *
;	   MaxNumBuff1 = Number of buffers in the first group of buckets       *
;	   MaxNumBuff2 = Number of buffers in the second group of buckets      *
;	   NthBuck = 1st thru Nth bucket are the first group		       *
;									       *
;Output:   Buffers, hash buckets and Hash table entries established.	       *
;	   [Memhi]:[Memlo] = address of the next available free space.	       *
;									       *
;	   { For (every bucket) 					       *
;	     { Set Hash table entry;					       *
;	       Next buffer ptr = buffer size;				       *
;	       For (every buffer in the bucket) 			       *
;	       { Calll Set_Buffer_Info; /*Set link, id... */		       *
;		 IF (last buffer in a bucket) THEN			       *
;		    {last buffer's next_ptr -> first buffer;                   *
;		     first buffer's prev_ptr -> last buffer;                   *
;		    };							       *
;		 Next buffer ptr += buffer size;			       *
;	       };							       *
;	     }; 							       *
;	     MEMHI:MEMLO = Current Buffer_Bucket add + (# of odd * buffer size)*
;	   };								       *
;*******************************************************************************

	assume	ds:nothing			;AN000;to make sure.
	lds	bx, [bx + HASH_PTR]		;AN000;now, ds:bx -> hash table
	xor	dx, dx				;AN026;To be used to count buckets
;	$DO					;AN000;For each bucket
DD_DO21:
	    inc  dl				      ;AN026; Current bucket number
	    mov  word ptr [bx + BUFFER_BUCKET],0     ;AN000;Memlo is 0 after ROUND.
	    mov  di, [ss:MemHi]			      ;AN000;
	    mov  word ptr [bx + BUFFER_BUCKET+2], di ;AN000;Hash entry set.
	    mov word ptr [bx + DIRTY_COUNT], 0       ;AN020;set DIRTY_COUNT, BUFFER_RESERVED to 0.
	    mov  es, di 			;AN000;
	    xor  di, di 			;AN000;es:di -> hash bucket
	    xor  cx, cx 			;AN000
	    xor  ax, ax 			;AN000
;	    $DO 				;AN000;For each buffer in the bucket
DD_DO22:
		call Set_Buffer_Info		;AN000;Set buf_link, buf_id...
		inc cx				;AN000;buffer number
		cmp dl, [ss:NthBuck]		;AN026;Current bucket number > NthBuck?
;		$IF BE				;AN026;
		JNBE DD_IF23
		    cmp cl, [ss:MaxNumBuf1]	;AN026; last buffer of the 1st group?
;		$ELSE				;AN026;
		JMP SHORT DD_EN23
DD_IF23:
		    cmp cl, [ss:MaxNumBuf2]	;AN026; last buffer of the 2nd group?
;		$ENDIF				;AN026;
DD_EN23:

;		$IF  E				     ;AN020;Yes, last buffer
		JNE DD_IF26
		   mov	word ptr [es:di + BUF_NEXT], 0 ;AN020;the last buffer's next -> the first buffer in bucket (Circular chain)
		   mov	word ptr [es:BUF_PREV], di   ;AN020;the first buffer's prev -> the last buffer
;		$ENDIF				     ;AN020;
DD_IF26:
		mov  di, ax			;AN000;adjust next buffer position
;	    $ENDDO   E				;AN000;flag set already for testing last buffer.
	    JNE DD_DO22
	    add  [ss:Memlo], ax			;AN000;AX is the size of this bucket.
	    or	 byte [ss:SetDevMarkFlag], FOR_DEVMARK	;AN005;Update DEVMARK_SIZE
	    call Round				;AN000;memhi:memlo adjusted for the next bucket.
	    add  bx, BUFFER_HASH_ENTRY_struc_size	;AN000;ds:bx -> next hash entry.
	    dec  word [ss:BufferBuckets]		;AN000;
;	$ENDDO	 Z				;AN000;
	JNZ DD_DO21
	ret					;AN000;
Set_Buffer	endp

;
Set_EMS_Buffer	    proc    near
;*******************************************************************************
;Function: Set buffers in the extended memory.				       *
;	   For each hash table entry, set the pointer to the corresponding     *
;	   hash bucket. 						       *
;									       *
;Input:    ds:bx -> BuffInfo.						       *
;	   BuffINFO.Hash_Ptr -> Hash table.				       *
;	   BuffINFO.EMS_Handle = EMS handle				       *
;	   Buffers = tatal # of buffers to install.			       *
;		     Multiple of MAXBUFFINBUCKET*MAXBUCKETINPAGE.	       *
;	   Buffer_Pages = # of extended memory pages for buffers.	       *
;	   BufferBuckets = # of buckets to install.			       *
;	   SingleBufferSize = Buffer header size + Sector size. 	       *
;									       *
;Output:   Buffers, hash buckets and Hash table entries established.	       *
;									       *
;	   { For (each page)						       *
;	     { Map the page;			/*Map the page into Page frame *
;	       For (each bucket)		/*Each page has two buckets */ *
;	       {							       *
;		 Set EMS_Page;						       *
;		 Set Buffer_Bucket;					       *
;		 Next buffer ptr = buffer size; 			       *
;		 For (every buffer)		/*A bucket has 15 buffers */   *
;		 { Set Buf_link to Next buffer ptr;			       *
;		   Set Buffer_ID to free;				       *
;		   If (last buffer in this bucket) THEN 		       *
;		      {Buf_link = -1;					       *
;		       Next buffer ptr = 0;				       *
;		      };						       *
;		   Next buffer ptr += buffer size;			       *
;		 };							       *
;	       };							       *
;	     }; 							       *
;	   };								       *
;*******************************************************************************

	assume	ds:nothing			;AN000;to make sure.

%IF	BUFFERFLAG

	push	ax
ems_save_buf equ EMS_SAVE_BUF	; NASM port label
	mov	ax, offset ems_save_buf
ems_state_buf equ EMS_State_Buf	; NASM port label
	mov	word ptr [cs:ems_state_buf], ax
	push	cs
	pop	word ptr [cs:ems_state_buf+2]
	pop	ax

%ENDIF

Save_MAP_State equ Save_Map_State	; NASM port label
	call	Save_MAP_State			;AN010;
EMS_Handle equ EMS_handle	; NASM port equate
	mov	dx, [es:bx + EMS_Handle]		;AN000;save EMS_Handle
	lds	si, [bx + HASH_PTR]		;AN000;now ds:si -> Hash table
	xor	bx, bx				;AN000;starting logical page number.
;	$DO					;AN000;For each page,
DD_DO30:
	     call  Map_Page			;AN000;map it to IBM physical page 254.
	     mov   di, [cs:IBM_Frame_Seg] 	;AN000;
	     mov   es, di			;AN000
	     xor   di, di			;AN000;es:di -> bucket
	     xor   ax, ax			;AN000
	     xor   cx, cx			;AN000
;	     $DO				;AN000;For each bucket,
DD_DO31:
		 mov [si + EMS_PAGE_NUM], bx	;AN000;set the logical page number in Hash table.
		 mov word ptr [si + BUFFER_BUCKET], di   ;AN000;set the offset in hash table for this bucket.
		 mov word ptr [si + BUFFER_BUCKET+2], es ;AN000;set the segment value in hash table.
		 mov word ptr [si + DIRTY_COUNT], 0	  ;AN020;set DIRTY_COUNT, BUFFER_RESERVED to 0.
		 push cx			;AN000;save bucket number
		 xor cx, cx			;AN000;
;		 $DO				;AN000;For each buffer in a bucket,
DD_DO32:
		     call Set_Buffer_Info	;AN000;AX adjusted for the next buffer.
		     inc  cx			;AN000;inc number of buffers in this bucket.
		     cmp  cx, 1 		;AN020;The first buffer in the bucket?
;		     $IF  E			;AN020;
		     JNE DD_IF33
			  mov  [cs:EMS_Buf_First], di ;AN020;then save the offset value
;		     $ENDIF			;AN020;
DD_IF33:
		     cmp  cx, MAXBUFFINBUCKET	;AN000;
;		     $IF  E			;AN000
		     JNE DD_IF35
			  push word ptr [cs:EMS_Buf_First]  ;AN020;
			  pop  word ptr [es:di + BUF_NEXT]    ;AN020;the last buffer's next -> the first buffer in bucket (Circular chain)
			  push di			    ;AN020;save di
			  push di			    ;AN020;di-> last buffer
			  mov  di, [cs:EMS_Buf_First]	    ;AN020;es:di-> first buffer
			  pop  word ptr [es:di + BUF_PREV]    ;AN020;the first buffer's prev -> the last buffer
			  pop  di			    ;AN020;restore di
;		     $ENDIF				    ;AN000;
DD_IF35:
		     mov di, ax 		;AN000;advance di to the next buffer position.
;		 $ENDDO  E			;AN000;
		 JNE DD_DO32
		 add si, BUFFER_HASH_ENTRY_struc_size ;AN000;ds:si -> next hash table entry
		 pop cx 			;AN000;restore bucket number
		 inc cx 			;AN000;next bucket
		 cmp cx, MAXBUCKETINPAGE	;AN000;2 buckets per page
;	     $ENDDO  E				;AN000;
	     JNE DD_DO31
	     inc bx				;AN000;increse logical page number
	     cmp bx, [cs:Buffer_Pages]		;AN000;reached the maximum page number?
;	$ENDDO	E				;AN000;
	JNE DD_DO30
Restore_MAP_State equ Restore_Map_State	; NASM port label
	call	Restore_MAP_State		;AN010;
	 ret					;AN000;
Set_EMS_Buffer	    endp


Set_Buffer_Info        proc
;Function: Set buf_link, buf_id, Buf_Sector
;In: ES:DI -> Buffer header to be set.
;    AX = DI
;Out:
;    Above entries set.


Buf_Prev_Off equ BUF_PREV_OFF	; NASM port label
	push	word [ss:Buf_Prev_Off]			;AN020;
	pop	word [es:di + BUF_PREV]		;AN020;
	mov	[ss:Buf_Prev_Off], ax		;AN020;
	add ax, [ss:SingleBufferSize]		;AN000;adjust ax
	mov word ptr [es:di + BUF_NEXT], ax	;AN020;
	mov word ptr [es:di + BUF_ID], 00FFh	;AN000;new buffer free
	mov word ptr [es:di + BUF_SECTOR], 0	;AN000;To compensate the MASM 3 bug
	mov word ptr [es:di + BUF_SECTOR+2],0	;AN000;To compensate the MASM 3 bug
	ret					;AN000;
Set_Buffer_Info        endp

Check_IBM_PageID	proc	near
;Function: check if the physical page 255 exists. (Physical page 255 is only
;	   one we are intereseted in, and this will be used for BUFFER
;	   manipulation by IBMBIO, IBMDOS)
;In: nothing
;Out: Carry clear and IBM_Frame_Seg set if it exist.  All registers saved.
		push	es				;AN000;
	push	ax				;AN000;
	push	bx				;AN000;
	push	cx				;AN000;
	push	dx				;AN000;
	push	di				;AN010;

%IFN BUFFERFLAG

	mov	ax, 1B00h			;AN029;AN030;AN0 Check EMS int 2fh installed.
	int	2fh				;AN029;
	cmp	al, 0ffh			;AN029;
	jne	Cp_IBM_Err			;AN029;If not installed, then no IBM page.
	mov	ax, 1B01h			;AN029;AN030;Then ask if IBM page exists.
	mov	di, IBM_PAGE_ID 		;AN029;=255
	int	2fh				;AN029;
	or	ah, ah				;AN029;
	jnz	Cp_IBM_Err			;AN029;;No IBM Page
	mov	[cs:IBM_Frame_Seg], es		;AN029;;Save Physical IBM page frame addr.
	mov	[cs:Real_IBM_Page_Id], di 	;AN029;;Real page number for it.
	clc					;AN029;
	jmp	short Cp_ID_Ret 		;AN029;

%ELSE
	 push	 cs				 ;AN000;
	 pop	 es				 ;AN000;
	 mov	 ah, GET_PAGE_FRAME		 ;AN010;=58h
	 mov	 al, GET_NUM_PAGEFRAME		 ;AN010;=01h How many page frames?
	 int	 EMS_INT			 ;AN010;
	 or	 ah, ah 			 ;AN010;
	 jnz	 hkn_err			 ;AN010;
	 cmp	 cx, MAX_NUM_PAGEFRAME		 ;AN010;
	 ja	 hkn_err			 ;AN010; cannot handle this big number
	 push	 cx				 ;AN010;
	 mov	 ah, GET_PAGE_FRAME		 ;AN010;
	 mov	 al, GET_PAGEFRAME_TAB		 ;AN010;
Frame_info_Buffer equ Frame_Info_Buffer	; NASM port label
	 mov	 di, offset Frame_info_Buffer	 ;AN010;
	 int	 EMS_INT			 ;AN010;
	 pop	 cx				 ;AN010;
	 or	 ah, ah 			 ;AN010;
cp_IBM_Err equ Cp_IBM_Err	; NASM port label
	 jnz	 cp_IBM_Err			 ;AN010;
Cp_IBM_ID:					 ;AN010;

;	mov	dx, [es:di]
;	mov	[cs:FIRST_PAGE], dx
;	mov	dx, [es:di+2]
;	mov	[cs:FIRST_PAGE+2], dx

	xor	dx, dx

;	int	3
find_page:
	cmp	word [es:di], 0a000h ; is current page above 640K
	jb	check_next		; NO - goto check_last

	inc	dx		; count the no. of pages above 640K

	cmp	dx, 1
	jne	first_ok

	mov	ax, [es:di]
	mov	[cs:FIRST_PAGE], ax
	mov	ax, [es:di+2]
	mov	[cs:FIRST_PAGE+2], ax

first_ok:
	mov	ax, [cs:FIRST_PAGE]
	cmp	ax, [es:di]	; is this page less than the one we have in
				; FIRST_PAGE
	jbe	check_last	; NO - goto check_last
	mov	ax, [es:di]	; update FIRST_PAGE with this page segment
	mov	[cs:FIRST_PAGE], ax
	mov	ax, [es:di+2]
	mov	[cs:FIRST_PAGE+2], ax
	jmp	check_next
	nop	; identicalise

cp_ibm_err equ Cp_IBM_Err	; NASM port label
hkn_err: jmp	cp_ibm_err
	nop	; identicalise

check_last:
	mov	ax, [cs:LAST_PAGE]	;
	cmp	ax, [es:di]	; is this page greater than the one we have in
				; LAST_PAGE?
	ja	check_next		; NO - goto next
	mov	ax, [es:di]	; update LAST_PAGE with this value.
	mov	[cs:LAST_PAGE], ax
	mov	ax, [es:di+2]
	mov	[cs:LAST_PAGE+2], ax

check_next:
	add	di, 4
	loop	find_page

	cmp	dx, 3			; there should be at least 3 pages
					; above 640K for the buffers to be
					; installed.
	jb	Cp_IBM_Err

	mov	ax, [cs:LAST_PAGE]
	mov	[cs:IBM_Frame_Seg], ax
	mov	ax, [cs:LAST_PAGE+2]
	mov	[cs:Real_IBM_Page_Id], ax
	mov	[cs:NPA640], dx
	clc
Cp_Id_Ret equ Cp_ID_Ret	; NASM port label
	jmp	short Cp_Id_Ret

%ENDIF


;	 cmp	 word ptr [es:di+2], IBM_PAGE_ID ;AN010; the second word is the id
;	 je	 Got_IBM_ID			 ;AN010;
;	 add	 di, 4				 ;AN010; advance to the next row (4 bytes)
;	 loop	 Cp_IBM_ID			 ;AN010;

Cp_IBM_Err:					;AN010;;AN029;
	stc					;AN000;;AN029;
	jmp	short Cp_ID_Ret 		;AN000;;AN029;

;Got_IBM_ID:					 ;AN000;
;	 mov	 ax, word ptr [es:di]		 ;AN010;Physical seg. addr.
;	 mov	 cs:IBM_Frame_Seg, ax		 ;AN000;
;	 clc					 ;AN000;
Cp_ID_Ret:					;AN000;
	pop	di				;AN010;
	pop	dx				;AN000;
	pop	cx				;AN000;
	pop	bx				;AN000;
	pop	ax				;AN000;
	pop	es				;AN000;
	ret					;AN000;
Check_IBM_PageID	endp

;
Save_Map_State	proc				;AN010;
;Function: Save the map state.
;In)
;    EMS_Ctrl_Tab = double word pointer to EMS_state control table address
;    EMS_state_Buf = double word pointer to EMS_MAP_BUFF address
;Out) Map state saved
	push	ax				;AN010;
	push	ds				;AN010;
	push	si				;AN010;
	push	es				;AN010;
	push	di				;AN010;
	lds	si, [cs:EMS_Ctrl_Tab]		;AN010;
	les	di, [cs:EMS_state_Buf]		;AN010;
	mov	ah, EMAP_STATE			;AN010; =4Fh
	mov	al, GET_MAP_STATE		;AN010; =00h
	int	EMS_INT 			;AN010;
	pop	di				;AN010;
	pop	es				;AN010;
	pop	si				;AN010;
	pop	ds				;AN010;
	pop	ax				;AN010;
	ret					;AN010;
Save_Map_State	endp
;
Restore_Map_State	proc			;AN010;
	push	ax				;AN010;
	push	ds				;AN010;
	push	si				;AN010;
	lds	si, [cs:EMS_state_Buf]		;AN010;
	mov	ah, EMAP_STATE			;AN010;
	mov	al, SET_MAP_STATE		;AN010;
	int	EMS_INT 			;AN010;
	pop	si				;AN010;
	pop	ds				;AN010;
	pop	ax				;AN010;
	ret					;AN010;
Restore_Map_State	endp
;
Map_Page	proc	near			;AN000;
;Function: Map the logical page in BX of handle in DX to the physical page 255
;In)
;    BX = logical page number
;    DX = EMS handle
;    EMS_Ctrl_Tab = double word pointer to EMS_state control table address
;    EMS_state_Buf = double word pointer to EMS_MAP_BUFF address
;Out) Logical page mapped into first phsical page frame.
;    AX saved.

	push	ax				;AN000;
	mov	ah, EMAP_L_TO_P 		;AN000;
Real_IBM_PAGE_ID equ Real_IBM_Page_Id	; NASM port label
	mov	al, byte ptr [cs:Real_IBM_PAGE_ID]	 ;AN029;= 255
	int	EMS_INT 			;AN000;
	pop	ax				;AN000;
	ret					;AN000;
Map_Page	endp				;AN000;
;
%endif	; BUF2

Roundup proc
;In: DX;AX - operand
;    CX    - divisor
;    Important: DX should be less than CX.
;out: AX - Quotient (Rounded up)

	div cx					;AN000;
	or  dx, dx				;AN000;
	jz  RU_ret				;AN000;
	inc AX					;AN000;
RU_ret: 					;AN000;
	ret					;AN000;
Roundup endp
;------------------------------------------------------------------------------
;J.K. 5/6/86. IBMSTACK initialization routine.
	%IF	STACKSW
;.SALL

;=== Push trace listing source: stkinit.nas
%include "stkinit.nas" ; NASM included file
;=== Pop trace listing source

;.XALL
	%ENDIF
;------------------------------------------------------------------------------

%if 0
	public	SetDevMark
SetDevMark	proc
;Set the DEVMARK for MEM command.
;In: [MEMHI] - the address to place DEVMARK
;    [MEMLO] = 0
;    AL = ID for DEVMARK_ID
;OUT: DEVMARK established.
;     the address saved in [cs:DevMark_Addr]
;     [MEMHI] increase by 1.

	push	es				;AN005;
	push	cx				;AN005;

	mov	cx, [cs:memhi]			;AN005;
	mov	[cs:DevMark_Addr],cx		;AN005;
	mov	es, cx				;AN005;
	mov	[es:DEVMARK_ID], al		;AN005;
	inc	cx				;AN007;
	mov	[es:DEVMARK_SEG], cx		;AN007;

	pop	cx				;AN005;
	pop	es				;AN005;
	inc	word [cs:memhi]			;AN005;
	ret					;AN005;
SetDevMark	endp
%endif

;*******************************************************************************
;Function: Load  SHARE.EXE, if Big_Media_Flag = 1 and SHARE.EXE has not been   *
;	   loaded yet.							       *
;	   This routine will use the same path for SHELL= command.	       *
;	   If SHELL= command has not been entered, then default to the root    *
;	   directory.							       *
;	   If load fails, then issue message "Warning: SHARE.EXE not loaded"   *
;									       *
;Input:    Big_Media_Flag, COMMND					       *
;Output:   Share.exe loaded if necessary.				       *
;									       *
;*******************************************************************************
LoadShare	proc	near			;AN021;
 assume ds:SYSINITGROUP, es:nothing, ss:SYSINITGROUP
	cmp	byte [Big_Media_Flag], 1		;AN021;
	jne	LShare_Ret			;AN021;
;Check if SHARE is already loaded.
	mov	ax, 1000h			;AN021;multShare installation check
	int	2fh				;AN021;
	cmp	al, 0ffh			;AN021;
	jz	LShare_Ret			;AN021;Share already loaded!
;SHARE not loaded.
	push	cs				;AN021;
	pop	ds				;AN021;
 assume ds:SYSINITGROUP
	push	cs				;AN021;
	pop	es				;AN021;
 assume es:SYSINITGROUP
	mov	si, offset COMMND		;AN021;
	mov	di, offset PathString		;AN021;
LShare_String:					;AN021;
	movsb					;AN021;
	cmp	byte ptr [di-1], 0		;AN021;reached to the end?
LShare_string equ LShare_String	; NASM port label
	jne	LShare_string			;AN021;
	mov	si, offset PathString		;AN021;SI= start of PathString
LShare_Tail:					;AN021;
	dec	di				;AN021;
	cmp	byte ptr [di], "\"		;AN021;
	je	LShare_Got_Tail 		;AN021;
	cmp	byte ptr [di], ":"		;AN021;
	je	LShare_Got_Tail 		;AN021;
	cmp	di, si				;AN021;No path case (e.g. SHELL=command.com)
	je	LShare_Got_Tail_0		;AN021;
	jmp	LShare_Tail			;AN021;
LShare_Got_Tail:				;AN021;di -> "\" or ":"
	inc	di				;AN021;
LShare_Got_Tail_0:				;AN021;
	mov	si, offset LShare		;AN021;
LShare_Set_Filename:				;AN021;
	movsb					;AN021;Tag "SHARE.EXE",0,0Ah to the path.
	cmp	byte ptr [di-1], 0Ah		;AN021;Line feed?
	jne	LShare_Set_Filename		;AN021;
;Now, we got a path,filename with no parameters for SHARE.EXE
	mov	si, offset PathString		;AN021;
	or	word [Install_Flag], SHARE_INSTALL	;AN021;Signals Do_Install_Exec that this is for SHARE.EXE.
	call	Do_Install_Exec 		;AN021;execute it.
	jnc	LShare_Ret			;AN021;No problem
;Load/Exec failed.  Show "Warning: SHARE should be loaded for large media"
	push	cs				;AN021;
	pop	ds				;AN021;
 assume ds:SYSINITGROUP
	mov	dx, offset ShareWarnMsg 	;AN021;WARNING! SHARE should be loaded...
	invoke	Print				;AN021;
LShare_Ret:					;AN021;
	ret					;AN021;
LoadShare	endp				;AN021;

; (no prior section) ; SYSINITSEG	ENDS


global init2_relocate_device
global init2_SNextMCB
extern dosentry_xmsentry
%include "codesw.mac"
%include "init.asm"

sysinit_msg:
.warn_upb:		db "Warning: init unable to relocate UPBs!",13,10
.warn_upb.size: equ $ - .warn_upb
.warn_dpb:		db "Warning: init unable to relocate DPBs!",13,10
.warn_dpb.size: equ $ - .warn_dpb
.nullbyte:		db 0

	   END
