/* trap3200.S -- Initialize lowest level for VIOS interrupt handling
 * copyright (c) 1984  American Information Systems Corporation
 *
 *	Daniel Steinberg
 *	November, 1984
 *
 *	AIS/UNIX-System V.2  code format
 *
 * This file makes the following assumptions about mapping:
 *
 *	1) All VIOS/Monitor code is mapped (read-only)
 *		virtual<->physical in Supervisor State.
 *
 *	2) Absolute RAM is assumed to be at or near address 0.
 *
 *	3) The 1st two pages (1024 bytes) of physical RAM are mapped (read-only)
 *		virtual<->physical in Supervisor State and includes:
 *			The VIOS/RAM-Monitor Module Tables
 *			The Interrupt Dispatch Tables
 *			The Memory Bitmap
 *			The User-State Debug flag
 *			The Reset Address
 *
 *
 * This module DOES NOT save/restore floating point registers!!
 */
#define ASOURCE
#include "viosconf.h"

#include "RAMmonsize.m"
#include "RAMviosaddr.m"
#include "3200config.h"
#include "vioslink.h"
#include "vmdispatch.h"

#ifndef DEBUG1
#define DEBUG1
#endif

	.file	"trap3200.S"
	.text

#define Setvector(x)	addr	vios_/**/x,(I_VEC + (x * 4))(r1)
#define Settrap(x,y)	addr	y/**/_/**/x,I_/**/x(r1)

/* vios_init () -- Initialize AIS/VIOS
 *
 *	This routine must be called with only the return address on the
 *	stack, since it switches processor stacks!
 */
	.globl	_vios_init
_vios_init:
	bicpsrw	$PSR_I		/* disable interrupts */
	jsr	_vios_data_init	/* init everything (see vioinit.c) */

		/* Locate some memory for temporary stack */

	addr	@A_Grain,tos	/* push size to locate */
	movqd	$0,tos		/* set FALSE (locate only) */
	jsr	_gettopmem	/* find some memory */
	adjspb	$-8		/* pop args */

	addr	@A_oskdispatch,@A_state	/* set OS Kernel state */
	movd	tos,r1		/* pop return address */
	lprd	sp,r0		/* set temporary stack for cmd interpreter */
	bispsrw	$PSR_I		/* enable interrupts */
	jump	r1		/* return to caller */


/* init_3200 () -- Initialize VIOS interrupt dispatching tables */
	.globl	_init_3200
_init_3200:

#ifdef DEBUG3   /*************************************************************/
	cmpd	$A_reset_addr,$(1024 - 4)	/* all flags in 1st 2 pages? */
	bls	mapok
	bpt
mapok:
#endif /* DEBUG3 *************************************************************/

	addr	@A_viosdispatch,r1	/* get interrupt dispatch table */

#ifdef REV_2A /****************** CPU REVISION-2A **********************/
	Setvector(UA_INT)		/* uart-A vector */
	Setvector(UB_INT)		/* uart-B vector */

	Setvector(HOST_INIT)		/* host bus init */
#endif /************************* CPU REVISION-2A **********************/

	Setvector(CSR_I_INT)		/* CSR int vector */
	Setvector(TIMER_INT)		/* clock int */

	Settrap(NMI,vios)		/* set local NMI routine */

	addr	@A_oskdispatch,r2	/* copy to OS kernel dispatch table */
	addr	@(TRAPS+VECTORS),r0	/* size (in quads) of entire table */
	movsd				/* copy to OS kernel table */

	addr	@A_viosdispatch,r1	/* get addr of VIOS dispatch table to */
	addr	@A_osudispatch,r2	/*  copy to OS user dispatch table */
	addr	@(TRAPS+VECTORS),r0	/* size (in quads) of entire table */
	movsd				/* copy to OS user table */

	addr	@A_oskdispatch,r1	/* get OS kernel table address */
	Settrap(SVC,osk)		/* set local kernel svc handler */
	addr	@A_osidispatch,r2	/*  copy to OS interrupt table */
	addr	@(TRAPS+VECTORS),r0	/* size (in quads) of entire table */
	movsd				/* copy to OS int table */

	addr	@A_osudispatch,r1	/* get OS user table address */
	Settrap(ABT,osu)		/* local handlers for context switch */
	Settrap(FPU,osu)
	Settrap(ILL,osu)
	Settrap(SVC,osu)
	Settrap(DVZ,osu)
	Settrap(FLG,osu)
	Settrap(UND,osu)
	Settrap(BPT,osu)
	Settrap(TRC,osu)

	ret	$0


	.globl	_ena_ints
	.globl	_dis_ints
