	.TITLE ROLLOUT - SYSTEM ROLLOUT PROGRAM
	.IDENT	/02/

;++
;
; Facility: Special Rollout System Checkpoint Routine
;
; Abstract: ROLLOUT contains the code necessary to save
;	    the volatile state necessary for restart when
;	    ROLLIN is executed.  Operationally, it saves
;	    the contents of physical memory to the system
;	    dump file, SYSDUMP.DMP; after emulating
;	    EXE$POWERFAIL.
;
; Enviornment: MODE=User , IPL=0
;
; Privilages: CHMK
;
; Author: W. CRAIG BLASINGAME - Seattle Software Services
;	  Created under PL90 contract - Date: 30-Aug-79
;
; Modified by:
;
; Version: 1
;
;--

;
; Include files:
;
	$IPLDEF				; DEFINE INTERRUPT PRIORITY LEVELS
	$PRDEF				; DEFINE PROCESSOR REGISTER NUMBERS
	$RPBDEF				; DEFINE RESTART PARAMETER BLOCK OFFSETS
	$SSDEF				; ERROR MESSAGES




;
; MACROS:
	
	.MACRO	ERROR	NO
	.NARG	TEST
		TSTL	(SP)+		; SKIP R0
		POPR	#^M<R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,AP,FP>
	.IF NE TEST
		MOVL	NO,R0
	.ENDC
		REI
	.ENDM

;

;
; Equated Symbols:
INTSTK		=	1		; Flag on SCB to vector to interrupt stack
RESTRT_POWERUP	=	3		; Power recovery restart code
RPB_SAVED_Q1	=	RPB$K_LENGTH	; Offset to saved RPB values
					;  BASE:+4 to BASE:+12
RPB_SAVED_Q2	=	RPB_SAVED_Q1+8	; Offset to saved RPB values
					;  BASE:+12 to BASE:+20
RPB_PHY_IOVEC	=	RPB_SAVED_Q2+8	; Offset to stored address of bootdriver
					;  in the ROLLEDOUT system (physical)
RPB_ROLLIN_CODE	=	RPB_PHY_IOVEC+4	; Offset to HALT instruction in ROLLIN
;
; Own Storage:
;

;
	.PAGE
	.PSECT YROLLD,LONG,RD,WRT,NOEXE		;DATA
	.PSECT	YROLL,LONG,PIC,SHR,NOWRT	;CODE 
	.SBTTL ROLL_MAIN - MAIN ROUTINE OF ROLLOUT/IN PROGRAM
	
;	ROLL_MAIN is contained within the FORTRAN Routine ROLLMAIN
	
	.SBTTL ROLL_PFAIL - TRANSFER TO INTERRUPT STACK ROUTINE

;++
;
; Functional Description:
;	During ROLLOUT:
;		ROLL_PFAIL is entered from ROLLOUT_MAIN via a CHMK.
;		It establishes ROLL_PFAIL_IS as the interrupt service
;		routine for IPL-31 Kernal Stack Invalid exceptions, then causes
;	an exception by cleaning the KSP and depositing @SP .
;	During ROLLIN:
;		ROLL_PFAIL is reentered via a REI from EXE$RESTART.
;		It replaces the SCB vector displaced during ROLLOUT and
;		also removes the rollout code from the System Restart
;		Parameter Block (RPB).
;
; Calling Sequence: CHMK
;
; Input Parameters:
;	00(SP) - PC at time of CHMK, In ROLLOUT_MAIN
;	04(SP) - PSL (User Mode) at time of CHMK
;	AP - 0 (no arguments)
;
; Implicit Inputs:
;	All processor registers
;	System Control Block Base (SCBB) located via SCB$AL_BASE
;	Restart Parameter Block located via EXE$GL_RPB.
;
;--



	-
tart Pa
ROLL_PFAIL::	.WORD	^M<R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11>	

1$:	DSBINT				; Set IPL to 31

	MOVAL	@#SCB$AL_BASE,R1	; System Control Block Base Address
	MOVL	^X08(R1),R11		; Store current contents of KSNV vector.
	MOVAL	ROLL_PFAIL_IS+INTSTK,-	; Establish new interrupt service routine.
		^X08(R1)
	MFPR	#PR$_KSP,R10		; Save contents of stack pointer
	MTPR	#0,#PR$_KSP		; ; Make it invalid
	CLRL	(SP)			; Cause execption
