;;	extended-IPL:
;;		multi OS boot utility for IBM PC/AT and compatibles
;;					Auther: takamiti@tsden.org
;;

NULL		equ 00h
BELL		equ 07h
CR		equ 0Dh
LF		equ 0Ah
ENTER_SCAN	equ 01Ch
EXEC_KEY	equ 4F00h		; END key

VIDEOBIOS	equ 10h
DISKBIOS	equ 13h
KEYBIOS		equ 16h

BIOS_LOC	equ 7C00h
BOOT_LOC	equ 0600h
IPLMAGICVAL	equ 0AA55h

PART_TAB	equ BOOT_LOC + 01BEh

magicval	equ BOOT_LOC + 01FEh
kbd_stat	equ 0417h
fd_stat		equ 043Fh
nr_hdds		equ 0475h

DGROUP		group	_DATA, _BSS
		assume	cs:_TEXT, ds:DGROUP

_DATA		segment word public 'DATA'
_DATA		ends

_BSS		segment word public 'BSS'
_BSS		ends

_TEXT		segment byte public 'CODE'
		assume cs:_TEXT

;=======================================================
;		extendedIPL
;=======================================================
		public	_extendedIPL
_extendedIPL	proc	near
base:		cli
		xor	ax,ax
		mov	ss,ax
		mov	es,ax
		mov	ds,ax
		mov	sp,BIOS_LOC
		mov	si,sp
		sti
		cld
		mov	di,BOOT_LOC
		mov	cx,256
		repnz	movsw
		mov	ax,offset start - base + BOOT_LOC
		push	ax
		ret

start:
chk_pause:	test	byte ptr DGROUP:[kbd_stat],03h
		jnz	chk_table
		test	byte ptr DGROUP:[fd_stat],0Fh
		jnz	chk_pause
		mov	cx,4
		mov	di,PART_TAB
		mov	dh,30h
auto1:		inc	dh
		test	byte ptr [di],80h
		jnz	boot_1
		add	di,16
		loop	auto1

chk_table:	call	initCRT
		mov	cx,4
		mov	di,PART_TAB
		mov	dx,3130h
		mov	si,offset guid_msg - base + BOOT_LOC
		call	putstr
chtabloop:	inc	dx
		test	byte ptr [di],80h
		jz	prntab
		mov	dh,dl
		and	byte ptr [di],7Fh
prntab:		mov	ah,2
		mov	al,dl
		call	putSPC
		mov	bl,[di+4]
		or	bl,bl
		jz	nosys
		mov	ax,0673h
		call	putSPC
		xchg	ax,bx
		call	hex2
nosys:		call	putCRLF
		add	di,16
		loop	chtabloop
		call	putCRLF
retry:		mov	si,offset sel_msg - base + BOOT_LOC
		call	putstr
keyin:		mov	al,dh
		call	putch
keyin1:		xor	ah,ah
		int	KEYBIOS
		cmp	al,30h
		jc	sel_ok
		cmp	al,34h
		ja	keyin1
		mov	dh,al			; save
		jmp	short retry

sel_ok:		cmp	ax,EXEC_KEY
		jz	boot_1
		cmp	ah,ENTER_SCAN		; scan code
		jnz	keyin1
boot_1:		mov	di,dx
		sub	dh,30h
		jz	switch_HD

		xchg	ax,bp
		dec	dh
		mov	al,16
		mul	dh
		add	ax,PART_TAB
		xchg	ax,si			; partition table address in si
		cmp	byte ptr [si+4],0
		jz	wrong_sys
		mov	dx,[si]
		mov	dl,DGROUP:[drive - base + BOOT_LOC]
		add	dl,050h
		mov	cx,[si+2]
		push	bp
		push	di
		call	HDread
		pop	di
		pop	ax
		cmp	al,LF			; <Ctrl>+<Enter>
		jz	exec_loader
		cmp	word ptr [bx + 1feh],IPLMAGICVAL
		jz	exec_loader
wrong_sys:	push	ax
		mov	al,BELL
		call	putch
		mov	dx,di
		pop	ax
		cmp	ax,offset start - base + BOOT_LOC
		jnz	retry
		jmp	chk_table

exec_loader:	mov	[si],dl
		or	al,al
		jnz	skip
		cmp	dl,080h
		jnz	skip
		xor	dh,dh
		mov	cx,1
		mov	bp,0301h
		mov	bx,BOOT_LOC
		call	HDio
skip:		call	initCRT
		db	0EAh
		dw	BIOS_LOC
		dw	0		; jmp	far BIOS_LOC

