#define LOCORE
#include <vax/mtpr.h>
#include <vax/pte.h>
#include <vax/psl.h>
#include <vax/cons.h>
#include <vax/cpu.h>
#include <vax/pcb.h>
#include <vax/clock.h>

/* This defines the UNIX "software extension" as well, but it's harmless */
#include <vax/pcb.m>

#include "syscall.h"

#include "../sys/rciext/kacomm.h"
#include "../sys/rciext/kaipcr.h"

#include "regs.h"
#include "sirr.h"

#define HIGH           0x1f        /* max IPL */
#define ASTQSIZE       16          /* max ASTs queued for delivery */
#define CRASHINFO_SIZE 420         /* sizeof(CRASHINFO) - see kacrash.h */
#define TOY_PHYS       0x200b8000  /* phys addr of TOY stuff */
#define TOY_RAM        0x1c        /* offset of TOY RAM */
#define CPMBX          (TOY_RAM+0) /* CPMBX offset into TOY */
#define BDR_PHYS       0x20080000  /* phys addr of BDR */
#define IPCR_BASE      0x20001f40  /* phys addr of IPCR base - we assume all IPCRs fall in the same page */
/* Bytes of system virtual address space above that required to map	 */
/*  physical memory.  4Mb for Q-bus, 2Mb for other stuff.  The 8k areas	 */
/*  for the I/O page and the Q-bus mapping registers come out of this	 */
/*  2Mb area, as does the space for the TOY clock and anything else	 */
/*  that needs to be mapped.  This size is needed so we can calculate	 */
/*  how much pte space we have to allocate for the system page table.	 */
#define SYS_XVA 10*1024*1024
	.globl	_consputs
#define DUMPSTR(s) pushr $0xfff;.data;9:.asciz s;.text;pushab 9b;calls $1,_dumpstr;popr $0xfff
#define PRINT(s) pushr $0xfff;.data;9:.asciz s;.text;pushab 9b;calls $1,_consputs;popr $0xfff
#define PANIC(s) .data;9:.asciz s;.text;pushab 9b;calls $1,_panic
#define STRING(label,s) .data;label:.asciz s;.text

	.globl	_SCB_stray
#define STRAY .long _SCB_stray
#define IV(x) .globl _SCB_/**/x;.long _SCB_/**/x+1
#define KV(x) .globl _SCB_/**/x;.long _SCB_/**/x
#define STRAY16 STRAY;STRAY;STRAY;STRAY;\
		STRAY;STRAY;STRAY;STRAY;\
		STRAY;STRAY;STRAY;STRAY;\
		STRAY;STRAY;STRAY;STRAY

	.data
	.align		2
scb:
/*00*/	STRAY;		IV(mchk);	IV(kspinval);	IV(powerfail)
/*10*/	KV(privinst);	KV(xfc);	KV(resoprnd);	KV(radrmod)
/*20*/	KV(accvio);	KV(xinval);	KV(tracepend);	KV(bpt)
/*30*/	STRAY;		KV(arithtrap);	STRAY;		STRAY
/*40*/	KV(chmk);	KV(chme);	KV(chms);	KV(chmu)
/*50*/	STRAY;		STRAY;		STRAY;		STRAY
/*60*/	STRAY;		STRAY;		STRAY;		STRAY
/*70*/	STRAY;		STRAY;		STRAY;		STRAY
/*80*/	STRAY;		IV(soft1);	IV(soft2);	IV(soft3)
/*90*/	IV(soft4);	IV(soft5);	IV(soft6);	IV(soft7)
/*a0*/	IV(soft8);	IV(soft9);	IV(soft10);	IV(soft11)
/*b0*/	IV(soft12);	IV(soft13);	IV(soft14);	IV(soft15)
/*c0*/	IV(timer);	STRAY;		KV(emulate);	KV(emulateFPD)
/*d0*/	STRAY;		STRAY;		STRAY;		STRAY
/*e0*/	STRAY;		STRAY;		STRAY;		STRAY
/*f0*/	STRAY;		STRAY;		IV(crx);	IV(ctx)
/*100*/	STRAY16		/* these are device adaptor interrupts */
/*140*/	STRAY16		/* eg, Unibus adaptors */
/*180*/	STRAY16		/* but uVAXen don't *have* such things */
/*1c0*/	STRAY16		/* so we ignore them all */
/*200*/	STRAY;		IV(doorbell);	STRAY;		STRAY
/*210*/	STRAY;		STRAY;		STRAY;		STRAY
/*220*/	STRAY;		STRAY;		STRAY;		STRAY
/*230*/	STRAY;		STRAY;		STRAY;		STRAY
/*240*/	STRAY16		/* these (200-2fc) are device vectors */
/*280*/	STRAY16		/* all slaves have for device interrupts */
/*2c0*/	STRAY16		/* is the interprocessor doorbell */
scbend:
scbbuf:
	.space		2048
	.align		2
	.globl	_intstack
	.globl	eintstack
_intstack:
	.space		2048
eintstack:
_kstackredzone:
	.space		1024
	.globl	_kernstack
	.globl	ekernstack
_kernstack:
	.space		10240
ekernstack:
	.align		2
	.globl	_pcb
_pcb:
	.space		512
	.align		2
	.comm	_scb,4
	.globl	_scbsize
_scbsize:
	.long		scbend-scb
	.globl	_cpu		/* set before bss gets cleared */
_cpu:
	.space		4
	.globl	_bdr		/* set before bss gets cleared */
