*
*	ZKick V3.01 -- Copyright (C) 1991 by Daniel Zenchelsky
*
*		This program may be freely copied, as long as all copyright
*		notices are left intact and unchanged.
*


   SECTION   code

   NOLIST
   INCLUDE "exec/types.i"
   INCLUDE "exec/initializers.i"
   INCLUDE "exec/libraries.i"
   INCLUDE "exec/lists.i"
   INCLUDE "exec/alerts.i"
   INCLUDE "exec/resident.i"
   INCLUDE "exec/memory.i"
   INCLUDE "exec/tasks.i"
   INCLUDE "exec/execbase.i"
   INCLUDE "libraries/expansion.i"

   INCLUDE "zkick.i"
   INCLUDE "mmu.i"

   LIST

   XDEF   Reboot
   XDEF   _MakeRomTag
   XDEF   _config
   XDEF   _connum
   XDEF   _memory
   XDEF   _memnum
   XDEF   _Survive
   XDEF   _MMU

   XDEF	_NOMMU
   XDEF   _NOCHECKSUM
   XDEF   _NORESET
   XDEF   _DEBUG
   XDEF   _PRINT
   XDEF	_LOADC0
   XDEF	_V175

   XDEF   _StartKick

   ;------ These don't have to be external, but it helps some
   ;------ debuggers to have them globally visible
   XDEF   modName
   XDEF   MemName
   XDEF   _InitRoutine
   XDEF   initDDescrip
   XDEF   ABSEXECBASE
   XDEF   SaveMem
   XDEF   KickMem
   XDEF   KickTag
   XDEF   expansionname
   XDEF   ExpansionBase
   XDEF   ConfigCopy
   XDEF   AddMem
   XDEF   EndTag
   XDEF	CheckSum

   XREF   _LVOSumKickData

   XREF   _LVOOpenLibrary
   XREF   _LVOCloseLibrary
   XREF   _LVOAddConfigDev
   XREF   _LVOAllocConfigDev
   XREF   _LVOCopyMem
   XREF   _LVOAddMemList
   XREF   _LVOSetFunction
   XREF   _LVOSuperState
   XREF   _LVOSupervisor
   XREF   _LVODisable

;
; Offsets from ExecBase
;

*KickMemPtr	EQU	$222
*KickTagPtr	EQU	$226
*KickCheckSum	EQU	$22a
*WarmCapture	EQU	50
*CoolCapture	EQU	46
*ColdCapture	EQU	42
ExecVersion	EQU	$14

ROMVersion	EQU	$FC0010

VERSION:	EQU	3
REVISION:	EQU	01


_MakeRomTag:
	move.l ABSEXECBASE,a6
;
; Set up KickMemPtr
;
	lea.l KickMem+14,a0
	move.w #1,(a0)+			; Number of Entries = 1
	lea.l SaveMem,a1
	move.l a1,(a0)+			; Allocation Start
	lea.l EndTag-SaveMem,a1		; Allocation Length
	move.l a1,(a0)+
	lea.l KickMem,a0

	move.l KickMemPtr(a6),(a0)	; old pointer in ln_Succ

	move.l a0,KickMemPtr(a6)
	
;
; Set up KickTagPtr
;
	lea KickTag,a0

	move.l KickTagPtr(a6),4(a0)	; Old pointer at the end of the table
	beq.s .nomore

	bset.b #7,4(a0)			; Bit 31 = Extend table

.nomore:
	move.l a0,KickTagPtr(a6)

;
; Calculate checksum
;

	jsr _LVOSumKickData(a6)
	move.l d0,KickCheckSum(a6)
;
; Setup reboot code
;
	jsr SetVectors
	rts

;-----------------------------------------------------------------------
; From here on is protected from erasure during reboot
;-----------------------------------------------------------------------

SaveMem:

KickMem:
	DC.L 0,0,0,0,0,0

KickTag:
	DC.L	initDDescrip
	DC.L	$0

