*
* $Header: DH0:src/omti/dist/src/bootblock/1.3/BootBlock.a,v 1.1 92/11/25 02:12:35 Barnard Exp $
*

*
* Disk-Bootblock for AmigaOS 1.3
*

* Dieser Bootblock holt den Boot-Track von der Platte

				NOLIST
				INCLUDE	"exec/types.i"
				INCLUDE	"exec/io.i"
				INCLUDE	"exec/resident.i"
				INCLUDE	"exec/memory.i"
				INCLUDE	"exec/alerts.i"
				INCLUDE	"exec/execbase.i"
				INCLUDE	"devices/trackdisk.i"
				INCLUDE	"hardware/cia.i"
				include	"libraries/dos.i"
				LIST

* Verwendete Funktionen

AllocMem		equ		-198
FreeMem			equ		-210

AllocSignal		equ		-330
FreeSignal		equ		-336

OpenDevice		equ		-444
CloseDevice		equ		-450

DoIO			equ		-456

FindResident	equ		-96
FindTask		equ		-294

Enable			equ		-126
Disable			equ		-120

Alert			equ		-108
KickSumData		equ		-612

* Hardware-Konstanten

execbase		equ			4
ciaa			equ			$BFE001		; Adresse der cia

**** Eingebundene System-Files

				NOLIST

				include	"//asminclude/parablock.i"	; Definitionen fuer Parameter
				include	"//asminclude/omti.i"		; Befehle und Fehlermeldungen
				include	"//asminclude/omtihard.i"	; Hardware-Konstante

				LIST

BOOTBLOCK_VERSION	equ	1

* Groesse eines OMTI-Sektors:

SECSIZE			equ	512

bootid			equ	'OMTI'

**********************************************************

bootbufsize		equ	(TD_SECTOR*2)	; Buffer fuer zwei Sektoren


bootblockbegin

typ				dc.b	'D','O','S',0
chksum			dc.l	0
rootblock		dc.l	880

* Hier gehts los...

start			bra.s	codebegin

id				dc.l	bootid

codebegin		bsr		harddiskboot		; Schaue, ob OMTI da
				move.l	d0,-(a7)			; Return-Code ist Startadresse fuer Track...
				beq.s	normboot			; == 0? Dann ganz normal booten...
				bsr		omtires				; Mache den Boot-Code resident
				bra.s	dosok

normboot		lea		dosname(pc),a1
				move.l	execbase,a6
				jsr		FindResident(a6)
				tst.l	d0
				beq.s	dosnotok
				movea.l	d0,a0				; Adresse der DOS-Lib nach A0
				move.l	RT_INIT(a0),(a7)	; Adresse des Init-Vektors der DOS-Lib auf den Stack legen
dosok			moveq.l	#-1,d0
dosnotok		not.l	d0
				move.l	(a7)+,a0
				rts

dosname			dc.b	'dos.library',0
TDName			dc.b	'trackdisk.device',0
strn			dc.b	'hardstrap',0


* Initialize Drive Charakteristics fuer Drive 0
* 1 Cylinder, 1 Head, Red. Write Current, Precomp. Cyl

InitDrive		dc.b	14-1,omti_c_idc,$00,$00,$00,$00,$00
				dc.b	$00,$01,$01,$03,$ff,$01,$2c,$00

* ReadFirst: Lies ersten Block von der Platte; verwende dazu Steprate 7

readfirst		dc.b	6-1,omti_c_read,$00,$00,$00,$01,$07

BootDrive		dc.b	$ff					; 00: Drive 0 booten
											; ff: Drive 1 booten

				cnop	0,2

mement			dc.l	0				; ml_Node.ln_Succ
				dc.l	0				; ml_Node.ln_Pred
				dc.b	0				; ml_Node.ln_Type
				dc.b	0				; ml_Node.ln_Pri
				dc.l	0				; ml_Node.ln_Name
				dc.w	1				; ml_NumEntries
mem				dc.l	0				; ml_ME[1].meu_Addr		Pointer auf meinen Speicherblock
				dc.l	1024			; ml_ME[1].me_Length	Bytes in einem Bootblock

tagqueue		dc.l	0
				dc.l	0

* Resident-Struktur