_ena_ints:
	bispsrw	$PSR_I			/* Enable interrupts */
	ret	$0

_dis_ints:
	bicpsrw	$PSR_I			/* Disable interrupts */
	ret	$0

	.globl	_ints_enabled
_ints_enabled:
	sprd	psr,r0			/* Read psr into r0 */
	andd	$PSR_I,r0		/* Mask off all but interrupt enable */
	ret	$0			/* return TRUE if ints enabled */

gotomonitor:
	jump	illegal_int		/* THIS WILL NOT RETURN! */
/*  */
/* Traps always caught by VIOS */

vios_NMI:
#ifdef REV_2A /****************** CPU REVISION-2A **********************/
	tbitb	$B_SBUS_TIMEOUT,@(UART_TMODETECT + U_INPORT)
	bfc	nmibrk		/* branch if memory timeout occurred */

	tbitb	$B_SBUS_PARITY,@(UART_TMODETECT + U_INPORT)
	bfs	nmibrk		/* branch if not a parity error */
#endif /************************* CPU REVISION-2A **********************/

	tbitw	$PSR_B_U,6(sp)		/* parity error in REAL User state? */
	bfs	osu_PARITY		/* yes...handle like a user trap */

/* Unrecoverable Parity Error */

	save	[r0,r1,r2,r4,r5,r6,r7]
	addr	tos,r6			/* save OS stack pointer */

		/* *** TEMPORARILY INVALIDATE THE STACK POINTER *** */
		/* ***  DO NOT STEP OR BREAKPOINT IN THIS CODE  *** */

	lprd	sp,$A_viosstack		/* set VIOS stack */

#ifdef MMU /********************** MMU Available ***********************/
	smr	msr,r5		/* save current mapping */
	movd	r5,r2		/* but disable kernel translation */
	bicd	$(MSR_TS),r2
	lmr	msr,r2
#endif /************************** MMU Available ***********************/

		/* *** END OF INVALIDATED STACK POINTER CODE *** */

	/* Disable PICK byte-swapping */
	movb	$PICK_ENABLE,@(UART_PARENABLE + U_CLROUT)

	jsr	parity_message	/* print parity error address */

		/* *** TEMPORARILY INVALIDATE THE STACK POINTER *** */
		/* ***  DO NOT STEP OR BREAKPOINT IN THIS CODE  *** */

#ifdef MMU /********************** MMU Available ***********************/
	lmr	msr,r5		/* re-enable kernel translation */
#endif /************************** MMU Available ***********************/
	lprd	sp,r6		/* and reset kernel stack pointer */

		/* *** END OF INVALIDATED STACK POINTER CODE *** */

	restore	[r0,r1,r2,r4,r5,r6,r7]

nmibrk:
        movqd   $1,tos		/* trap number 1 */
        br      gotomonitor	/* ****** Enable Parity Checking ********* */


/*
 * Traps caught from OS-kernel
 * Supervisor Calls:
 *	1) Going to user state
 *	2) Enable interrupt dispatching
 *	3) Disable interrupt dispatching
 *	4) Check memory-bitmap
 *	5) Print console message
 *
 *	10) Set kernel trap dispatching
 *	11) Set user trap dispatching
 *	12) VIOS I/O Request
 *
 * *** NOTE WELL ***
 *	PICK byte-swapping is NOT turned off in the Kernel SVC traps,
 *	since it is assumed that it was turned off before switching
 *	to Kernel State in the first place.  If the Operating System
 *	Kernel manually sets PICK_ENABLE, all hell will break loose here!!
 */
