; MoveSSP.a
; Copy the system's stack from Chip RAM to Fast RAM, generally to be called
; as part of one's Startup-Sequence.
;
; Written by Christoper A. Wichura (caw@miroc.chi.il.us)
; Created: 3/4/90
;
; This is really a conversion of MoveSSP.c by Roger Uzun into 68k code,
; with various `optimizations' being made as well.
;
; The arp library is required to use this program.  I used it for its
; FPrintf function as well as getting an easy way out of not having to
; decide if I needed to close the stdout filehanle, which is opened with
; ArpOpen() and closed (if needed) by ArpExit().
;
; It is fully residentiable, though to do so would be stupid as it will
; not do anything after the first invocation.
;
; This file supports being called by WorkBench.  However, you will have
; to supply your own `.info' file for it (if anyone comes up with a really
; nice looking one then UUencode it and send it to me).
;
; I moved it to ML to make it smaller (i.e., no longer needed the Lattice
; startup code which eats a bunch of memory up).  I also added some
; messages to let you know what has happened, which MoveSSP.c didn't do.
; I also made it use CopyMem() to copy the old SSP over into the new one.
; Q:  Is the system stack quarenteed to meet the requirements for a
; CopyMemQuick() call?  Also, does CopyMem() automatically recognize if the
; parameters passed to it are valid to CopyMemQuick() and forward the call
; instead of trying to handle it itself?  Mail me...
;
; I have not noticed any tremendous speed increase in using this program,
; but it can't really hurt.  The people who will get the biggest benefit
; from it are those with 32 bit RAM.
;
; My AutoDocs say that the UserState() function is broken.  Welp, it is
; used in this file.  It doesn't seem to cause any problems, but just what
; about it is broken?  Somebody send me mail...

 NOLIST
 INCLUDE "libraries/ArpBase.i"
 INCLUDE "exec/execbase.i"
 INCLUDE "exec/memory.i"
 INCLUDE "libraries/dosextens.i"
 LIST

 XREF _LVOOpenLibrary
 XREF _LVOCloseLibrary
 XREF _LVOForbid
 XREF _LVOWaitPort
 XREF _LVOGetMsg
 XREF _LVOReplyMsg
 XREF _LVOAllocMem
 XREF _LVOCopyMem
 XREF _LVODisable
 XREF _LVOEnable
 XREF _LVOSuperState
 XREF _LVOUserState

CALL	MACRO
	jsr _LVO\1(a6)
	ENDM

  SECTION MoveSSP,CODE

; arp resident tag goes here
	RESIDENT 4*1024

init:
	movem.l	d2-d7/a2-a5,-(sp)
	movea.l	4,a6
	lea	ARPlib(pc),a1
	moveq	#39,d0
	CALL	OpenLibrary
	tst.l	d0
	bne.s	__main

	lea	DOSlib(pc),a1
	CALL	OpenLibrary
	tst.l	d0
	beq.s	bomb

	move.l	d0,a6
	CALL	Output
	move.l	d0,d1
	beq.s	bomb

	lea	Msg1(pc),a0
	move.l	a0,d2
	moveq	#Msg1Len,d3
	CALL	Write

	move.l	a6,a1
	movea.l	4,a6
	CALL	CloseLibrary
	moveq	#0,d0

bomb:
	addq.l	#8,sp
	rts

WBMSG	EQUR	d7
LOMEM	EQUR	d6
HIMEM	EQUR	d5
SIZE	EQUR	d4
STDOUT	EQUR	d3
NEWMEM	EQUR	a2
MYPROC	EQUR	a3

__main:
	movea.l	a6,a5		; save exec base pointer
	movea.l	d0,a6		; put arp base where we can use it

	CALL	Output		; get stdout handle
	move.l	d0,STDOUT

	move.l	ThisTask(a5),MYPROC	; get pointer to our process

; check for workbench
	moveq	#0,WBMSG	; clear wb flag

	tst.l	pr_CLI(MYPROC)
	bne.s	FromCLI

	exg	a5,a6		; get exec base
	lea	pr_MsgPort(MYPROC),a0
	CALL	WaitPort
	lea	pr_MsgPort(MYPROC),a0
	CALL	GetMsg
	move.l	d0,WBMSG	; save wbench startup message
	exg	a5,a6		; get back arp base

; we need a console window for workbench users

	lea	Console.MSG(pc),a0
	move.l	a0,d1
	move.l	#MODE_NEWFILE,d2

; we use arpopen to get the console.  thus the ArpExit call at the end of
; this file will free it for us automatically if we got it.

	CALL	ArpOpen

	move.l	d0,STDOUT	; did we get the console
	beq	Exit	; no so die

	lsl.l	#2,d0
	movea.l	d0,a0

	move.l	fh_Type(a0),pr_ConsoleTask(a3)