_bdr:
	.space		4
	.globl	_memsize	/* set before bss gets cleared */
_memsize:
	.space		4
	.comm	_freephys,4
	.comm	_freevirt,4
	.comm	_ipcrs,4
	.comm	_slavenum,4
	.comm	_crashinfo,CRASHINFO_SIZE
	.comm	_time100,4
	.comm	_timesch,4
	.comm	_astfxn100,4
	.comm	_astarg100,4
	.comm	_asttime100,4
	.comm	_astfxnsch,4
	.comm	_astargsch,4
	.comm	_asttimesch,4
	.comm	_astactive,4
	.comm	_astpq,8
	.comm	_astfq,8
	.comm	_astqs,ASTQSIZE*16
	.comm	_sch_missedticks,4
	.comm	_bootcount,4
	.comm	_toy,4
	.comm	_Qbus,4
	.comm	_IOpage,4
	.comm	_Qbusmapregs,4
	.comm	_fromarea,4
	.comm	_toarea,4
	.comm	_bboards,16
	.comm	_ourbb,4
	.comm	_export_clocks,4
	.comm	_clock_asts,4*4*4	/* 4 * sizeof(TIMER), see clock.h */
	.comm	_uapage,4
	.globl	_trapregs
_trapregs:
	.globl	_trapr0
_trapr0:
	.space		4
	.globl	_trapr1
_trapr1:
	.space		4
	.globl	_trapr2
_trapr2:
	.space		4
	.globl	_trapr3
_trapr3:
	.space		4
	.globl	_trapr4
_trapr4:
	.space		4
	.globl	_trapr5
_trapr5:
	.space		4
	.globl	_trapr6
_trapr6:
	.space		4
	.globl	_trapr7
_trapr7:
	.space		4
	.globl	_trapr8
_trapr8:
	.space		4
	.globl	_trapr9
_trapr9:
	.space		4
	.globl	_trapr10
_trapr10:
	.space		4
	.globl	_trapr11
_trapr11:
	.space		4
	.globl	_trapr12
_trapr12:
	.globl	_trapap
_trapap:
	.space		4
	.globl	_trapr13
_trapr13:
	.globl	_trapfp
_trapfp:
	.space		4


/* ipl 0x1f; mapen 0; on interrupt stack; don't trust anything else */
	.text
	.globl	start
start:
	nop;nop		/* harmless entry mask, or two nops; whichever */
/* relocate into low core, if not there already */
	movab		1f,r6
	movab		2f,r7
	movab		_end,r8
	movab		0x80000000,r11
	jeql		2f
	subl3		r6,r7,r0
	movc3		r0,(r6),(r8)
	jmp		(r8)
1:	subl2		r11,r7
	subl3		r11,r8,r10
	clrl		r9
4:	movl		$0x1000,r6
	cmpl		r10,r6
	jgeq		3f
	movl		r10,r6
3:	movc3		r6,(r11),(r9)
	addl2		r6,r11
	addl2		r6,r9
	subl2		r6,r10
	jgtr		4b
	jmp		(r7)
2:
/* stop the clock, in case it's running */
	mtpr		$0,$ICCS
/* load isp */
	movab		eintstack,sp
/* DUMPSTR may be used at any point below this */
/* set cpmbx to really halt on a halt instruction */
	insv		$3,$0,$2,*$TOY_PHYS+CPMBX
/* get cpu type */
	mfpr		$SID,r0
	extzv		$24,$8,r0,_cpu
/* save BDR contents */
	movl		*$BDR_PHYS,_bdr
/* set system control block base */
	movab		scbbuf,r11
	addl2		$511,r11
	bicl2		$511,r11
	movc3		_scbsize,scb,(r11)
	movab		(r11),_scb
	mtpr		r11,$SCBB
/* count up memory */
	clrl		r7
1:	pushl		$4
	pushl		r7
	calls		$2,_badaddr
	tstl		r0
	bneq		2f
	acbl		$0x7fffffff,$64*1024,r7,1b
2:
/* leave an area for uVAX II console scratch pad at the top */
	subl2		$4096,r7
	movl		r7,_memsize
/* clear kernel bss */
	movab		_end,r11
	movab		_edata,r10
1:	clrq		(r10)
	acbl		r11,$8,r10,1b
/* save next free physical addr */
	movab		_end,_freephys
/* set up system ptes; map all of physical space into low system virtual */
	movl		_freephys,r0
	mtpr		r0,$SBR
	movl		_memsize,r0
	divl2		$512,r0
	divl3		$512,$SYS_XVA,r1
	addl3		r1,r0,r2
	mtpr		r2,$SLR
	mull3		$4,r2,r3
	addl2		r3,_freephys
	mfpr		$SBR,r9
	movl		$PG_V|PG_KW,r8
1:	movl		r8,(r9)+
	incl		r8
	sobgtr		r0,1b
	addl2		$511,_freephys
	bicl2		$511,_freephys
/* save next free virtual addr, for when we go mapped */
	bicl2		$~PG_PFNUM,r8
	mull2		$512,r8
	addl3		$0x80000000,r8,_freevirt
/* double map into P0 space, so when we go mapped we can run long enough */
	mfpr		$SBR,r0
	cmpl		_cpu,$VAX_620
	jeql		1f
	addl2		$0x80000000,r0
1:	mtpr		r0,$P0BR
	mfpr		$SLR,r0
	mtpr		r0,$P0LR
