;	PAGE	,132			;
	%warning out: ...MSINIT.ASM
;=======================================================
;REVISION HISTORY:
;AN000; - NEW Version 4.00. J.K.
;AC000; - Modified Line 4.00. J.K.
;ANxxx; - PTMyyy
;==============================================================================
;AN001; P87 Set the value of MOTOR START TIME Variable		    6/25/87 J.K.
;AN002; P40 Boot from the system with no floppy diskette drives     6/26/87 J.K.
;AN003; D9  Double Word MOV instruction for 386 based machine	    7/1/87  J.K.
;AN004; D64 Extend DOS 3.3 FAT tables to 64 K entries.		    7/8/87  J.K.
;AN005; D113 Disable I/O access to unformatted media		    9/03/87 J.K.
;AN006; p941 D113 does not implemented properly.		    9/11/87 J.K.
;AN007; p969 Should Honor OS2 boot record.			    9/11/87 J.K.
;AN008; p985 Allow I/O access to unformtted media		    9/14/87 J.K.
;AN009; p1535 Disallow I/O access to unformtted media		   10/15/87 J.K.
;AN010; p2349 Cover DOS 3.3 and below FDISK bug 		   11/10/87 J.K.
;AN011; P2431 OS2 boot record version number is at offset 7 (not 8)11/12/87 J.K.
;AN012; P2900 DOS 4.0 does not recognize 3.0 formatted media	   12/18/87 J.K.
;AN013; P3409 Extended keyboard not recognized			   02/05/88 J.K.
;AN014; D486 Share installation for big media			   02/23/88 J.K.
;AN015; P3929 Boot record buffer overlaps MSBIO code		   03/18/88 J.K.
;==============================================================================

	itest equ 0

	%include "entryseg.nas"
	%include "dcodeseg.nas"
	%include "lmacros3.mac"

addsection DOSSTART, align=16 PUBLIC class=DOSSTART
; (no prior section) ; DOSSTART		ENDS

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

	%include "lstruct.mac"
	%include "sysinisw.mac"
	%include "msgroup.mac"	;DEFINE CODE SEGMENT

	addsection BIOCODE
	usesection DOSENTRYINIT

	%include "msdskpr.mac"
	%include "msequ.mac"
	%include "msmacro.mac"
	%include "msextrn.mac"
	%include "biostruc.mac"
	%include "cmosequ.mac"
	%include "cputype.mac"
	%include "arena.mac"
	%include "codesw.mac"
	%include "haltflag.mac"
 global flag_no_halt_tagcrash, flag_no_halt_mcb
 global flag_no_halt_hmcb, flag_no_halt_hmcb_free
 extern haltflags

	usesection DOSENTRYINIT

		; For lDOS lCFG block
LCFG_CheckDebugger	equ 20
LCFG_Verbose		equ 21
LCFG_ScanMode		equ 22
LCFG_HaltFlag		equ 26
LCFG_DBG_CHECK		equ 1		; flag: check debugger present, run int3
LCFG_DBG_ASSUME		equ 2		; flag: default to assume debugger present
LCFG_DBG_ONLY_VALID	equ 4
LCFG_DBG_ONLY_IISP	equ 8
; For the FreeDOS kernel the CONFIG block CheckDebugger value is
;  as yet used as an ordinal: < 1, == 1, or > 1. However, we use
;  ours here as 8 independent flags that can be set individually.

; THE FOLLOWING LABEL DEFINES THE END OF THE AT ROM PATCH.  THIS IS USED AT
; CONFIGURATION TIME.
;J.K. 10/2/86 Warning!!! This code will be dynamically relocated by MSINIT.

	PUBLIC	ENDATROM		;NOT REFERENCES EXTERNALLY, BUT
					; JUST TO CAUSE ENTRY IN LINK MAP
ENDATROM LABEL	BYTE


usesection BIOCODE

;CMOS Clock setting support routines used by MSCLOCK.

	EXTRN	base_century:byte
	EXTRN	base_year:byte
	EXTRN	month_tab:byte

	public	near_daycnt_to_day	;J.K. 4/30/86 for real time clock support
near_daycnt_to_day	proc	near	;J.K. 4/30/86 for real time clock support
;Entry: [DAYCNT] = number of days since 1-1-80
;Return: CH - centry in BCD, CL - year in BCD, DH - month in BCD, DL - day in BCD

 assume ds:nothing, es:nothing, ss:nothing
	push ds
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP

daycnt equ DAYCNT	; NASM port label
	push	word [daycnt]		;save daycnt
	cmp	word [daycnt], (365*20+(20/4)) ;# of days from 1-1-1980 to 1-1-2000
	jae	century20
	mov	byte [base_century], 19
	mov	byte [base_year], 80
	jmp	years
century20:				;20th century
	mov	byte [base_century], 20
	mov	byte [base_year], 0
	sub	word [daycnt], (365*20+(20/4)) ;adjust daycnt
years:
	xor	dx, dx
	mov	ax, [daycnt]
	mov	bx, (366+365*3) 	;# of days in a Leap year block
	div	bx			;AX = # of leap block, DX = daycnt
	mov	[daycnt], dx		;save daycnt left
;	or	ah, ah			;ax should be less than 256
;	jz	OK1
;	 jmp	 Erroroccur
;OK1:
	mov	bl,4
	mul	bl			;AX = # of years. Less than 100 years!
	add	[base_year], al		;So, ah = 0. Adjust year accordingly.
	inc	word [daycnt]			;set daycnt to 1 base
	cmp	word [daycnt], 366		;the daycnt here is the remainder of the leap year block.
	jbe	Leapyear		;So, it should within 366+355+355+355 days.
	inc	byte [base_year]		;First if daycnt <= 366, then leap year
	sub	word [daycnt], 366		;else daycnt--, base_year++;
					;And the next three years are regular years.
	mov	cx, 3
Regularyear:
	cmp	word [daycnt], 365		;for(i=1; i>3 or daycnt <=365;i++)
YearDone equ Yeardone	; NASM port label
	jbe	YearDone		;{if (daycnt > 365)
	inc	byte [base_year]		;  { daycnt -= 365
	sub	word [daycnt], 365		;  }
regularyear equ Regularyear	; NASM port label
	loop	regularyear		;}
;	 jmp	 Erroroccur		 ;cannot come to here
Leapyear:
	mov	byte [month_tab+1],29 ;leap year. change the month table.
Yeardone:
	xor	bx,bx
	xor	dx,dx
	mov	ax, [daycnt]
	mov	si, offset month_tab
	mov	cx, 12
Months:
	inc	bl			;
	mov	dl, byte ptr [si]	;compare daycnt for each month until fits
	cmp	ax, dx			;dh=0.
	jbe	Month_done
	inc	si			;next month
	sub	ax, dx			;adjust daycnt
	loop	Months
;	 jmp	 Erroroccur
Month_done:
	mov	byte [month_tab+1], 28 ;restore month table value
	mov	dl, bl
	mov	dh, [base_year]
	mov	cl, [base_century]	;now, al=day, dl=month,dh=year,cl=century
	call	near_bin_to_bcd		; convert "day" to bcd
	xchg	dl, al			;dl = bcd day, al = month
	call	near_bin_to_bcd
	xchg	dh, al			;dh = bcd month, al = year
	call	near_bin_to_bcd
	xchg	cl, al			;cl = bcd year, al = century
	call	near_bin_to_bcd
	mov	ch, al			;ch = bcd century
	pop	word [daycnt]		;restore original value
	pop ds
 assume ds:nothing
	ret
near_daycnt_to_day	endp

	public	near_bin_to_bcd
near_bin_to_bcd	proc	near		;J.K. 4/30/86 for real time clock support
;Convert a binary input in AL (less than 63h or 99 decimal)
;into a bcd value in AL.  AH destroyed.
	push	cx
	xor	ah, ah
	mov	cl, 10
	div	cl		;al - high digit for bcd, ah - low digit for bcd
	mov	cl, 4
	shl	al, cl		;mov the high digit to high nibble
	or	al, ah
	pop	cx
	ret
near_bin_to_bcd	endp

	EXTRN  BIN_DATE_TIME:BYTE
	EXTRN  MONTH_TABLE:WORD
	EXTRN  DAYCNT2:WORD
	EXTRN  FEB29:BYTE
	EXTRN  TimeToTicks:Word 	;indirect intra-segment call address

;
; THE K09 REQUIRES THE ROUTINES FOR READING THE CLOCK BECAUSE OF THE SUSPEND/
; RESUME FACILITY. THE SYSTEM CLOCK NEEDS TO BE RESET AFTER RESUME.
;

; THE FOLLOWING ROUTINE IS EXECUTED AT RESUME TIME WHEN THE SYSTEM
; POWERED ON AFTER SUSPENSION. IT READS THE REAL TIME CLOCK AND
; RESETS THE SYSTEM TIME AND DATE, AND THEN IRETS.

relocated i6C
INT6C	PROC	FAR
 assume ds:nothing, es:nothing, ss:nothing
	call biocode_get_ds_dosbiodata
 assume ds:DOSGROUP

	CALL	near_read_real_date	; GET THE DATE FROM THE CLOCK
	MOV	[DAYCNT],SI		; UPDATE DOS COPY OF DATE
	CALL	near_read_real_time	; GET THE TIME FROM THE RTC
;SB33019***************************************************************
	MOV	AH, 01h 		; COMMAND TO SET THE TIME      ;SB;3.30
	INT	1Ah			; CALL ROM-BIOS TIME ROUTINE   ;SB;3.30
;SB33019***************************************************************
	iret

INT6C	ENDP


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


	usesection DOSENTRYINIT

;*********************************************************
;	SYSTEM INITIALIZATION
;
;	THE ENTRY CONDITIONS ARE ESTABLISHED BY THE BOOTSTRAP
;	LOADER AND ARE CONSIDERED UNKNOWN. THE FOLLOWING JOBS
;	WILL BE PERFORMED BY THIS MODULE:
;
;	1.	ALL DEVICE INITIALIZATION IS PERFORMED
;	2.	A LOCAL STACK IS SET UP AND DS:SI ARE SET
;		TO POINT TO AN INITIALIZATION TABLE. THEN
;		AN INTER-SEGMENT CALL IS MADE TO THE FIRST
;		BYTE OF THE DOS
;	3.	ONCE THE DOS RETURNS FROM THIS CALL THE DS
;		REGISTER HAS BEEN SET UP TO POINT TO THE START
;		OF FREE MEMORY. THE INITIALIZATION WILL THEN
;		LOAD THE COMMAND PROGRAM INTO THIS AREA
;		BEGINNING AT 100 HEX AND TRANSFER CONTROL TO
;		THIS PROGRAM.
;
;********************************************************

; FIRST LOCATION OF FREEABLE SPACE (?)
; This is the same offset in DOSENTRY as ENDATROM.
	EVENB
checkdebugger:	db 0

addsection DOSDATAMCB, PUBLIC class=DOSDATAMCB align=16
addsection SYSINITMCB, PUBLIC class=SYSINITMCB align=16
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 SYSINITTRAIL

	align 2, db 0
nextupb:	dd 0
auxbuff_segorsel:
Init_BootSeg:	dw ?			; seg addr of buffer for reading boot record
FakeFloppyDrv:	db 0			; If 1, then No diskette drives in the system.
FBIGFAT:	db 0			; FLAGS FOR DRIVE

	evenb
BDS_diskette_template:
	dw	-1, -1			;LINK TO NEXT STRUCTURE
	DB	0			;INT 13 DRIVE NUMBER
	DB	0			;LOGICAL DRIVE LETTER
	DW	512			;PHYSICAL SECTOR SIZE IN BYTES
	DB	-1			;SECTORS/ALLOCATION UNIT
	DW	1			;RESERVED SECTORS FOR DOS
	DB	2			;NO. ALLOCATION TABLES
	DW	64			;NUMBER DIRECTORY ENTRIES
	DW	9*40			;NUMBER SECTORS (AT 512 BYTES EA.)
	DB	00000000B		;MEDIA DESCRIPTOR, INITIALLY 00H.
	DW	2			;NUMBER OF FAT SECTORS
	DW	9			;SECTOR LIMIT
	DW	1			;HEAD LIMIT
	DW	0			;HIDDEN SECTOR COUNT (low word)
	dw	0			;J.K. Hidden sector (high)
	dw	0			;J.K. Number sectors (low)
	dw	0			;J.K. Number sectors (high)
	DB	0			; TRUE => LARGE FATS
	DW	0			;OPEN REF. COUNT

	DB	3			;FORM FACTOR
	DW	0020H			;VARIOUS FLAGS
;	DB	9 DUP (0)		;RESERVED FOR FUTURE USE
	DW	40			; NUMBER OF CYLINDERS
; RECOMMENDED BPB FOR DRIVE.
	DW	512			;BYTES PER SECTOR
	DB	1			;SECTORS/ALLOCATION UNIT
	DW	1			;RESERVED SECTORS FOR DOS
	DB	2			;NO. ALLOCATION TABLES
	DW	0E0H			;NUMBER DIRECTORY ENTRIES
	DW	9*40			;NUMBER SECTORS (AT 512 BYTES EA.)
	DB	0F0H			;MEDIA DESCRIPTOR, INITIALLY F0H.
	DW	2			;NUMBER OF FAT SECTORS
	DW	9			;SECTOR LIMIT
	DW	2			;HEAD LIMIT
	DW	0			;HIDDEN SECTOR COUNT(low)
	dw	0			;J.K. Hidden sector count (high)
	dw	0			;J.K. Number sectors (low)
	dw	0			;J.K. Number sectors (high)
	DB	6 DUP (?)
	DB	-1			;LAST TRACK ACCESSED ON THIS DRIVE
	DW	-1			;KEEP THESE TWO CONTIGUOUS (?)
	DW	-1
	DB	"NO NAME    ",0         ;VOLUME ID FOR THIS DISK
	dd	0	     ;Current volume serial number from Boot record
	db	"FAT12   ",0 ;Current file system id from Boot record

	evenb
; THE FOLLOWING TWO BYTES ARE USED TO SAVE THE INFO RETURNED BY INT 13, AH = 8
; CALL TO DETERMINE DRIVE PARAMETERS.
NUM_HEADS dw	2			; NUMBER OF HEADS RETURNED BY ROM
SEC_TRK   DB	9			; SEC/TRK RETURNED BY ROM
NUM_CYLN  DB	40			; NUMBER OF CYLINDERS RETURNED BY ROM


EXT_BOOT_SIG_OFF equ 11+BPB_TYPE_struc_size ;AN000; 3 byte jmp+8 byte OEM +extended bpb


	EVENB
DISKTABLE DW	512,	0100H,	64,	0
	DW	2048,	0201H,	112,	0
	DW	8192,	0402H,	256,	0
	DW	32680,	0803H,	512,	0      ;Warning !!! Old values
;	DW	20740,	0803H,	 512,	0	;PTM P892 J.K. 12/3/86 DOS 3.3 will use this.
						;J.K.3/16/87 P54 Return back to old value for compatibility.!!!
	DW	65535,	1004H,	1024,	0

;DISKTABLE2 DW	 32680,  0803H,  512,	 0	;Warning !!! Old values  ;J.K.3/16/87 P54 Return to old value!!!
;DISKTABLE2 DW	 20740,  0803H,  512,	 0	 ;PTM p892 J.K. 12/3/86 DOS 3.3 will use this.
;	 DW	 65535,  0402H,  512,	 FBIG
;AN000;
;DISKTABLE2 dw	 0, 32680, 0803h, 512, 0	 ;table with the assumption of the
;	    dw	2h, 0000h, 0402h, 512, FBIG	 ;total fat size <= 64KB.
;	    dw	4h, 0000h, 0803h, 512, FBIG	 ;-This will cover upto 134 MB
;	    dw	8h, 0000h, 1004h, 512, FBIG	 ;-This will cover upto 268 MB
;	    dw 10h, 0000h, 2005h, 512, FBIG	 ;-This will cover upto 536 MB

;AN004 Default DiskTable under the assumption of Total FAT size <= 128 KB, and
;	the maxium size of FAT entry = 16 Bit.
DiskTable2  dw	 0, 32680, 0803h, 512, 0	;For compatibility.
	    dw	4h, 0000h, 0402h, 512, FBIG	;Covers upto 134 MB media.
	    dw	8h, 0000h, 0803h, 512, FBIG	;	upto 268 MB
	    dw 10h, 0000h, 1004h, 512, FBIG	;	upto 536 MB
	    dw 20h, 0000h, 2005h, 512, FBIG	;	upto 1072 MB
	    dw 40h, 0000h, 4006h, 512, FBIG	;	upto 2144 MB
	    dw 80h, 0000h, 8007h, 512, FBIG	;	upto 4288 MB...

	align 2, db 0
Mini_BPB_ptr	dw	DSKDRVS		;temporary variable used to save the
					;Mini Disk BPB pointer address in DskDrvs.
DSKDRVS	times 32 dw 0
.end:
	dw 0				; allow overflowing entry


usesection DOSENTRYINIT

BIOS_DATE DB	'01/10/84',0     ;This is used for checking AT ROM BIOS date.


usesection SYSINITTRAIL

; THE FOLLOWING ARE THE RECOMMENDED BPBS FOR THE MEDIA THAT WE KNOW OF SO
; FAR.

; 48 TPI DISKETTES
	EVENB
BPB48T	DW	512
	DB	2
	DW	1
	DB	2
	DW	112
	DW	2*9*40
	DB	0FDH
	DW	2
	DW	9
	DW	2
	DW	0
	dw	0		;AN000;  hidden sector High
	dd	0		;AN000;  extended total sectors

; 96TPI DISKETTES
	EVENB
BPB96T	DW	512
	DB	1
	DW	1
	DB	2
	DW	224
	DW	2*15*80
	DB	0F9H
	DW	7
	DW	15
	DW	2
	DW	0
	dw	0		;AN000;  hidden sector High
	dd	0		;AN000;  extended total sectors

BPBSIZ	equ	$-BPB96T

; 3 1/2 INCH DISKETTE BPB

	EVENB
BPB35	DW	512
	DB	2
	DW	1			; DOUBLE SIDED WITH 9 SEC/TRK
	DB	2
	DW	70h
	DW	2*9*80
	DB	0F9H
	DW	3
	DW	9
	DW	2
	DW	0
	dw	0		;AN000;  hidden sector High
	dd	0		;AN000;  extended total sectors

	EVENB