FromCLI:
	lea	Banner.MSG(pc),a0	; print a blurb
	move.l	STDOUT,d0	; get stdout
	CALL	FPrintf

	move.l	SysStkLower(a5),LOMEM	; get low stack ptr
	move.l	SysStkUpper(a5),HIMEM	; get high stack ptr

; check if we are already in fast memory
	cmpi.l	#$200000,HIMEM
	blt.s	1$
	cmpi.l	#$C00000,HIMEM
	bcc.s	1$

	lea	AlreadyFast.MSG(pc),a0
	move.l	STDOUT,d0	; get stdout
	CALL	FPrintf
	bra	Exit

; we need to move the thing over so figure out its size.  we will print
; its current start address before moving it, though.

1$:	move.l	HIMEM,SIZE
	sub.l	LOMEM,SIZE

	move.l	SIZE,-(sp)	; push size  onto stack for printf
	move.l	HIMEM,-(sp)	; push himem onto stack for printf
	move.l	LOMEM,-(sp)	; push lomem onto stack for printf

	movea.l	sp,a1		; get address of args array
	lea	OldLoc.MSG(pc),a0	; get message to print
	move.l	STDOUT,d0	; get stdout
	CALL	FPrintf		; call ARP print command
	lea	12(sp),sp	; pop values off stack

; we need to allocate a new stack in fast memory for these folks

	move.l	SIZE,d0
	move.l	#MEMF_FAST|MEMF_CLEAR,d1
	exg	a5,a6
	CALL	AllocMem
	exg	a5,a6

	tst.l	d0
	bne.s	2$

	lea	NoFast.MSG(pc),a0
	move.l	STDOUT,d0	; get stdout
	CALL	FPrintf
	bra	Exit

2$	movea.l	d0,NEWMEM

; ok we have new memory so now we need to copy the stack over

	exg	a5,a6	; get execbase in a6
	CALL	Disable	; freeze the system while we do the copy

	movea.l	LOMEM,a0
	movea.l	NEWMEM,a1
	move.l	SIZE,d0
	CALL	CopyMem

; now fix pointers in exec base

	move.l	NEWMEM,HIMEM	; make new himem pointer
	add.l	SIZE,HIMEM

	move.l	NEWMEM,SysStkLower(a6)
	move.l	HIMEM,SysStkUpper(a6)

	CALL	SuperState	; go to supervisor mode
	sub.l	LOMEM,d0	; find position in old stack
	add.l	NEWMEM,d0	; get position in new stack
	CALL	UserState	; return to user state
	
	CALL	Enable		; re-enable interrupts
	exg	a5,a6		; reload ARP base

; ok we have fixed everything up so print new address of stack

	move.l	NEWMEM,-(sp)	; push new location onto stack for printf
	movea.l	sp,a1		; get address of args array
	lea	NewLoc.MSG(pc),a0	; get message to print
	move.l	STDOUT,d0	; get stdout
	CALL	FPrintf		; call ARP print command
	addq	#4,sp		; pop value off stack

Exit:
	tst.l	WBMSG		; started from workbench?
	beq.s	1$

; if we started from workbench then call dos' Delay() function to give
; them time to see what we said

	move.l	#300,d1
	CALL	Delay

	exg	a5,a6		; get exec base
	CALL	Forbid		; forbid and return startup message to
	movea.l	WBMSG,a1	; workbench
	CALL	ReplyMsg
	exg	a5,a6		; get back arp base

1$	movem.l	(sp)+,d2-d7/a2-a5
	moveq	#0,d0
	CALL	ArpExit

; here we have all the text and whatnot for this program

DOSlib	dc.b "dos.library",0

Msg1	dc.b "You need "
ARPlib	dc.b "arp.library",0
	dc.b " V39+",10,0
Msg1Len	EQU *-Msg1

Console.MSG:
	dc.b	'CON:40/30/560/45/MoveSSP',0

Banner.MSG:
	dc.b	'MoveSSP v1.0 ',$a9,' 1990 by Christoper A. Wichura '
	dc.b	'(caw@miroc.chi.il.us)',10,0

AlreadyFast.MSG:
	dc.b	'SSP is already located in fast memory.',10,0

NoFast.MSG:
	dc.b	'Could not allocate fast memory for new SSP.',10,0

OldLoc.MSG:
	dc.b	'SSP currently located at $%08lx-$%08lx (%ld bytes).',10,0

NewLoc.MSG:
	dc.b	'Moved to $%08lx in fast memory.',10,0

	END