/* make kernel text readonly for both user and kernel */
	movab		_etext,r10
	addl2		$511,r10
	divl2		$512,r10
	mfpr		$SBR,r9
	movl		$PG_V|PG_URKR,r8
1:	movl		r8,(r9)+
	incl		r8
	sobgtr		r10,1b
/* make scbreadonly as redzone for interrupt stack */
	divl3		$512,_scb,r0
	bisl3		$PG_V|PG_KR,r0,r8
	mfpr		$SBR,r9
	moval		(r9)[r0],r9
	addl3		$511,_scbsize,r10
	divl2		$512,r10
1:	movl		r8,(r9)+
	incl		r8
	sobgtr		r10,1b
/* set up kernel stack redzone */
	movab		_kstackredzone,r0
	addl2		$511,r0
	divl2		$512,r0
	mfpr		$SBR,r1
	moval		(r1)[r0],r1
	bicl2		$PG_PROT,(r1)
	bisl2		$PG_KR,(r1)
/* now go to mapped mode */
	mtpr		$0,$TBIA
	mtpr		$1,$MAPEN
	/* pc, stack now in P0 space */
	jmp		*$0f
0:	/* pc now back in system space */
	bisl2		$0x80000000,sp
	/* stack now back in system space */
/* map the TOY clock */
	movl		_freevirt,r2
	addl2		$512,_freevirt
	bicl3		$0x80000000,r2,r0
	divl2		$512,r0
	mfpr		$SBR,r1
	bisl2		$0x80000000,r1
	divl3		$512,$TOY_PHYS,r3
	bicl2		$~PG_PFNUM,r3
	bisl3		$PG_V|PG_UW,r3,(r1)[r0]
	mtpr		r2,$TBIS
	movab		(r2),_toy
/* map the IPCRs */
	pushl		$PG_V|PG_KW
	pushl		$IPCR_BASE&~511
	pushl		$1
	calls		$3,_mapit
	movaw		(IPCR_BASE&511)(r0),_ipcrs
/* map the Q-bus */
	pushl		$PG_V|PG_UW
	pushl		$KA_QBUSBASE
	ashl		$-9,$KA_QBUSSIZE,-(sp)
	calls		$3,_mapit
	movl		r0,_Qbus
/* map the Q-bus I/O page */
	pushl		$PG_V|PG_UW
	pushl		$KA_QBUSIOBASE
	ashl		$-9,$KA_QBUSIOSIZE,-(sp)
	calls		$3,_mapit
	movl		r0,_IOpage
/* map the Q-bus mapping registers */
	pushl		$PG_V|PG_UW
	pushl		$KA_QMAPBASE
	ashl		$-9,$KA_QBUSSIZE,r0
	ashl		$2,r0,r0
	ashl		$-9,r0,-(sp)
	calls		$3,_mapit
	movl		r0,_Qbusmapregs
/* figure out which slave we are */
	extzv		$10,$2,_bdr,_slavenum
/* get message area physical addresses in r10 and r11 */
	tstl		_slavenum
	jneq		1f
	PANIC("this is a slave kernel and must be run on a slave processor")
1:	mull3		$KA_MSGBUFSIZE*4,_slavenum,r11
	addl2		$KA_X_TO_Y(0,KA_ARBITER),r11
	mull3		$KA_MSGBUFSIZE,_slavenum,r10
	addl2		$KA_X_TO_Y(KA_ARBITER,0),r10
/* set up the message areas */
	pushl		$PG_V|PG_KW
	pushl		r11
	ashl		$-9,$KA_MSGBUFSIZE,-(sp)
	calls		$3,_mapit
	movl		r0,_toarea
	pushl		$KA_MSGBUFSIZE
	calls		$1,_getphys
	pushl		$PG_V|PG_KW
	pushl		r0
	ashl		$-9,$KA_MSGBUFSIZE,-(sp)
	calls		$3,_mapit
	movl		r0,_fromarea
	clrq		(r0)
	clrl		8(r0)
	pushl		r10
	ashl		$-9,$KA_MSGBUFSIZE,-(sp)
	pushl		_fromarea
	calls		$3,_qbaccess
/* set up the blackboard areas */
	movl		$KA_BBOARD(3),r9
	movl		$3,r8
1:	cmpl		r8,_slavenum
	jneq		2f
	bisl3		$0x80000000,_freephys,_ourbb
	addl2		$KA_BBOARDSIZE,_freephys
	pushl		r9
	ashl		$-9,$KA_BBOARDSIZE,-(sp)
	pushl		_ourbb
	calls		$3,_qbaccess
	pushl		$PG_UW	/* made user writable by John Lloyd */
	ashl		$-9,$KA_BBOARDSIZE,-(sp)
	pushl		_ourbb
	calls		$3,_setpprot
	movl		_ourbb,r0
	jbr		3f
2:	pushl		$PG_V|PG_URKW
	pushl		r9
	ashl		$-9,$KA_BBOARDSIZE,-(sp)
	calls		$3,_mapit
3:	movl		r0,_bboards[r8]
	subl2		$KA_BBOARDSIZE,r9
/* blee.	sobgeq		r8,1b */
	decl		r8
	jgeq		1b
/* set up the user-accessible memory page */
	bisl3		$0x80000000,_freephys,_uapage
	addl2		$512,_freephys
	extzv		$9,$21,_uapage,r0
	mfpr		$SBR,r1
	bisl2		$0x80000000,r1
	moval		(r1)[r0],r0
	bicl2		$PG_PROT,(r0)
	bisl2		$PG_UW,(r0)
	mtpr		_uapage,$TBIS