BPBTABLE DW	BPB48T			; 48TPI DRIVES
	DW	BPB96T			; 96TPI DRIVES
	DW	BPB35			; 3.5" DRIVES
					;DW	 BPB48T 	     ; NOT USED - 8" DRIVES
					;DW	 BPB48T 	     ; NOT USED - 8" DRIVES
					;DW	 BPB48T 	     ; NOT USED - HARD FILES
					;DW	 BPB48T 	     ; NOT USED - TAPE DRIVES
					;DW	 BPB48T 	     ; NOT USED - OTHER

	usesection DOSENTRYINIT

%if 0
	align 2, db 0
PATCHTABLE LABEL BYTE
	DW	10,MEDIA_PATCH
	DW	3,GETBP1_PATCH
	DW	3,SET_PATCH
	DW	3,DISKIO_PATCH
	DW	3,DSKERR_PATCH
	DW	3,DSKERR_LBA_PATCH
	DW	3,CHANGED_PATCH
	DW	3,INIT_PATCH
	DW	0
%endif

	ASSUME	DS:NOTHING,ES:NOTHING

		; INP:	from lkernpl
		;	cx:di -> lCFG block passed from drkernpl or inicomp
		;	dl = load unit
		;	ds:bp = ss:bp -> load partition boot sector with (E)BPB
	PUBLIC	INIT
INIT	PROC	NEAR
	MESSAGE FTESTINIT,<"IBMBIO",CR,LF>
	CLI
 assume ds:nothing, es:nothing, ss:nothing

		; Get lCFG items to use later.
	mov es, cx
 assume es:nothing
	mov al, byte [es:di + LCFG_CheckDebugger]
	mov byte [cs:checkdebugger], al
	push word [es:di + LCFG_Verbose]
	push word [es:di + LCFG_ScanMode]
	push word [es:di + LCFG_HaltFlag]

		; init pointers needed by relocation (i13 etc)
	xor ax, ax
	mov ds, ax
 assume ds:IVT
	mov ax, DOSSTART
	mov word [31h * 4 + 2], ax
	mov ds, ax
 assume ds:DOSGROUP
	mov word [dosdata_to_doscode], DOSCODEGROUP
	pop word [haltflags]
	mov ax, DOSENTRY
	mov ds, ax
 assume ds:DOSENTRYGROUP
%if _RELOCATEDOSCODE
 extern ..@dosentry_doscode_segment
	mov word [..@dosentry_doscode_segment], DOSCODEGROUP
%endif


 extern sysinit_bootdrive_hidden, sysinit_bootdrive_unit

init_bootdrive:
	mov ax, SYSINITSEG
	mov es, ax			; modified to use ax
					;  (preserve dl = load unit)
 assume es:SYSINITGROUP
	pop word [es:load_mode]
 extern verbose_mode
	pop word [es:verbose_mode]

	mov ax, word [bp + bsBPB + bpbHiddenSectors + 2]
	mov word [es:sysinit_bootdrive_hidden + 2], ax
	mov ax, word [bp + bsBPB + bpbHiddenSectors]
	mov word [es:sysinit_bootdrive_hidden], ax
	mov byte [es:sysinit_bootdrive_unit], dl


 extern kernelcommandline
 extern kernelcommandline.end
 extern commandnames

		; copied from ecm contribution to FreeDOS kernel.asm
initialise_command_line_buffer:
	mov ax, sp			; ax = original sp
	push ss
	pop ds
 assume ds:nothing
	mov si, bp			; ds:si = original ss:bp

		; Note that the kernel command line buffer in
		;  the init data segment is pre-initialised to
		;  hold 0x00 0xFF in the first two bytes. This
		;  is used to indicate no command line present,
		;  as opposed to an empty command line which
		;  will hold 0x00 0x00.
		; If any of the branches to .none are taken then
		;  the buffer is not modified so it retains the
		;  0x00 0xFF contents.
	cmp si, - lsvCommandLine.start	; buffer fits below ss:bp ?
	jb .none			; no -->
	cmp word [si + lsvCommandLine.signature], lsvclSignature
					; signature passed to us ?
	jne .none			; no -->
	lea si, [si + lsvCommandLine.start]
					; -> command line buffer
	cmp ax, si			; stack top starts below-or-equal buffer ?
	ja .none			; no -->
	mov di, kernelcommandline	; our buffer
	mov cx, lsvclBufferLength - 1
	xor ax, ax
	push di
	rep movsb		; copy up to 255 bytes
	stosb			; truncate
	pop di
	mov ch, 1		; cx = 256
	repne scasb		; scan for terminator
	rep stosb		; clear remainder of buffer
				; (make sure we do not have 0x00 0xFF
				;  even if the command line given is
				;  actually the empty string)
.none:


init_cmdline_terminators:
	push es
	pop ds
 assume ds:SYSINITGROUP

	mov di, kernelcommandline
	mov si, di
	mov cx, 256
	xor ax, ax
	repne scasb
	dec di
	mov word [kernelcommandline.end], di
	mov di, si		; -> start
	push si
@@:
	cmp si, word [kernelcommandline.end]
	jae @F
	lodsb			; get text
	stosb			; store text
	cmp al, ';'		; was semicolon ?
	jne @B			; no, loop -->
	cmp byte [si], ';'	; escaped ?
	je .escapesemicolon	; yes -->
	mov byte [di - 1], 0	; no, treat as terminator
	jmp @B

.escapesemicolon:
	inc si			; -> past next semicolon
	jmp @B

@@:
	movsb			; copy the NUL
	dec di			; -> at the NUL
	mov word [kernelcommandline.end], di
				; update the end offset (<= before)
	pop si

parse_config:
.loopcommand:
	db __TEST_IMM8		; skip inc
@@:
	inc si
	cmp byte [si], 32
	je @B
	cmp byte [si], 9
	je @B

	cmp byte [si], 0	; empty ?
	je .donename		; yes -->

	mov di, commandnames
.loopname:
	mov ax, [di]
	inc ax
	jz .unknownname
	scasw			; skip function pointer field
	scasw			; skip content field
	push si
	push ax
	push di
	mov di, [di]
.comparename:
	lodsb
	cmp al, 0
	je .next
	cmp al, 'a'
	jb @F
	cmp al, 'z'
	ja @F
	sub al, 20h
@@:
	scasb
	jne .next
	cmp byte [di], 0
	jne .comparename
	lodsb
	cmp al, 0
	je .found
	cmp al, 32
	je .found
	cmp al, 9
	je .found
	cmp al, '='
	je .found
.next:
	pop di
	pop ax
	pop si
	scasw			; skip name field
	jmp .loopname

.unknownname:
	push si

extern unknown_command
	mov si, unknown_command
	mov bx, 7
	db __TEST_IMM16		; skip int
@@:
	int 10h
	lodsb
	mov ah, 0Eh
	test al, al
	jnz @B
	pop si
	push si
@@:
	lodsb
	cmp al, 9
	je @B
	cmp al, 32
	je @B
	dec si
	db __TEST_IMM16		; skip int
@@:
	int 10h
	lodsb
	mov ah, 0Eh
	test al, al
	jz @F
	cmp al, 32
	jb .ctrl
	cmp al, 127
	jb @B
.ctrl:
	mov al, '.'
	jmp @B
@@:
	pop si
	mov ax, 0E00h + '"'
	int 10h
	mov ax, 0E00h + 13
	int 10h
	mov ax, 0E00h + 10
	int 10h
	jmp .donename

@@:
	lodsb
.found:
	cmp al, 32
	je @B
	cmp al, 9
	je @B
	cmp al, '='
	jne @FF
@@:
	lodsb
@@:
	cmp al, 32
	je @BB
	cmp al, 9
	je @BB

	dec si			; -> content
	pop di
	mov word [di - 2], si
	pop ax
		; INP:	si -> past an optional equals sign and blanks
		;	di -> -> command name
		; CHG:	ax, si, di, cx, bx, dx, bp
		; STT:	ds = es => SYSINIT
		;	cs => DOSENTRY
	call ax
	pop si
.donename:
@@:
	lodsb
	cmp al, 0
	jne @B
	cmp si, word [kernelcommandline.end]
	jbe .loopcommand		; (ZR means an empty command at end)


init_orig13:
	XOR	AX,AX
	MOV	DS,AX
 assume ds:IVT
	mov ch, 0

;
; PRESERVE ORIGINAL INT 13 VECTOR
;   WE NEED TO SAVE INT13 IN TWO PLACES IN CASE WE ARE RUNNING ON AN AT.
; ON ATS WE INSTALL THE IBM SUPPLIED ROM_BIOS PATCH DISK.OBJ WHICH HOOKS
; INT13 AHEAD OF ORIG13.  SINCE INT19 MUST UNHOOK INT13 TO POINT TO THE
; ROM INT13 ROUTINE, WE MUST HAVE THAT ROM ADDRESS ALSO STORED AWAY.
;
	MOV	AX,[13H*4]
	MOV	WORD PTR [cs:ORIG13],AX
	MOV	AX,[13H*4+2]
	MOV	WORD PTR [cs:ORIG13+2],AX

init_irt:
 extern InterruptRestorationTable
	push cs
	pop es			; => IRT
 assume es:DOSENTRYGROUP
	cld
	mov si, InterruptRestorationTable	; access with es
.:
	xor ax, ax
	es lodsb
	cmp al, -1
	je .done
	xchg di, ax		; di = interrupt number
	add di, di
	add di, di		; ds:di -> interrupt vector
	xchg si, di		; es:di -> IRT, ds:si -> vector
	movsw
	movsw
	xchg si, di
	jmp .
.done:

;
; SET UP INT 13 FOR NEW ACTION
;
extern msdisk_i13
	MOV	WORD PTR [13H*4],OFFSET msdisk_i13
	MOV	[13H*4+2],CS

;
; SET UP INT 19 FOR NEW ACTION
;
extern i19
	MOV	WORD PTR [19H*4],OFFSET i19
	MOV	[19H*4+2],CS
	STI
	INT	11H			;GET EQUIPMENT STATUS
;J.K.6/24/87 We have to support a system that does not have any diskette
;drives but only hardfiles.  This system will IPL from the hardfile.
;If the equipment flag bit 0 is 1, then the system has diskette drive(s).
;Otherwise, the system only have hardfiles.
;Important thing is that still, for compatibility reason, the drive letter
;for the hardfile start from "C".  So, we still need to allocate dummy BDS
;drive A and driver B.	In SYSINIT time, we are going to set CDS table entry
;of DPB pointer for these drives to 0, so any user attempt to access this
;drives will get "Invalid drive letter ..." message.  We are going to
;establish "FAKEFLOPPYDRV" flag.  ***SYSINIT module should call INT 11h to check
;if there are any diskette drivers in the system or not.!!!***

;SB34INIT001**************************************************************
;SB	check the register returned by the equipment determination interrupt
;SB	we have to handle the case of no diskettes in the system by faking
;SB	two dummy drives.
;SB	if the register indicates that we do have floppy drives we don't need
;SB	to do anything special.
;SB	if the register indicates that we don't have any floppy drives then
;SB	what we need to do is set the FakeFloppyDrv variable, change the 
;SB	register to say that we do have floppy drives and then go to execute
;SB	the code which starts at NOTSINGLE.  This is because we can skip the
;SB	code given below which tries to find if there are one or two drives
;SB	since we already know about this.  6 LOCS

	test	al, 1
	jnz	DO_FLOPPY
	mov	ax, SYSINITSEG
	mov	ds, ax
 assume ds:SYSINITGROUP
	mov	al, 1			; set to indicate 2 floppies 
	mov	[FakeFloppyDrv], al	; fake floppy
	jmp	short NOTSINGLE

DO_FLOPPY:

;SB34INIT001**************************************************************
   ;
   ; Determine if there are one or two diskette drives in system
   ;
	ROL	AL,1			;PUT BITS 6 & 7 INTO BITS 0 & 1
	ROL	AL,1
	AND	al, 3			;ONLY LOOK AT BITS 0 & 1
	JNZ	NOTSINGLE		;ZERO MEANS SINGLE DRIVE SYSTEM
	INC	AX			;PRETEND IT'S A TWO DRIVE SYSTEM
	call dosentry_init_get_ds_dosbiodata
 assume ds:DOSGROUP
	INC	byte [SINGLE]		;REMEMBER THIS
NOTSINGLE:
	push cs
	pop ds
 assume ds:DOSENTRYGROUP

	INC	AX			;AX HAS NUMBER OF DRIVES, 2-4
					;IS ALSO 0 INDEXED BOOT DRIVE IF WE
					;  BOOTED OFF HARD FILE
	MOV	CL,AL			;CH IS FAT ID, CL # FLOPPIES
	TEST	DL,80H			;BOOT FROM FLOPPY ?
	JNZ	GOTHRD			;NO.
	XOR	AX,AX			;INDICATE BOOT FROM DRIVE A
GOTHRD:
;
;   AX = 0-BASED DRIVE WE BOOTED FROM
;   CL = NUMBER OF FLOPPIES INCLUDING FAKE ONE
;   CH = MEDIA BYTE
;
	MESSAGE FTESTINIT,<"INIT",CR,LF>
	XOR	DX,DX

	PUSH	CX			;SAVE NUMBER OF FLOPPIES AND MEDIA BYTE
	MOV	AH,CH			;SAVE FAT ID TO AH
	PUSH	AX			;SAVE BOOT DRIVE NUMBER, AND MEDIA BYTE
;J.K. Let Model_byte, Secondary_Model_Byte be set here!!!
;SB33020******************************************************************
	stc
	mov	ah,0c0h 		; return system environment    ;SB;3.30
	int	15h			; call ROM-Bios routine        ;SB;3.30
;SB33020******************************************************************
	call dosentry_init_get_ds_dosbiodata
 assume ds:DOSGROUP
	jc	No_Rom_System_Conf	; just use Model_Byte
	test	ah, ah			; double check
	jnz	No_Rom_System_Conf
	mov	al, [ES:BX + bios_SD_modelbyte] ;get the model byte
	mov	[Model_Byte], al
	mov	al, [ES:BX + bios_SD_scnd_modelbyte] ;secondary model byte
	mov	[Secondary_Model_Byte], al
	jmp	short Turn_Timer_On
No_Rom_System_Conf:
	MOV	SI,0FFFFH		;MJB001
	MOV	ES,SI			;MJB001
 assume es:nothing
	MOV	AL,[ES:0EH]		; GET MODEL BYTE ARR 2.41
MODEL_BYTE equ Model_Byte	; NASM port label
	MOV	[MODEL_BYTE],AL	      ; SAVE MODEL BYTE ARR 2.41
Turn_Timer_On:
	MOV	AL,EOI
	OUT	AKPORT,AL		;TURN ON THE TIMER

;     NOP out the double word MOV instruction in MSDISK, if
;     this is not a 386 machine...
	Get_CPU_Type			; macro to determine cpu type
	cmp	al, 2			; is it a 386?
	jne	Skip_Patch_DoubleWordMov; no: skip the patch

Patch_DoubleWordMov:
 extern dosbiodata_have_386
	not byte [dosbiodata_have_386]	; = 0FFh
Skip_Patch_DoubleWordMov:
	MESSAGE FTESTINIT,<"COM DEVICES",CR,LF>
;SB33IN1*********************************************************

	mov	si,offset COM4DEV 
	call	AUX_INIT
	mov	si,offset COM3DEV
	call	AUX_INIT
;SB33IN1*********************************************************
	MOV	SI,OFFSET COM2DEV
	CALL	AUX_INIT		;INIT COM2
	MOV	SI,OFFSET COM1DEV
	CALL	AUX_INIT		;INIT COM1

	MESSAGE FTESTINIT,<"LPT DEVICES",CR,LF>
	MOV	SI,OFFSET LPT3DEV
	CALL	PRINT_INIT		;INIT LPT3
	MOV	SI,OFFSET LPT2DEV
	CALL	PRINT_INIT		;INIT LPT2
	MOV	SI,OFFSET LPT1DEV
	CALL	PRINT_INIT		;INIT LPT1

	XOR	DX,DX
	MOV	DS,DX			;TO INITIALIZE PRINT SCREEN VECTOR
	MOV	ES,DX
 assume ds:IVT, es:IVT

	XOR	AX,AX
	MOV	DI,INITSPOT
	STOSW				;INIT FOUR BYTES TO 0
	STOSW

	MOV	AX,CS			;FETCH SEGMENT

extern i1B
	MOV	WORD [BRKADR], i1B	;BREAK ENTRY POINT
	MOV	[BRKADR+2],AX		;VECTOR FOR BREAK

;*********************************************** ARR 2.15
; SINCE WE'RE FIRST IN SYSTEM, NO NEED TO CHAIN THIS.
;	CLI				; ARR 2.15 DON'T GET BLOWN
;	MOV	DS:WORD PTR TIMADR,OFFSET TIMER ; ARR 2.15 TIMER ENTRY POINT
;	MOV	DS:TIMADR+2,AX		; ARR 2.15 VECTOR FOR TIMER
;	STI
;*********************************************** ARR 2.15

; BAS DEBUG
extern i29
	MOV	WORD [CHROUT*4], i29
	MOV	WORD PTR [CHROUT*4+2],AX

extern entry_iret
	MESSAGE FTESTINIT,<"INTERRUPT VECTORS",CR,LF>
	MOV	BX, entry_iret		;WILL INITIALIZE REST OF INTERRUPTS

	mov di, 4 * 4

	push ax				; preserve segment
	push bx				; preserve offset
debugger_check:
	mov al, byte [cs:checkdebugger]
	test al, LCFG_DBG_ONLY_VALID
	jz @F
		; ds => IVT
	cmp word [3 * 4], -1
	je .nocheck
	cmp word [3 * 4 + 2], 0
	je .nocheck
@@:
	test al, LCFG_DBG_ONLY_IISP
	jz @F
		; ds => IVT
	les bx, [3 * 4]			; es:bx -> int 3 handler
 assume es:nothing
	cmp bx, -18			; valid ? (could tear word access ?)
	ja .nocheck			; no, cannot be a valid IISP header -->
	cmp word [es:bx + 6], "KB"	; signature present ?
	jne .nocheck			; no -->
@@:
	test al, LCFG_DBG_CHECK
	jnz .check
.nocheck:
	mov byte [cs:.patch], 90h	; do not check
	jmp @F				; (flush queue for the SMC)
