;*************************************************************************
;*                                                                       *
;* LoadKickC0 V1.0 -- Copyright 1991 by Matthias Scheler                 *
;*                                                                       *
;*      This program may be freely copied, as long as all copyright      *
;*      notices are left intact and unchanged.                           *
;*                                                                       *
;*************************************************************************

		CSECT text,0

		INCLUDE "exec/types.i"
		INCLUDE "exec/execbase.i"
		INCLUDE "exec/resident.i"

_AbsExecBase	EQU 4

PatchOffset	EQU $7FF00

		XREF _SysBase
		XREF _LVODisable
		XREF _LVOSuperState
       
		XREF rtable

		XDEF _StartKick
_StartKick:	movem.l 4(sp),a2/a3

; relocate kickstart image

		move.l a3,d0		; calculate offset for relocation
		sub.l #$200000,d0
		lea rtable(pc),a0
RelocKickImage:	move.l (a0)+,d1
		beq.s PatchKickImage
		add.l d0,0(a2,d1.l)
		bra.s RelocKickImage

; patch kickstart memory configuration

PatchKickImage:	move.l a3,d0
		swap d0
		addq.l #$08,d0		; ($C80000 - $C00000) / $10000 = $08
		move.w d0,$2B4(a2)
		move.w d0,$2C8(a2)

; relocate tag for patch

		move.l a3,a1
		add.l #PatchOffset,a1
		
		lea ResetTag(pc),a0
		move.l a1,RT_MATCHTAG(a0)
		lea RT_SIZE(a1),a5
		move.l a5,RT_ENDSKIP(a0)
		move.l a5,RT_INIT(a0)
		lea ResetName-ResetTag(a1),a5
		move.l a5,RT_NAME(a0)

; copy patch into kickstart image

		move.l a2,a1
		add.l #PatchOffset,a1
		move.w #(ResetEnd-ResetTag)/2-1,d0
PatchResetCode:	move.w (a0)+,(a1)+
		dbf d0,PatchResetCode

; prepare reboot

		move.l a2,KickSource
		move.l a3,KickTarget

		move.l _SysBase(a4),a6
		lea StartKick(pc),a0
		bsr SetCold

		jsr _LVODisable(a6)     ; interrupts off
		jsr _LVOSuperState(a6)	; call copy code in supervisor mode

		bra Reboot

; init and save some exec pointers

StartKick:	move.l KickSource(pc),a0
		move.l KickTarget(pc),a1
		lea 2(a1),a2

		move.w LIB_NEGSIZE(a6),d2
		movem.l KickMemPtr(a6),d3-d5

; copy kickstart image and recalculate checksum

		moveq #8,d0		; clear old checksum
		swap d0
		clr.l -24(a0,d0.l)

		moveq #2,d0		; 131072 * 4 = 524288
		swap d0
		moveq #0,d1
CopyKickImage:	add.l (a0),d1
		bcc.s NoOverFlow1
		addq.l #1,d1
NoOverFlow1:	move.l (a0)+,(a1)+
		subq.l #1,d0
		bne.s CopyKickImage

		not.l d1
		move.l d1,-24(a1)

; create a faked execbase, so that a hard disk driver gets a chance to survive

		lea 0(a1,d2.w),a6
		move.l a6,_AbsExecBase.w

		move.l #$00220002,SoftVer(a6)
		move.l a6,d0
		not.l d0
		move.l d0,ChkBase(a6)
		clr.l ColdCapture(a6)
		clr.l CoolCapture(a6)
		clr.l WarmCapture(a6)            

		lea SoftVer(a6),a0
		moveq #23,d0
		moveq #0,d1
SumLoop1:	add.w (a0)+,d1
		dbf d0,SumLoop1
		not.w d1
		move.w d1,(a0)

		movem.l d3-d5,KickMemPtr(a6)

; start OS 2.0 first time

		jmp (a2)

KickSource:	dc.l 0
KickTarget:	dc.l 0

; reset tag

ResetTag:	dc.w RTC_MATCHWORD
		dc.l 0
		dc.l 0
		dc.b RTF_COLDSTART
		dc.b 37
		dc.b 0
		dc.b 109
		dc.l 0
		dc.l 0
		dc.l 0

; set cold capture when OS 2.0 is running

		lea RestartKick(pc),a0
SetCold:	move.l a0,ColdCapture(a6)
SumExec:	lea SoftVer(a6),a0
		moveq #23,d0
		moveq #0,d1
SumLoop2:	add.w (a0)+,d1
		dbf d0,SumLoop2
		not.w d1
		move.w d1,(a0)
		rts

; restart kickstart 2.0

RestartKick:	lea SoftVer(a6),a0
		moveq #23,d0
		moveq #0,d1
SumLoop3:	add.w (a0)+,d1
		dbf d0,SumLoop3
		not.w d1
		move.w d1,(a0)

; check kickstart

		lea ResetTag(pc),a0
		sub.l #PatchOffset,a0
		lea 2(a0),a1

		moveq #2,d0		; 131072 * 4 = 524288
		swap d0
		moveq #0,d1
CheckKickImage:	add.l (a0)+,d1
		bcc.s NoOverFlow3
		addq.l #1,d1
NoOverFlow3:	subq.l #1,d0
		bne.s CheckKickImage

		addq.l #1,d1
		bne.s ColdReboot	; kickstart is corrupt

		jmp (a1)		; jump into OS 2.0

; reboot

ColdReboot:	clr.l ChkBase(a6)	; force complete reset
Reboot:		lea $01000000,a0	; entry point for rom kickstart
		sub.l -20(a0),a0
		move.l 4(a0),a0
		jmp -2(a0)		; jump on reset instruction

ResetName:	dc.b "LoadKickC0",0
		ds.w 0

ResetEnd:
		END