;
; Interrupt occurs here.  ROLL_PFAIL_IS is entered at
; IPL=31 on the Interrupt Stack.
; Control will return to the next instruction during
; system ROLLIN.

; R0 = 1 INDICATES SUCCESS
	
5$:	MOVZBL	#RPB$K_LENGTH,R5 ; Establish offset in RPB of ROLLOUT Code.
	MOVL	@#EXE$GL_RPB,R6		; Virtual address of RPB
	ADDL	R5,R6			; Point to code area
10$:	MOVL	R5,(R6)+		; Move position marker in
	ADDL2	S^#4,R5			; Point R5 to next long word.
	CMPL	#^X200,R5	; Branch if still addressing RPB page
	BNEQ	10$
	BLBC	R0,30$		; BRANCH IF ERROR
20$:	MFPR	#PR$_TXCS,R6	; Get console transmitter status
	BBC	#7,R6,20$	; Wait until ready
	MTPR	#^XF04,#PR$_TXDB; Send code to clear warmstart disable flag
21$:	MFPR	#PR$_TXCS,R6	; Get status
	BBC	#7,R6,21$	; Wait until done
				; Note:
				;   This is to emulate what EXE$INIT would have done.
				; When EXE$RESTART sent ^XF03 to clear warmstart,
				; it actually cleared coldstart since we got 
				; to that code via cold boot and not through
				; the restart referee.
30$:
	ENBINT			; Set IPL back to user level.
	RET			; Return to user level in ROLLIN_MAIN

	.PAGE
	.SBTTL	ROLL_PFAIL_IS - POWERFAIL IMMULATION ROUTINE

;++
; Functional Description:
;	ROLL_PFAIL_IS is entered on the interrupt stack with
;	IPL=31 as a result of a kernal stack not valid exception.
;	The routine immulates EXE$POWERFAIL by saving the volitile machine
;	registers to the Restart Parameter Block (RPB).  It also
;	inserts code in the unused portion of the RPB to be used
;	during ROLLIN.
;
; Calling Sequence:
;	Software interrupt through vector ^X08 in the SCB.
;
; Input Parameters:
;	00(SP) - PC at time of interrupt
;	04(SP) - PSL at time of interrupt
;
; Implicit Parameters:
;	ALL registers and Processor registers
;	Restart Parameter Block located via EXE$GL_RPB
;
;--

	.ALIGN	LONG			; Exception and Interrupt routines must 
					; be longword aligned
ROLL_PFAIL_IS::				;
;	HALT
	ADDL2	#2,(SP)			; BUMP PC PAST FAULTING INST
	BICB2	#^X8,7(SP)		; CLEAR FIRST PART DONE BIT
	MTPR	R10,#PR$_KSP		; Restore KSP
	MOVL	R11,^X08(R1)		; Restore interrupt vector
	MOVL	#SS$_NORMAL,R0		; Assume success
	PUSHR	#^M<R0,R1,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,AP,FP> ; Save all registers
	MOVL	@#EXE$GL_RPB,R5		; Get address of restart parameter block
	MOVL	RPB$L_IOVEC(R5),R6	; Calculate the physical address of
	MOVL	@#MMG$GL_SPTBASE,R7	;  the boot driver in the present system
	EXTZV	#9,#21,R6,R8		;  and store for ROLLIN.
	ASHL	#2,R8,R8		;create offset
	EXTZV	#0,#21,(R7)[R8],R9	;get PFN
	ASHL	#9,R9,R9		;convert to address
	INSV	R6,#0,#9,R9		;add byte offset
	MOVL	R9,RPB_PHY_IOVEC(R5)	;save in RPB
;
	PUSHR	#^M<R0,R1,R2,R3,R4,R5>	; SAVE REGISTERS
	MOVC3	#ROLLINLENGTH,-		; Move ROLLIN code to RPB
		ROLLIN_PI,-
		RPB_ROLLIN_CODE(R5)
	POPR	#^M<R0,R1,R2,R3,R4,R5>	; RESTORE REGISTERS