@@:
.check:
	push ds
	pop es
 assume es:IVT
	test al, LCFG_DBG_ASSUME	; (NC)
	jz .runint3			; if to assume off --> (NC)
	stc				; assume on (CY)
.runint3:
.patch:	int3				; SMC: patched to NOP if not to run int3
	jc debugger_detected

debugger_disabled:
	mov di, 4 * 1
	pop bx
	pop ax				; = segment

	XCHG	AX,BX
	STOSW				;LOCATION 4
	XCHG	AX,BX
	STOSW				;INT 1		;LOCATION 6
	ADD	DI,4
	XCHG	AX,BX
	STOSW				;LOCATION 12
	XCHG	AX,BX
	STOSW				;INT 3		;LOCATION 14

	db 0A9h				; test ax, imm16 (skip pop, pop)
debugger_detected:
	pop bx
	pop ax
	XCHG	AX,BX
	STOSW				;LOCATION 16
	XCHG	AX,BX
	STOSW				;INT 4		;LOCATION 18

	MOV	WORD PTR [500H],DX	;SET PRINT SCREEN & BREAK =0
	MOV	WORD PTR [LSTDRV],DX	;CLEAN OUT LAST DRIVE SPEC

	MESSAGE FTESTINIT,<"DISK PARAMETER TABLE",CR,LF>

		; lDOS: our sector and initial loader do not relocate
		;	 the DPT so do it here instead. this code used
		;	 to be commented out.
	lds si, [DSKADR]		; DS:SI -> CURRENT TABLE  ARR 2.41
 assume ds:nothing
	MOV	DI,SEC9			; ES:DI -> NEW TABLE	  ARR 2.41
	push di
	MOV	CX,DISK_PARMS_struc_size;			  ARR 2.41
	REP	MOVSB			; COPY TABLE		  ARR 2.41
	PUSH	ES			;			  ARR 2.41
	POP	DS			; DS = 0		  ARR 2.41
 assume ds:IVT

	pop	WORD PTR [DSKADR]	;			  ARR 2.41
	MOV	WORD PTR [DSKADR+2],DS	; POINT DISK PARM VECTOR TO NEW TABLE
					;			  ARR 2.41
;SB34INIT002******************************************************************
;SB	We need to initalise the cs:MotorStartup variable from the disk 
;SB	parameter table at SEC9.  The offsets in this table are defined in
;SB	the DISK_PARMS struc in MSDSKPRM.INC.  2 LOCS

	mov	al,[SEC9 + DISK_MOTOR_STRT]
	call dosentry_init_get_es_dosbiodata
 assume es:DOSGROUP
MotorStartup equ MOTORSTARTUP	; NASM port label
	mov	[es:MotorStartup],al
;SB34INIT002******************************************************************
	CMP	byte [es:MODEL_BYTE],0FDH       ; IS THIS AN OLD ROM?	ARR 2.41
	JB	NO_DIDDLE		; NO			  ARR 2.41
	MOV	WORD [(SEC9 + DISK_HEAD_STTL)],0200H+NORMSETTLE
					; SET HEAD SETTLE AND MOTOR START
					; ON PC-1 PC-2 PC-XT HAL0 ARR 2.41
	MOV	byte [(SEC9 + DISK_SPECIFY_1)],0DFH
					; SET 1ST SPECIFY BYTE
					; ON PC-1 PC-2 PC-XT HAL0 ARR 2.41
NO_DIDDLE:				;			  ARR 2.41
	INT	12H			;GET MEMORY SIZE--1K BLOCKS IN AX
	MOV	CL,6
	SHL	AX,CL			;CONVERT TO 16-BYTE BLOCKS(SEGMENT NO.)
	POP	CX			; RETREIVE BOOT DRIVE NUMBER, AND FAT ID
		; cl = boot drive, 0 = A:
	MOV	DX,SYSINITSEG
	MOV	DS,DX

	ASSUME	DS:SYSINITGROUP

	MOV	[MEMORY_SIZE],AX
	INC	cx
	MOV	[DEFAULT_DRIVE],CL	;SAVE DEFAULT DRIVE SPEC

	xor	cx,cx

; IMPORTANT: SOME OLD IBM HARDWARE GENERATES SPURIOUS INT F'S DUE TO BOGUS
; PRINTER CARDS.  WE INITIALIZE THIS VALUE TO POINT TO AN IRET ONLY IF

; 1) THE ORIGINAL SEGMENT POINTS TO STORAGE INSIDE VALID RAM.

; 2) THE ORIGINAL SEGMENT IS 0F000:XXXX

; THESES ARE CAPRICIOUS REQUESTS FROM OUR OEM FOR REASONS BEHIND THEM, READ
; THE DCR'S FOR THE IBM DOS 3.2 PROJECT.

	MOV	es,cx			; cx := SEGMENT FOR INT 15
 assume es:IVT
	MOV	AX,WORD PTR [es:(0FH*4+2)]

	CMP	AX,[MEMORY_SIZE]	; CONDITION 1
	Jbe	RESETINTF

	CMP	AX,0F000H		; CONDITION 2
	JNE	KEEPINTF

RESETINTF:
	MOV	WORD PTR [es:0FH*4], entry_iret
	MOV	WORD PTR [es:0FH*4+2],CS
KEEPINTF:

; END IMPORTANT

;SB34INIT003****************************************************************
;SB We will check if the system has IBM extended key board by
;SB looking at a byte at 40:96.  If bit 4 is set, then extended key board
;SB is installed, and we are going to set KEYRD_Func to 10h, KEYSTS_Func to 11h
;SB for the extended keyboard function. Use cx as the temporary register. 8 LOCS

	test byte [es:0496h], 0001_0000b	; get keyboard flag

	call dosentry_init_get_ds_dosbiodata
 assume ds:DOSGROUP
	PUSH	ds
	POP	ES
 assume es:DOSGROUP

	jz	ORG_KEY				; orginal keyboard
KEYRD_func equ KEYRD_Func	; NASM port label
KEYSTS_func equ KEYSTS_Func	; NASM port label
	mov	word [KEYRD_func], 11_10h	; change for extended keyboard functions
		; KEYSTS_Func is directly behind KEYRD_Func
ORG_KEY:

;SB34INIT003****************************************************************

;**************************************************************
;	WILL INITIALIZE THE NUMBER OF DRIVES
;	AFTER THE EQUIPMENT CALL (INT 11H) BITS 6&7 WILL TELL
;	THE INDICATIONS ARE AS FOLLOWS:
;
;	BITS	7	6	DRIVES
;		0	0	1
;		0	1	2
;		1	0	3
;		1	1	4
;**************************************************************

	call	CMOS_Clock_Read     ;Before doing anythig else if CMOS clock exists,
				    ;then set the system time according to that.
				    ;Also, reset the cmos clock rate.

	MESSAGE FTESTINIT,<"DISK DEVICES",CR,LF>

	POP	AX			;NUMBER OF FLOPPIES AND FAT ID
	XOR	AH,AH			; CHUCK FAT ID BYTE
	MOV	[cs:DRVMAX],AL	      ;AND SET INITIAL NUMBER OF DRIVES
	MESSAGE FTESTINIT,<"BEFORE INT 13",CR,LF>

determine_fhave96:
	mov dx, SYSINITSEG
	mov ds, dx
 assume ds:SYSINITGROUP
	xor dx, dx			; dl = unit 0
	cmp byte [FakeFloppyDrv],1
	push cs
	pop ds
 assume ds:DOSENTRYGROUP
	je .none

.LOOP_DRIVE:
	CMP	DL,[DRVMAX]
	jae	.done

; CHECK FOR CHANGELINE SUPPORT ON DRIVE
;SB33023********************************************************************
	mov	AH, 15h      ;SB	; set command to get DASD type
	stc
	int	13h	     ;SB	; call ROM-BIOS
;SB33023********************************************************************
	JC	.NEXTDRIVE
	CMP	AH,02			; CHECK FOR PRESENCE OF CHANGELINE
	je .have96

.NEXTDRIVE:
	INC	dx
	JMP	.LOOP_DRIVE

; WE HAVE A DRIVE WITH CHANGE LINE SUPPORT.
; shortcut to the end of the loop, ignoring any additional units
;  that may also have change line support.
.have96:
	call dosentry_init_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov byte [FHAVE96], 1		; REMEMBER THAT WE HAVE 96TPI DISKS

.DONE_DRIVES:
.done:
.none:
	; proceeds to STATIC_CONFIGURE


usesection SYSINITTRAIL

alloc_upb:
 assume ds:nothing, es:nothing, ss:nothing
	push ax
	push bx
	push cx
	les di, [cs:nextupb]
	mov ax, es
	test ax, ax
	jz .alloc
	add di, BDSM_type_struc_size
	mov word [cs:nextupb], di	; -> next UPB
	mov cl, 4
	lea bx, [di + BDSM_type_struc_size + 15]
					; -> behind next UPB, round up
	cmp bx, word [cs:nextupb]
	jb mem_err_j
	shr bx, cl			; to paragraphs
	mov ah, 4Ah
	int 21h				; resize
	jnc @F
mem_err_j: equ $
 extern MEM_ERR
	jmp MEM_ERR

.alloc:
	mov ah, 48h
	mov bx, paras(BDSM_type_struc_size)
	int 21h
	jc mem_err_j
	mov es, ax
 assume es:nothing
	mov word [cs:nextupb + 2], ax
@@:
	pop cx
	pop bx
	pop ax
	retn


	global INITUPB
INITUPB:

;SB33021********************************************************************
	mov	DL, 80h     ;SB 	; tell rom bios to look at hard drives
	mov	AH, 8h	    ;SB 	; set command to get drive parameter
	stc
	int	13h	    ;SB 	; call ROM-BIOS to get number of drives

	assume es:nothing
;SB33021********************************************************************
	JC	ENDDRV			;CARRY INDICATES OLD ROM, SO NO HARDFILE
	MOV	[cs:HNUM],DL
ENDDRV:
	MESSAGE FTESTINIT,<"SETTING UP BDSS",CR,LF>