/* initialize the pcb */
	movab		_pcb,r0
	movab		ekernstack,PCB_KSP(r0)
	mnegl		$1,PCB_ESP(r0)
	mnegl		$1,PCB_SSP(r0)
	mnegl		$1,PCB_USP(r0)
	clrl		PCB_P0BR(r0)
	movl		$AST_NONE,PCB_P0LR(r0)
	clrl		PCB_P1BR(r0)
	clrl		PCB_P1LR(r0)
	movab		1f,PCB_PC(r0)
	movl		$PSL_IPL,PCB_PSL(r0)
/* and shift to kernel mode, get off intstack (keep ipl at 31) */
	bicl2		$0x80000000,r0
	mtpr		r0,$PCBB
	ldpctx
	rei
1:
/* start the times off at zero */
	clrl		_time100
	clrl		_timesch
	clrl		_sch_missedticks
/* set up the AST queues */
	calls		$0,_init_ast
/* initialize the timers */
	calls		$0,_init_timers
/* clear the signal handlers */
	calls		$0,_init_sig_handlers
/* enable console serial line, timer, and doorbell interrupts */
	mtpr		$TXCS_IE,$TXCS
	mtpr		$RXCS_IE,$RXCS
	mtpr		$ICCS_IE,$ICCS
	calls		$0,_enable_scheduler
	movl		_slavenum,r0
	movl		_ipcrs,r1
	movw		$KA_DBIE|KA_LMEAE,(r1)[r0]
/* clear any soft interrupt requests lying around */
	mtpr		$0,$SISR
/* set cpmbx to indicate boot successful */
	movab		*_toy,r0
	insv		$0,$2,$1,CPMBX(r0)
/* count the number of successful boots */
	incl		_bootcount
/* now call main */
	calls		$0,_main
/* should never reach here */
	PANIC("main returned")

	.globl	_restart
_restart:
	.word		0
	mtpr		$HIGH,$IPL
	mtpr		$0,$ICCS
	mtpr		$0,$RXCS
	mtpr		$0x80,$TXCS
	mtpr		$0,$SISR
	mtpr		$4,$ASTLVL
	movpsl		r0
	bitl		$PSL_IS,r0
	jneq		1f
	svpctx
1:	mfpr		$SBR,r0
	cmpl		_cpu,$VAX_620
	jeql		1f
	addl2		$0x80000000,r0
1:	mtpr		r0,$P0BR
	mfpr		$SLR,r0
	mtpr		r0,$P0LR
	movab		0f,-(sp)
	bicl2		$0x80000000,(sp)
	rsb
0:	mtpr		$0,$MAPEN
	pushl		$0x041f0000
	pushaw		start+2
	rei

	.globl	_reboot
_reboot:
	.word	0
	mfpr		$MAPEN,r0
	jeql		1f
	movab		*_toy,r0
	insv		$2,$0,$2,CPMBX(r0)
	jbr		2f
1:	insv		$2,$0,$2,*$TOY_PHYS+CPMBX
2:	halt
	jbr		2b

/* Utility routines */

/* qbaccess(va,npg,phys) */
/* makes npg pages of memory, kernel virtual address of which is va, */
/*  accessible via Q-bus address phys */
	.globl	_qbaccess
	.align	2
_qbaccess:
	.word		0x1c
	movl		4(ap),r0
	movl		8(ap),r1
	movl		12(ap),r2
	tstl		r1
	jgtr		1f
	ret
1:	mfpr		$SBR,r3
	bisl2		$0x80000000,r3
	bicl2		$0x80000000,r0
	ashl		$-9,r0,r0
	subl2		$KA_QBUSBASE,r2
	ashl		$-9,r2,r2
	movl		_Qbusmapregs,r4
1:	bicl3		$~PG_PFNUM,(r3)[r0],(r4)[r2]
	bisl2		$KA_QMAP_V,(r4)[r2]
	incl		r0
	incl		r2
	sobgtr		r1,1b
	ret

/* mapit(npgs,phys,prot) */
/* maps npgs of memory, starting with physical address phys */
/* prot is pte bits, all except PG_PFNUM (note: don't forget PG_V) */
/* the resulting virtual address is the return value */
	.globl	_mapit
	.align	2
_mapit:
	.word		0x7c
	movl		_freevirt,r2
	movab		(r2),r6
	ashl		$9,4(ap),r0
	addl2		r0,_freevirt
	bicl3		$0x80000000,r2,r0
	ashl		$-9,r0,r0
	mfpr		$SBR,r1
	bisl2		$0x80000000,r1
	ashl		$-9,8(ap),r3
	bicl2		$~PG_PFNUM,r3
	movl		4(ap),r4
	movl		12(ap),r5
1:	bisl3		r5,r3,(r1)[r0]
	mtpr		r2,$TBIS
	addl2		$512,r2
	incl		r0
	incl		r3
	sobgtr		r4,1b
	movl		r6,r0
	ret

/* setpprot(virt,npgs,prot) */
/* sets the protection on npgs of virtual memory starting with the page */
/*  containing virt to prot.  Leaves all other bits in the page tables */
/*  unchanged.  Assumes virt is a kernel space address. */
	.globl	_setpprot
	.align	2