osk_SVC:
	addqd	$(SVC_LENGTH+1),tos	/* skip svc instruction and code */
	save	[r0,r1,r2,r4,r5,r6,r7]
	movd	-1(28(sp)),r0		/* get svc code (byte after SVC) */
	checkb	r1,quicksvcs,r0		/* is it a simple cmd? */
	bfs	chkslow			/*  no...try others */
	addr	tos,r6			/* save OS stack pointer */

		/* *** TEMPORARILY INVALIDATE THE STACK POINTER *** */
		/* ***  DO NOT STEP OR BREAKPOINT IN THIS CODE  *** */

	lprd	sp,$A_viosstack		/* set VIOS stack */

#ifdef MMU /********************** MMU Available ***********************/
	smr	msr,r5		/* save current mapping */
	movd	r5,r2		/* but disable kernel translation */
	bicd	$(MSR_TS),r2
	lmr	msr,r2
#endif /************************** MMU Available ***********************/

		/* *** END OF INVALIDATED STACK POINTER CODE *** */

qcase:	casew	qsvc[r1:w]	/* dispatch on svc code */
quicksvcs:
	.byte	SLOWSVCS-1, FASTSVCS
qsvc:	.word	to_user_svc - qcase
	.word	enable_ints_svc - qcase
	.word	disable_ints_svc - qcase
	.word	memcheck_svc - qcase
	.word	console_msg_svc - qcase
	.word	pick_user_svc - qcase

chkslow:
	checkb	r1,slowsvcs,r0	/* is it any other valid code? */
	bfs	badsvc		/*  no....forget it */

#ifdef MMU /********************** MMU Available ***********************/
	smr	msr,r5		/* save current mapping */
	movd	r5,r2		/* but disable user translation */
	bicd	$(MSR_TU),r2
	lmr	msr,r2
#endif /************************** MMU Available ***********************/

	movd	36(sp),r2	/* get address of argument list */
scase:	casew	ssvc[r1:w]	/* dispatch on svc code */
slowsvcs:
	.byte	LASTSVC, SLOWSVCS
ssvc:	.word	kernel_trap_svc - scase
	.word	user_trap_svc - scase
	.word	vios_request_svc - scase

badsvc:	restore	[r0,r1,r2,r4,r5,r6,r7]
	movqd	$5,tos		/* push SVC trap code */
	br	gotomonitor	/* and go to the Ram-Monitor */



/* Quicksvcs -- Supervisor translation is off / R5: saved MSR */
/*		VIOS stack set / R6: saved SP (Kernel Stack) */

pick_user_svc:		/* OS Kernel is switching to PICK-enabled user state */
	movb	$PICK_ENABLE,@(UART_PARENABLE + U_SETOUT)

to_user_svc:		/* OS Kernel is about to switch to user state */
	addr	@A_osudispatch,@A_state	/* set new state */

		/* *** TEMPORARILY INVALIDATE THE STACK POINTER *** */
		/* ***  DO NOT STEP OR BREAKPOINT IN THIS CODE  *** */

#ifdef MMU /********************** MMU Available ***********************/
	lmr	msr,r5		/* re-enable kernel translation */
#endif /************************** MMU Available ***********************/
	lprd	sp,r6		/* and reset kernel stack pointer */

		/* *** END OF INVALIDATED STACK POINTER CODE *** */

	restore	[r0,r1,r2,r4,r5,r6,r7]
	andw	$(~(PSR_I)),6(sp)	/* no ints until we get to user-state */
	rett	$0			/* i wanna go back */