;
	MOVAB	@#EXE$GQ_SYSDMP,R4	;GET ADDRESS OF DESCRIPTOR FOR DUMP FILE
	ADDL3	(R4),4(R4),R0		;COMPUTE CHECK SUM
	BNEQ	5$			;CONTINUE IF FILE NOT NULL
	ERROR	#SS$_ENDOFFILE
5$:	MCOML	R0,R0			;COMPLEMENT
	CMPL	R0,@#EXE$GL_DMPCHK	;COMPARE WITH CHECK SUM
	BEQL	6$			;BRANCH IF OK
	ERROR	#SS$_FILACCERR
6$:	MOVL	(R4)+,R9		;GET SIZE OF DUMP FILE
	BGTR	7$			;BRANCH IF NOT NEG OR ZERO
	ERROR	#SS$_ENDOFFILE
7$:	MOVL	(R4),R10		;AND LBN
	BGTR	8$			;BRANCH IF CONTIGUOUS
	ERROR	#SS$_FILNOTCNTG
8$:	ADDL2	#3,R10			;SKIP HEADER AND ERRLOGS
;
; PREPARE TO:
; WRITE ALL OF MEMORY STARTING AT 0 TO REMAINDER OF DUMP FILE
; THE ASSUMPTIONS ARE MADE THAT MEMORY EXISTS CONTIGUOUSLY STARTING AT
; PHYSICAL PAGE 0 AND THAT THE SPT WAS LOCATED IN THE HIGHEST PHYSICAL
; PAGES USED.
;
	CLRL	R7			;SET STARTING ADDRESS
	MFPR	#PR$_SBR,R8		;PHYSICAL ADDDRESS OF SPT
	MFPR	#PR$_SLR,R0		;LENGTH OF SPT
	MOVAL	(R8)[R0],R8		;COMPUTE END OF DUMP
	SUBL2	#3,R9			; ACCOUNT FOR HEADER AND 2 ERRLOG BUFFS
	ASHL	#-9,R8,R2		; CONVERT BYTES TO BLOCKS
	CMPL	R2,R9			; CHECK FOR FILE BIG ENOUGH
	BLEQU	10$			; BRANCH IF OK
	ERROR	#SS$_INSFBUFDP
;
; NOW SAVE THE VOLATILE REGISTERS 
;

10$:
	MFPR	#PR$_TODR,@#EXE$GL_PFAILTIM	; Save time of day at power fail
	MFPR	#PR$_PCBB,RPB$L_PCBB(R5); Save physical address of current pcb
	MFPR	#PR$_SCBB,RPB$L_SCBB(R5); Save physical address of System Control Block
	MFPR	#PR$_SBR,RPB$L_SBR(R5)	; Save physical address of System page table
	MFPR	#PR$_SISR,RPB$L_SISR(R5); Save software interrupt summary register
	MFPR	#PR$_SLR,RPB$L_SLR(R5)	; Save SPT length
;
; Save all other volatile processor registers on the current stack (ISP)
;
	MFPR	#PR$_KSP,-(SP)		; Save kernel stack pointer
	MFPR	#PR$_ESP,-(SP)		; Save exec stack pointer
	MFPR	#PR$_SSP,-(SP)		; Save supervisor stack pointer
	MFPR	#PR$_USP,-(SP)		; Save user stack pointer
	MFPR	#PR$_ASTLVL,-(SP)	; Save AST level
	MFPR	#PR$_PME,-(SP)		; Save performance monitor enable
	MFPR	#PR$_P0BR,-(SP)		; Save P0 base register
	MFPR	#PR$_P0LR,-(SP)		; Save P0 length register
	MFPR	#PR$_P1BR,-(SP)		; Save P1 base register
	MFPR	#PR$_P1LR,-(SP)		; Save P1 length register
	MFPR	#PR$_SBIMT,-(SP)	; Save SBI maintenance register

	.PAGE