tag				dc.w	RTC_MATCHWORD		; Tag-Matchword
matchtag		dc.l	0					; Pointer auf Matchword
endskip			dc.l	0					; Pointer to Code-Ende
				dc.b	RTF_COLDSTART		; Nach dem DOS initialisieren
				dc.b	BOOTBLOCK_VERSION	; Version
				dc.b	NT_UNKNOWN			; Typ unbekannt
				dc.b	-45					; Init-Pri
names			dc.l	0					; Pointer auf Name
ids				dc.l	0					; Pointer auf Id
init			dc.l	0					; Pointer auf Code

				cnop 0,2

* Ab hier wird von der Harddisk gebootet

harddiskboot	movem.l	d7/a4/a2,-(a7)			; rette D7 und A2/4

				move.l	#bootbufsize,d0			; und Buffer fuer 2 Sektoren belegen
				move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1	; Platz im Chipmem belegen

				jsr		AllocMem(a6)			; Speicherplatz holen
				tst.l	d0						; Speicher da?
				beq		nocon					; Nein...
				movea.l	d0,a4					; Pointer nach A4

				lea		omtibase,a2			; Adresse des Controllers in A2
				clr.b	oreset(a2)			; Resette Controller
				moveq.l	#-1,d0				; Lade Timeout-Counter
iscontrthere	btst.b	#oBSY,ostatus(a2)	; Ist Controller noch idle?
				dbeq	d0,iscontrthere		; Warte in Schleife
				bne		nocmem				; Ja, also kein Controller da

				moveq.l	#-1,d0				; Lade Timeout-Counter