qsvcret:

		/* *** TEMPORARILY INVALIDATE THE STACK POINTER *** */
		/* ***  DO NOT STEP OR BREAKPOINT IN THIS CODE  *** */

#ifdef MMU /********************** MMU Available ***********************/
	lmr	msr,r5		/* re-enable kernel translation */
#endif /************************** MMU Available ***********************/
	lprd	sp,r6		/* and reset kernel stack pointer */

		/* *** END OF INVALIDATED STACK POINTER CODE *** */

qsvcrestore:
	restore	[r0,r1,r2,r4,r5,r6,r7]
	rett	$0			/* i wanna go back */
#ifdef DEBUG3   /*************************************************************/
	bpt
#endif /* DEBUG3 *************************************************************/


enable_ints_svc:	/* OS Kernel is now accepting interrupts */
	movd	@A_state,r7		/* save state */
	cmpd	$A_osidispatch,r7	/* entered from interrupt? */
	beq	qsvcret			/* yes...ignore this call */
	movqb	$1,@A_OS_Completion	/* set TRUE */
	addr	@A_viosdispatch,@A_state	/* see if interrupts pending */
	br	dq_osinterrupts		/* merge with interrupt exit below */


disable_ints_svc:	/* OS Kernel is now declining interrupts */
	cmpd	$A_osidispatch,@A_state	/* entered from interrupt? */
	beq	qsvcret			/* yes...ignore this call */
	movqb	$0,@A_OS_Completion	/* set FALSE */
	br	qsvcret


memcheck_svc:		/* OS wants to know if memory is there */
	addr	_chk_bitmap,tos	/* get address of routine to call */
	br	execcall	/* call it below */

console_msg_svc:	/* Print an emergency message on console */
	addr	_printf,tos	/* get address of routine to call */

execcall:
		/* *** TEMPORARILY INVALIDATE THE STACK POINTER *** */
		/* ***  DO NOT STEP OR BREAKPOINT IN THIS CODE  *** */

#ifdef MMU /********************** MMU Available ***********************/
	lmr	msr,r5		/* re-enable kernel translation */
#endif /************************** MMU Available ***********************/

	movd	36(r6),r1	/* get ptr to args on OS stack */
	movd	4(r1),r0	/* get 2nd arg */
	movd	0(r1),r1	/* get 1st arg */

#ifdef MMU /********************** MMU Available ***********************/
	lmr	msr,r2		/* re-disable kernel translation */
#endif /************************** MMU Available ***********************/

		/* *** END OF INVALIDATED STACK POINTER CODE *** */

	movd	tos,r2		/* get address of routine to call */
	movd	r0,tos		/* push 2nd arg */
	movd	r1,tos		/* push 1st arg */
	jsr	r2		/* go execute a function (on VIOS stack) */
				/* leave args on stack since SP loaded soon */

		/* *** TEMPORARILY INVALIDATE THE STACK POINTER *** */
		/* ***  DO NOT STEP OR BREAKPOINT IN THIS CODE  *** */

#ifdef MMU /********************** MMU Available ***********************/
	lmr	msr,r5		/* re-enable kernel translation */
#endif /************************** MMU Available ***********************/
	lprd	sp,r6		/* get back to kernel stack */

		/* *** END OF INVALIDATED STACK POINTER CODE *** */

	movd	r0,36(sp)	/* set result back on stack */
	br	qsvcrestore	/* and that's all */



/* Slowsvcs -- User translation off / r5: saved MSR / r2: argument block ptr */

kernel_trap_svc:	/* Set OS Kernel trap entries for Kernel traps */
			/* NOTE: once set, they cannot be removed easily! */
	addr	@A_oskdispatch,r0	/* get addr of kernel dispatch table */
	movd	r2,r4			/* save ptr to argument block */
	bsr	set_traps		/* copy supplied trap addresses */
	movd	r4,r2			/* restore original arg ptr */
	addr	@A_osidispatch,r0	/* get k-completion dispatch table */
ku_trap_svc:
	bsr	set_traps		/* copy supplied trap addresses */