_setpprot:
	.word	0xc
	mfpr		$IPL,r3
	mtpr		$HIGH,$IPL
	movl		8(ap),r2
	jleq		1f
	bicl3		$0x80000000,4(ap),r0
	ashl		$-9,r0,r0
	mfpr		$SBR,r1
	bisl2		$0x80000000,r1
	moval		(r1)[r0],r0
	movl		12(ap),r1
2:	bicl2		$PG_PROT,(r0)
	bisl2		r1,(r0)+
	sobgtr		r2,2b
	mtpr		$0,$TBIA
1:	mtpr		r3,$IPL
	ret

/* getphys(nbytes) */
/* gets physical memory, rounding nbytes up to full pages */
/* returns starting physical address */
	.globl	_getphys
	.align	2
_getphys:
	.word	0
	addl3		$511,4(ap),r1
	bicl2		$511,r1
	movl		_freephys,r0
	addl2		r1,_freephys
	cmpl		_freephys,_memsize
	jleq		1f
	PANIC("out of physical memory")
1:	ret

/* badaddr(addr,type) returns 1 if *addr causes a machine check. */
/* type determines type of access: 1=byte, 2=word, 4=long */
	.globl	_badaddr
	.align	2
_badaddr:
	.word		0x18
	movl		$1,r0
	mfpr		$IPL,r1
	mtpr		$HIGH,$IPL
	movl		4(ap),r3
	movl		8(ap),r4
	movab		8f,mchk_expected
	casel		r4,$1,$3
0:	.word		1f-0b
	.word		2f-0b
	.word		3f-0b
	.word		4f-0b
3:	PANIC("invalid badaddr")
1:	tstb		(r3)
	jbr		6f
2:	tstw		(r3)
	jbr		6f
4:	tstl		(r3)
6:	clrl		r0
8:	clrl		mchk_expected
	mtpr		r1,$IPL
	ret

/* prober(addr,size) tests size bytes starting at addr with prober. */
/* returns 1 on failure, 0 on success */
	.globl	_prober
_prober:
	.word		0
	movl		4(ap),r0
	movl		8(ap),r1
	tstl		r1
	jleq		9f
	cmpl		r1,$512
	jleq		1f
0:	prober		$0,$1,(r0)
	jeql		8f
	addl2		$512,r0
	acbl		$513,$-512,r1,0b
1:	prober		$0,r1,(r0)
	jneq		9f
8:	movl		$1,r0
	ret
9:	clrl		r0
	ret

/* probew(addr,size) tests size bytes starting at addr with probew. */
/* returns 1 on failure, 0 on success */
	.globl	_probew
_probew:
	.word		0
	movl		4(ap),r0
	movl		8(ap),r1
	tstl		r1
	jleq		9f
	cmpl		r1,$512
	jleq		1f
0:	probew		$0,$1,(r0)
	jeql		8f
	addl2		$512,r0
	acbl		$513,$-512,r1,0b
1:	probew		$0,r1,(r0)
	jneq		9f
8:	movl		$1,r0
	ret
9:	clrl		r0
	ret

	.globl	_panic
_panic:
	.word	0
	mtpr		$HIGH,$IPL
	pushl		$1
	calls		$1,_saveregs
	.globl	_panicstr
	movab		*4(ap),_panicstr
	PRINT("panic: ")
	pushl		_panicstr
	calls		$1,_consputs
	PRINT("\n")
	calls		$0,_debugger
	halt

	.globl	_saveregs
_saveregs:
	.word	0
	jsb		saveregs
	movl		fp,r0
	movl		4(ap),r1
3:	movl		8(r0),_trapap
	movl		12(r0),_trapfp
	moval		20(r0),r2
	moval		_trapr0,r3
	extzv		$48,$12,(r0),r4
2:	blbc		r4,1f
	movl		(r2)+,(r3)
1:	addl2		$4,r3
	extzv		$1,$11,r4,r4
	jneq		2b
	movl		_trapfp,r0
	sobgeq		r1,3b
	ret

	.globl	saveregs
saveregs:
	movl		r0,_trapr0
	movl		r1,_trapr1
	movl		r2,_trapr2
	movl		r3,_trapr3
	movl		r4,_trapr4
	movl		r5,_trapr5
	movl		r6,_trapr6
	movl		r7,_trapr7
	movl		r8,_trapr8
	movl		r9,_trapr9
	movl		r10,_trapr10
	movl		r11,_trapr11
	movl		ap,_trapap
	movl		fp,_trapfp
	rsb

	.align	2
_SCB_stray:
	PANIC("stray interrupt")
	.align	2
_SCB_accvio:
	pushr		$0x3fff
	pushab		(sp)
	pushab		15*4(sp)
	calls		$2,_accvio
	popr		$0x3fff
	movab		8(sp),sp
	jmp		ureturn
	.align	2
_SCB_arithtrap:
	pushr		$0x3fff
	pushab		(sp)
	pushab		15*4(sp)
	calls		$2,_arithtrap
	popr		$0x3fff
	tstl		(sp)+
	jmp		ureturn
	.align	2
_SCB_bpt:
	pushr		$0x3fff
	pushab		(sp)
	pushab		15*4(sp)
	calls		$2,_bpt
	popr		$0x3fff
	jmp		ureturn
	.align	2
_SCB_chme:
	.word		0xffff
	.align	2
_SCB_chmk:
/* clearast() has been streamlined because it's heavily used */
	cmpl		(sp),$SYS_clearast
	jneq		1f
	mtpr		$HIGH,$IPL
	tstl		(sp)+
	jbr		clearast /* ...who does the rei itself */