; read IPL sector from next HD 
switch_HD:	mov	al,byte ptr DGROUP:[drive - base + BOOT_LOC]
		sub	al,30h
		inc	ax
		cmp	al,byte ptr DGROUP:[nr_hdds]
		jc	swhd1
		xor	ax,ax
swhd1:		push	ax
		add	al,30h
		mov	DGROUP:[drive - base + BOOT_LOC],al
		pop	dx
		or	dl,80h
		xor	dh,dh
		mov	cx,1
		call	HDread
		mov	si,BIOS_LOC + 1BEh
		mov	di,PART_TAB
		mov	cx,33
		repnz	movsw
		jmp	chk_table

HDread:		mov	bx,BIOS_LOC	; load address 0x7C00L
		mov	bp,0201h	; read a sector in BIOS_LOC
HDio:		mov	di,8
HDretry:	mov	ax,bp
		int	DISKBIOS
		jnc	exit_
		dec	di
		jns	HDretry
; Disk BIOS error
		push	ax
		mov	ax,033fh
		call	putSPC
		pop	ax
		mov	al,ah
		call	hex2
		hlt
		jmp	$

putspace:	mov	al,20h
putch:		push	bx
		mov	ah,14
		mov	bx,1
		int	VIDEOBIOS
		pop	bx
exit_:		ret

putCRLF:	mov	si,offset crlf_msg - base + BOOT_LOC
putstr:		lodsb
		or	al,al
		jz	exit_
		call	putch
		jmp	short putstr

hex2:		push	ax
		push	cx
		mov	cl,4
		shr	al,cl
		pop	cx
		call	hex1
		pop	ax
hex1:		and	al,0Fh
		add	al,30h
		cmp	al,3Ah
		jc	pr_hex
		add	al,7
pr_hex:		jmp	short putch

putSPC:		push	ax
		push	cx
		mov	cl,ah
p_spc_loop:	call	putspace
		loop	p_spc_loop
		pop	cx
		pop	ax
		jmp	short putch

initCRT:	mov	ax,2
		int	VIDEOBIOS
		ret

guid_msg:	db	"Part.  System"
crlf_msg:	db	CR, LF, NULL
sel_msg:	db	CR
		db	"Boot #"
drive:		db	30h
		db	":"
		db	NULL
		db	20 dup(0ffh)
_extendedIPL	endp


;=======================================================
;		FDtestIPL
;=======================================================
		public	_FDtestIPL
_FDtestIPL	proc	near
Fbase:		cli
		xor	ax,ax
		mov	ss,ax
		mov	es,ax
		mov	ds,ax
		mov	sp,BIOS_LOC
		mov	si,sp
		sti
		cld
		mov	di,BOOT_LOC
		mov	cx,256
		repnz	movsw
		mov	ax,offset Fstart - Fbase + BOOT_LOC
		push	ax
		ret

Fstart:		push	ax
		mov	dx,80h
		call	Fgettable
		mov	al,90h
		mov	DGROUP:[fdhook - Fbase + BOOT_LOC],al	; ^^;
		pop	ax
Fchkpause:	test	byte ptr DGROUP:[kbd_stat],03h
		jnz	Fchktable
		test	byte ptr DGROUP:[fd_stat],0Fh
		jnz	Fchkpause
		mov	cx,4
		mov	di,PART_TAB
		mov	dh,30h
Fauto1:		inc	dh
		test	byte ptr [di],80h
		jnz	Fboot1
		add	di,16
		loop	Fauto1

Fchktable:	call	FinitCRT
		mov	cx,4
		mov	di,PART_TAB
		mov	dx,3130h
		mov	si,offset Fguidmsg - Fbase + BOOT_LOC
		call	Fputstr
Fchtabloop:	inc	dx
		test	byte ptr [di],80h
		jz	Fprntab
		mov	dh,dl
		and	byte ptr [di],7Fh
Fprntab:	mov	ah,2
		mov	al,dl
		call	FputSPC
		mov	bl,[di+4]
		or	bl,bl
		jz	Fnosys
		mov	ax,0673h
		call	FputSPC
		xchg	ax,bx
		call	Fhex2
Fnosys:		call	FputCRLF
		add	di,16
		loop	Fchtabloop
		call	FputCRLF
Fretry:		mov	si,offset Fselmsg - Fbase + BOOT_LOC
		call	Fputstr
Fkeyin:		mov	al,dh
		call	Fputch
Fkeyin1:	xor	ah,ah
		int	KEYBIOS
		cmp	al,30h
		jc	Fselok
		cmp	al,34h
		ja	Fkeyin1
		mov	dh,al		; save
		jmp	short Fretry

Fselok:		cmp	ax,EXEC_KEY
		jz	Fboot1
		cmp	ah,ENTER_SCAN		; scan code
		jnz	Fkeyin1