#ifdef MMU /********************** MMU Available ***********************/
	lmr	msr,r5		/* re-enable user translation */
#endif /************************** MMU Available ***********************/
	br	qsvcrestore	/* that's all */


user_trap_svc:		/* Set OS Kernel trap entries for User traps */
	addr	@A_osutraps,r0	/* get address of dispatch table */
	br	ku_trap_svc	/* merge with code above */


/* set_traps -- Copy traps supplied from OS Kernel */
set_traps:
	addr	@TRAPS,r1	/* get number of traps to try */
kloop:	cmpqd	$0,0(r2)	/* this entry point zero? */
	beq	knxt		/*  yes..skip it */
	movsud	r2,r0		/*  no...copy to intbase (movsud 0(r2),0(r0)) */
knxt:	addqd	$4,r0		/* increment table ptrs */
	addqd	$4,r2
	acbd	$-1,r1,kloop	/* and loop thru all possible traps */
	ret	$0



vios_request_svc:	/* Queue a request to the VIOS and reschedule it */
	addr	@A_viosstack,r0	/* get address of new stack */
	addr	@VIO_ARGS,r1	/* get number of arguments in arg block */
	addr	r2[r1:d],r2	/* point to end of argument list */
vloop:	addqd	$-4,r2		/* perform a manual auto-decrement */
	addqd	$-4,r0
	movsud	r2,r0		/* copy arguments onto vios stack */
	acbd	$-1,r1,vloop	/* (note tricky use of addr-access in movsud) */
	addr	tos,r6		/* save kernel stack pointer */

		/* *** TEMPORARILY INVALIDATE THE STACK POINTER *** */
		/* ***  DO NOT STEP OR BREAKPOINT IN THIS CODE  *** */

	lprd	sp,r0		/* set the stack pointer to 1st argument addr */

#ifdef MMU /********************** MMU Available ***********************/
	movd	r5,r4		/* disable kernel translation */
	bicd	$(MSR_TS),r4	/* (and restore old user-translation state) */
	lmr	msr,r4
#endif /************************** MMU Available ***********************/

		/* *** END OF INVALIDATED STACK POINTER CODE *** */

	movd	@A_state,r7			/* Save old state */
	addr	@A_viosdispatch,@A_state	/* set environment to VIOS */
	bispsrw	$PSR_I		/* all set...enable interrupts */
	jsr	_vios_iorequest	/* and call the VIOS (args are on stack) */
	bicpsrw	$PSR_I		/* back to uninterruptible state */
	

		/* *** TEMPORARILY INVALIDATE THE STACK POINTER *** */
		/* ***  DO NOT STEP OR BREAKPOINT IN THIS CODE  *** */

#ifdef MMU /********************** MMU Available ***********************/
	lmr	msr,r5		/* map OS kernel stack for a usec */
#endif /************************** MMU Available ***********************/

	movd	r0,36(r6)	/* put return val (pktaddr) where arg ptr was */

#ifdef MMU /********************** MMU Available ***********************/
	lmr	msr,r4		/* reset VIOS-state mapping */
#endif /************************** MMU Available ***********************/

		/* *** END OF INVALIDATED STACK POINTER CODE *** */

	adjspb	$-(VIO_ARGS * 4)	/* [optional] pop args off stack */
	br	osktrapexit	/* reschedule the OS, if not doing so already */

/*  */
/* Traps caught from OS-user */
osu_FPU:
        movqd   $T_FPU,tos		/* trap number 3 */
        br      user_traps
osu_ILL:
        movqd   $T_ILL,tos		/* trap number 4 */
        br      user_traps
osu_SVC:
        movqd   $T_SVC,tos		/* trap number 5 */
        br      user_traps
osu_DVZ:
        movqd   $T_DVZ,tos		/* trap number 6 */
        br      user_traps
osu_FLG:
        movqd   $T_FLG,tos		/* trap number 7 */
	br      user_traps
