/* shared.S  -  Routines shared by the first and the second boot loader */

/* Written 1992-1994 by Werner Almesberger */

! display _must_ be the first routine in this file !

display:
#ifdef SECOND_STAGE
	seg	cs		! use a serial port ?
	cmp	slbase,#0
	je	nodser		! no -> go on
	call	serdisp
nodser:
#endif
	xor	bh,bh		! display on screen
	mov	ah,#14
	int	0x10
	ret

#ifdef SECOND_STAGE
serdisp:push	dx		! wait for space in the send buffer
	push	ax
	seg	cs
	mov	dx,slbase
	add	dx,#5
serwait:in	al,dx
	test	al,#0x10	! break -> set break flag
	jz	nobrk
	seg	cs
	mov	byte ptr break,#1
nobrk:	test	al,#0x20	! ready to send ?
	jz	serwait		! no -> wait
	sub	dx,#5		! send the character
	pop	ax
	out	dx,al
	pop	dx		! done
	ret
#endif

tord:	br	dord		! ...
tolner5:br	linerr5		! ...

cread:	test	dl,#LINEAR_FLAG	! linear address ?
	jz	tord		! no -> go on
	and	dl,#0xff-LINEAR_FLAG ! remove flag
	mov	t_secs,al	! save number of sectors
lnread:	push	cx		! keep linear address
	push	dx
	push	bx		! BX is used as scratch
	push	cx		! LSW
	push	dx		! MSW with drive
	mov	ah,#8		! get drive geometry (do not clobber ES:DI)
	push	es
	push	di
	int	0x13
	pop	di
	pop	es
	jc	tolner5		! error -> quit
	mov	bl,dh		! BL <- #heads
	pop	dx		! get MSW
	mov	t_drive,dl	! save drive
	mov	dl,dh		! linear address into DX:AX
	xor	dh,dh
	mov	bh,dh		! (clear BH too)
	pop	ax
	push	cx		! compute #cyls-1
	xchg	ch,cl
	rol	ch,1
	rol	ch,1
	and	ch,#3
	mov	n_cyl,cx	! save #cyls-1
	pop	cx
	and	cx,#0x3f	! CX <- #secs
	mov	n_secs,cx
	div	cx		! AX <- track, DX <- sector
	inc	dl
	mov	t_sector,dl
	xor	dx,dx		! divide by #heads
	inc	bx
	div	bx		! AX <- cylinder, DX <- head
	mov	dh,dl		! set up DX (head:drive)
	mov	dl,t_drive
	cmp	ax,n_cyl	! valid cylinder number ?
	ja	linerr3		! no -> error
	xchg	ah,al		! build cylinder number
	ror	al,1
	ror	al,1
	or	al,t_sector
	mov	cx,ax
	pop	bx		! restore BX
	and	ax,#0x3f	! read beyond end of track ?
	add	ax,t_secs
	cmp	ax,n_secs
	jna	intrk		! no -> go on
	mov	al,n_secs	! read to end of track
	sub	al,t_sector
	inc	al
	jmp	lrd		! read it
intrk:	mov	al,t_secs	! read all sectors
lrd:	push	ax		! save AX and BX
	push	bx
	call	dord		! read the sector(s)
	pop	bx		! restore AX and BX and the linear address
	pop	ax
	pop	dx
	pop	cx
	jc	linerr		! error -> quit
	sub	t_secs,al	! adjust sector count
	jz	lindone		! zero -> done
	xor	ah,ah		! increase linear address
	add	cx,ax
	adc	dh,#0
	xchg	ah,al		! move BX
	add	ah,ah
	add	bx,ax
	jc	interr		! crossing segment boundaries -> error
	br	lnread		! process remaining sectors
linerr5:pop	dx		! discard stack contents
	pop	cx
	pop	bx
	pop	dx
	pop	cx
	ret			! (carry is already set)
linerr3:pop	bx		! pop BX and linear address
	pop	dx
	pop	cx
interr:	xor	ax,ax		! zero indicates internal error
linerr:	stc			! error
	ret
lindone:clc			! no error
	ret			! done

dord:	seg	cs		! set command
	mov	ah,(dsk_cmd)
#ifdef DBG_LREAD
	push ax
	push bx
	push cx
	push dx
	push es
	push dx
	push cx
	push bx
	push ax
	mov bx,#sax
	call say
	pop ax
	call wout
	mov bx,#sbx
	call say
	pop ax
	call wout
	mov bx,#scx
	call say
	pop ax
	call wout
	mov bx,#sdx
	call say
	pop ax
	call wout
	mov bx,#ses
	call say
	pop ax
	call wout
	mov bx,#sdone
	call say
	pop dx
	pop cx
	pop bx
	pop ax
#endif
	int	0x13		! read or write
	ret

dsk_cmd:.byte	2		! read

n_cyl:	.word	0		! temporary space
n_secs:	.word	0
t_drive:.byte	0
t_sector:.byte	0
t_secs:	.word	0