_StartKick:	DC.L $00000000
OldAddMemList:	DC.L	$00000000
_Survive:		DC.L	$00000000
_MMU:		DC.L	$00000000
_NOMMU:		DC.L $00000000
_NOCHECKSUM:	DC.L $00000000
_NORESET:		DC.L	$00000000
_DEBUG:		DC.L $00000000
_PRINT:		DC.L $00000000
_LOADC0:		DC.L	$00000000
_V175:		DC.L $00000000

;
; --- ColdReboot()
;

		XREF	_LVOSupervisor

MAGIC_ROMEND	    EQU $01000000   ;End of Kickstart ROM
MAGIC_SIZEOFFSET    EQU -$14	    ;Offset from end of ROM to Kickstart size
V36_EXEC	    EQU 36	    ;Exec with the ColdReboot() function
TEMP_ColdReboot     EQU -726	    ;Offset of the V36 ColdReboot function


_ColdReboot:	move.l	ABSEXECBASE,a6
		cmp.w	#V36_EXEC,LIB_VERSION(a6)
		blt.s	old_exec
		jmp	TEMP_ColdReboot(a6)     ;Let Exec do it...
		;NOTE: Control flow never returns to here


;---- manually reset the Amiga ---------------------------------------------
old_exec:	lea.l	GoAway(pc),a5           ;address of code to execute
		jsr	_LVOSupervisor(a6)      ;trap to code at (a5)...
		;NOTE: Control flow never returns to here


;-------------- MagicResetCode ---------DO NOT CHANGE-----------------------
		CNOP	0,4			;IMPORTANT! Longword align!
GoAway: 	lea.l	MAGIC_ROMEND,a0 	;(end of ROM)
		sub.l	MAGIC_SIZEOFFSET(a0),a0 ;(end of ROM)-(ROM size)=PC
		move.l	4(a0),a0                ;Get Initial Program Counter
		subq.l	#2,a0			;now points to second RESET
		reset				;first RESET instruction
		jmp	(a0)                    ;CPU Prefetch executes this
		;NOTE: the RESET and JMP instructions must share a longword!
;---------------------------------------DO NOT CHANGE-----------------------

;
; Set up the reboot routines
;

SetVectors:


	PUTMSG <'SetVectors'>

	tst.l _LOADC0
	beq.s 1$
	move.l #0,MaxExtMem(a6)
	
1$:	lea.l ColdRoutine,a0
	move.l a0,ColdCapture(a6)

	lea.l CoolRoutine,a0
	move.l a0,CoolCapture(a6)

; Recalculate checksum

	lea $22(a6),a0
	moveq #$16,d0
	moveq #0,d1
sumloop:
	add.w (a0)+,d1
	dbra d0,sumloop
	not.w d1
	move.w d1,$52(a6)

	rts

tmp:	dc.l 0

ColdRoutine:
	
	NS_PUTMSG <'ColdRoutine'>

	move.l a5,tmp				; We can't test ExecBase because 1.3
							; will use the 2.0 ExecBase.
	and.w #$FFF0,tmp			; So we look at the return address
	cmp.w #$00F0,tmp			; to see if we are running from ROM.
							; <-- Should check for $F80000-$FFFFFF
	bne DoneCold

	NS_PUTMSG <'Version 1.2/1.3 ColdCapture'>

	cmp.l #-$1,d6			; Test to see if there is a delayed GURU
	beq NoGuru			; If not, skip this.
	move.l #$48454C50,0		; move "HELP" to location 0
						; KickStart 2.0 will take care of the rest

NoGuru:

	cmp.l #$B7FC0004,$1e(a5)	; Verify that this is really 1.2/1.3
	bne.s skipfix
	move.l $3E(A6),A3		; Skip version and >512k chip mem
	jmp $1e(a5)			; checks

skipfix:

	NS_PUTMSG <'skipfix'>

DoneCold:
	jmp (a5)

CoolRoutine:

	PUTMSG <'CoolRoutine'>

	movem.l a0-a6/d0-d7,-(SP)

	move.l ABSEXECBASE,a6			

	move.w ROMVersion,a0		; If we're running under 2.0
	cmp.w ExecVersion(a6),a0		; skip this.
	bne.s DoneCool

	PUTMSG <'Version 1.2/1.3 CoolCapture'>
	
	movea.l a6,a1			; Keep exec 1.2/1.3 from stomping
	lea.l NewAddMemList,a0	; on the first few bytes
	move.l a0,d0			; of kickstart memory.
	lea.l _LVOAddMemList,a0
	jsr _LVOSetFunction(a6)
	move.l d0,OldAddMemList