osu_BPT:
        addr	@T_BPT,tos		/* trap number 8 */
	br	ubreak
osu_TRC:
        addr	@T_TRC,tos		/* trap number 9 */
ubreak:	cmpqb	$0,@A_debug_user_state
	bne	gotomonitor	/* if true, go to RamMonitor */
	br	user_traps

osu_UND:
        addr	@T_UND,tos		/* trap number 10 */
        br      user_traps

osu_PARITY:
#ifdef REV_2A /****************** CPU REVISION-2A **********************/
	/* re-enable parity detection */
	movb	$(SBUS_PARENABLE),@(UART_PARENABLE + U_CLROUT)
	movb	$(SBUS_PARENABLE),@(UART_PARENABLE + U_SETOUT)
#endif /************************* CPU REVISION-2A **********************/

	addr	@I_PARITY,tos		/* Parity error trap */
	br	user_traps

osu_ABT:
        movqd   $T_ABT,tos		/* trap number 2 */

user_traps:			/* traps from OS-User state */
	save	[r0,r1,r2]	/* get some work space */
	movd	12(sp),r0	/* get trap number */

		/* *** TEMPORARILY INVALIDATE THE STACK POINTER *** */
		/* ***  DO NOT STEP OR BREAKPOINT IN THIS CODE  *** */

#ifdef MMU /********************** MMU Available ***********************/
	smr	msr,r2		/* get interrupted mapping state */
	movd	r2,r1		/* copy it */
	bicd	$(MSR_TS),r1	/* disable kernel mapping */
	lmr	msr,r1		/* set new msr value for now */
#endif /************************** MMU Available ***********************/

	/* Disable PICK byte-swapping */
	movb	$PICK_ENABLE,@(UART_PARENABLE + U_CLROUT)

	movd	@A_osutraps[r0:d],r0	/* get address of OS dispatch entry */
	cmpqd	$0,r0			/* got one? */
	beq	nousertrap		/*  no....go to Ram-Monitor */

	addr	@A_oskdispatch,@A_state	/* switch to kernel state */

#ifdef MMU /********************** MMU Available ***********************/
	lmr	msr,r2		/* reset old mapping state */
#endif /************************** MMU Available ***********************/

		/* *** END OF INVALIDATED STACK POINTER CODE *** */

	movd	r0,12(sp)	/* set handler address after saved regs */
	restore	[r0,r1,r2]
	ret	$0	/* simulate direct trap to actual trap handler */

nousertrap:	/* *** STACK POINTER STILL INVALID AT THIS POINT */
#ifdef MMU /********************** MMU Available ***********************/
	lmr	msr,r2		/* reset old mapping state */
#endif /************************** MMU Available ***********************/

		/* *** END OF INVALIDATED STACK POINTER CODE *** */

	restore	[r0,r1,r2]
	br	gotomonitor

/*  */
/* Vectored interrupt entry points */

#ifdef REV_2A /****************** CPU REVISION-2A **********************/

vios_UA_INT:		/* uart-A vector */
	save	[r0,r1,r2,r4,r5,r6,r7]	/* save registers */
	addr	_uart_a,r0		/* get address of service routine */
	br	vec_disp

vios_UB_INT:		/* uart-B vector */
	save	[r0,r1,r2,r4,r5,r6,r7]	/* save registers */
	addr	_uart_b,r0		/* get address of service routine */
	br	vec_disp

vios_HOST_INIT:		/* host bus init */
	save	[r0,r1,r2,r4,r5,r6,r7]	/* save registers */
	addr	_host_businit,r0	/* get address of service routine */
	br	vec_disp

#endif /************************* CPU REVISION-2A **********************/


vios_CSR_I_INT:		/* CSR int vector */
	save	[r0,r1,r2,r4,r5,r6,r7]	/* save registers */
	addr	_host_interrupt,r0	/* get address of service routine */
	br	vec_disp