;
; SCAN THE LIST OF DRIVES TO DETERMINE THEIR TYPE.  WE HAVE THREE FLAVORS OF
; DISKETTE DRIVES:
;
;   48TPI DRIVES    WE DO NOTHING SPECIAL FOR THEM
;   96TPI DRIVES    MARK THE FACT THAT THEY HAVE CHANGELINE SUPPORT.
;   3 1/4 DRIVES    MARK CHANGELINE SUPPORT AND SMALL.
;
; THE FOLLOWING CODE USES REGISTERS FOR CERTAIN VALUES:
;   DL - PHYSICAL DRIVE
;   DS:DI - POINTS TO CURRENT BDS
;   CX - FLAG BITS FOR BDS
;   DH - FORM FACTOR FOR THE DRIVE (1 - 48TPI, 2 - 96TPI, 3 - 3.5" MEDIUM)
;
	XOR	DL,DL			; START OUT WITH DRIVE 0.

	call sysinit_get_ds_dosbiodata
 assume ds:DOSGROUP
	MOV	byte [EOT],9
;J.K.6/24/87 Check if the system has no physical diskette drives.
;J.K. If it is, then we don't have to set BDS tables.  But since we
;J.K. pretend that we have 2 floppies, we are going to reserve two
;J.K. BDS tables for the fake drive A, and B. and set the end of link
;J.K. pointer.

;SB34INIT004*********************************************************
;SB	Check to see if we are faking floppy drives.  If not we don't 
;SB	do anything special.  If we are faking floppy drives we need
;SB	to set aside two BDSs for the two fake floppy drives.  We 
;SB	don't need to initalise any fields though. So starting at START_BDS
;SB	use the link field in the BDS structure to go to the second BDS
;SB	in the list and initalise it's link field to -1 to set the end of
;SB	the list.  Then jump to the routine at DoHard to allocate/initialise
;SB     the BDS for HardDrives.

	cmp	byte [cs:FakeFloppyDrv],1
	jnz	LOOP_DRIVE		; system has floppy
link equ LINK	; NASM port equate
	call alloc_upb
	push cs
	pop ds
 assume ds:SYSINITGROUP
	mov si, BDS_diskette_template	; access with ds
	mov cx, BDS_TYPE_struc_size
	push di
	rep movsb
	push es
	pop ds
 assume ds:nothing, es:nothing
	pop di
	mov byte [di + DRIVELET], 0
	call Install_BDSM_and_set_bpb

	call alloc_upb
	push cs
	pop ds
 assume ds:SYSINITGROUP
	mov si, BDS_diskette_template	; access with ds
	mov cx, BDS_TYPE_struc_size
	push di
	rep movsb
	push es
	pop ds
 assume ds:nothing, es:nothing
	pop di
	mov byte [di + DRIVELET], 1
	call Install_BDSM_and_set_bpb

DoHard equ DOHARD	; NASM port label
	jmp	DoHard			; allocate/initialise BDS for HardDrives
;SB34INIT004*********************************************************

LOOP_DRIVE:
	call sysinit_get_ds_dosentry	; DRVMAX in DOSENTRY
 assume ds:DOSENTRYGROUP
	CMP	DL,[DRVMAX]
	jae	DONE_DRIVES

	call alloc_upb
	push cs
	pop ds
 assume ds:SYSINITGROUP
	mov si, BDS_diskette_template	; access with ds
	mov cx, BDS_TYPE_struc_size
	push di
	rep movsb
	pop di
	; XOR	CX,CX			; ZERO ALL FLAGS (cx already zero)

	MOV	DH,FF48TPI		; SET FORM FACTOR TO 48 TPI
	MOV	byte [NUM_CYLN],40	      ; 40 TRACKS PER SIDE

	PUSH	DS
	PUSH	DI
	PUSH	DX
	PUSH	CX

;SB33022********************************************************************
	MOV	AH, 8h			;GET DRIVE PARAMETERS	       ;SB;3.30
	stc
	INT	13h			;CALL ROM-BIOS		       ;SB;3.30
;SB33022********************************************************************
	jc	NOPARMSFROMROM		; GOT AN OLD ROM

;J.K. 10/9/86 If CMOS is bad, it gives ES,AX,BX,CX,DH,DI=0. CY=0.
;In this case, we are going to put bogus informations to BDS table.
;We are going to set CH=39,CL=9,DH=1 to avoid divide overflow when
;they are calculated at the later time.  This is just for the Diagnostic
;Diskette which need MSBIO,MSDOS to boot up before it sets CMOS.
;This should only happen with drive B.

	CMP	CH,0			; if ch=0, then cl,dh=0 too.
	JNE	PFR_OK
	MOV	CH,39			; ROM gave wrong info.
	MOV	CL,9			; Let's default to 360K.
	MOV	DH,1
PFR_OK:
	INC	CH			; MAKE NUMBER OF CYLINDERS 1-BASED
	MOV	byte ptr [NUM_HEADS],DH	; SAVE PARMS RETURNED BY ROM
	inc	word ptr [NUM_HEADS]	; MAKE NUMBER OF HEADS 1-BASED
	AND	CL,00111111B		; EXTRACT SECTORS/TRACK
	MOV	[SEC_TRK],CL
	MOV	[NUM_CYLN],CH	      ; ASSUME LESS THAN 256 CYLINDERS!!

	call sysinit_get_ds_dosbiodata
 assume ds:DOSGROUP
; MAKE SURE THAT EOT CONTAINS THE MAX NUMBER OF SEC/TRK IN SYSTEM OF FLOPPIES
	CMP	CL,[EOT]			; MAY SET CARRY
	JBE	EOT_OK
	MOV	[EOT],CL
EOT_OK:
	POP	CX
	POP	DX
	POP	DI
	POP	DS
 assume ds:SYSINITGROUP

; CHECK FOR CHANGELINE SUPPORT ON DRIVE
;SB33023********************************************************************
	mov	AH, 15h      ;SB	; set command to get DASD type
	stc
	int	13h	     ;SB	; call ROM-BIOS
;SB33023********************************************************************
	JC	CHANGELINE_DONE
	CMP	AH,02			; CHECK FOR PRESENCE OF CHANGELINE
	JNE	CHANGELINE_DONE
;
; WE HAVE A DRIVE WITH CHANGE LINE SUPPORT.
;
	MESSAGE FTESTINIT,<"96TPI DEVICES",CR,LF>

	OR	CL,FCHANGELINE		; SIGNAL TYPE
;
; WE NOW TRY TO SET UP THE FORM FACTOR FOR THE TYPES OF MEDIA THAT WE KNOW
; AND CAN RECOGNISE. FOR THE REST, WE SET THE FORM FACTOR AS "OTHER".
;
CHANGELINE_DONE:
	push cs
	pop ds
 assume ds:SYSINITGROUP
; 40 CYLINDERS AND 9 OR LESS SEC/TRK, TREAT AS 48 TPI MEDIUM.
	CMP	byte [NUM_CYLN],40
	JNZ	TRY_80
	CMP	byte [SEC_TRK],9
	JBE	GOT_FF			; dh = FF48TPI -->
GOTOTHER:
	MOV	DH,FFOTHER		; WE HAVE A "STRANGE" MEDIUM
	JMP	SHORT GOT_FF

;
; 80 CYLINDERS AND 9 SECTORS/TRACK => 720 KB DEVICE
; 80 CYLINDERS AND 15 SEC/TRK => 96 TPI MEDIUM
;
TRY_80:
	MOV	DH,FF96TPI		; in case it is 96 TPI
	CMP	byte [NUM_CYLN],80
	JNZ	GOTOTHER		; resets dh
	CMP	byte [SEC_TRK],15
	JZ	GOT_FF			; (dh = FF96TPI)
	CMP	byte [SEC_TRK],9
	JNZ	GOTOTHER		; resets dh
	MOV	DH,FFSMALL		; reset dh
GOT_FF:
	JMP	SHORT NEXTDRIVE

; WE HAVE AN OLD ROM, SO WE EITHER HAVE A 48TPI OR 96TPI DRIVE. IF THE DRIVE
; HAS CHANGELINE, WE ASSUEM IT IS A 96TPI, OTHERWISE WE TREAT IT AS A 48TPI.

NOPARMSFROMROM:
	POP	CX
	POP	DX
	POP	DI
	POP	DS
 assume ds:SYSINITGROUP

;SB33024****************************************************************
	MOV	AH, 15h 		; SET COMMAND TO GET DASD TYPE ;SB;3.30
	stc
	INT	13h			; CALL ROM-BIOS 	       ;SB;3.30
;SB33024****************************************************************
	JC	NEXTDRIVE
	CMP	AH,2			; IS THERE CHANGELINE?
	JNZ	NEXTDRIVE
	OR	CL,FCHANGELINE
	MOV	byte [NUM_CYLN],80
	MOV	DH,FF96TPI
	MOV	AL,15			; SET EOT IF NECESSARY

	call sysinit_get_ds_dosbiodata
 assume ds:DOSGROUP
	CMP	AL, [EOT]
	JBE	EOT_OK2
	MOV	[EOT],AL
EOT_OK2:

NEXTDRIVE:
	OR	CL,FI_OWN_PHYSICAL	; SET THIS TRUE FOR ALL DRIVES
	MOV	BH,DL			;SAVE INT13 DRIVE NUMBER

; WE NEED TO DO SPECIAL THINGS IF WE HAVE A SINGLE DRIVE SYSTEM AND ARE SETTING
; UP A LOGICAL DRIVE. IT NEEDS TO HAVE THE SAME INT13 DRIVE NUMBER AS ITS
; COUNTERPART, BUT THE NEXT DRIVE LETTER. ALSO RESET OWNERSHIP FLAG.
; WE DETECT THE PRESENCE OF THIS SITUATION BY EXAMINING THE FLAG SINGLE FOR THE
; VALUE 2.

	call sysinit_get_ds_dosbiodata
 assume ds:DOSGROUP
	CMP	byte [SINGLE],2
	JNZ	NOT_SPECIAL
	DEC	BH			; INT13 DRIVE NUMBER SAME FOR LOGICAL DRIVE
	XOR	CL,FI_OWN_PHYSICAL	; RESET OWNERSHIP FLAG FOR LOGICAL DRIVE
NOT_SPECIAL:
; THE VALUES THAT WE PUT IN FOR RHDLIM AND RSECLIM WILL ONLY REMAIN IF THE
; FORM FACTOR IS OF TYPE "FFOTHER".
	mov ds, word [cs:nextupb + 2]
 assume ds:UPB
	MOV	ax, [cs:NUM_HEADS]
	MOV	WORD PTR [DI + RHDLIM],AX
	MOV	AL,[cs:SEC_TRK]
	MOV	WORD PTR [DI + RSECLIM],AX
	MOV	WORD PTR [DI + FLAGS],CX
	MOV	BYTE PTR [DI + FORMFACTOR],DH
	MOV	BYTE PTR [DI + DRIVELET],DL
	MOV	BYTE PTR [DI + DRIVENUM],BH
	MOV	BL,BYTE PTR [cs:NUM_CYLN]
	MOV	BYTE PTR [DI + CCYLN],BL	; ONLY THE L.S. BYTE IS SET HERE
	call Install_BDSM_and_set_bpb
	call sysinit_get_es_dosbiodata
 assume es:DOSGROUP
	CMP	byte [es:SINGLE],1		; SPECIAL CASE FOR SINGLE DRIVE SYSTEM
	JNZ	NO_SINGLE
	MESSAGE FTESTINIT,<"SINGLE DRIVE SYSTEM",CR,LF>
	inc	byte [es:SINGLE]		; DON'T LOSE INFO THAT WE HAVE SINGLE SYSTEM
	OR	CX,FI_AM_MULT
	OR	WORD PTR [DI + FLAGS],CX
	inc dx

	call alloc_upb
	push cs
	pop ds
 assume ds:SYSINITGROUP, es:UPB
	mov si, BDS_diskette_template	; access with ds
	push cx
	mov cx, BDS_TYPE_struc_size
	push di
	rep movsb
	pop di				; di -> next UPB
	pop cx
	JMP	SHORT NEXTDRIVE 	; USE SAME INFO FOR BDS A PREVIOUS
NO_SINGLE:
	inc dx
	JMP	LOOP_DRIVE

DONE_DRIVES:

; SET UP ALL THE HARD DRIVES IN THE SYSTEM

DOHARD:
 assume ds:nothing, es:nothing, ss:nothing

extern partition_table, partition_table.end
extern load_mode, load_scan_flags, load_partition_cycle
extern load_current_partition, load_unit, load_amount_units
extern next_block_device_unit

	push cs
	pop ds
 assume ds:SYSINITGROUP
	mov ax, DiskSector		; ! must be aligned to paragraph boundary
	mov cl, 4
	shr ax, cl
	add ax, DOSENTRY
	mov word [Init_BootSeg], ax
	mov al, [HARDNUM]
	mov [next_block_device_unit], al
	call .init

	testopt [load_mode], mode_dlasort_zero
	jz .once

	mov bx, scan_priority_primary
	call .pass
	mov bx, scan_early_primary
	call .pass
	mov bx, scan_logical_ignore_lba_if
	call .pass
	mov bx, scan_subsequent_primary
	call .pass
	jmp .done


.pass:
.passloop:
	call nextunit
	jc .passdone

	push bx
	mov cx, .each
	call bx
	pop bx
	jmp .passloop

.passdone:
.init:
	mov byte [load_unit], 7Fh
	mov al, byte [HNUM]
	mov byte [load_amount_units], al
	retn


.once:
	call nextunit
	jc .done

	mov cx, .each
	call scan_priority_primary
	mov cx, .each
	call scan_early_primary
	mov cx, .each
	call scan_logical_ignore_lba_if
	mov cx, .each
	call scan_subsequent_primary
	jmp .once

.each equ handle_each_partition

.done:
	jmp hdd_done


scan_logical_ignore_lba_if:
	testopt [BDS_harddisk_template + FLAGS], F_LBA
	jnz scan_logical
	push word [load_mode]
	clropt [load_mode], mode_first_type_ext15
	setopt [load_mode], mode_ignore_ext15
	call scan_logical
	pop word [load_mode]
	retn


scanptab_error:
bootcmd:
.fail_read:
	 push cs
	 pop es
 assume es:SYSINITGROUP
	mov di, msg.bootfail_read_errorcode
	mov al, ah
extern hexbyte
	call hexbyte
	mov dx, msg.bootfail_read
.fail:
	 push cs
	 pop es
 assume es:SYSINITGROUP
	 push cs
	 pop ds
 assume ds:SYSINITGROUP
	push dx
	mov dx, msg.bootfail
extern init2_disp_msg_asciz_cs_dx
	call init2_disp_msg_asciz_cs_dx
	pop dx
	call init2_disp_msg_asciz_cs_dx
	mov sp, bp			; abort pass
	pop bp
	retn


		; INP:	load_amount_units = remaining amount units
		;	load_unit = prior unit
		; OUT:	CY if units exhausted
		;	NC if another unit follows,
		;	 load_unit = next unit to process
		;	 ds:di -> UPB template,
		;	  with CHS geometry and LBA flag setup
		; CHG:	ax, cx, dx, di, es
		; STT:	ds = cs
nextunit:
.loop:
	inc byte [load_unit]

	xor ax, ax
	mov word [load_partition_cycle], ax

	cmp byte [load_amount_units], 1
	jb .ret			; CY if branching
	mov dl, byte [load_unit]
	call query_geometry_upb
	dec byte [load_amount_units]
	jc .loop		; just skip unit if error -->
	clc			; NC
.ret:
	retn


upb_reset:
	mov byte [FBIGFAT], 0		; ASSUME 12 BIT FAT
	retn


		; INP:	dl = unit number
		; OUT:	CY if error getting geometry
		;	NC if success
		;	ds:di -> UPB template
		; STT:	ds = cs
		; CHG:	ax, cx, dx, di, es
query_geometry_upb:
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
extern BDS_harddisk_template
	mov di, BDS_harddisk_template
	call upb_reset
	mov byte [di + DRIVENUM], dl
	push bx
	mov word [di + FLAGS], FI_OWN_PHYSICAL | FNON_REMOVABLE
					; F_LBA clear
	call detectlba
	jc .no_lba
	setopt [di + FLAGS], F_LBA	; set flag
.no_lba:
	mov byte [di + FORMFACTOR], FFHARDFILE

	push di
	mov ah, 08h			; set command to get drive parameters
	stc
	int 13h				; call rom-bios disk routine
	pop di
; DH IS NUMBER OF HEADS-1
; DL IS NUMBER OF HARD DISKS ATTACHED
; LOW 6 BITS OF CL IS SECTORS/TRACK
; HIGH 2 BITS OF CL WITH CH ARE MAX # OF CYLINDERS
	xchg dh, dl			; dl = maximum head
	mov dh, 0			; dx = maximum head (preserve CF !)
	inc dx				; GET NUMBER OF HEADS (preserve CF !)
	mov word [di + HDLIM], dx
	pop bx
	jc .ret				; CARRY HERE MEANS NO HARD DISK
	and cl, 3Fh			; EXTRACT NUMBER OF SECTORS/TRACK
					; (NC)
	mov byte [di + SECLIM], cl
.ret:
	retn


		; INP:	al = partition type
		; OUT:	CY or NZ or both if not a known type
		;	NC, ZR if known type we can access
		; STT:	ds = cs
load_is_known:
 assume ds:SYSINITGROUP, es:nothing, ss:nothing
	cmp al, ptFAT12
	je .isknown		; ZR if branches
	cmp al, ptFAT16_16BIT_CHS
	je .isknown		; ZR if branches
	cmp al, ptFAT16_CHS
	je .isknown		; ZR if branches
	cmp al, ptFAT16
	jne .notknown		; NZ if branches
.isknown_lba:
	testopt [BDS_harddisk_template + FLAGS], F_LBA
	jz .discard
	testopt [load_mode], mode_disable_lba
	jz .isknown		; ZR if branches
.discard:
	stc
	retn

.isknown:
.notknown:
	clc
	retn


hdd_done:
 assume ds:SYSINITGROUP, es:nothing
	mov al, byte [next_block_device_unit]
	call sysinit_get_ds_dosentry	; DRVMAX in DOSENTRY
 assume ds:DOSENTRYGROUP
	MOV	[DRVMAX],AL

; END OF DRIVE INITIALIZATION.

	CALL	SETDRVPARMS

write_dskdrvs_upb:
	push cs
	pop ds
 assume ds:SYSINITGROUP
	les di, [nextupb]
 assume es:UPB
	mov ax, es
	test ax, ax
	jz .done
	add di, BDSM_type_struc_size + 1; -> behind last UPB
	jc .mem_err_j
	and di, ~1			; round to word boundary
	mov si, DSKDRVS
	mov bx, [Mini_BPB_ptr]
	sub bx, si
	mov cx, bx
	add bx, di
	jc .mem_err_j
	add bx, 15			; -> behind wanted list
	jc .mem_err_j
	cmp bx, word [nextupb]
	jb mem_err_j
	push cx
	mov cl, 4
	shr bx, cl			; to paragraphs
	pop cx
	mov ah, 4Ah
	int 21h				; resize
	jnc @F
.mem_err_j:
	jmp mem_err_j
@@:
	shr cx, 1
	push di
	rep movsw
	call sysinit_get_ds_dosbiodata
 assume ds:DOSGROUP
 extern dskdrvs_indirect
	mov word [dskdrvs_indirect + 2], es
	pop word [dskdrvs_indirect]

	mov ax, es
	dec ax
	mov es, ax
 assume es:MCB
	mov word [es:arena_owner], 8
				; init owner
	mov di, arena_reserved
	 push cs
	 pop ds
 assume ds:SYSINITGROUP
	mov si, upb_smcb
	mov cx, 3 + 8
	rep movsb		; init name and type

.done:
	retn

upb_smcb:
	db 0,0,0
	db "S",0		; name "S"
	db 9			; type S_UPB
	times 5 db 0


		; INP:	dx:ax = first sector
		;	bx:0 -> buffer
		; OUT:	es = input bx
		;	dx:ax = incremented
		;	bx => after read data
		; CHG:	-
		; STT:	ds = cs
read_ae_512_bytes:
 assume ds:SYSINITGROUP
	push dx
	push ax
	push bx
	push cx
	mov es, bx
 assume es:nothing
	xor bx, bx		; es:bx -> buffer
	mov cx, 0201h		; cx = function code and count
	push di
	mov di, BDS_harddisk_template
				; ds:di -> template
	call readsector_flag
	pop di
	jc scanptab_error
	pop cx
	pop bx
	pop ax
	pop dx
	add bx, paras(512)
	inc ax
	jnz .
	inc dx
.:
	retn


overridedef DEBUG4, 0
%define _SCANPTAB_PREFIX
%define _SCANPTAB_DEBUG4_PREFIX
%assign _PARTITION_TABLE_IN_CS 1
%define _BASE bp
%assign _SPT_ELD 0
%assign _MODE 1
%assign _SPT_MULTIPASS 1
%include "scanptab.asm"
resetdef DEBUG4


usesection DOSENTRYINIT

;J.K. 9/24/86 We now decide, based on the configurations available so far, what
;code or data we need to keep as a stay resident code.	The following table
;shows the configurations under consideration.	They are listed in the order
;of their current position memory.
;Configuration will be done in two ways:
;First, we are going to set "Static configuration".  Static configuration will
;consider from basic configuration to ENDOF96TPI configuration.  The result
;of static configuration will be the address the Dynamic configuration will
;use to start with.
;Secondly, "Dynamic cofiguration" will be performed.  Dynamic configuration
;involves possible relocation of CODE or DATA.	Dynamic configuration routine
;will take care of BDSM tables and AT ROM Fix module thru K09 suspend/resume
;code individually.  After these operation, FINAL_DOS_LOCATION will be set.
;This will be the place SYSINIT routine will relocate MSDOS module for good.
;
;   1.	 BASIC CONFIGURATION FOR IBMBIO (EndFloppy, EndSwap)
;   2.	 ENDONEHARD
;   3.	 ENDTWOHARD
;   4.	 END96TPI	;a system that supports "Change Line Error"
;   5.	 End of BDSM	;BDSM tables for mini disks.
;   6.	 ENDATROM	;Some of AT ROM fix module.
;   7.	 ENDCMOSCLOCKSET;Supporting program for CMOS clock write.
;   8.	 ENDK09 	;K09 CMOS Clock module to handle SUSPEND/RESUME operation.
;
; lDOS: Only END96TPI and ENDATROM are still used of all these.
;  END96TPI and ENDFLOPPY are equal now, so only the first one
;  is still used. (END96TPI is in ms96tpi.nas included by
;  msbio2.nas, which aligns to a paragraph boundary before
;  mshard.nas's IBM_DISK_IO. The latter is the start of the
;  "AT ROM fix module" that ends at ENDATROM.)
; Update lDOS 2025 September: Instead of END96TPI now the label
;  DOSENTRY_INIT_START is used (in mshard.nas).
; The UPBs (aka BDS tables) are handled later by INITUPB (in
;  SYSINIT segment, source in this file) and are allocated
;  using an S MCB as the DOS is already available then. (The
;  UPBs are relocated into HMA, UMA, or LMA later.)
; The CMOS and K09 code is now in the DOSCODE segment, except
;  for the i6C entrypoint (in entry.asm).

;J.K. 9/24/86.

STATIC_CONFIGURE:
 assume ds:nothing, es:nothing, ss:nothing
 extern DOSENTRY_INIT_START
	mov	ax, DOSENTRY_INIT_START
	call dosentry_init_get_ds_dosbiodata
 assume ds:DOSGROUP
fHave96 equ FHAVE96	; NASM port label
	cmp	byte [fHave96], 0		;Is change line support there?
Config96 equ CONFIG96	; NASM port label
	jnz	Config96		;Yes.

Basic_Floppy:
	; mov	ax, offset ENDFLOPPY
		; ldos: do leave DOSENTRY data up to END96TPI resident
		; ldos: ENDFLOPPY equals END96TPI now that the code
		;  has been moved out of the DOSENTRY section.
Dynamic_Configure equ DYNAMIC_CONFIGURE	; NASM port label
	jmp	Dynamic_Configure	;static configuration is done!

;
; KEEP THE 96TPI CODE
;
CONFIG96:
;
; SAVE OLD INT 13 VECTOR
;
	push cs
	pop ds
 assume ds:DOSENTRYGROUP
	push ds
	pop es
 assume ds:DOSENTRYGROUP, es:DOSENTRYGROUP

	PUSH	AX
	PUSH	DS
	XOR	AX,AX
	MOV	DS,AX
 assume ds:IVT

	MOV	AX,[4 * 13H]
	MOV	WORD PTR [es:REAL13],AX
	MOV	AX,[4 * 13H+2]
	MOV	WORD PTR [es:REAL13+2],AX
;
; INSERT NEW VECTOR
;
extern ms96tpi_i13
	MOV	WORD PTR [4 * 13H],OFFSET ms96tpi_i13
	MOV	[4 * 13H + 2], es

	POP	DS
 assume ds:DOSENTRYGROUP
	POP	AX

DYNAMIC_CONFIGURE:
	push ds
	pop es
 assume es:DOSENTRYGROUP
	cld					;clear direction

CheckATROM:
	call	Get_Para_Offset			;For dynamic allocation, we are
						;going to use offset address that
						;is in paragraph boundary.


	call dosentry_init_get_ds_dosbiodata
 assume ds:DOSGROUP
	cmp	byte [Model_Byte], 0FCh		;AT ?
	jnz	CheckCMOSClock

	push ax
	mov	DL, 80h			; tell rom bios to look at hard drives
	mov	AH, 8h			; set command to get drive parameter
	stc
	int	13h			; call ROM-BIOS to get number of drives
	pop ax
	jc	CheckCMOSClock
	test dl, dl			; No hard file?
	jz	CheckCMOSClock

	mov	si, 0F000h
	mov	es, si			       ;ES -> BIOS segment
	assume	es:nothing		       ;
	push cs
	pop ds
 assume ds:DOSENTRYGROUP
	mov	si, offset BIOS_DATE	       ;
	mov	di, 0FFF5H		       ;ROM BIOS string is at F000:FFF5
Cmpbyte:				       ;Only patch ROM for bios dated 01/10/84
	cmpsb				       ;
	jnz	CheckCMOSClock		       ;
	cmp	byte ptr [si-1],0	       ;
	jnz	Cmpbyte 		       ;
SetRomCode:				       ;Now we have to install ROM fix
					       ;AX is the address to move.
	push ds
	pop es
 assume es:DOSENTRYGROUP

	mov	word ptr [ORIG13], ax
	mov	word ptr [ORIG13+2], ds		;set new ROM bios int 13 vector
	mov	cx, offset ENDATROM
	mov	si, offset IBM_DISK_IO
	sub	cx, si				;size of AT ROM FIX module
	mov	di, ax				;destination
	rep	movsb				;relocate it
	mov	ax, di				;new ending address
	call	Get_Para_Offset 		;in AX

CheckCMOSClock:
	push cs
	pop ds
 assume ds:DOSENTRYGROUP
	push	ds
	pop	es				;set ES to CODE seg
 assume ds:DOSENTRYGROUP, es:DOSENTRYGROUP

CheckK09:
;SB33025****************************************************************
	push	ax			;save ax		     ;SB  ;3.30*
	push es

	mov ah, 0C0h
	stc
	int 15h
 assume es:nothing
	jc .no_k09_if_CY
	test byte [es:bx + 5], 1 << 3
	stc
	jz .no_k09_if_CY

	mov	ax,4100h		;Q: is it a K09 	     ;SB  ;3.30*
	mov	bl,0			;			     ;SB  ;3.30*
	stc
	int	15h			;			     ;SB  ;3.30*
;SB33025****************************************************************
.no_k09_if_CY:
	pop es
 assume es:DOSENTRYGROUP
	pop	ax
	jc	CONFIGDONE

	push	ax
	push	ds
	call dosentry_init_get_ds_dosbiodata
 assume ds:DOSGROUP
fHaveK09 equ FHAVEK09	; NASM port label
	mov	byte [fHaveK09], 1			;remember we have a K09 type
	xor	ax,ax
	mov	ds, ax
 assume ds:IVT

 extern i6C
	mov	word ptr [4 * 6Ch], i6C	;new INT 6Ch handler
	mov	[4 * 6Ch +2], cs

	pop	ds
 assume ds:DOSENTRYGROUP
	pop	ax				;restore the ending address

; SET UP CONFIG STUFF FOR SYSINIT

CONFIGDONE:			;AX is final ending address of MSBIO.
	MOV	DX,SYSINITSEG
	MOV	DS,DX
 assume ds:SYSINITGROUP

	; SUB	AX,OFFSET START$	; (zero)
	ADD	AX,15
	RCR	AX,1
	SHR	AX, 1
	SHR	AX, 1
	SHR	AX, 1
	add ax, DOSENTRY
	MOV	[behind_dosentry_segment], AX
	mov al, [cs:DRVMAX]
	mov [HARDNUM], al		; REMEMBER WHICH DRIVE IS HARD DISK

	MESSAGE FTESTINIT,<"FINAL DOS LOCATION IS ">
	MNUM	FTESTINIT,FINAL_DOS_LOCATION
	MESSAGE FTESTINIT,<CR,LF>
	PUSH	CS
	POP	DS

 assume ds:DOSENTRYGROUP, es:nothing

%if 0
call_purge_96tpi:
	CMP	BYTE [FHAVE96],0
	JNZ	.no
	CALL	PURGE_96TPI		;MJB001 ELIMINATE CALLS TO 96TPI HOOHAH
.no
%endif

relocate_sysinit_and_early_dos:
	MESSAGE FTESTINIT,<"SYSINIT",CR,LF>
	ZWAIT
	MESSAGE FTESTINIT,<"ON TO SYSINIT...",CR,LF>

extern SYSSIZE, afterdosdatalabel, afterdoscodelabel, doscode_start, doscode_mcb

	mov bx, SYSINITMCB
	mov ds, bx
 assume ds:nothing
	mov cl, 4
	shr word [mcbSize], cl		; make paragraphs
	mov bx, DOSDATAMCB
	mov ds, bx
 assume ds:nothing
	shr word [mcbSize], cl		; make paragraphs
%if _RELOCATEDOSCODE
	mov bx, DOSCODEGROUP
	mov ds, bx
 assume ds:DOSCODEGROUP
	shr word [doscode_mcb + mcbSize], cl
					; make paragraphs
%endif

	MOV AX, SYSSIZE + 16 wrt SYSINITSEG
	call dosentry_init_ParaRound
	xchg cx, ax
%if _RELOCATEDOSCODE
	mov ax, afterdoscodelabel wrt DOSCODEGROUP
	call dosentry_init_ParaRound
%else
	xor ax, ax
%endif

	mov bx, SYSINITSEG
	mov ds, bx
 assume ds:SYSINITGROUP
	mov dx, [MEMORY_SIZE]
	sub dx, cx			; => SYSINIT destination
	jc .oom
	sub dx, paras(SYSINITSTACK)	; leave stack buffer
	jc .oom
	mov si, dx
	sub dx, 1			; leave buffer for first UMCB,
					;  => SYSINIT MCB destination
	jbe .oom
	sub dx, ax			; => early DOSCODE destination
	mov di, dx
	jc .oom
	add cx, ax

	mov ax, afterdosdatalabel wrt DOSSTART
	call dosentry_init_ParaRound
	sub dx, ax			; => early DOSDATA destination
	jc .oom
	push dx
	sub dx, 1			; => DOSDATA S MCB
	jc .oom
	add cx, ax
	inc cx

		; Note: This check is only valid if there is no
		;  data to still be used between the relocate
		;  block and the end of the DOSENTRY section.
		; This is now true with DOSDATA being relocated.
	mov ax, end_of_dosentry_init_late
	call dosentry_init_ParaRound
	add ax, DOSENTRY
	cmp dx, ax
	jae @F

.oom:
dosentry_init_oom:
	mov si, dosentry_init_msg.oom	; access with cs
	mov ah, 0Eh
	mov bx, 7
	db __TEST_IMM16			; skip int
.msgloop:
	int 10h
	cs lodsb
	test al, al
	jnz .msgloop
.halt:
	int3
	sti
	hlt
	jmp .halt

@@:
	pop bp
	cli
	align 2, nop
.stack:
	push cs
	pop ss
	mov sp, .stack
 assume ss:DOSENTRYGROUP
%if (.stack - INIT) < 512
 %error Too small DOSENTRY init stack
%endif
	mov ax, DOSDATAMCB
	call dosentry_init_movp

	xor ax, ax
	mov ds, ax
 assume ds:IVT
	xchg ax, bp
	mov word [31h * 4 + 2], ax	; init => DOSDATA
%if _RELOCATEDOSCODE
	mov ds, ax
 assume ds:DOSGROUP
	mov word [dosdata_to_doscode], di
	mov ax, DOSENTRY
	mov ds, ax
 assume ds:DOSENTRYGROUP
 extern ..@dosentry_doscode_segment
	mov word [..@dosentry_doscode_segment], di
%endif
	sti

 extern GOINIT
	mov cx, dx			; => DOSDATA S MCB
	mov ax, GOINIT
	push si
	push ax
	retf

INIT	ENDP


dosentry_init_ParaRound:
 assume ds:nothing, es:nothing, ss:nothing
	ADD	AX,15
	RCR	AX,1
	SHR	AX,1
	SHR	AX,1
	SHR	AX,1
	retn


		; Move paragraphs
		;
		; INP:	ax:0-> source
		;	dx:0-> destination
		;	cx = number of paragraphs
		; CHG:	-
		; Note:	Doesn't work correctly on HMA; doesn't always wrap to LMA either.
		;	Do not provide a wrapped/HMA source or destination!
dosentry_init_movp:
 assume ds:nothing, es:nothing, ss:nothing
	push cx
	push ds
	push si
	push es
	push di

	cmp ax, dx		; source above destination ?
	ja .up			; yes, move up (forwards) -->
	je .return		; same, no need to move -->
	push ax
	add ax, cx		; (expected not to carry)
	cmp ax, dx		; end of source is above destination ?
	pop ax
	ja .down		; yes, move from top down -->
	; Here, the end of source is below-or-equal the destination,
	;  so they do not overlap. In this case we prefer moving up.

.up:
	push ax
	push dx
.uploop:
	mov ds, ax
	mov es, dx
 assume ds:nothing, es:nothing
	xor di, di
	xor si, si		; -> start of segment
	sub cx, 1000h		; 64 KiB left ?
	jbe .uplast		; no -->
	push cx
	mov cx, 10000h /2
	rep movsw		; move 64 KiB
	pop cx
	add ax, 1000h
	add dx, 1000h		; -> next segment
	jmp short .uploop	; proceed for more -->
.uplast:
	add cx, 1000h		; restore counter
	shl cx, 1
	shl cx, 1
	shl cx, 1		; *8, paragraphs to words
	rep movsw		; move last part
	pop dx
	pop ax
	jmp short .return

.down:
	std			; _AMD_ERRATUM_109_WORKAROUND as below
.dnloop:
	sub cx, 1000h		; 64 KiB left ?
	jbe .dnlast		; no -->
	push ax
	push dx
	add ax, cx
	add dx, cx
	mov ds, ax		; -> 64 KiB not yet moved
	mov es, dx
 assume ds:nothing, es:nothing
	pop dx
	pop ax
	mov di, -2
	mov si, di		; moved from last word down
	push cx
	mov cx, 10000h /2
	rep movsw		; move 64 KiB
	pop cx
	jmp short .dnloop	; proceed for more -->
.dnlast:
	add cx, 1000h		; restore counter
	shl cx, 1
	shl cx, 1
	shl cx, 1		; *8, paragraphs to words
	mov di, cx
	dec di
	shl di, 1		; words to offset, -> last word
	mov si, di
	mov ds, ax
	mov es, dx		; first segment correct
 assume ds:nothing, es:nothing


	numdef AMD_ERRATUM_109_WORKAROUND, 1
%if 0

Jack R. Ellis pointed out this erratum:

Quoting from https://www.amd.com/system/files/TechDocs/25759.pdf page 69:

109   Certain Reverse REP MOVS May Produce Unpredictable Behavior

Description

In certain situations a REP MOVS instruction may lead to
incorrect results. An incorrect address size, data size
or source operand segment may be used or a succeeding
instruction may be skipped. This may occur under the
following conditions:

* EFLAGS.DF=1 (the string is being moved in the reverse direction).

* The number of items being moved (RCX) is between 1 and 20.

* The REP MOVS instruction is preceded by some microcoded instruction
  that has not completely retired by the time the REP MOVS begins
  execution. The set of such instructions includes BOUND, CLI, LDS,
  LES, LFS, LGS, LSS, IDIV, and most microcoded x87 instructions.

Potential Effect on System

Incorrect results may be produced or the system may hang.

Suggested Workaround

Contact your AMD representative for information on a BIOS update.

%endif

%if _AMD_ERRATUM_109_WORKAROUND
	jcxz @FF
	cmp cx, 20
	ja @FF
@@:
	movsw
	loop @B
@@:
%endif
	rep movsw		; move first part
	cld
.return:
	pop di
	pop es
 assume es:nothing
	pop si
	pop ds
 assume ds:nothing
	pop cx
	retn

end_of_dosentry_init_late:

dosentry_init_msg:
.oom:	asciz "lDOS load error: Out of memory for SYSINIT relocation.",13,10


 global cmdline_noop, cmdline_checkdebugger, cmdline_verbose, cmdline_scanmode
 global cmdline_haltflag
cmdline_noop:
	retn


cmdline_error:
 assume es:SYSINITGROUP, ds:SYSINITGROUP
 extern invalid_number
	mov si, invalid_number
	mov bx, 7
	db __TEST_IMM16		; skip int
@@:
	int 10h
	lodsb
	mov ah, 0Eh
	test al, al
	jnz @B
	mov si, word [ds:bp]	; -> command name
	db __TEST_IMM16		; skip int
@@:
	int 10h
	lodsb
	mov ah, 0Eh
	test al, al
	jnz @B
@@:
	mov ax, 0E00h + '"'
	int 10h
	mov ax, 0E00h + 13
	int 10h
	mov ax, 0E00h + 10
	int 10h
	retn


		; INP:	ds:si -> after number
		; OUT:	ZR if NUL reached
		;	NZ if not NUL,
		;	 ds:si -> first non-blank, non-comma, non-NUL
		;	 al = byte [ds:si]
cmdline_next:
 assume es:SYSINITGROUP, ds:SYSINITGROUP
.:
	lodsb
	cmp al, 32
	je .
	cmp al, 9
	je .
	cmp al, ','
	je .
	dec si
	test al, al
	retn


		; INP:	si -> past an optional equals sign and blanks
		;	di -> -> command name
		; CHG:	ax, si, di, cx, bx, dx, bp
		; STT:	ds = es => SYSINIT
		;	cs => DOSENTRY
cmdline_checkdebugger:
 assume es:SYSINITGROUP, ds:SYSINITGROUP
	mov bp, di
.loop:
	call parsenumber
	jc cmdline_error
	test dh, dh
	jnz cmdline_error
	cmp bl, 1
	jb .or
	je .clr
.replace:
	mov byte [cs:checkdebugger], dl
	jmp .next

.or:
	or byte [cs:checkdebugger], dl
	jmp .next

.clr:
	not dl
	and byte [cs:checkdebugger], dl
.next:
	call cmdline_next
	jnz .loop
	retn


		; INP:	si -> past an optional equals sign and blanks
		;	di -> -> command name
		; CHG:	ax, si, di, cx, bx, dx, bp
		; STT:	ds = es => SYSINIT
		;	cs => DOSENTRY
cmdline_verbose:
 assume es:SYSINITGROUP, ds:SYSINITGROUP
	mov bp, di
.loop:
	call parsenumber
	jc cmdline_error
	test dh, dh
	jnz cmdline_error
	cmp bl, 1
	jb .or
	je .clr
.replace:
	mov byte [verbose_mode], dl
	jmp .next

.or:
	or byte [verbose_mode], dl
	jmp .next

.clr:
	not dl
	and byte [verbose_mode], dl
.next:
	call cmdline_next
	jnz .loop
	retn


cmdline_scanmode:
 assume es:SYSINITGROUP, ds:SYSINITGROUP
	mov bp, di
.loop:
 extern sysinit_cmdline_scanmode_keyword
	call far sysinit_cmdline_scanmode_keyword
					; ! call far into unrelocated SYSINIT
	jnc .replace
	call parsenumber
	jc cmdline_error
	cmp bl, 1
	jb .or
	je .clr
.replace:
	mov word [load_mode], dx
	jmp .next

.or:
	or word [load_mode], dx
	jmp .next

.clr:
	not dx
	and word [load_mode], dx
.next:
	call cmdline_next
	jnz .loop
	retn


		; INP:	si -> past an optional equals sign and blanks
		;	di -> -> command name
		; CHG:	ax, si, di, cx, bx, dx, bp
		; STT:	ds = es => SYSINIT
		;	cs => DOSENTRY
cmdline_haltflag:
 assume es:SYSINITGROUP, ds:SYSINITGROUP
	mov bp, di
.loop:
	call parsenumber
	jc cmdline_error
	call dosentry_init_get_ds_dosdata
 assume ds:DOSGROUP
	cmp bl, 1
	jb .or
	je .clr
.replace:
	mov word [haltflags], dx
	jmp .next

.or:
	or word [haltflags], dx
	jmp .next

.clr:
	not dx
	and word [haltflags], dx
.next:
	push es
	pop ds
 assume ds:SYSINITGROUP
	call cmdline_next
	jnz .loop
	retn


		; INP:	si -> number input text
		; OUT:	NC if success,
		;	 dx = number
		;	 bl = 0 if +, 1 if -, 2 else
parsenumber:
	xor bx, bx
	lodsb
	cmp al, '+'
	je @F
	inc bx
	cmp al, '-'
	je @F
	inc bx
	dec si
@@:
 extern ldos_getnum_far
	call far ldos_getnum_far
	retn


usesection SYSINITTRAIL

		; INP:	si -> number input text
		; OUT:	CY if error
		;	NC if success,
		;	 dx = number
 global ldos_getnum
ldos_getnum:
	mov cx, 10
.before:
	lodsb
	cmp al, 32
	je .before
	cmp al, 9
	je .before
	cmp al, '='
	je .before
	cmp al, ':'
	je .before
	dec si
	mov di, si		; di -> first digit
.preloop:
	lodsb
	cmp al, '_'
	je .preloop
	call capitalise
	cmp al, '0'
	jne .not0
	cmp cl, 10		; base changed to hex?
	jne .hexit		;  then it's a hexit -->
	or ch, 1
	jmp .preloop
.not0:
	cmp al, 'H'
	je .h
	cmp al, 'X'
	jne .notx
.h:
	test ch, 2		; hexits before ?
	jnz .gotsome
	mov di, si
.gotsome:
	cmp cl, 10		; multiple h/x ?
	jne .bad		; reject -->
	mov cl, 16
	jmp .preloop
.notx:
	call ishex
	jc .preend
.hexit:
	or ch, 2		; note hexit
	jmp .preloop

.preend:
	test ch, ch
	jz .bad
	dec si
	test ch, 2
	jz .onlyzero
	cmp di, si
	je .bad
	mov si, di
.onlyzero:
	mov ch, 0
	xor di, di

.loop:
	lodsb
	cmp al, '_'
	je .loop
	call ishex
	jc .end
	cmp al, cl
	jae .bad
	xchg di, ax
	mul cx
	xchg di, ax
	test dx, dx
	jnz .bad
	mov ah, 0
	add di, ax
	jc .bad
	jmp .loop

.bad:
	stc
	retn

.end:
	dec si
.endloop:
	lodsb
	call capitalise
	cmp al, 'X'
	je .endloop
	cmp al, 'H'
	je .endloop
	dec si
	mov dx, di
	clc
	retn


ishex:
	call capitalise
	sub al, '0'
	jc .ret
	cmp al, 10
	jb .ret_cmc
	sub al, 'A' - ('9' + 1)
	jc .ret
	cmp al, 10
	jb .ret
	cmp al, 16
.ret_cmc:
	cmc
.ret:
	retn


capitalise:
	cmp al, 'a'
	jb .gotcap
	cmp al, 'z'
	ja .gotcap
	xor al, 'A' ^ 'a'
.gotcap:
	retn


usesection DOSENTRYINIT

dosentry_init_getdosdata:
 assume ds:nothing, es:nothing, ss:nothing
	push ds
	mov ax, 0
	mov ds, ax
 assume ds:IVT
	mov ax, [31h * 4 + 2]
	pop ds
 assume ds:nothing
	retn

dosentry_init_get_ds_dosdata:
dosentry_init_get_ds_dosbiodata:
 assume ds:nothing, es:nothing, ss:nothing
	push ax
	call dosentry_init_getdosdata
	mov ds, ax
 assume ds:DOSGROUP
	pop ax
	retn

dosentry_init_get_es_dosbiodata:
 assume ds:nothing, es:nothing, ss:nothing
	push ax
	call dosentry_init_getdosdata
	mov es, ax
 assume es:DOSGROUP
	pop ax
	retn


;****************************

Get_Para_Offset proc	near
 assume ds:nothing, es:nothing, ss:nothing
;in:  AX - offset value
;out: AX - offset value adjusted for the next paragraph boundary.
	add	ax, 15		;make a paragraph
	rcr	ax, 1
	shr	ax, 1
	shr	ax, 1
	shr	ax, 1
	shl	ax, 1		;now, make it back to offset value
	shl	ax, 1
	shl	ax, 1
	shl	ax, 1
	ret
Get_Para_Offset endp

;AN004; Don't need this procedure. Get_FAT_Sector replace this.
;	READ A FAT SECTOR INTO FAT LOCATION
;GETFAT  PROC	 NEAR
;	 XOR	 DI,DI			 ; OFFSET
;	 MOV	 DX,1			 ; RELATIVE SECTOR (1ST SECTOR OF FAT)
;	 MOV	 CX,FATLEN		 ; READ ENTIRE FAT.
;	 MOV	 AX,FATLOC		 ;
;	 MOV	 ES,AX			 ; LOCATION TO READ
;	 MOV	 AX,DRVFAT	       ; AH FAT ID BYTE, AL DRIVE
;	 JMP	 DISKRD
;GETFAT  ENDP


usesection SYSINITTRAIL

 extern allocate_temporary_block, alloc_init
 extern sysinit_getdosdata

 global sysinit_get_ds_dosbiodata
 global sysinit_get_ds_dosentry
sysinit_get_ds_dosbiodata:
 assume ds:nothing, es:nothing, ss:nothing
	push ax
	call sysinit_getdosdata
	mov ds, ax
 assume ds:DOSGROUP
	pop ax
	retn

sysinit_get_ds_dosentry:
 assume ds:nothing, es:nothing, ss:nothing
	mov ds, word [cs:.segment]
 assume ds:DOSENTRYGROUP
	retn

	align 2, db 0
.segment:	dw DOSENTRY

 global sysinit_get_es_dosbiodata
 global sysinit_get_es_dosentry
sysinit_get_es_dosbiodata:
 assume ds:nothing, es:nothing, ss:nothing
	push ax
	call sysinit_getdosdata
	mov es, ax
 assume es:DOSGROUP
	pop ax
	retn

sysinit_get_es_dosentry:
 assume ds:nothing, es:nothing, ss:nothing
	mov es, word [cs:sysinit_get_ds_dosentry.segment]
 assume es:DOSENTRYGROUP
	retn

extern dosdata_to_doscode

get_ds_biocode:
 assume ds:nothing, es:nothing, ss:nothing
	mov ds, word [cs:.value]
 assume ds:IVT
	mov ds, word [31h * 4 + 2]
 assume ds:DOSGROUP
	mov ds, word [dosdata_to_doscode]
 assume ds:DOSCODEGROUP
	retn

	align 2, nop
.value:	dw 0

extern biocode_retf

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

transfer_sysinitseg_to_biocode:		; near call ip: in_ip_out_cs
 assume ds:nothing, es:nothing, ss:nothing
	push ax				; in_ax_out_ip
	mov ax, biocode_retf
	push ax				; out_retf
	push ax				; out_destination + 2
	push ax				; out_destination + 0
	lframe 0
	lpar word, in_ip_out_cs
	lpar word, in_ax_out_ip
	lpar word, out_retf
	lpar dword, out_destination
	lenter
	push ds
	push si
	mov si, cs			; si = cs
	xchg si, word [bp + ?in_ip_out_cs]
					; set cs, get ip
	push si				; preserve ip for later
	lodsw				; skip jmp short
	cs lodsw			; get destination
	mov word [bp + ?out_destination + 0], ax
					; set destination
	call get_ds_biocode		; ds => BIOCODE
 assume ds:DOSCODEGROUP
	mov word [bp + ?out_destination + 2], ds
					; => BIOCODE
	pop ax
	xchg ax, word [bp + ?in_ax_out_ip]
					; ax = original ax, set out ip
	pop si
	pop ds
 assume ds:nothing
	lleave
	retf



		; INP:	es:si -> partition table entry,
		;	 si = load_partition_table .. load_partition_table+48,
		;	 es = cs
		;	bp + di -> above part table metadata,
		;	 dwo [bp + di - 4] = root (outermost extended position)
		;	 dwo [bp + di - 8] = base (current table position)
		; CHG:	ax, bx, (cx), dx
handle_each_partition:
 assume es:SYSINITGROUP, ds:SYSINITGROUP
	mov al, byte [es:si + piType]
	call load_is_known
	jc .discard
	jz @F

.discard:
	retn

@@:
	push cx
	push di
	push bp
	push si
	push es

	setopt [load_scan_flags], 32	; a logical or primary partition found
		; Hmm. If we reject the partition later, then we
		;  still have set this flag here. But, that matches
		;  what lMS-DOS did before (invalid partition stops
		;  the scan in current MBR/EPBR). So it stays so.

	mov ax, [bp + di - 8]
	mov dx, [bp + di - 6]		; base (current table position)
	add ax, [es:si + 8]
	adc dx, [es:si + 8 + 2]		; add offset to logical partition
	mov cl, [BDS_harddisk_template + DRIVENUM]

	call sysinit_get_ds_dosbiodata
 assume ds:DOSGROUP
	lds	di, [Start_BDS]
 assume ds:nothing
@@:
	cmp di, -1
	je .notduplicate
	cmp byte [di + DRIVENUM], cl
	jne @F
	cmp word [di + HIDSEC_L], ax
	jne @F
	cmp word [di + HIDSEC_H], dx
	je .duplicate
@@:
	lds di, [di + LINK]
 assume ds:nothing
	jmp @BB

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

	mov di, msg.duplicate_hidden_l
extern hexword
	call hexword
	xchg ax, dx
	mov di, msg.duplicate_hidden_h
	call hexword
	xchg ax, cx
	mov di, msg.duplicate_unit
	call hexbyte

	mov dx, msg.bootfail
	call init2_disp_msg_asciz_cs_dx
	mov dx, msg.duplicate
	call init2_disp_msg_asciz_cs_dx
	jmp partition_reject


.notduplicate:
	push cs
	pop ds
 assume ds:SYSINITGROUP
	mov di, BDS_harddisk_template
					; Hidden sectors (based on EPBR)
	mov [di + HIDSEC_L], ax		;   BPB->HIDSECCT = P->PARTITIONBEGIN;
	mov [di + HIDSEC_H], dx
	mov al, [next_block_device_unit]
	mov [di + DRIVELET], al


;   SETHARD - GENERATE BPB FOR A VARIABLE SIZED HARD FILE.  IBM HAS A
;   PARTITIONED HARD FILE; WE MUST READ PHYSICAL SECTOR 0 TO DETERMINE WHERE
;   OUR OWN LOGICAL SECTORS START.  WE ALSO READ IN OUR BOOT SECTOR TO
;   DETERMINE VERSION NUMBER

;   INPUTS:	DL IS ROM DRIVE NUMBER (80 OR 81)
;		DS:DI POINTS TO BDS
;   OUTPUTS:	CARRY CLEAR -> BPB IS FILLED IN
;		CARRY SET   -> BPB IS LEFT UNINITIALIZED DUE TO ERROR

 assume ds:SYSINITGROUP, es:nothing, ss:nothing
				; Note: Partitiontype 6 means either
				;1).the partition has not been formatted yet, or
				;2).(# of sectors before the partition +
				;    # of sectors in this partition) > word boundary
				;	i.e., needs 32 bit sector calculation, or
				;3).the partition is not a FAT file system.