1:	pushr		$0x3fff
	pushab		(sp)
	pushab		15*4(sp)
	calls		$2,_syscall
	popr		$0x3fff
	tstl		(sp)+
	jmp		ureturn
	.align	2
_SCB_chms:
	.word		0xffff
	.align	2
_SCB_chmu:
	.word		0xffff
	.align	2
_SCB_crx:
	pushr		$0x3f
	calls		$0,_crxint
	popr		$0x3f
	rei
	.align	2
_SCB_ctx:
	pushr		$0x3f
	calls		$0,_ctxint
	popr		$0x3f
	rei
	.data
	.lcomm	sch_hardcount,2
	.lcomm	sch_up,1
	.text
	.align	2
_enable_scheduler:
	.word		0
	pushl		$2
	addl3		$4*2,_ipcrs,-(sp)
	calls		$2,_badaddr
	tstl		r0
	jneq		1f
	movl		_ipcrs,r0
	bicw3		$0x8000,4*2(r0),sch_hardcount

	movw		$0x8000,4*2(r0) /* XXX */
	clrw		4*2(r0)	 /* XXX */

	movb		$1,sch_up
	ret
1:	clrb		sch_up
	ret
	.align	2
_SCB_doorbell:
	pushr		$0xf
	movl		$3,r3
2:	cmpl		r3,_slavenum
	jeql		1f
	movl		_ourbb,r0
	moval		8(r0)[r3],r0
	mull3		$16,r3,r1	/* 16 = sizeof(TIMER) [clock.h] */
	moval		_clock_asts,r2
	addl2		r1,r2
	tstl		8(r2)		/* fxn */
	jeql		1f
	cmpl		4(r2),(r0)	/* timeout (vs. new clock value) */
	jgtr		1f
	pushr		$0x3f
	pushl		12(r2)		/* arg */
	pushl		8(r2)		/* fxn */
	clrl		8(r2)		/* fxn */
	calls		$2,_ast
	popr		$0x3f
1:	sobgtr		r3,2b
	tstb		sch_up
	jeql		dbl_chkmsgq
	movl		_ipcrs,r0
	bicw3		$0x8000,4*2(r0),r1
	cmpw		r1,sch_hardcount
	jeql		dbl_chkmsgq
	jlss		dbl_wrapped
	subw3		sch_hardcount,r1,r2	/* r2 = increase in ticks */
	jbr		dbl_inctime
dbl_wrapped:
	movw		sch_hardcount,r2
	movw		r2,r3
1:	bisw2		r3,r2
	extzv		$1,$15,r3,r3
	jneq		1b
	incw		r2
	addw2		r1,r2
	subw2		sch_hardcount,r2	/* r2 = increase in ticks */
dbl_inctime:
	movw		r1,sch_hardcount
	movzwl		r2,r2
	addl2		r2,_timesch
	decl		r2
	jleq		1f
	addl2		r2,_sch_missedticks
1:	movl		_timesch,*_ourbb
	tstl		_astfxnsch
	jeql		1f
	decl		_asttimesch
	subl2		r2,_asttimesch
	jgtr		1f
	pushr		$0x3f
	pushl		_astargsch
	pushl		_astfxnsch
	clrl		_astfxnsch
	calls		$2,_ast
	popr		$0x3f
1:	/* jbr		dbl_chkmsgq */
dbl_chkmsgq:
	movl		_fromarea,r0
	cmpl		(r0),8(r0)
	jeql		1f
	mtpr		$SIR_DOORBELL,$SIRR
1:	popr		$0xf
	rei
	.align	2
_SCB_emulate:
	jmp		_emuvec		/* in emulate.s */
	.align	2
_SCB_emulateFPD:
	PANIC("emulateFPD")
	.align	2
_SCB_kspinval:
	PANIC("kspinval")
	.align	2
_SCB_mchk:
	.data
	.lcomm	mchk_expected,4
	.text
	tstl		mchk_expected
	jneq		1f
	jsb		saveregs
	pushr		$0x3f
	pushab		6*4(sp)
	calls		$1,_mchk
	popr		$0x3f
	addl2		(sp)+,sp
	jmp		ureturn
1:	addl2		(sp)+,sp
	movl		mchk_expected,(sp)
	jmp		ureturn
	.align	2
_SCB_powerfail:
	PANIC("powerfail")
	.align	2
_SCB_privinst:
	pushr		$0x3fff
	pushab		(sp)
	pushab		15*4(sp)
	calls		$2,_privinst
	popr		$0x3fff
	jmp		ureturn
	.align	2
_SCB_radrmod:
	pushr		$0x3fff
	pushab		(sp)
	pushab		15*4(sp)
	calls		$2,_radrmod
	popr		$0x3fff
	jmp		ureturn
	.align	2
_SCB_resoprnd:
	pushr		$0x3fff
	pushab		(sp)
	pushab		15*4(sp)
	calls		$2,_resoprnd
	popr		$0x3fff
	jmp		ureturn
	.align	2
_SCB_soft1:
	PANIC("soft1")
	.data
	.comm	_resched_ast,4
	.text
	.align	2
	.globl	ureturn
ureturn:
	mfpr		$IPL,-(sp)
	cmpl		(sp),$SIR_AST
	jgeq		1f
	mtpr		$SIR_AST,$IPL
1:	tstl		(sp)+
	tstl		_resched_ast
	jeql		1f
	mtpr		$SIR_AST,$SIRR
