; rootsect.s

;------------------------------------------------------------------------
;									:
; Hard Disk Root Sector							:
; Initiates boot from a hard disk partition, contains hard disk 	:
; read-sector subroutine for use by partition's	boot code.		:
;									:
; Copyright 1986, 1987, 1988, 1989, 1990 Atari Corp.			:
; All Rights Reserved							:
;									:
; Jul-24-1989	ml.	Modified this for TT.				:
;			New ROMs will pass the following to this	:
;			root sector:					:
;			d3.l = $444d4172 ("DMAr") to indicate the XBIOS	:
;				call for DMAread exists.		:
;			d4.w = boot unit # (iff d3.l = "DMAr")		:
;			d5.w = user-preference (ignore for now!!)	:
;			d7.b = ACSI device # in upper 3 bits		:
;				(should ignore d7.b if d4.w is valid)	:
; Feb-05-1990	ml.	Modified to reflect the latest boot spec. which	:
;			includes booting UNIX on the TT.		:
;			Removed code that handles MSDOS root sector.	:
;			Handled user-preference as stated in latest	:
;			TT boot spec.					:
; Feb-14-1990	ml.	If a user-preference is passed in through d5 	:
;			but no entry matches it, just quit.  Maybe the	:
;			preference is for another kind of device.	:
; Jul-25-1990	ml.	Modified handling of user-preference code, so	:
;			that bits 1 & 2 of byte 0 of a partition entry	:
;			do not participate in the comparison.  (This 	:
;			lifts the assumption that they have to be 0.)	:
;									:
;------------------------------------------------------------------------


;---- Hardware registers:
diskctl		equ	$ffff8604	; (W) disk controller data access
fifo		equ	$ffff8606	; (W) DMA mode control
dmahigh		equ	$ffff8609	; (B) DMA base high
dmamid		equ	$ffff860b	; (B) DMA base medium
dmalow		equ	$ffff860d	; (B) DMA base low
gpip		equ	$fffffa01	; (B) bit 5 is DMA interrupt line

;---- OS locations:
flock		equ	$43e		; (W) DMA chip lock variable
_bootdev	equ	$446		; (W) boot device number
_hz_200		equ	$4ba		; (L) 200 hz timer tick
_drvbits	equ	$4c2		; (L) logical drive map
_dskbufp	equ	$4c6		; (L) -> 1K disk buffer
_sysbase	equ	$4f2		; (L) -> OS header

;--- Magic numbers:
bootmagic	equ	$1234		; executable boot sector checksum
DMAr		equ	$444d4172	; DMAread() 


;+
;  Root Sector
;
;  First branch (+0) goes to partition booter;
;  Second branch (+2) goes to disk read routine.
;  Bfat (+6) is a flag for size of FAT entries
;
;-
_rootstart::
base:	bra.s	rootboot	; boot some partition
	bra	dmaread		; read sectors


;+
;  rootboot - locate a bootable partition and boot from it
;
;    - If the [ALT] key is down, just exit;
;    - Search for bootable partition in sector image;
;    - If none, just return;
;    - Otherwise, load partition's boot sector into upper half
;      of the 1K buffer, checksum it, and execute it if it
;      checks out;
;    - Adjust D7 on return so the DMA bus will not lock up.
;
;-
rootboot:			; if this code fails, there's no C:
	bclr.b	#2,_drvbits+3	; so, clobber 'C' bit in _drvbits
	move.w	#0,_bootdev	; initialise bootdev to be A:
	movem.l	d3/d5,-(sp)	; save d3 and d5
	move.w	#-1,-(sp)	; get state of the shift keys
	move.w	#$0b,-(sp)	; d0 = Kbshift()
	trap	#13
	addq.w	#4,sp		; clean-up stack
	btst	#3,d0		; is [ALT] down?
	bne.s	rb_r		; (yes, just return)

	moveq	#3,d0		; d0 = partition count
	moveq	#$00f8,d1	; d1 = mask for boot value
	lea	base+$1c6(pc),a0 ; a0 -> first partition entry
	cmpi.l	#DMAr,d3	; does DMAread() exist?
	beq.s	rb_0		; if it does, d4 = physical unit number
	moveq	#-1,d4		; else d4 = -1 => no DMAread in ROM
	moveq	#$80,d2		; d2 = old boot value
	bra.s	rb_1		; and boot the old way

rb_0:	move.b	d5,d2		; else, is there a user preference?
	beq.s	rb_5		; if not, boot the first bootable partition
rb_1:	btst.b	#0,(a0)		; does partition exist?
	beq.s	rb_2		; if not, try next partition slot
	and.b	d1,(a0)		; mask off irrelevant bits
	cmp.b	(a0),d2		; p_flg matches boot value?
	beq.s	rb_3		; (yes --- boot the partition)