;J.K.  Until we get the real logical boot record and get the bpb,
;DRVLIM_H,DRVLIM_L will be used instead of DRVLIM for the convenience of
;the computation.
;At the end of this procedure, if a BPB information is gotten from
;the valid boot record, then we are going to use those BPB information
;without change.
;Otherwise, if (hidden sectors + total sectors) <= a word, then
;we will move DRVLIM_L to DRVLIM and zero out DRVLIM_L entry to make
;it a conventional BPB format.

	mov ax, word [es:si + piLength]		; # of sectors (Low)
	mov dx, word [es:si + piLength + 2]	;AN000; # of sectors (High)
	mov	word ptr [di + DRVLIM_H], dx
	mov	word ptr [di + DRVLIM_L], ax ;   BPB->MAXSEC = P->PARTITIONLENGTH;
	test dx, dx
	jnz OKDrive_Cont
	cmp ax, 64			;   IF (P->PARTITIONLENGTH < 64)
	jb partition_reject		;	RETURN -1;

OKDrive_Cont:				;AN000;

	add ax, [di + HIDSEC_L]
	adc dx, [di + HIDSEC_H]		; dx:ax = sector after partition
Okdrive equ OKDRIVE	; NASM port label
	jnc Okdrive
	mov cx, ax
	or cx, dx
        jz Okdrive
	  MESSAGE FTESTHARD,<"PARTITION INVALID",CR,LF>
	or byte [FBIGFAT], FTOOBIG