waitforselect	clr.b	oselect(a2)			; Starte Select-Phase
				btst.b	#oBSY,ostatus(a2)	; Geht Controller auf Select?
				dbne	d0,waitforselect	; Nein, warte
				beq		nocmem				; Timeout: Kein Controller :(

				lea		InitDrive(pc),a1	; Initialisierung fuer Controller
				move.b	BootDrive(pc),d7	; Hole das Boot-Drive
				andi.b	#LUNMASK,d7			; LUN-Bit ausmaskieren
				or.b	d7,2(a1)			; und ins Kommando einfuegen
				bsr		doomtioi			; zum Omti schicken

waitstata		btst.b	#oIO,ostatus(a2)	; warten, bis
				beq.s	waitstata			; noch Daten von Host zum Controller?

rerror			tst.b	(a2)				; odata, wg. Platz - Dummy-Read (Status-Byte)

				lea		readfirst(pc),a1	; Ersten Sektor von der Platte holen
				or.b	d7,2(a1)			; LUN ins Kommando einfuegen
				bsr		doomti				; Kommando schicken

waitreq2a		btst.b	#oREQ,ostatus(a2)	; warten, bis Controller Datenbytes hat
				beq.s	waitreq2a
				btst.b	#oCD,ostatus(a2)	; ist Richtung Controller->Host?
				bne.s	rerror				; Nein, Fehler!

				movea.l	a4,a1				; Pointer auf Block nach A1
				moveq.l	#1,d0				; 1 Block holen
				bsr		readblocks			; und laden
				bne		nocmem				; Return-Status notZero: Fehler

				cmp.l	#paraid,auf_para(a4); Ist es ein Parameter-Block?
				bne		nocmem				; Nein: Platte ist illegal:Ende

* Jetzt einen Init-Request ab a4 + SECSIZE aufbauen

				lea		SECSIZE(a4),a1		; Pointer auf freien Speicher
				move.l	a1,-(a7)			; merken...

				move.b	#14-1,(a1)+			; 14 Bytes muessen zum Controller
				move.b	#omti_c_idc,(a1)+	; Kommando speichern
				clr.l	(a1)+				; Vier Nullen speichern
				clr.b	(a1)+				; Eine Null speichern
				lea		drvpara_hicyl(a4),a0	; A0: Pointer auf drvpara_

				move.b	(a0)+,(a1)+			; Hoechster anfahrbarer Zylinder
				move.b	(a0)+,(a1)+			; (Byte wg. Ungerade!)

				move.b	(a0)+,(a1)+			; Anzahl der Koepfe
				addq	#1,a0

				move.b	(a0)+,(a1)+			; Write Current kopieren
				move.b	(a0)+,(a1)+			; (Byte wg. Ungerade!)

				move.b	(a0)+,(a1)+			; Write Precompensation kopieren
				move.b	(a0)+,(a1)+

				clr.b	(a1)+						; und eine Null speichern

				movea.l	(a7),a1				; Anfang neu setzen
				or.b	d7,2(a1)			; LUN und ins Kommando einfuegen
				bsr		doomti				; und Drive richtig initialisieren

waitstatb		btst.b	#oIO,ostatus(a2)	; Warten, bis Omti Statusbyte schickt
				beq.s	waitstatb
				tst.b	(a2)				; odata, wg. Platz - Dummy Statusbyte auslesen

				movea.l	(a7),a1				; Pointer auf Platz zurueck
				move.b	#6-1,(a1)+			; 6 Bytes muessen zum Controller
				move.b	#omti_c_read,(a1)+	; Block-Lese Kommando speichern

* WARNUNG!  Aufgrund von Platzproblemen im Boot-Sektor kann nur ein Track zwischen
* 0 und 255 als Starttrack verwendet werden (dies ist keine reelle Einschraenkung :)

				move.b	boot_head(a4),(a1)		; Boot-Kopf holen
				move.b	boot_lun(a4),d0			; Boot-LUN holen
				andi.b	#LUNMASK,d0				; Nur LUN_MASK verwenden
				or.b	d0,(a1)+				; und eintragen

				move.b	boot_sector(a4),(a1)+	; Boot-Sektor eintragen

				move.w	boot_track(a4),d1		; Boot-Track holen
				move.b	d1,(a1)+				; Lower Sector eintragen
				clr.l	d0						; D0 loeschen
				move.b	boot_blocks(a4),d0		; Anzahl der zu ladenden Bloecke holen
				move.b	d0,(a1)+				; und in Befehl eintragen
				move.b	drvpara_step(a4),(a1)	; Steprate in Befehl

				lsl.l	#8,d0					; Anzahl der Bloecke in Bytes umrechnen
				lsl.l	#1,d0					; In Bytes umrechnen
				move.l	d0,d7					; Anzahl der Bytes merken...
				moveq.l	#MEMF_PUBLIC,d1			; Speicher holen
				jsr		AllocMem(a6)
				tst.l	d0					; Wenn kein Speicher, dann GURU!
				bne.s	gotmem
				move.l	#AT_DeadEnd!AG_NoMemory,d7
				sub.l	a5,a5
				jmp		Alert(a6)			; Software Error: GURU Meditation...

gotmem			movea.l	d0,a0				; Pointer auf Speicher nach A0
				movea.l	(a7)+,a1			; Pointer auf Kommando nach A1 und vom Stack entfernen

* Ab a4+SECSIZE steht jetzt das Lese-Kommando, dass den Boot-Track von
* der Platte holt

				bsr		doomti				; Kommando schicken
				clr.l	d0
				move.b	boot_blocks(a4),d0	; Block-Count zurueck
				movea.l	a0,a1
				bsr		readblocks			; Blocks einlesen
				movea.l	a0,a2				; Pointer auf Block retten
				bne.s	error				; Fehler? Dann Ende
				cmp.l	#'BOOT',(a0)+		; Ist es ein Bootbarer Track?
				bne.s	error
				move.l	a0,d0				; Startadresse nach D0 laden
				bra.s	tfin				; Ja, dann Routine aufrufen

error			movea.l	a2,a1
				move.l	d7,d0
				jsr		FreeMem(a6)			; Speicher fuer Boottrack freigeben

nocmem			movea.l	a4,a1				; Pointer auf Buffer nach A1
				move.l	#bootbufsize,d0		; Diesen Speicher freigeben
				jsr		FreeMem(a6)

nocon			clr.l	d0					; Dos Resident noch holen

tfin			movem.l	(a7)+,a2/a4/d7			; Register restoren
sorry			rts


* DoOmti schickt ein Kommando zum Omti

* A2: Adresse des Kontrollers

doomti			btst.b	#oBSY,ostatus(a2)		; Ist Omti bereit?
				bne.s	doomti					; nein, warten
doomtioi		clr.b	oselect(a2)				; Omti selecten
				btst.b	#oBSY,ostatus(a2)		; Controller bereit?
				beq.s	doomtioi
				clr.w	d0
				move.b	(a1)+,d0				; Anzahl der Transferbytes nach D0 holen
waitreq			btst.b	#oREQ,ostatus(a2)		; und bei jedem Request ein Byte rueber
				beq.s	waitreq
				move.b	(a1)+,(a2)				; odata, wg. Platz
				dbf.w	d0,waitreq
				rts

rbwaitreq		btst.b	#oREQ,ostatus(a2)		; Will Omti Byte uebertragen?
				beq.s	rbwaitreq				; Nein, dann warte
				btst.b	#oCD,ostatus(a2)		; Richtung ok?
				bne.s	waitreq3				; Nein...
				move.w	#SECSIZE-1,d1			; Count fuer Sektor nach D1
dwaitreq		btst.b	#oREQ,ostatus(a2)		; Request?
				beq.s	dwaitreq				; nein, dann warte drauf...
				move.b	(a2),(a1)+				; odata, wg. Platz - sonst hole Byte
				dbf.w	d1,dwaitreq				; und Schleife

* ReadBlocks liest Datenbloecke vom Omti

* A2: Adresse des Controllers
* A1: Zeiger auf Daten
* D0: Blockcount


readblocks		dbf.w	d0,rbwaitreq			; Warte, dass Controller bereit
waitreq3		btst.b	#oREQ,ostatus(a2)		; Noch Requests da?
				beq.s	waitreq3				; Nein, dann warte
				btst.b	#sCS,(a2)				; odata, wg. Platz - Ist das Fehler-Bit gesetzt?
				bne.s	rblr					; != 0? Dann Fehler!
				addq.w	#1,d0					; D0 loeschen -> alles ok
rblr			rts

* OmtiRes macht diesen Bootblock resident

* A6: ExecBase

omtires			move.l	#1024,d0				; Speicher fuer Bootblock allozieren
				moveq.l	#MEMF_PUBLIC!MEMF_CHIP,d1	; MUSS im Chip-Mem stehen, weil zum Zeitpunkt
													; des Resident-Scans noch *KEINE* externen
													; Erweiterungen initialisiert sind !!!!
				jsr		AllocMem(a6)
				tst.l	d0						; Speicher da?
				bne.s	bootmem
				rts								; Kein Speicher? Dann Ende

bootmem			move.l	d0,a0					; Pointer auf Speicher nach A0
				lea		bootblockbegin(pc),a1	; Hier geht der Bootblock los...
				move.w	#256-1,d1				; 256 Langworte...
copybootblock	move.l	(a1)+,(a0)+				; in unseren Speicher kopieren
				dbf.w	d1,copybootblock

				move.l	d0,a0		; Pointer auf Speicher zurueck

				move.l	a0,mem-bootblockbegin(a0)		; Lade Start des Blocks in die Mem-Struktur

				lea		tag-bootblockbegin(a0),a0		; Lade Pointer auf den Resident-Block nach a0
				move.l	a0,matchtag-tag(a0)	; Lade Zeiger auf Tag-Struktur nach RT_MATCHTAG

				lea		initcode-tag(a0),a1	; Lade Zeiger auf den Code
				move.l	a1,endskip-tag(a0)		; nach ENDSKIP
				move.l	a1,init-tag(a0)			;  und in die Init-Adresse

				lea		strn-tag(a0),a1
				move.l	a1,names-tag(a0)
				move.l	a1,ids-tag(a0)		; Strings eintragen

				lea		tagqueue-tag(a0),a1		; Pointer auf TagQueue nach A1
				move.l	a0,(a1)+				; und Code eintragen

				jsr		Disable(a6)				; Sperren, wir wollen in die Exec-Base

				move.l	KickTagPtr(a6),(a1)		; Pointer auf Romtags speichern
				beq.s	noprev
				bset.b	#7,(a1)
noprev			subq.l	#4,a1
				move.l	a1,KickTagPtr(a6)		; Pointer auf KickTag in die ExecBase

				lea		(mement-tag)(a0),a1		; Jetzt MemEntry in KickMem eintragen
				move.l	KickMemPtr(a6),(a1)
				move.l	a1,KickMemPtr(a6)

				jsr		KickSumData(a6)		; Checksumme ueber ExecBase neu berechnen
				move.l	d0,KickCheckSum(a6)	; und eintragen...

				jsr		Enable(a6)			; Multitasking wieder freigeben

				rts

* Booten von der Platte

initcode		move.l	a0,-(a7)
				bsr		harddiskboot				; von der Platte booten
				tst.l	d0
				beq.s	endinitcode
				movea.l	d0,a0						; Wenn der Code, ok, dann starten
				jsr		(a0)
				move.l	(a7)+,a0
				moveq.l	#-1,d0						; Alles ok
				rts

endinitcode		move.l	(a7)+,a0
				clr.l	d0
				rts

ende			end