vios_TIMER_INT:		/* clock int */
	save	[r0,r1,r2,r4,r5,r6,r7]	/* save registers */
	addr	_clock_interrupt,r0	/* get address of service routine */

/* vec_disp -- Dispatch according to interrupted processing state */

vec_disp:
	movd	@A_state,r7		/* save interrupted processing state */
	addr	@A_viosdispatch,r1	/* get VIOS state table */
	cmpd	r1,r7			/* VIOS interrupted? */
	bne	c1os			/* no */
c1vios:
	jsr	r0			/* yes...call int routine directly */
	restore	[r0,r1,r2,r4,r5,r6,r7]	/* restore regs */

	/* TEMPORARY */
	cmpqb	$0,@(INTCTLR + ICU_HVCT)	/* simulate an reti */
	rett	$0	/* reti */		/* interrupt complete */

#ifdef DEBUG3   /*************************************************************/
	bpt
#endif /* DEBUG3 *************************************************************/

c1os:
c1oskernel:
c1osinterrupt:
c1osuser:
	movw	34(sp),r4		/* get PSR at interrupt */
	addr	tos,r6			/* get SP at interrupt */

		/* *** TEMPORARILY INVALIDATE THE STACK POINTER *** */
		/* ***  DO NOT STEP OR BREAKPOINT IN THIS CODE  *** */

	lprd	sp,$A_viosstack		/* set VIOS stack */

#ifdef MMU /********************** MMU Available ***********************/
	smr	msr,r5		/* get interrupted mapping state */
	movd	r5,r2		/* copy it */
	bicd	$(MSR_TS),r2	/* disable kernel mapping */
	lmr	msr,r2		/* set new msr value for now */
#endif /************************** MMU Available ***********************/

		/* *** END OF INVALIDATED STACK POINTER CODE *** */

	/* Disable PICK byte-swapping */
	movb	$PICK_ENABLE,@(UART_PARENABLE + U_CLROUT)

	movd	r1,@A_state		/* set VIOS state */
	jsr	r0			/* call int handler w/ints disabled */

	cmpqb	$0,@(INTCTLR + ICU_HVCT)	/* simulate an reti */
osktrapexit:
	cmpd	r7,$A_osidispatch	/* OS Completion interrupted? */
	bne	c2os			/* no */

c2osinterrupt:			/* was processing OS completions */
	bsr	runvios			/* make sure the VIOS gets a shot */
oskret:
	movd	r7,@A_state		/* restore interrupted state */

		/* *** TEMPORARILY INVALIDATE THE STACK POINTER *** */
		/* ***  DO NOT STEP OR BREAKPOINT IN THIS CODE  *** */

#ifdef MMU /********************** MMU Available ***********************/
	lmr	msr,r5			/* turn Kernel mapping on? */
#endif /************************** MMU Available ***********************/
	lprd	sp,r6			/* and restore stack ptr */

		/* *** END OF INVALIDATED STACK POINTER CODE *** */

straightback:
	restore	[r0,r1,r2,r4,r5,r6,r7]	/* restore working regs */
	rett	$0			/* back to interrupted code */

#ifdef DEBUG3   /*************************************************************/
	bpt
#endif /* DEBUG3 *************************************************************/

c2os:
c2osuser:
c2oskernel:
	bsr	runvios			/* run the VIOS, if necessary */
dq_osinterrupts:
	cmpqb	$0,@A_OSscheduled	/* OS have any completions waiting? */
	beq	osreturn		/* no */
	cmpqb	$0,@A_OS_Completion	/* yes...enabled? */
	beq	osreturn		/* no */
	adjspb	$4			/* push a dummy variable */
	addr	tos,tos			/* push a dummy argument */
	jsr	_dq_oscompletion	/* get next routine to call */
	adjspb	$-4			/* pop ptr to arg */
	movd	tos,r1			/* get value to push on kernel stack */

	cmpqb	$0,r0			/* got a procedure to call? */
	beq	osreturn		/* no */

	addr	@A_osidispatch,@A_state	/* set OS Completion state */

		/* *** TEMPORARILY INVALIDATE THE STACK POINTER *** */
		/* ***  DO NOT STEP OR BREAKPOINT IN THIS CODE  *** */