OKDRIVE:

	testopt [di + FLAGS], F_LBA
	jnz okdrive_lba

	sub ax, 1
	sbb dx, 0			; dx:ax = last sector of partition
	neartransfer lbatochs		; convert to CHS
	jc partition_reject		; if CHS overflow -->

okdrive_lba:

	mov	dx,[di + HIDSEC_H]
	mov	ax,[di + HIDSEC_L]	; BOOT SECTOR NUMBER


;J.K. For convenience, we are going to read the logical boot sector
;into cs:DiskSector area.

;SB34INIT009*************************************************************
;SB  Read in boot sector using BIOS disk interrupt.  The buffer where it
;SB  is to be read in is cs:Disksector.
	call sysinit_get_es_dosentry	; DISKSECTOR in DOSENTRY
 assume es:DOSENTRYGROUP
	mov	bx,offset DiskSector	; access with es
	mov	cx,0201h	; read, one sector
	call readsector_flag
	jc partition_reject		;AN000; Exceeds the limit of Int 13h
;SB34INIT009*************************************************************

	call have_bpb
	jnc @F
 assume ds:SYSINITGROUP
extern BADBLOCK
	MOV	DX,OFFSET BADBLOCK
extern PRINT
	call PRINT
	jmp partition_reject
@@:

	push es
		; At this point we're sure to set up the drive.
		;  So, copy over the template to the next UPB.
	inc byte [next_block_device_unit]
					; remember which DOS drive is next
	mov si, di
	call alloc_upb			; (will halt system on error)
 assume es:UPB
	mov cx, BDS_TYPE_struc_size
	push di
	rep movsb
	pop di				; di -> next UPB
	 push es
	 pop ds				; ds:di -> UPB
 assume ds:UPB
	call Install_BDSM_and_set_bpb	; INSTALL BDS INTO LINKED LIST
	pop es
 assume es:DOSENTRYGROUP


; cs:Disksec contains THE BOOT SECTOR.	IN THEORY, (HA HA) THE BPB IN THIS THING
; IS CORRECT.  WE CAN, THEREFORE, SUCK OUT ALL THE RELEVANT STATISTICS ON THE
; MEDIA IF WE RECOGNIZE THE VERSION NUMBER.

; look for a signature for msdos...
	cmp	word ptr [es:bx+3], "M" + ("S" << 8)
	jne	notmssig
	cmp	word ptr [es:bx+5], "D" + ("O" << 8)
	jne	notmssig
	cmp	byte ptr [es:bx+7], "S"
	je	sigfound
; ...or perhaps pcdos...
notmssig:
	CMP	WORD PTR [es:bx+3], "I" + ("B" << 8)
	jne	notibmsig
	CMP	WORD PTR [es:bx+5], "M" + (" " << 8)
	je	sigfound

notibmsig:
	CMP	WORD PTR [es:bx+3], "O" + ("S" << 8)
	jne	acceptbpb
	CMP	WORD PTR [es:bx+5], "2" + (" " << 8)
	jne	acceptbpb	; ecm: not MSDOS nor IBM nor OS/2, accept BPB -->

sigfound:			; signature was found, now check version

check3point0:
Cover_Fdisk_Bug equ Cover_FDISK_Bug	; NASM port label
	call	Cover_Fdisk_Bug 		;AN010;
		; ecm: only reject "MSDOS3.0" or "IBM  3.0"
	CMP	WORD PTR [es:bx+8],"3" + ("." << 8)
	jne	acceptbpb
	cmp	byte ptr [es:bx+10],"0"         ;do not trust 3.0 boot record. But still legal J.K. 4/15/86
	jne	acceptbpb			;AN012; if version >= 3.1, then O.K.
	jmp	unknown3point0
acceptbpb:
COPYBPB:
; WE HAVE A VALID BOOT SECTOR. USE THE BPB IN IT TO BUILD THE
; BPB IN BIOS. IT IS ASSUMED THAT ONLY SECPERCLUS, CDIR, AND
; CSECFAT NEED TO BE SET (ALL OTHER VALUES IN ALREADY). FBIGFAT
; IS ALSO SET.