rb_2:	adda.w	#12,a0		; bump to next partition entry
	dbra	d0,rb_1		; (no --- look for other partitions)
	bra.s	rb_r		; boot value search fails, return to ROMs
				; boot the first bootable partition
rb_5:	btst.b	#0,(a0)		; does partition exist?
	beq.s	rb_6		; if not, try next partition slot
	and.b	d1,(a0)		; partition has a non-zero boot value?
	bne.s	rb_3		; (yes --- boot the partition)
rb_6:	adda.w	#12,a0		; (no --- bump to next partition entry)
	dbra	d0,rb_5		; look for other partitions
				; if none is bootable, return to ROMs

;+
;  Return to BIOS boot routine:
;    - hack D7 so BIOS never does any more reads
;      (so the DMA bus will not lock up).
;
;  Modified 18-Feb-1988 by AKP to hack D7 (and stop looking on the DMA bus)
;  ONLY on 11/20-derived ROMs.  Newer ROMs have this bug fixed.
;-
rb_r:	addq.w	#$08,sp		; clean up stack
rb_bs:	move.l	_sysbase,a0	; get the system header address
	move.l	$18(a0),d0	; d0.l = MMDDYYYY of ROM date
	swap	d0		; d0.l = YYYYMMDD of ROM date
	cmp.l	#$19870422,d0	; does this version of ROM need bootstop?
	bcc.s	dontstop	; nope, if OS is built on or after 4/22/87
	move.w	#$100-$20,d7	; prevent any other boot sector loads
dontstop:
	rts			; no bootable partitions


;+
;  Handle bootable partition:
;    - read its boot sector;
;    - checksum it;
;    - if it is executable, call it.
;-
rb_3:	move.l	4(a0),d6	; d6 = sector number
	moveq	#1,d5		; d5 = sector count = 1
	lea	base+$200(pc),a4 ; a4 -> upper half of 1K buffer
	bsr.s	dmaread		; read partition's boot sector
	tst.w	d0		; successful?
	bne.s	rb_r		; (punt on failure)

	move.l	a4,a0		; a0 -> buffer to checksum
	move.w	#$0ff,d1	; checksum $100 words
	moveq	#0,d0		; initialise checksum = 0
rb_4:	add.w	(a0)+,d0	; add (next) word
	dbra	d1,rb_4		; (loop for every word)
	cmp.w	#bootmagic,d0	; is the sector executable?
	bne.s	rb_r		; (no --- return to OS)
	lea	dmaread(pc),a3	; a3 -> disk read routine
	lea	rb_bs(pc),a5	; a5 -> bootstop code
	movem.l	(sp)+,d3/d5	; restore d3 and d5
	jmp	(a4)		; yes --- jump there


;+
;  dmaread - read sectors from hard disk
;	Passed:	d4.w = physical unit number (if DMAread() is in ROM)
;			or -1 (if DMAread() is not in ROM)
;		d5.w = sector count
;		d6.l = sector number
;		d7.b = ddd00000 ('ddd' is the ACSI device number, 0..7)
;		a4.l -> buffer address
;
;    Returns:	EQ: success
;		NE: read failed;
;
;    Uses:	a5-a6/d0-d1 for dmaread here
;		a0-a2/d0-d2 for DMAread in ROM
;-
dmaread:
	movem.l	d0-d2/a0-a2,-(sp)
	pea	msg(PC)
	move.w	#9,-(sp)
	trap	#1
	addq	#6,sp
	movem.l	(sp)+,d0-d2/a0-a2
	move.w	d4,-(sp)	; pdev
	move.l	a4,-(sp)	; buf
	move.w	d5,-(sp)	; count
	move.l	d6,-(sp)	; sectnum
	move.w	#$2a,-(sp)	; DMAread(sectnum, count, buf, pdev)
	trap	#14
	adda.w	#$0e,sp		; clean up stack
ww_w:	rts			; return

msg:	dc.b	"Clams got legs!\r\n",0


;--- bytes in the command packet:
dmr_st:		dc.l	$0000008a	; byte 1 (devno = 0, blockno = 0)
		dc.l	$0000008a	; byte 2 (blockno = 0)
		dc.l	$0000008a	; byte 3 (blockno = 0)
		dc.l	$0001008a	; byte 4 (count = 1)


_rootend::

    bss
;+
;  Hard disk partition information
;
;-
format_info:	ds.b	12	; formatting information
hd_size:	ds.l	1	; hd_siz
part0:		ds.b	12	; partition 0
part1:		ds.b	12	; partition 1
part2:		ds.b	12	; partition 2
part3:		ds.b	12	; partition 3
bsl_st:		ds.l	1	; bad sector list start
bsl_cnt:	ds.l	1	; bad sector list count
checksum:	ds.w	1	; (reserved for sector chksum)