DoneCool:
	movem.l (SP)+,a0-a6/d0-d7
	rts

NewAddMemList:

	PUTMSG <'NewAddMemList'>

	rts

;-----------------------------------------------------------------------
; A romtag structure.  Both "exec" and "ramlib" look for
; this structure to discover magic constants about you
; (such as where to start running you from...).
;-----------------------------------------------------------------------

   ; Most people will not need a priority and should leave it at zero.
   ; the RT_PRI field is used for _configuring the roms.  Use "mods" from
   ; wack to look at the other romtags in the system

MYPRI   EQU   107 	

initDDescrip:
               ;STRUCTURE RT,0
     DC.W    RTC_MATCHWORD      ; UWORD RT_MATCHWORD
     DC.L    initDDescrip       ; APTR  RT_MATCHTAG
     DC.L    EndTag             ; APTR  RT_ENDSKIP
     DC.B    RTF_COLDSTART      ; UBYTE RT_FLAGS
     DC.B    VERSION            ; UBYTE RT_VERSION
     DC.B    NT_UNKNOWN         ; UBYTE RT_TYPE
     DC.B    MYPRI              ; BYTE  RT_PRI
     DC.L    modName            ; APTR  RT_NAME
     DC.L    idString           ; APTR  RT_IDSTRING
     DC.L    _InitRoutine       ; APTR  RT_INIT


   ; this is the name that the module will have
modName:	DC.B   'zkick.romtag',0

idString:   dc.b   'zkick.romtag 3.01 (7/10/91)',13,10,0

MemName:	dc.b  'zkick memory',0

expansionname:	dc.b  'expansion.library',0

	CNOP 0,4

ABSEXECBASE	EQU 	$00000004
ExpansionBase:	DC.L 	$00000000
ConfigCopy:	DC.L 	$00000000


_InitRoutine:

	movem.l d0-d7/a0-a6,-(a7)

	PUTMSG <'InitRoutine'>

	move.l ABSEXECBASE,a6		; If we're running under 1.2/1.3
	move.l ROMVersion,a0		; we wan't to start KickStart
	cmp.l ExecVersion(a6),a0		; from _StartKick
	bne okversion

	tst.l	_NOCHECKSUM
	bne.s	skipsum

	move.l	_StartKick,a0		; Checksum KickStart image
	move.l	#$80000,d1		; at _StartKick
	jsr 	CheckSum
	tst.l	d0
	bne		panic

	PUTMSG <'KickStart Checksum valid'>
 
skipsum:
							; Let's be doubly cautious:
	jsr 	_LVOSuperState(a6)
	move.l	_StartKick,a0		; Verify that there's a
							; KickStart image at
	cmp.w	#$4ef9,2(a0)		; _StartKick
	bne		panic

	PUTMSG <'KickStart checks out OK'>

	tst.l _NOMMU
	bne.s 1$

	move.l	ABSEXECBASE,a6		; If there is an MMU
	jsr		_LVODisable(a6)	; disable it before
	tst.l 	_MMU				; starting KickStart
	beq		1$
	move.l	#0,a0
	jsr		SetTC

1$:	
	PUTMSG <'Jumping to KickStart'>

	move.l _StartKick,A0
	move.l 4(A0),A0
	jmp	(A0)					; Start KickStart

panic:						; Uh oh, doesn't look like
							; KickStart at _StartKick
	PUTMSG <'panic!'>

	clr.l	ColdCapture(a6)	
	clr.l	CoolCapture(a6)
	clr.l	WarmCapture(a6)	; Clear vectors and reboot
	clr.l	KickTagPtr(a6)
	clr.l	KickMemPtr(a6)

	jmp Reboot
	
okversion:

	PUTMSG <'okversion'>

	tst.l _Survive			; Do we want to survive?
	beq.s 2$
	jsr SetVectors			; Set up Capture vectors
						; for reboot survival