;If it is non FAT based system, then just copy the BPB from the BOOT sector
;into the BPB in BDS table, and also set the Boot serial number, Volume id,
;and System ID according to the Boot record.
;For the non_FAT system, don't need to set the other value. So just
;do GOODRET.- J.K.

	cmp	byte [es:Ext_Boot_Sig], EXT_BOOT_SIGNATURE ;AN000;
	jne	COPYBPB_FAT		;AN000; Conventional Fat system
	cmp	byte [es:NumberOfFats], 0	;AN000; If (# of FAT <> 0) then
	jne	COPYBPB_FAT		;AN000;   a Fat system.
;J.K. Non Fat based media.
	push	di			;AN000; Sav Reg.
	push	ds			;AN000;
	push es

	push	ds			;AN000;
	pop	es			;AN000; now es:di -> bds
 assume es:UPB
	call sysinit_get_ds_dosentry	; DISKSECTOR in DOSENTRY
 assume ds:DOSENTRYGROUP
	mov	si, offset Bpb_In_Sector ;AN000; ds:si -> BPB in Boot ; access with ds
	add	di, BYTEPERSEC		;AN000; es:di -> BPB in BDS
	mov	cx, BPB_TYPE_struc_size	;AN000;
	rep	movsb			;AN000;

	pop es
 assume es:DOSENTRYGROUP
	pop	ds			;AN000; Restore Reg.
 assume ds:UPB
	pop	di			;AN000;
	neartransfer Mov_Media_IDs	;AN000; Set Volume id, SystemId, Serial.
init_GoodRet equ init_GOODRET	; NASM port label
	jmp	init_GoodRet

COPYBPB_FAT:				;AN000;  Fat system
	xor	dx,dx			;AN000;
	mov	si, offset Bpb_In_Sector ;AN000;  es:bx -> bpb in boot ; access with es
	mov	ax, [es:si + SECNUM]	;AN000;  total sectors
	test ax, ax			;AN000; double word sector number?
	jnz	Fat_Big_Small		;AN000;  No. Conventional BPB.
	mov	ax, word ptr [es:si + SECNUM_L] ;AN000; Use double word
	mov	dx, word ptr [es:si + SECNUM_H] ;AN000;

Fat_Big_Small:				 ;AN000; Determine Fat entry size.
;At this moment DX;AX = Total sector number
	mov bx, [es:si + RESNUM]
	mov [di + RESSEC], bx
	sub	ax,bx			;AN000; Subtract # reserved
	sbb	dx,0			;AN000;
	mov	bx, [es:si + FATSIZE]	;AN000;  BX = Sectors/Fat
	mov	[di + CSECFAT],bx 	;AN000;  Set in BDS BPB
	xor cx, cx
	mov cl, [es:si + FATNUM]
	mov [di + CFAT], cl
	jcxz .none
.loop:
	sub	ax,bx			;AN000; Subtract # fat sectors
	sbb	dx,0			;AN000;
	loop .loop
.none:
	mov	bx, [es:si + DIRNUM]	;AN000;  # root entries
cDIR equ CDIR	; NASM port equate
	mov	[di + cDIR],bx		;AN000;  Set in BDS BPB

	MOV	CL,4
	shr	bx,cl			;AN000;  Div by 16 ents/sector
	sub	ax,bx			;AN000;  sub # dir sectors
	sbb	dx,0			;AN000;
					;AN000; DX;AX now contains the # of data sectors
	MOV	CL, [es:si + SECALL]	; SECTORS PER CLUSTER
	dec cx
	mov ch, 0
	inc cx				; translate EDR-DOS 0 to 256
	MOV	[DI + SECPERCLUS],CL	; SET IN BIOS BPB (truncated)
;	 XOR	 DX,DX
;	 MOV	 CH,DH
	MNUM	FTESTHARD,CX
	MESSAGE FTESTHARD,<" SECPERCLUS",CR,LF>
;J.K. 3/16/87 P54 Returning back to old logic for compatibility reason.
;So, use the old logic again that once had been commented out!!!!!!!!!!!!
;Old logic to determine FAT Entry Size J.K. 12/3/86
	call sysinit_get_es_dosbiodata
 assume es:DOSGROUP
	push	ax			;AN000;
	xchg	ax, dx			; ax = high word, clobber dx
	xor	dx,dx			;AN000;
	div	cx			;AN000; cx = sectors per cluster
	mov	[es:Temp_H],ax		;AN000;
	pop	ax			;AN000;
	DIV	CX			;AN000;  [Temp_H];AX NOW CONTAINS THE # CLUSTERS.
	cmp	word [es:Temp_H],0		;AN000;
	ja	TooBig_Ret		;AN000;  Too big cluster number
	CMP	AX,4096-10		; IS THIS 16-BIT FAT?
	JB	CopyMediaID		; NO, small FAT
	OR	byte [cs:FBIGFAT],FBIG	; 16 BIT FAT
;End of Old logic
CopyMediaID:
	neartransfer Mov_Media_IDs	;AN000; Copy Filesys_ID, Volume label,
					;and Volume serial to BDS table, if extended
					;boot record.
	JMP	Massage_bpb		;AN000; Now final check for BPB info. and return.

TooBig_Ret:				;AN000;
	OR	byte [cs:FBIGFAT],FTOOBIG
	JMP	init_GOODRET		;AN000; Still drive letter is assigned
					;AN000; But useless. To big for
					;AN000; current PC DOS FAT file system
; UNKNOWN:
;	or	[di].FLAGS, UNFORMATTED_MEDIA	;AN005; Set unformatted media flag.
	; preceeding line commented out 10/88 by MRW--  The boot signature
	;   may not be recognizable, but we should TRY and read it anyway.
						;AN006;
						;AN008; For the time being, allow it.
						;AN009; Now implemented again
; Unknown3_0:				;AN012;Skip setting UNFORMATTED_MEDIA bit
unknown3point0:
 assume es:DOSENTRYGROUP
	MESSAGE FTESTHARD,<"UNKNOWN HARD MEDIA. ASSUMING 3.0.",CR,LF>
	mov	dx, [di + DRVLIM_H]	;AN000;
	mov	ax, [di + DRVLIM_L]	;AN000;
DISKTABLE2 equ DiskTable2	; NASM port label
	MOV	SI,OFFSET DISKTABLE2	; access with cs
.SCAN:
;	 CMP	 AX,[SI]
;	 JBE	 GOTPARM
;	 ADD	 SI,4 * 2

	cmp	dx, word ptr [cs:si]	;AN000;
GotParm equ GOTPARM	; NASM port label
	jb	GotParm 		;AN000;
	ja	.Scan_Next		;AN000;
	cmp	ax, word ptr [cs:si+2]	;AN000;
	jbe	GotParm 		;AN000;
.Scan_Next:				;AN000;
	add	si, 5 * 2		;AN000;
	JMP	.SCAN			;AN000;  Covers upto 512 MB media
GOTPARM:
;	 MOV	 CL,BYTE PTR [SI+6]
	mov	cl,byte ptr [cs:si+8]	;AN000;  Fat size for FBIGFAT flag
	OR	[cs:FBIGFAT],CL
;	 MOV	 CX,[SI+2]
;	 MOV	 DX,[SI+4]
	mov	cx, word ptr [cs:SI+4]	;AN000;
	mov	dx, word ptr [cs:SI+6]	;AN000;

;	DX = NUMBER OF DIR ENTRIES,
;	CH = NUMBER OF SECTORS PER CLUSTER
;	CL = LOG BASE 2 OF CH

;	NOW CALCULATE SIZE OF FAT TABLE

	MNUM	FTESTHARD,AX
	MESSAGE FTESTHARD,<" SECTORS ">
	MNUM	FTESTHARD,DX
	MESSAGE FTESTHARD,<" DIRECTORY ENTRIES ">
	MNUM	FTESTHARD,CX
	MESSAGE FTESTHARD,<" SECPERCLUS|CLUSSHIFT">

	MOV	WORD PTR [CDIR + DI],DX	;SAVE NUMBER OF DIR ENTRIES

;Now, CX = SecPerClus|Clusshift
;     [DI.CDIR] = number of directory entries.

	mov	dx, [di + DRVLIM_H]	;AN000;
	mov	ax, [di + DRVLIM_L]	;AN000;
	MOV	BYTE PTR [SECPERCLUS + DI],CH ;SAVE SECTORS PER CLUSTER
	TEST	byte [cs:FBIGFAT],FBIG		;   IF (FBIGFAT)
	JNZ	DOBIG			;	GOTO DOBIG;
	 MESSAGE FTESTHARD,<" SMALL FAT",CR,LF>
;J.K. We don't need to change "small fat" logic since it is gauranteed
;that double word total sector will not use 12 bit fat (unless
;it's sectors/cluster >= 16 which will never be in this case.)
;So in this case we assume DX = 0 !!!.

	XOR	BX,BX
	MOV	BL,CH
	DEC	BX
	ADD	BX,AX			;AN000;  DX=0
	SHR	BX,CL			;   BX = 1+(BPB->MAXSEC+SECPERCLUS-1)/
	INC	BX			;	    SECPERCLUS
	AND	BL,11111110B		;   BX &= ~1; (=NUMBER OF CLUSTERS)
	MOV	SI,BX
	SHR	BX,1
	ADD	BX,SI
	ADD	BX,511			;   BX += 511 + BX/2
	SHR	BH,1			;   BH >>= 1; (=BX/512)
	MOV	BYTE PTR [DI + CSECFAT],BH ;SAVE NUMBER OF FAT SECTORS
Massage_BPB equ Massage_bpb	; NASM port label
	JMP	SHORT Massage_BPB
DOBIG:
;J.K. For BIGFAT we do need to extend this logic to 32 bit sector calculation.
	  MESSAGE FTESTHARD,<" BIG FAT",CR,LF>
	MOV	CL,4			; 16 (2^4) DIRECTORY ENTRIES PER SECTOR
	push	dx			;AN000; Save total sectors (high)
	mov	dx,[CDIR + DI]		;AN000;
	SHR	DX,CL			; CSECDIR = CDIR / 16;
	SUB	AX,DX			; DX;AX -= CSECDIR; DX;AX -= CSECRESERVED;
	pop	dx			;AN000;
	SBB	dx,0			;AN000;
;	 DEC	 AX			 ; AX = T - R - D
	SUB	ax,1			;AN000; DX;AX = T - R - D
	SBB	dx,0			;AN000;
	MOV	BL,2
	MOV	BH,[SECPERCLUS + DI]	; BX = 256 * SECPERCLUS + 2
;	 XOR	 DX,DX
;J.K. I don't understand why to add BX here!!!
	ADD	AX,BX			; AX = T-R-D+256*SPC+2
	ADC	DX,0
	SUB	AX,1			; AX = T-R-D+256*SPC+1
	SBB	DX,0
;J.K. Assuming DX in the table will never be bigger than BX.
	DIV	BX			; CSECFAT = CEIL((TOTAL-DIR-RES)/
					;		 (256*SECPERCLUS+2));
	MOV	WORD PTR [DI + CSECFAT],AX ; NUMBER OF FAT SECTORS
;J.K. Now, set the default FileSys_ID, Volume label, Serial number
	MOV	BL,[cs:FBIGFAT]
	MOV	[DI + FATSIZ],BL		; SET SIZE OF FAT ON MEDIA
	neartransfer Clear_IDs		;AN000;

;J.K. At this point, in BPB of BDS table, DRVLIM_H,DRVLIM_L which were
;set according to the partition information. We are going to
;see if (hidden sectors + total sectors) > a word.  If it is true,
;then no change.  Otherwise, DRVLIM_L will be moved to DRVLIM
;and DRVLIM_L will be set to 0.
;We don't do this for the bpb information from the boot record. We
;are not going to change the BPB information from the boot record.
Massage_bpb:				;AN000;
 assume es:nothing
	mov	dx, [di + DRVLIM_H]	;AN000;
	mov	ax, [di + DRVLIM_L]	;AN000;
	cmp	dx,0			;AN000; Double word total sector?
	ja	init_GOODRET		;AN000; don't have to change it.
	cmp	word [di + HIDSEC_H], 0	;AN000;
	ja	init_GOODRET		;AN000; don't have to change it.
	add	ax, [di + HIDSEC_L]	;AN000;
	jc	init_GOODRET		;AN000; bigger than a word boundary
	mov	ax, [di + DRVLIM_L]	;AN000;
	mov	[di + DRVLIM], ax 	;AN000;
	mov	word [di + DRVLIM_L], 0	;AN000;
init_GOODRET:
	cmp	word [di + DRVLIM_H], 0	;AN014; Big media?
	jbe	Not_BigMedia		;AN014; No.
	push	es			;AN014;
	push	ax			;AN014;
	mov	ax, SYSINITSEG		;AN014;
	mov	es, ax			;AN014;
 assume es:SYSINITGROUP
	mov	byte [es:Big_Media_Flag], 1	;AN014; Set the flag in SYSINITSEG.
	pop	ax			;AN014;
	pop	es			;AN014;
 assume es:nothing
Not_BigMedia:				;AN014;
	MOV	BL,[cs:FBIGFAT]
	MOV	[DI + FATSIZ],BL		; SET SIZE OF FAT ON MEDIA

partition_reject:
	 push cs
	 pop ds
 assume ds:SYSINITGROUP
	call upb_reset
	pop es
 assume es:SYSINITGROUP
	pop si
	pop bp
	pop di
	pop cx
	retn


		; INP:	es:bx -> transfer address
		;	cl = count
		;	ch = 02h (function code for read CHS)
		;	dx:ax = sector number
		;	ds:di -> UPB
		; CHG:	ax, cx, dx
		; OUT:	CY if error,
		;	 ah = error code
		;	NC if success
readsector_detect:
 assume ds:UPB, es:nothing, ss:nothing
	push cx
	push dx
	mov dl, byte ptr [di + DRIVENUM]
	call detectlba
	pop dx
	pop cx
	jmp readsector_NC_LBA

readsector_flag:
 assume ds:UPB, es:nothing, ss:nothing
	test word ptr [di + FLAGS], F_LBA
	jnz readsector_NC_LBA		; --> (NC)
	stc

readsector_NC_LBA:
	push ds
	push si
	jc readsector_chs
readsector_lba:
	push word ptr [di + DRIVENUM]
	neartransfer lba_packet_setup
 assume ds:DOSGROUP
	pop dx				; dl = unit
	jmp readsector_common

readsector_chs:
	push cx
	neartransfer lbatochs
	pop ax
	jc readsector_ret_ah
	neartransfer chstotuple

readsector_common:
	int 13h
readsector_ret:
	pop si
	pop ds
 assume ds:UPB
	retn

readsector_ret_ah:
	mov ah, 04h			; sector not found
	jmp readsector_ret


		; INP:	dl = unit number
		; OUT:	CY no LBA
		;	NC LBA
		; CHG:	cx
detectlba:
 assume ds:nothing, es:nothing, ss:nothing
	push ax
	push bx
	push dx
	push ds

	mov ax, 40h
	mov ds, ax
 assume ds:nothing
; Setting ds = 40h is a Book8088 bugfix, refer to
;  http://www.bttr-software.de/forum/forum_entry.php?id=21061

	mov ax, 4100h
	mov bx, 55AAh
	xor cx, cx
	xor dh, dh
	stc
	int 13h
	pop ds
 assume ds:nothing
	jc detectlba_ret		; --> CY
	cmp bx, 0AA55h
	stc				; CY
	jne detectlba_ret
	shr cx, 1			; CY if have LBA access functions
	cmc				; NC if have
detectlba_ret:
	pop dx
	pop bx
	pop ax
	ret


Cover_FDISK_Bug		proc			      ;AN010;
 assume ds:UPB, es:DOSENTRYGROUP, ss:nothing
;FDISK of PC DOS 3.3 and below, OS2 1.0 has a bug.  The maximum number of
;sector that can be handled by PC DOS 3.3 ibmbio should be 0FFFFh.
;Instead, sometimes FDISK use 10000h to calculate the maximum number.
;So, we are going to check that if SECNUM + Hidden sector = 10000h
;then subtrack 1 from SECNUM.
	push	ax				      ;AN010;
	push	dx				      ;AN010;
	push	si				      ;AN010;
	cmp	byte [es:Ext_Boot_Sig], EXT_BOOT_SIGNATURE ;AN010;
	je	CFB_Retit			      ;AN010;if extended BPB, then >= PC DOS 4.00
	cmp	word ptr [es:bx+7], ("0" << 8) + "1"   ;AN011; OS2 1.0 ? = IBM 10.0
	jne	CFB_Chk_SECNUM			      ;AN010;
	cmp	byte ptr [es:bx+10], "0"              ;AN010;
	jne	CFB_Retit			      ;AN010;
CFB_Chk_SECNUM:					      ;AN010;
BPB_In_Sector equ Bpb_In_Sector	; NASM port label
	mov	si, offset BPB_In_Sector	      ;AN010;
	cmp	word [es:si + SECNUM], 0		      ;AN010;Just to make sure.
	je	CFB_Retit			      ;AN010;
	mov	ax, [es:si + SECNUM]		      ;AN010;
	add	ax, [es:si + HIDDEN_L]		      ;AN010;
	jnc	CFB_Retit			      ;AN010;
	test	ax, ax				      ;AN010;if carry set and AX=0?
	jnz	CFB_Retit			      ;AN010;
	dec	word [es:si + SECNUM]			      ;AN010;  then decrease SECNUM by 1.
	dec	word [di + DRVLIM_L]			      ;AN010;
CFB_Retit:					      ;AN010;
	pop	si				      ;AN010;
	pop	dx				      ;AN010;
	pop	ax				      ;AN010;
	ret					      ;AN010;
Cover_FDISK_Bug		endp			      ;AN010;


; SETDRVPARMS SETS UP THE RECOMMENDED BPB IN EACH BDS IN THE SYSTEM BASED ON
; THE FORM FACTOR. IT IS ASSUMED THAT THE BPBS FOR THE VARIOUS FORM FACTORS
; ARE PRESENT IN THE BPBTABLE. FOR HARD FILES, THE RECOMMENDED BPB IS THE SAME
; AS THE BPB ON THE DRIVE.

; NO ATTEMPT IS MADE TO PRESERVE REGISTERS SINCE WE ARE GOING TO JUMP TO
; SYSINIT STRAIGHT AFTER THIS ROUTINE.

SETDRVPARMS PROC NEAR
 assume ds:nothing, es:nothing, ss:nothing
	MESSAGE FTESTINIT,<"SETTING DRIVE PARAMETERS",CR,LF>
	XOR	BX,BX
	call sysinit_get_es_dosbiodata
 assume es:DOSGROUP
	LES	DI,[es:START_BDS] ; GET FIRST BDS IN LIST
 assume es:UPB
NEXT_BDS:
	CMP	DI,-1
	JNZ	DO_SETP
DONE_SETPARMS:
	RET

DO_SETP:
 assume es:UPB
	PUSH	ES
	PUSH	DI			; PRESERVE POINTER TO BDS
	MOV	BL,[ES:DI + FORMFACTOR]
	CMP	BL,FFHARDFILE
	JNZ	NOTHARDFF

	xor	dx,dx			;AN000;
	MOV	AX,[ES:DI + DRVLIM]
	test ax, ax			;AN000;
	jnz	GET_cCYL		;AN000;
	mov	dx,[es:di + DRVLIM_H]	;AN000; Use Double word sector number
	MOV	AX,[ES:DI + DRVLIM_L]	;AN000;
GET_cCYL:
	push	dx			;AN000;
	PUSH	AX
	MOV	AX,WORD PTR [ES:DI + HDLIM]
	MUL	WORD PTR [ES:DI + SECLIM] ;Assume Sectorsp per cyl. < 64K.
	MOV	CX,AX			; CX HAS # SECTORS PER CYLINDER
	POP	AX			;
	pop	dx			;AN000; Restore drvlim.
	push	ax			;AN000;
	xchg	ax, dx			; ax = high word, clobber dx
	xor	dx,dx			;AN000;
	div	cx			;AN000;
	push ds
	call sysinit_get_ds_dosbiodata
 assume ds:DOSGROUP
	mov	[Temp_H],ax		;AN000; AX be 0 here.
	pop ds
 assume ds:nothing
	pop	ax			;AN000;
	DIV	CX			; DIV #SEC BY SEC/CYL TO GET # CYL.
	OR	DX,DX
	JZ	NO_CYL_RND		; CAME OUT EVEN
	INC	AX			; ROUND UP
NO_CYL_RND:
	MOV	[ES:DI + CCYLN],AX
	MESSAGE FTESTINIT,<"CCYLN ">
	MNUM	FTESTINIT,AX
	MESSAGE FTESTINIT,<CR,LF>
	PUSH	ES
	POP	DS
 assume ds:UPB
	LEA	SI,[DI + BYTEPERSEC]	; DS:SI -> BPB FOR HARD FILE
	JMP	SHORT SET_RECBPB

NOTHARDFF:
;J.K. We don't use the extended BPB for a floppy.
;J.K.6/24/87

;SB34INIT007******************************************************************
;SB	If Fake floppy drive variable is set then we don't have to handle this
;SB	BDS.  We can just go and deal with the next BDS at label Go_To_Next_BDS.

	cmp	byte [cs:FakeFloppyDrv],1
Go_To_Next_BDS equ GO_TO_NEXT_BDS	; NASM port label
	jz	Go_To_Next_BDS
;SB34INIT007******************************************************************

	CMP	BL,FFOTHER		; SPECIAL CASE "OTHER" TYPE OF MEDIUM
	JNZ	NOT_PROCESS_OTHER
PROCESS_OTHER:
	MOV	AX,[es:DI + CCYLN]
	mul word [es:DI + RHDLIM]
	mul word [es:DI + RSECLIM]
	MOV	[es:DI + RDRVLIM],AX 	; HAVE THE TOTAL NUMBER OF SECTORS
	DEC	AX

;J.K. Old logic was...
;	 MOV	 BX,515
;	 DIV	 BX
;	 OR	 DX,DX
;	 JZ	 NO_ROUND_UP
;	 INC	 AX			 ; ROUND UP NUMBER OF FAT SECTORS

;J.K. New logic to get the sectors/fat area.
					;Fat entry is assumed to be 1.5 bytes!!!
	mov	bx, 3
	mul	bx
	dec bx				; = 2
	div	bx
	xor	dx, dx
	xchg bl, bh			; bh = 2, bl = 0, bx = 512
	div	bx
	inc	ax

NO_ROUND_UP:
	MOV	[es:DI + RCSECFAT],AX
	JMP	SHORT GO_TO_NEXT_BDS
NOT_PROCESS_OTHER:
	SHL	BX,1			; BX IS WORD INDEX INTO TABLE OF BPBS
	push cs
	pop ds
 assume ds:SYSINITGROUP
	MOV	SI,WORD PTR [BPBTABLE + BX]	; GET ADDRESS OF BPB ; access with ds
SET_RECBPB:
	LEA	DI,[DI + RBYTEPERSEC]	; ES:DI -> RECBPB
	MOV	CX,BPBSIZ
	REP	MOVSB			; MOVE BPBSIZ BYTES
GO_TO_NEXT_BDS:
	POP	DI
	POP	ES			; RESTORE POINTER TO BDS
 assume es:UPB
	les di, [ES:DI + LINK]
	JMP	NEXT_BDS

SETDRVPARMS ENDP


usesection DOSENTRYINIT

;
; SI POINTS TO DEVICE HEADER
; J.K. 4/22/86 - print_init, aux_init is modified to eliminate the self-modifying
; J.K. code.

PRINT_INIT:
Get_device_number equ GET_DEVICE_NUMBER	; NASM port label
	call	Get_device_number
;SB33028*****************************************************************
	mov	ah,1			;initalize printer port        ;SB;3.30
	int	17h			;call ROM-Bios routine	       ;SB;3.30
;SB33028*****************************************************************
	ret

AUX_INIT:
	call	Get_device_number
;SB33028*****************************************************************
	mov	al,RSINIT		;2400,N,1,8 (MSEQU.INC)       ;SB ;3.30*
	mov	ah,0			;initalize AUX port	      ;SB ;3.30*
	int	14h			;call ROM-Bios routine	      ;SB ;3.30*
;SB33028*****************************************************************
	ret

GET_DEVICE_NUMBER:
;SI -> device header
	MOV	AL,[CS:SI+13]		;GET DEVICE NUMBER FROM THE NAME
	SUB	AL,"1"
	CBW
	MOV	DX,AX
	RET

%if 0
;
;   PURGE_96TPI NOP'S CALLS TO 96TPI SUPPORT.
;
PURGE_96TPI PROC NEAR			;MJB001
	PUSH	DS
	PUSH	ES

	PUSH	CS			;MJB001
	POP	ES			;MJB001
	PUSH	CS			;MJB001
	POP	DS			;MJB001
	; ASSUME	DS:BIOCODE,ES:BIOCODE

	MOV	SI,OFFSET PATCHTABLE
PATCHLOOP:
	LODSW
	MOV	CX,AX
	JCXZ	PATCHDONE
	LODSW
	MOV	DI,AX
	MOV	AL,90H
	REP	STOSB
	JMP	PATCHLOOP

PATCHDONE:
;**************NOT NEEDED ANY MORE***********************
;	MOV	DI,OFFSET FORMAT_PATCH	     ; ARR 2.42
;	MOV	AL,CS:INST_FAR_RET
;	STOSB
;********************************************************
	MOV	DI,OFFSET TABLE_PATCH	; ARR 2.42
	MOV	AX,OFFSET EXIT
	STOSW
	STOSW

	POP	ES
	POP	DS
	RET				;MJB001
PURGE_96TPI ENDP
%endif


usesection SYSINITTRAIL

set_bpb:
	push si
	push	bx			; now, set the DskDrvs pointer to BPB info
	mov	bx, [cs:Mini_BPB_ptr]
	lea	si, [di + BYTEPERSEC]	; points to BPB of BDSM
	mov	[cs:bx], si
	inc bx
	inc bx
	mov word [cs:Mini_BPB_ptr], bx	; advance to the next address
	pop	bx
	pop si
	retn

have_bpb:
	cmp word [cs:Mini_BPB_ptr], DSKDRVS.end
					; CY if valid to append another
	cmc				; NC if valid
	retn


;
;Install BDSM installs a BDSM (pointed by DS:DI) into the end of the current
;linked list of BDS.
;Also, set the current BDSM pointer segment to DS.
;At entry: DS:DI -> BDSM
;
Install_BDSM_and_set_bpb:
 assume ds:UPB, es:nothing, ss:nothing
	call set_bpb
Install_BDSM:
 assume ds:UPB, es:nothing, ss:nothing
	push	ax
	push	si
	push	es

 extern sysinit_have_bootdrive_preliminary
 extern sysinit_have_bootdrive_exact
	rol byte [cs:sysinit_have_bootdrive_exact], 1
	jc .skip

	testopt [di + FLAGS], FI_AM_MULT
	jz @F
	testopt [di + FLAGS], FI_OWN_PHYSICAL
	jz .skip
@@:
	mov al, [cs:sysinit_bootdrive_unit]
	cmp al, [di + DRIVENUM]
	jne .skip
	mov ax, [cs:sysinit_bootdrive_hidden]
	cmp ax, [di + HIDSEC_L]
	jne .prelim
	mov ax, [cs:sysinit_bootdrive_hidden + 2]
	cmp ax, [di + HIDSEC_H]
	jne .prelim
	not byte [cs:sysinit_have_bootdrive_exact]
	jmp .save

.prelim:
	rol byte [cs:sysinit_have_bootdrive_preliminary], 1
	jc .skip
	not byte [cs:sysinit_have_bootdrive_preliminary]
.save:
	mov al, [di + DRIVELET]
	inc ax
	mov byte [cs:DEFAULT_DRIVE], al
.done:
.skip:

	mov ax, -1
	mov word ptr [di + LINK + 2], ax
	mov word ptr [di + LINK], ax	; make sure it is a null ptr.

	call sysinit_get_es_dosbiodata
 assume es:DOSGROUP
Start_BDS equ START_BDS	; NASM port label
	les	si, [es:Start_BDS]	;start of the beginning of list
 assume es:UPB
	cmp si, ax
	jne I_BDSM_Next
	call sysinit_get_es_dosbiodata
 assume es:DOSGROUP
	mov word [es:Start_BDS], di
	mov word [es:Start_BDS + 2], ds
	jmp I_BDSM_ret

I_BDSM_Next:
 assume es:UPB
	cmp	word ptr [es:si + LINK], ax	;end of the list?
	je	I_BDSM_New
	les	si, [es:si + LINK]
	jmp	short I_BDSM_Next
I_BDSM_New:
	mov	word ptr [es:si + LINK + 2], ds
	mov	word ptr [es:si + LINK], di

I_BDSM_ret:
	pop	es
 assume es:nothing
	pop	si
	pop	ax
	ret

;***The following code is not needed any more.	Don't show any
;***messages to be compatible with the behavior of IBMBIO.COM.
;;Show the message "Mini disk installed ..."
;;This routine uses WRMSG procedure which will call OUTCHR.
;Show_Installed_Mini:
;	 push	 ax
;	 push	 bx
;	 push	 ds
;
;	 mov	 al, MiniNum		 ;logical drive number
;	 add	 al, Drv_Letter_Base	 ;='A'
;	 mov	 Mini_Drv_Let, al
;	 mov	 si, offset Installed_Mini
;	 call	 WRMSG
;
;	 pop	 ds
;	 pop	 bx
;	 pop	 ax
;	 ret
;**End of mini disk initialization**	;J.K. 4/7/86

msg:
.bootfail:			asciz "Boot error: "
.bootfail_read:			db "Reading partition table sector failed (error "
.bootfail_read_errorcode:	asciz "__h).",13,10
.duplicate:			db "Duplicate partition login attempt, unit="
.duplicate_unit:		db "--h, hidden="
.duplicate_hidden_h:		db "----_"
.duplicate_hidden_l:		asciz "----h.",13,10
.bootfail_sig_parttable:	ascii "Partition table signature missing"
				asciz " (is not AA55h).",13,10
.boot_too_many_partitions_error:asciz "Too many partitions (or a loop).",13,10
.boot_partition_cycle_error:	asciz "Partition table cycle detected.",13,10


	usesection DOSENTRYINIT

CMOS_Clock_Read proc	near
; IN ORDER TO DETERMINE IF THERE IS A CLOCK PRESENT IN THE SYSTEM, THE FOLLOWING
; NEEDS TO BE DONE.
	push ds
	call dosentry_init_get_ds_dosbiodata
 assume ds:DOSGROUP, es:nothing, ss:nothing
	PUSH	AX
	PUSH	CX
	PUSH	DX
	PUSH	BP

	XOR	BP,BP
LOOP_CLOCK:
	XOR	CX,CX
	XOR	DX,DX
;SB33030********************************************************************
	MOV	AH,2			;READ REAL TIME CLOCK	      ;SB ;3.30
	INT	1Ah			;CALL ROM-BIOS ROUTINE	      ;SB ;3.30
;SB33030********************************************************************
	CMP	CX,0
	JNZ	CLOCK_PRESENT

	CMP	DX,0
	JNZ	CLOCK_PRESENT

	CMP	BP,1			; READ AGAIN AFTER A SLIGHT DELAY, IN CASE CLOCK
	JZ	NO_READDATE		; WAS AT ZERO SETTING.

	INC	BP			; ONLY PERFORM DELAY ONCE.
	MOV	CX,4000H
DELAY:
	LOOP	DELAY
	JMP	LOOP_CLOCK

CLOCK_PRESENT:
	mov	byte [HaveCMOSClock], 1	;J.K. Set the flag for cmos clock

	call	CMOSCK			;J.K. Reset CMOS clock rate that may be
					;possibly destroyed by CP DOS and POST routine did not
					;restore that.

	PUSH	SI
	MESSAGE FTESTINIT,<"CLOCK DEVICE",CR,LF>
	push cs
	call transfer_read_real_date	;MJB002 READ REAL-TIME CLOCK FOR DATE

	CLI				;MJB002
	MOV	[DAYCNT],SI	      ;MJB002 SET SYSTEM DATE
	STI				;MJB002
	POP	SI			;MJB002
NO_READDATE:
	POP	BP
	POP	DX
	POP	CX
	POP	AX
	pop ds
 assume ds:nothing
	RET

		; INP:	dword [ss:sp] = far return address
transfer_read_real_date:
 assume ds:nothing, es:nothing, ss:nothing
	push ax
	push ax
	mov ax, near_read_real_date
	push ax
	lframe 0
	lpar word, orig_ax_near_ret		; original ax
	lpar word, transfer_segment
	lpar word, transfer_offset		; already initialised
	lenter
	push ds
	call dosentry_init_get_ds_dosdata
 assume ds:DOSGROUP
	mov ax, word [dosdata_to_doscode]
	pop ds
 assume ds:nothing
	mov word [bp + ?transfer_segment], ax
 extern biocode_retf
	mov ax, biocode_retf
	xchg ax, word [bp + ?orig_ax_near_ret]
	lleave
	retf


CMOS_Clock_Read endp
;
;J.K. 10/28/86
;J.K. THE FOLLOWING CODE IS WRITTEN BY JACK GULLEY IN ENGINEERING GROUP.
;J.K. CP DOS IS CHANGING CMOS CLOCK RATE FOR ITS OWN PURPOSES AND IF THE
;J.K. USE COLD BOOT THE SYSTEM TO USE PC DOS WHILE RUNNING CP DOS, THE CMOS
;J.K. CLOCK RATE ARE STILL SLOW WHICH SLOW DOWN DISK OPERATIONS OF PC DOS
;J.K. WHICH USES CMOS CLOCK.  PC DOS IS PUT THIS CODE IN MSINIT TO FIX THIS
;J.K. PROBLEM AT THE REQUEST OF CP DOS.
;J.K. THE PROGRAM IS MODIFIED TO BE RUN ON MSINIT. Equates are defined in CMOSEQU.INC.
;J.K. This program will be called by CMOS_Clock_Read procedure.
;
;  The following code CMOSCK is used to insure that the CMOS has not
;	had its rate controls left in an invalid state on older AT's.
;
;	It checks for an AT model byte "FC" with a submodel type of
;	00, 01, 02, 03 or 06 and resets the periodic interrupt rate
;	bits incase POST has not done it.  This initilization routine
;	is only needed once when DOS loads.  It should be ran as soon
;	as possible to prevent slow diskette access.
;
;	This code exposes one to DOS clearing CMOS setup done by a
;	resident program that hides and re-boots the system.
;
CMOSCK	PROC	NEAR			;	CHECK AND RESET RTC RATE BITS
 assume ds:DOSGROUP, es:nothing

;Model byte and Submodel byte were already determined in MSINIT.
	push	ax
Model_byte equ Model_Byte	; NASM port label
	cmp	byte [Model_byte], 0FCh	;check for PC-AT model byte
					 ;	 EXIT IF NOT "FC" FOR A PC-AT
	JNE	CMOSCK9 		; Exit if not an AT model

	CMP	byte [Secondary_Model_Byte],06H  ; Is it 06 for the industral AT
	JE	CMOSCK4 		; Go reset CMOS periodic rate if 06
	CMP	byte [Secondary_Model_Byte],04H  ; Is it 00, 01, 02, or 03
	JNB	CMOSCK9 		; EXIT if problem fixed by POST
					;J.K. Also,Secondary_model_byte = 0 when AH=0c0h, int 15h failed.
CMOSCK4:				;	RESET THE CMOS PERIODIC RATE
					;  Model=FC submodel=00,01,02,03 or 06
;SB33IN2***********************************************************************

	mov	al,CMOS_REG_A | NMI	;NMI disabled on return
	mov	ah,00100110b		;Set divider & rate selection
	call	CMOS_WRITE

;SB33IN2***********************************************************************

					;	CLEAR SET,PIE,AIE,UIE AND SQWE
	mov	al,CMOS_REG_B | NMI	;NMI disabled on return
	call	CMOS_READ
	and	al,00000111b		;clear SET,PIE,AIE,UIE,SQWE
	mov	ah,al
	mov	al,CMOS_REG_B		;NMI enabled on return
	call	CMOS_WRITE

;SB33IN3***********************************************************************

CMOSCK9:				;	EXIT ROUTINE
	pop	ax
	RET				; RETurn to caller
					;  Flags modifyied
CMOSCK	ENDP
;PAGE
;--- CMOS_READ -----------------------------------------------------------------
;		READ BYTE FROM CMOS SYSTEM CLOCK CONFIGURATION TABLE	       :
;									       :
; INPUT: (AL)=	CMOS TABLE ADDRESS TO BE READ				       :
;		BIT    7 = 0 FOR NMI ENABLED AND 1 FOR NMI DISABLED ON EXIT    :
;		BITS 6-0 = ADDRESS OF TABLE LOCATION TO READ		       :
;									       :
; OUTPUT: (AL)	VALUE AT LOCATION (AL) MOVED INTO (AL).  IF BIT 7 OF (AL) WAS  :
;		ON THEN NMI LEFT DISABLED.  DURING THE CMOS READ BOTH NMI AND  :
;		NORMAL INTERRUPTS ARE DISABLED TO PROTECT CMOS DATA INTEGRITY. :
;		THE CMOS ADDRESS REGISTER IS POINTED TO A DEFAULT VALUE AND    :
;		THE INTERRUPT FLAG RESTORED TO THE ENTRY STATE ON RETURN.      :
;		ONLY THE (AL) REGISTER AND THE NMI STATE IS CHANGED.	       :
;-------------------------------------------------------------------------------

CMOS_READ	PROC	NEAR		;	READ LOCATION (AL) INTO (AL)
 assume es:nothing,ds:nothing
	PUSHF				; SAVE INTERRUPT ENABLE STATUS AND FLAGS
;SB33IN4********************************************************************

	cli
	push	bx
	push	ax			;save user NMI state
	or	al,NMI			;disable NMI for us
	out	CMOS_PORT,al
	nop				;undocumented delay needed
	in	al,CMOS_DATA		;get data value

	 ;set NMI state to user specified 
	mov	bx,ax			;save data value
	pop	ax			;get user NMI
	and	al,NMI
	or	al,CMOS_SHUT_DOWN
	out	CMOS_PORT,al
	nop
	in	al,CMOS_DATA

	mov	ax,bx			;data value
	pop	bx

;SB33IN4********************************************************************
	PUSH	CS			; *PLACE CODE SEGMENT IN STACK AND
	CALL	CMOS_POPF		; *HANDLE POPF FOR B- LEVEL 80286
	RET				; RETURN WITH FLAGS RESTORED

CMOS_READ	ENDP

CMOS_POPF	PROC	NEAR		;	POPF FOR LEVEL B- PARTS
	IRET				; RETURN FAR AND RESTORE FLAGS

CMOS_POPF	ENDP

;--- CMOS_WRITE ----------------------------------------------------------------
;		WRITE BYTE TO CMOS SYSTEM CLOCK CONFIGURATION TABLE	       :
;									       :
; INPUT: (AL)=	CMOS TABLE ADDRESS TO BE WRITTEN TO			       :
;		BIT    7 = 0 FOR NMI ENABLED AND 1 FOR NMI DISABLED ON EXIT    :
;		BITS 6-0 = ADDRESS OF TABLE LOCATION TO WRITE		       :
;	 (AH)=	NEW VALUE TO BE PLACED IN THE ADDRESSED TABLE LOCATION	       :
;									       :
; OUTPUT:	VALUE IN (AH) PLACED IN LOCATION (AL) WITH NMI LEFT DISABLED   :
;		IF BIT 7 OF (AL) IS ON.  DURING THE CMOS UPDATE BOTH NMI AND   :
;		NORMAL INTERRUPTS ARE DISABLED TO PROTECT CMOS DATA INTEGRITY. :
;		THE CMOS ADDRESS REGISTER IS POINTED TO A DEFAULT VALUE AND    :
;		THE INTERRUPT FLAG RESTORED TO THE ENTRY STATE ON RETURN.      :
;		ONLY THE CMOS LOCATION AND THE NMI STATE IS CHANGED.	       :
;-------------------------------------------------------------------------------

CMOS_WRITE	PROC	NEAR		;	WRITE (AH) TO LOCATION (AL)
 assume es:nothing,ds:nothing
	PUSHF				; SAVE INTERRUPT ENABLE STATUS AND FLAGS
	PUSH	AX			; SAVE WORK REGISTER VALUES

	cli
	push	ax			;save user NMI state
	or	al,NMI			;disable NMI for us
	out	CMOS_PORT,al
	nop
	mov	al,ah
	out	CMOS_DATA,al		;write data

	 ;set NMI state to user specified 
	pop	ax 			;get user NMI
	and	al,NMI
	or	al,CMOS_SHUT_DOWN
	out	CMOS_PORT,al
	nop
	in	al,CMOS_DATA

;SB33IN5********************************************************************
	POP	AX			; RESTORE WORK REGISTERS
	PUSH	CS			; *PLACE CODE SEGMENT IN STACK AND
	CALL	CMOS_POPF		; *HANDLE POPF FOR B- LEVEL 80286
	RET

CMOS_WRITE	ENDP
;

%assign NUMBER_DOSENTRY_INIT_DISCARD $ - end_of_dosentry_init_late
%warning DOSENTRY discard size NUMBER_DOSENTRY_INIT_DISCARD
%if NUMBER_DOSENTRY_INIT_DISCARD < SYSINITSTACK + 64
	; 64 is for the first UMCB and a small safety margin
 %assign NUMBER_SYSINITSTACK SYSINITSTACK + 64
 %error DOSENTRY discard size NUMBER_DOSENTRY_INIT_DISCARD smaller than NUMBER_SYSINITSTACK
%endif


END$:
; (no prior section) ; CODE	ENDS
	END