;
; All volatile machine state necessary for restart has now been saved.
; At this point the interrupt stack contains:
;
;	+-------------------------+
;	|	   SBIMT	  | 00(SP)
;	+-------------------------+
;	|	   P1LR		  | 04(SP)
;	+-------------------------+
;	|	   P1BR		  | 08(SP)
;	+-------------------------+
;	|	   P0LR		  | 12(SP)
;	+-------------------------+
;	|	   P0BR		  | 16(SP)
;	+-------------------------+
;	|	   PME		  | 20(SP)
;	+-------------------------+
;	|	   ASTLVL	  | 24(SP)
;	+-------------------------+
;	|	   USP		  | 28(SP)
;	+-------------------------+
;	|	   SSP		  | 32(SP)
;	+-------------------------+
;	|	   ESP		  | 36(SP)
;	+-------------------------+
;	|	   KSP		  | 40(SP)
;	+-------------------------+
;	|	   R0		  | 44(SP)
;	+-------------------------+
;	|	   R1		  | 48(SP)
;	+-------------------------+
;	|	   R2		  | 52(SP)
;	+-------------------------+
;	|	   R3		  | 56(SP)
;	+-------------------------+
;	|	   R4		  | 60(SP)
;	+-------------------------+
;	|	   R5		  | 64(SP)
;	+-------------------------+
;	|	   R6		  | 68(SP)
;	+-------------------------+
;	|	   R7		  | 72(SP)
;	+-------------------------+
;	|	   R8		  | 76(SP)
;	+-------------------------+
;	|	   R9		  | 80(SP)
;	+-------------------------+
;	|	   R10		  | 84(SP)
;	+-------------------------+
;	|	   R11		  | 88(SP)
;	+-------------------------+
;	|	   AP		  | 92(SP)
;	+-------------------------+
;	|	   FP		  | 96(SP)
;	+-------------------------+
;	|	   PC		  | 100(SP)
;	+-------------------------+
;	|	   PSL		  | 104(SP)
;	+-------------------------+
;
	MOVL	SP,RPB$L_ISP(R5)	; Save final interrupt stack pointer
	MOVQ	RPB$L_BASE+4(R5),-	; Save 16 bytes of RPB to unused 
		RPB_SAVED_Q1(R5)
	MOVQ	RPB$L_BASE+12(R5),-	; area.
		RPB_SAVED_Q2(R5)
	
;
; WAIT 3 SECONDS TO ALLOW ANY OUTSTANDING OPERATION
; ON SYSTEM DEVICE TO COMPLETE
;
	PUSHR	#^M<R0,R1>		; SAVE REGISTERS
	MFPR	#PR$_TODR,R0		; GET CURRENT TIME
	ADDL2	#300,R0			; SET 3 SECOND INCREMENT
100$:	MFPR	#PR$_TODR,R1		; GET UPDATED TIME
	CMPL	R1,R0			; CHECK IF WAIT TIME COMPLETE
	BLSS	100$			; BRANCH IF WAIT NOT COMPLETE
	POPR	#^M<R0,R1>		; RESTORE REGISTERS
	
;
; NOW DUMP ALL OF CORE TO THE SYSDUMP FILE
;
;
	
	MOVL	R2,AP			;SAVE NO. OF BLOCKS TO WRITE
	BSBW	WRITEDUMP		;DUMP IT
	BLBS	R0,WAIT		; BRANCH IF NO ERRORS
	ADDL2	#44,SP		; UNWIND STACK
	CLRL	@#EXE$GL_PFAILTIM	; UNDO PFAIL INDICATOR
	ERROR			; DECLARE ERROR AND RETURN PRESENT R0
	
	.PSECT	YROLLD
	
	
MESSAGE1:
	.ASCIC	\  (HEX) PAGES OF MEMORY SAVED.\
MESSAGE:
	.ASCIC \%ROLLOUT-I-SUCCESS	SYSTEM ROLLOUT COMPLETE  \
MESSEND::
	.PSECT	YROLL
	
WAIT:
;		DECLARE SUCCESS
	CLRL	R11		; SET FOR CONSOL IO
	BSBW	EXE$OUTCRLF	; CARRIAGE RETURN,LF
	MOVAL	MESSAGE,R1
	BSBW	EXE$OUTCSTRING
	MOVL	AP,R1	;GET NUMBER OF PAGES SAVED
	BSBW	EXE$OUTHEX
	MOVAL	MESSAGE1,R1
	BSBW	EXE$OUTCSTRING
	BSBW	EXE$OUTCRLF