1:	rei
	.align	2
	.globl	clearast
clearast:
/* entered via branch from streamlined chmk handler for clearast() syscall */
/* on entry: ipl HIGH, stack ready to rei, mustn't mung registers */
	clrl		_astactive
	pushal		_astpq
	cmpl		_astpq+4,(sp)+
	jeql		1f
	mtpr		$SIR_AST,$SIRR
1:	rei
	.align	2
_SCB_soft2:				/* SIR_AST */
	clrl		_resched_ast
	pushl		r0
	bicl3		$~PSL_CURMOD,8(sp),r0
	cmpl		$PSL_CURMOD,r0
	jeql		1f
	incl		_resched_ast
	movl		(sp)+,r0
	rei
1:	movl		(sp)+,r0
	pushr		$0xfff
	moval		48(sp),r10
	moval		(sp),r9
	clrl		r0
	mtpr		$HIGH,$IPL
	tstl		_astactive
	jneq		1f
	movl		_uapage,r1
	tstl		12(r1)
	jneq		1f
	remque		*_astpq+4,r2
	jvc		2f
	clrl		16(r1)
	jbr		1f
2:	decl		16(r1)
	insque		(r2),_astfq
	movq		8(r2),r6
	movl		$1,_astactive
	incl		r0
1:	mtpr		$SIR_AST,$IPL
	tstl		r0
	jeql		ast_rei
	mfpr		$USP,r11
	movq		(r10),-(r11)
	pushl		r0
	bicl3		$~PSL_CURMOD,4(r11),r0
	cmpl		$PSL_CURMOD,r0
	jeql		1f
	PANIC("non-user mode in ast delivery?")
1:
	movl		(sp)+,r0
	subl2		$12*4,r11
	movc3		$12*4,(r9),(r11)
	movl		r7,-(r11)
	movl		r6,-(r11)
	mtpr		r11,$USP
	movab		ast_ret,(r10)
	movl		$PSL_PRVMOD|PSL_CURMOD,4(r10)
ast_rei:
	popr		$0xfff
	rei
1:	.word	0
	chmk		$SYS_clearast
	ret
ast_ret:
	movl		(sp)+,r0
	calls		$1,(r0)
	calls		$0,1b
	movab		48(sp),r0
	bicl3		$~(PSL_CURMOD|PSL_PRVMOD),4(r0),r1
	cmpl		r1,$PSL_CURMOD|PSL_PRVMOD
	jneq		bad_ast_rei
	popr		$0xfff
	rei
bad_ast_rei:
	bpt
	halt
	.globl	_ast
_ast:
	.word	0x0
	mfpr		$IPL,r0
	mtpr		$HIGH,$IPL
	remque		*_astfq+4,r1
	jvs		ast_q_full
	movl		4(ap),8(r1)
	movl		8(ap),12(r1)
	insque		(r1),_astpq
	movl		_uapage,r1
	incl		16(r1)
	tstl		_astactive
	jneq		1f
	movl		_uapage,r1
	tstl		12(r1)
	jneq		1f
	mtpr		$SIR_AST,$SIRR
1:	mtpr		r0,$IPL
	ret
	.globl	_init_ast
_init_ast:
	.word	0x4
	mfpr		$IPL,r2
	mtpr		$HIGH,$IPL
	movaq		_astpq,_astpq
	movaq		_astpq,_astpq+4
	movaq		_astfq,_astfq
	movaq		_astfq,_astfq+4
	movl		$ASTQSIZE-1,r0
1:	mull3		$16,r0,r1
	movab		_astqs[r1],r1
	insque		(r1),_astfq
	sobgeq		r0,1b
	clrl		_astactive
	movl		_uapage,r0
	clrl		12(r0)
	clrl		16(r0)
	mtpr		r2,$IPL
	ret
ast_q_full:
	PANIC("pending AST queue overflow")
	.align	2
_SCB_soft3:				/* SIR_EXIT */
	.globl		forced_exit
	jmp		forced_exit
	.align	2
_SCB_soft4:
	PANIC("soft4")
	.align	2
_SCB_soft5:
	PANIC("soft5")
	.align	2
_SCB_soft6:
	PANIC("soft6")
	.align	2
_SCB_soft7:
	PANIC("soft7")
	.align	2
_SCB_soft8:				/* SIR_DOORBELL */
	jsb		saveregs
	pushr		$0x3f
	calls		$0,_doorbell
	popr		$0x3f
	rei
	.align	2
_SCB_soft9:
	PANIC("soft9")
	.align	2
_SCB_soft10:
	PANIC("soft10")
	.align	2
_SCB_soft11:
	PANIC("soft11")
	.align	2
_SCB_soft12:
	PANIC("soft12")
	.align	2
_SCB_soft13:
	PANIC("soft13")
	.align	2
_SCB_soft14:
	PANIC("soft14")
	.align	2
_SCB_soft15:
	PANIC("soft15")
	.align	2
	.globl	_init_timers
_init_timers:
	.word		0x3c
	movc5		$0,(sp),$0,$4,_export_clocks
	movl		$3,r5
	movl		_slavenum,r0
	movl		_bboards[r0],r4
	moval		8(r4),r4
	moval		_clock_asts,r3