#ifdef MMU /********************** MMU Available ***********************/ */
	lmr	msr,r5			/* turn Kernel mapping back on? */
#endif /************************** MMU Available ***********************/ */
	lprd	sp,r6		/* set back to kernel stack */

		/* *** END OF INVALIDATED STACK POINTER CODE *** */

	bispsrw	$PSR_I		/* Enable interrupts */
	movd	r1,tos		/* push argument */
	jsr	r0		/* call OS kernel completion routine */
	adjspb	$-4		/* pop arg */
	bicpsrw	$PSR_I		/* disable interrupts again */

		/* *** TEMPORARILY INVALIDATE THE STACK POINTER *** */
		/* ***  DO NOT STEP OR BREAKPOINT IN THIS CODE  *** */

	lprd	sp,$A_viosstack	/* set back to VIOS state */

#ifdef MMU /********************** MMU Available ***********************/ */
	movd	r5,r2		/* shut off kernel translation again */
	bicd	$(MSR_TS),r2
	lmr	msr,r2
#endif /************************** MMU Available ***********************/ */

		/* *** END OF INVALIDATED STACK POINTER CODE *** */

	addr	@A_viosdispatch,@A_state	/* process ints correctly */
	br	c2oskernel	/* go back up and try again */


osreturn:			/* reschedule the operating system */

/* the following code is not? always redundant with the subsequent test */
	addr	@A_oskdispatch,r0	/* get OS kernel table */
	cmpd	r0,r7			/* interrrupted kernel? */
	beq	oskret			/* yes...go back */

	tbitw	$PSR_B_U,r4	/* returning to REAL User state? */
	bfc	oskret		/* no...kernel was starting up a user */

osuret:			/* re-enter the OS Kernel at rescheduler */
	addr	@A_oskdispatch,@A_state	/* set OS kernel state */

		/* *** TEMPORARILY INVALIDATE THE STACK POINTER *** */
		/* ***  DO NOT STEP OR BREAKPOINT IN THIS CODE  *** */

#ifdef MMU /********************** MMU Available ***********************/
	lmr	msr,r5		/* re-enable kernel mapping */
#endif /************************** MMU Available ***********************/
	lprd	sp,r6		/* set OS Kernel stack */

		/* *** END OF INVALIDATED STACK POINTER CODE *** */

	restore	[r0,r1,r2,r4,r5,r6,r7]
	movd	@(A_oskdispatch + (I_RSCH*4)),tos	/* reschedule addr */

#ifdef DEBUG3   /*************************************************************/
	cmpqd	$0,0(sp)	/* actually got one? */
	bne	rsch_ok		/* yes */
	addr	@I_RSCH,0(sp)	/* no....simulate trap */
	br	gotomonitor	/* break */
rsch_ok:
#endif /* DEBUG3 *************************************************************/

	ret	$0		/* simulate trap to OS Kernel dispatcher */



/* runvios -- enter the VIOS, if scheduled
 *	Must be called (via bsr) with interrupts disabled
 */
runvios:
	cmpqb	$0,@A_Vioexecuting	/* VIOS interrupted */
	bne	return
	movqd	$0,tos		/* set room for NULL argument */
rl:	cmpqb	$0,@A_Vioscheduled	/* VIOS scheduled to run? */
	beq	novios		/*  no....all done here */
	bispsrw	$PSR_I		/*  yes...enable interrupts */
	jsr	_vios_entry	/*  and enter the VIOS */
	bicpsrw	$PSR_I		/* disable interrupts on VIOS return */
	br	rl		/* and check again */
novios:
	adjspb	$-4		/* pop dummy argument */
return:	ret	$0		/* and return to caller */