LOOP:	BRB	LOOP				;WAIT FOR CONSOLE HALT


	.PAGE
	.SBTTL	WRITEDUMP - WRITE DATA TO DUMP FILE
;
; WRITE DATA TO SYSTEM DUMP FILE
;
; INPUTS:

;	R5 - ADDRESS OF RESTART PARAMETER BLOCK
;	R6 - ADDRESS OF BOOTDRIVER VECTOR
;	R7 - BUFFER ADDRESS
;	R8 - SIZE OF BUFFER IN BYTES
;	R9 - SIZE OF DUMP FILE IN BLOCKS
;	R10 - LBN OF DUMP FILE (UPDATED)
;
; OUTPUTS:
;	R7 - UPDATED
;	R8 - UPDATED
; 	R9 - UPDATED
;	R10 - UPDATED
;
	IOSIZE=127*512			;MAXIMUM TRANSFER SIZE
WRITEDUMP:				;
	MOVZWL	#IOSIZE,R3		;ASSUME MAXIMUM
	CMPL	R3,R8			;CHECK AGAINST REQUESTED SIZE
	BLEQ	10$			;LESS THAN TOTAL REQUEST
	MOVL	R8,R3			;ELSE LIMIT TO REQUEST SIZE
10$:	MOVAB	511(R3),R2		;ROUND TRANSFER SIZE TO PAGE BOUND
	ASHL	#-9,R2,R2		;AND CONVERT TO PAGE COUNT
	CMPL	R2,R9			;CHECK FOR OVER END OF FILE
	BLEQ	20$			;CONTINUE IF NOT
	MOVL	#SS$_INSFBUFDP,R0	;SET ERROR CODE
	RSB				;RETURN WITH ERROR
20$:	PUSHL	R5			;SET ADDRESS OF RPB
	EXTZV	#VA$V_SYSTEM,#1,R7,-(SP);USE SYSTEM BIT AS VIRTUAL FLAG
	PUSHL	S^#IO$_WRITELBLK	;SET FUNCTION CODE
	PUSHL	R10			;LBN IN DUMP FILE
	PUSHL	R3			;SIZE OF BUFFER IN BYTES
	PUSHL	R7			;ADDRESS OF BUFFER
	CALLS	#6,@(R6)[R6]		;CALL BOOTDRIVER
	BLBS	R0,25$			;CHECK FOR ERROR
	RSB				;RETURN IF ERROR
25$:
	ADDL	R3,R7			;UPDATE BUFFER ADDRESS
	ADDL	R2,R10			;UPDATE LBN
	SUBL	R2,R9			;AND SIZE OF FILE
	BLEQ	30$			;DONE IF END OF FILE
	SUBL	R3,R8			;UPDATE BYTE COUNT
	BGTR	WRITEDUMP		;RECYCLE IF NOT COMPLETE
30$:	RSB				;


	.PAGE
	.SBTTL	ROLLIN_PI - POSITION INDEPENDENT ROLLIN CODE

	.PSECT ZROLL,LONG,PIC,SHR,NOWRT
;++
;
; Functional Description:
;	ROLLIN_PI is entered from the ROLLIN Secondary Bootstrap
;	routine.
;	The code is located in the unused portion of the RPB.
;	Objective is to restore all physical memory starting at
;	location ^X200 by calling the device independent QIO
;	routine BOO$QIO.
;
; Enviornment:
;	Mode=Kernal, Menory Management OFF
;	IS=1, IPL=31
;
; Assumptions:
;	Machine configuration has not changed, (memory configuration,
;	disks, etc.); and thus the device independent boot driver was
;	located at the same physical address that it resided in the ROLLEDOUT
;	system.  During restoration of physical memory, this driver
;	code is assumed to overlay itself!!
;
; Calling Sequence:
;	JMP RPB_ROLLIN_CODE+4-^X200(SP)

;
; Input Parameters:

;	R5	- Address of Bootdriver vector (physical)
;	R6	- Buffer address in physical memory (updated)
;	R7	- Volatile
;	R8	- Logical Block number in file SYSDUMP.DMP (updated)
;	R9	- Blocks remaining in file (updated)
;	R11	- Base of RPB
;	SP	- Address of RPB+^X200
;	PR$_SCBB- Base of RPB (routine uses an abbreviated SCB)
;
; Implicit Inputs:
;	NONE
;
; Output Parameters:
;	AP	- RESTRT_POWERUP = 3 (indicates to EXE$RESTART that powerfail occured.
;
; Memory layout at start of ROLLIN_PI
;
;	+-----------------------------------------+ :BASE
;	!	First Longword of RPB		  !
;	+-----------------------------------------+ :BASE+4
;	!	ROLLIN SCB values point to HALT   !
;	+-----------------------------------------+ :BASE+20
;	!					  !
;	!	Restart Parameter Block (RPB)	  !
;	!					  !
;	+-----------------------------------------+ :BASE+RBP$K_LENGTH
;	!					  !
;	!       Saved :BASE+4 to :BASE+20	  !
;	!					  !
;	+-----------------------------------------+ :BASE+RPB$K_LENGTH+16
;	!					  !
;	!  Physical address of Bootdriver in	  !
;	!      saved system image		  !
;	!					  !
;	+-----------------------------------------+ :BASE+RPB$K_LENGTH+20
;	!					  !
;	!	HALT Instruction for possible	  !
;	!		Machine Check		  !
;	!					  !
;	+-----------------------------------------+ :BASE+RPB$K_LENGTH+24
;	!					  !
;	!	   ROLLIN Code			  !
;	!					  !
;	+-----------------------------------------+
;	!					  !
;	!	   ROLLIN STACK			  !
;	!					  !
;	+-----------------------------------------+ :BASE+^X200
;	!					  !
;	!	Primary Bootstrap Code		  !
;	!					  !
;	!					  !
;	+-----------------------------------------+ :PR$_SCBB
;	!					  !
;	!	   System Control Block		  !
;	!					  !
;	+-----------------------------------------+ :PFNMAP
;	!					  !
;	!		PFN Bitmap		  !
;	!					  !
;	+-----------------------------------------+ :PFNMAP+^X800
;	!					  !
;	!	     Bootstrap Stack		  !
;	!					  !
;	+-----------------------------------------+ :(SP)
;	!					  !
;	!	 Secondary Bootstrap Code	  !
;	!					  !
;	+-----------------------------------------+
;
; Equated Symbols

IOSIZE		=	127		; Max size of BOO$QIO transfer
					; 64KB
;
	.ALIGN LONG

ROLLIN_PI::
	HALT				; Service for machine checks

	.ALIGN LONG

20$:	MOVZBL	#IOSIZE,R7		; Assume maximum transfer
	CMPL	R7,R9			; Minimize with file size
	BLEQ	30$			; Smaller than remaining file size
	MOVL	R9,R7			; Set to remaining file size
30$:	PUSHL	R11			; Base of RPB
	PUSHL	#0			; Set mode to physical
	PUSHL	#IO$_READLBLK		; Set function to read
	PUSHL	R8			; Set Logical Block Number
	ROTL	#9,R7,-(SP)		; Set transfer size in bytes
	PUSHL	R6			; Set buffer address
	ADDL	4(SP),R6		; Update buffer address
	ADDL	R7,R8			;  and block number
	CALLS	#6,@(R5)[R5]		; Call bootdriver
	BLBS	R0,40$			; Branch if no errors
	HALT				; Neat error handling, huh?
40$:	SUBL	R7,R9			; Decrement blocks remaining
	BGTR	20$			; Another transfer if not done

	MTPR	RPB$L_SCBB(R11),#PR$_SCBB	; Set SCBB into restored system
	MOVQ	RPB_SAVED_Q1(R11),-	; Restore displaced RPB values.
		RPB$L_BASE+4(R11)
	MOVQ	RPB_SAVED_Q2(R11),-	;
		RPB$L_BASE+12(R11)
	MOVL	#RESTRT_POWERUP,AP	; Set up AP for EXE$RESTART
	JMP	@RPB$L_RESTART-^X200(SP); JUMP TO EXE$RESTART

ROLLINLENGTH=.-ROLLIN_PI
;
	.END