Fboot1:		mov	di,dx
		sub	dh,30h
		jz	FswitchHD

		xchg	ax,bp
		dec	dh
		mov	al,16
		mul	dh
		add	ax,PART_TAB
		xchg	ax,si			; partition table address
		cmp	byte ptr [si+4],0
		jz	Fwrongsys
		mov	dx,[si]
		mov	dl,byte ptr DGROUP:[Fdrive - Fbase + BOOT_LOC]
		add	dl,50h
		mov	cx,[si+2]
		push	bp
		push	di
		call	FHDread
		pop	di
		pop	ax
		cmp	al,LF			; <Ctrl>+<Enter>
		jz	Fexecloader
		cmp	word ptr [bx + 1feh],IPLMAGICVAL
		jz	Fexecloader
Fwrongsys:	push	ax
		mov	al,BELL
		call	Fputch
		mov	dx,di
		pop	ax
		cmp	ax,offset Fstart - Fbase + BOOT_LOC
		jnz	Fretry
		jmp	Fchktable

Fexecloader:	mov	byte ptr [si],dl
		call	FinitCRT
		db	0EAh
		dw	BIOS_LOC
		dw	0		; jmp	far BIOS_LOC

; read IPL sector from next HD 
FswitchHD:	mov	al,byte ptr DGROUP:[Fdrive - Fbase + BOOT_LOC]
		sub	al,30h
		inc	ax
		cmp	al,byte ptr DGROUP:[nr_hdds]
		jc	Fswhd1
		xor	ax,ax
Fswhd1:		push	ax
		add	al,30h
		mov	DGROUP:[Fdrive - Fbase + BOOT_LOC],al
		pop	dx
		or	dl,80h
		xor	dh,dh
Fgettable:	mov	cx,1
		call	FHDread
		mov	si,BIOS_LOC + 01BEh
		mov	di,PART_TAB
		mov	cx,33
		repnz	movsw
fdhook:		ret
		jmp	Fchktable

FHDread:	mov	bx,BIOS_LOC	; load address[0000:7C00]
		mov	di,8
FHDretry:	mov	ax,0201h	; read a sector in BIOS_LOC
		int	DISKBIOS
		jnc	Fexit
		dec	di
		jns	FHDretry
Ferror:		push	ax		; error starus
		mov	ax,033fh
		call	FputSPC
		pop	ax
		mov	al,ah
		call	Fhex2
		hlt
		jmp	$

Fputspace:	mov	al,20h
Fputch:		push	bx
		mov	ah,14
		mov	bx,1
		int	VIDEOBIOS
		pop	bx
Fexit:		ret

FputSPC:	push	ax
		push	cx
		mov	cl,ah
Fspcloop:	call	Fputspace
		loop	Fspcloop
		pop	cx
		pop	ax
		jmp	short Fputch

FputCRLF:	mov	si,offset Fcrlfmsg - Fbase + BOOT_LOC
Fputstr:	lodsb
		or	al,al
		jz	Fexit
		call	Fputch
		jmp	short Fputstr
Fhex2:		push	ax
		push	cx
		mov	cl,4
		shr	al,cl
		pop	cx
		call	Fhex1
		pop	ax
Fhex1:		and	al,0Fh
		add	al,30h
		cmp	al,3Ah
		jc	Fprhex
		add	al,7
Fprhex:		jmp	short Fputch

FinitCRT:	mov	ax,2
		int	VIDEOBIOS
		ret

Fguidmsg:	db	"Part.  System"
Fcrlfmsg:	db	CR, LF, NULL
Fselmsg:	db	CR
		db	"Boot #"
Fdrive:		db	30h
		db	":"
		db	NULL
is1st:		db	0
		db	30 dup(0ffh)
_FDtestIPL	endp

		public	_dmaoverrun
_dmaoverrun	proc	near
		push	bp
		mov	bp,sp
		mov	ax,ds
		mov	cl,4
		shl	ax,cl
		add	ax,[bp+4]
		mov	bx,[bp+6]
		dec	bx
		add	ax,bx
		mov	ax,0
		jnc	dma_ok
		inc	ax
dma_ok:		pop	bp
		ret
_dmaoverrun	endp

;;		public	_codecpy
_codecpy	proc	near
		push	bp
		mov	bp,sp
		push	ds
		push	di
		push	si
		mov	di,[bp+4]
		mov 	ax,cs
		mov	ds,ax
		mov	si,[bp+6]
		mov	cx,[bp+8]
		rep	movsb
		pop	si
		pop	di
		pop	ds
		pop	bp
		ret
_codecpy	endp

_TEXT		ends
		end