2$:	lea.l expansionname,A1
	clr.l D0	
	jsr _LVOOpenLibrary(a6)		; Open expansion.library
	move.l D0,ExpansionBase
	tst.l D0
	bne.s 1$
	jmp exit

1$:
	lea.l _config,a2
	move.l _connum,a3

	PUTMSG <'Adding expansion devices'>

loop:	
	cmp.l #0,a3
	beq close

	move.l ExpansionBase,a6		; For each configdev structure we
	jsr _LVOAllocConfigDev(a6)	; saved, allocate a fresh configdev
	move.l D0,ConfigCopy		; structure.
	tst.l D0
	bne.s 2$
	jmp close

2$:	
	move.l a2,A0
	move.l ConfigCopy,A1		; Copy the old configdev onto
	move.l #end_config-_config,D0	; the new one
	move.l ABSEXECBASE,a6
	jsr _LVOCopyMem(a6)

	move.l ConfigCopy,A0
	move.l ExpansionBase,a6
	jsr _LVOAddConfigDev(a6)		; Add it to the configdev list

	PUTMSG <'Linked 1 ConfigDev'>

	subq.l #1,a3
	add.l #end_config-_config,a2	; Go get another configdev structure
	jmp loop

close:
	move.l ExpansionBase,A1
	move.l ABSEXECBASE,a6		; Close expansion.library
	jsr _LVOCloseLibrary(a6)

AddMem:


	PUTMSG <'Adding Memory'>

	lea _memory,a2			; Do the same thing
	move.l _memnum,a3		; for the memory lists

AddMemLoop:
	cmp.l #0,a3
	beq.s exit

	move.l (a2),a0
	addq.l #4,a2
	move.l (a2),d0
	addq.l #4,a2
	move.l #MEMF_FAST+MEMF_PUBLIC,d1
	clr.l d2
	lea.l MemName,a1
	move.l ABSEXECBASE,a6
	jsr _LVOAddMemList(a6)
	
	PUTMSG <'Linked 1 mem board'>
	
	subq.l #1,a3
	jmp AddMemLoop

exit:
	movem.l (a7)+,d0-d7/a0-a6
	rts

CheckSum:

	PUTMSG <'CheckSum'>

	lsr.l	#2,d1
	subq.l	#1,d1
	moveq	#0,d0

1$:	add.l	(a0)+,d0
	bcc.s	2$
	addq.l	#1,d0

2$:	dbra	d1,1$
	sub.l	#$10000,d1
	bpl.s	1$
	addq.l	#1,d0
	rts

;======================================================================
;
;	This function sets the MMU TC register.  It assumes a 68020 
;	system with MMU, or a 68030 based system (eg, test for MMU before
;	you call this, or you wind up in The Guru Zone).  
;
;	SetTC(ULONG)
;		a0
;======================================================================

SetTC:

	PUTMSG <'SetTC'>

	move.l	4,a6				; Get ExecBase
	move.l	a5,-(sp)
	lea.l	1$,a5			; Get the start of the supervisor code
 	CALLSYS	Supervisor
	move.l	(sp)+,a5
	rts
1$
	_PMOVE	a0,tc			; Just set the TC register

			; Was _PMOVE (a0),tc  <-- Looked wrong!
	rte

Reboot:

	PUTMSG <'Reboot'>

	tst.l	_NOMMU
	bne.s	nommu

	PUTMSG <'Disabling MMU'>

	move.l	ABSEXECBASE,a6		; If there is an MMU,
	jsr		_LVODisable(a6)	; disable it before
	tst.l	_MMU				; rebooting.
	beq		nommu
	move.l	#0,a0
	jsr		SetTC
nommu:
	jmp		_ColdReboot

EndCode:

*********

	CNOP 0,4	; LongWord Align (For CopyMem)

_connum:	
	DS.L 1

_config:
	DS.L 17
end_config:
	DS.L 17*7

_memnum:	
	DS.L 1

_memory:
	DS.L 2
end_memory:
	DS.L 2*7

EndTag:

   END