1:	mull3		$16,r5,r0	/* 16 = sizeof(TIMER) [clock.h] */
	addl2		r3,r0
	moval		(r4)[r5],0(r0)	/* time pointer */
	clrl		4(r0)		/* timeout */
	clrq		8(r0)		/* fxn and arg */
	sobgeq		r5,1b
	clrl		_astfxn100
	clrl		_astfxnsch
	movl		_ourbb,r0
	movl		_slavenum,r1
	clrl		8(r0)[r1]
	ret
	.align	2
_SCB_timer:
	pushr		$0x07
/* BEGIN OLD TIMER CODE */
	incl		_time100
	movl		_ourbb,r0
	movl		_time100,4(r0)
	movl		(sp)+,r0
	tstl		_astfxn100
	jeql		1f
	decl		_asttime100
	jgtr		1f
	pushr		$0x3f
	pushl		_astarg100
	pushl		_astfxn100
	clrl		_astfxn100
	calls		$2,_ast
	popr		$0x3f
1:	pushr		$1
	movl		_uapage,r0
	tstl		(r0)
	jeql		1f
	decl		4(r0)
	jneq		1f
	pushr		$0x3e	/* no need to save r0 */
	pushl		8(r0)
	pushl		(r0)
	calls		$2,_ast
	popr		$0x3e	/* ...or restore it */
1:
/* END OLD TIMER CODE */
	movl		_ourbb,r0
	movl		_slavenum,r1
	moval		8(r0)[r1],r0
	incl		(r0)
	mull2		$16,r1		/* 16 = sizeof(TIMER) [clock.h] */
	moval		_clock_asts,r2
	addl2		r1,r2
	tstl		8(r2)		/* fxn */
	jeql		1f
	cmpl		4(r2),(r0)	/* timeout (vs. new clock value) */
	jgtr		1f
	pushr		$0x3f
	pushl		12(r2)		/* arg */
	pushl		8(r2)		/* fxn */
	clrl		8(r2)		/* fxn */
	calls		$2,_ast
	popr		$0x3f
1:
	movl		_slavenum,r1	/* as expected below */
#define FOO(n)	tstb		_export_clocks+ (n)		\
	;	jeql		1f				\
	;	movl		_bboards+ (4* (n)),r2		\
	;	movl		(r0),8(r2)[r1]			\
	;	bitb		$2,_export_clocks+ (n)		\
	;	jeql		1f				\
	;	movl		_ipcrs,r2			\
	;	bisw2		$KA_DBI,(2* (n))(r2)		\
	;		1:
	FOO(0)
	FOO(1)
	FOO(2)
	FOO(3)
#undef FOO
	movl		_fromarea,r0
	cmpl		(r0),8(r0)
	jeql		1f
	mtpr		$SIR_DOORBELL,$SIRR
1:	popr		$0x07
	rei
	.align	2
_SCB_tracepend:
	PANIC("tracepend")
	.align	2
_SCB_xfc:
	pushr		$0x3fff
	pushab		(sp)
	pushab		15*4(sp)
	calls		$2,_xfc
	popr		$0x3fff
	jmp		ureturn
	.align	2
_SCB_xinval:
	PANIC("xinval")

	.align	2
	.globl	_halt
_halt:
	.word	0
	halt
	ret
	.align	2
_mchk:
	.word	0
	movl		4(ap),r0
	bicl3		$~PSL_CURMOD,20(r0),r1
	cmpl		r1,$PSL_CURMOD
	jneq		1f
	cmpl		4(r0),$0x80
	jlss		1f
	cmpl		4(r0),$0x83
	jgtr		1f
	jlbc		4(r0),2f
	movl		8(r0),r2
	jbr		3f
2:	extzv		$30,$2,8(r0),r1
	casel		r1,$0,$3
4:	.word		5f-4b
	.word		6f-4b
	.word		7f-4b
	.word		1f-4b
5:	mfpr		$P0BR,r1
	cmpl		_cpu,$VAX_620
	jneq		2f
	insv		$1,$31,$1,r1
	jbr		2f
6:	mfpr		$P1BR,r1
	cmpl		_cpu,$VAX_620
	jneq		2f
	insv		$1,$31,$1,r1
	jbr		2f
7:	mfpr		$SBR,r1
	insv		$1,$31,$1,r1
2:	extzv		$9,$21,8(r0),r2
	bicl3		$~PG_PFNUM,(r1)[r2],r1
	extzv		$0,$9,8(r0),r2
	insv		r1,$9,$23,r2
3:	cmpl		r2,$0x30040000
	jlss		1f
	cmpl		r2,$0x30400000
	jgeq		1f
	pushl		r2
	pushal		4(r0)
	calls		$2,_kaqbmchk
	tstl		r0
	jeql		1f
	ret
1:	movl		4(ap),r0
	pushl		20(r0)
	pushl		16(r0)
	pushl		12(r0)
	pushl		8(r0)
	pushl		4(r0)
	.data
9:	.asciz	"mchk: %x va %08x state %x pc %08x psl %08x\n"
	.text
	pushab		9b
	calls		$6,_printf
	pushal		_trapregs
	calls		$1,_regdump
	PANIC("mchk")

	.align	2
	.globl	_dumpstr
_dumpstr:
	.word	4
	mfpr		$IPL,r2
	mtpr		$HIGH,$IPL
	movab		*4(ap),r0
1:	mfpr		$TXCS,r1
	bitl		$TXCS_RDY,r1
	jeql		1b
	movzbl		(r0)+,r1
	jeql		1f
	mtpr		r1,$TXDB
	jbr		1b
1:	mtpr		r2,$IPL
	ret
