#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 "../sys/rciext/kacomm.h"
#include "../sys/rciext/kaipcr.h"
#include "../sys/rciext/kamsgs.h"

#define HIGH 0x1f		/* max IPL */
#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 */

#define PANIC(s) .data;9:.asciz s;.text;pushab 9b;calls $1,_panic
#define PRINT(s) .data;9:.asciz s;.text;pushab 9b;calls $1,_dumpstr

	.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:
	.space		1024
	.align		2
	.globl	_intstack
	.globl	eintstack
_intstack:
	.space		2048
eintstack:
	.align		2
	.globl	_scb
_scb:
	.long		0
	.globl	_scbsize
_scbsize:
	.long		scbend-scb
	.globl	_memsize
_memsize:
	.long		0
	.globl	_freephys
_freephys:
	.long		0
	.globl	_cpu
_cpu:
	.long		0
	.globl	_bdr
_bdr:
	.long		0
	.globl	_fromarea
_fromarea:
	.long		0
	.globl	_toarea
_toarea:
	.long		0
	.globl	_maxcore
_maxcore:
	.long		0

/* 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		0,r11
	subl3		r6,r7,r0
	movc3		r0,(r6),(r8)
	jmp		(r8)
1:	subl3		r11,r8,r0
	movc3		r0,(r11),*$0
	subl3		r11,r7,r0
	jmp		(r0)
2:
/* stop the clock, in case it's running */
	mtpr		$0,$ICCS
/* load isp */
	movab		eintstack,sp
/* 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		scb,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
/* relocate into high core */
	movab		_end,r11
	movl		_memsize,r9
	subl2		r11,r9
	movab		1f,r8
	movc3		r11,0,(r9)
	addl2		r9,r8
	jmp		(r8)
1:	movab		eintstack,sp
	movab		scb,r11
	addl2		$511,r11
	bicl2		$511,r11
	addl3		r9,_scb,r10
	movc3		_scbsize,(r10),(r11)
	movab		(r11),_scb
	mtpr		r11,$SCBB
	divl3		$4,_scbsize,r0
1:	addl2		r9,(r11)+
	sobgtr		r0,1b
/* Set up message area on Q-bus */
	movab		0,r11
	subl2		$KA_MSGBUFSIZE,r11
	bicl2		$511,r11
	movl		r11,_fromarea
	clrq		(r11)
	clrl		8(r11)
	movl		r11,_maxcore
	extzv		$10,$2,_bdr,r0
	jneq		1f
	PANIC("this kernel won't run on this processor")
1:	mull3		$KA_MSGBUFSIZE*4,r0,r1
	addl3		$KA_X_TO_Y(0,KA_ARBITER),r1,_toarea
	mull2		$KA_MSGBUFSIZE,r0
	addl2		$KA_X_TO_Y(KA_ARBITER,0),r0
	subl2		$KA_QBUSBASE,r0
	ashl		$-9,r0,r0
	ashl		$-9,$KA_MSGBUFSIZE,r1
	movl		$KA_QMAPBASE,r2
	ashl		$-9,r11,r11
1:	bisl3		$0x80000000,r11,(r2)[r0]
	incl		r0
	incl		r11
	sobgtr		r1,1b
	movl		_fromarea,r11
	movl		_toarea,r10
	PRINT("Waiting for messages from master\r\n")
bootloop:
1:	movl		(r11),r0
	movl		8(r11),r1
	cmpl		r0,r1
	jeql		1b
	jsb		readmsgbyte
	cmpl		r0,$MSG_BOOTDATA
	jeql		bootdata
	cmpl		r0,$MSG_BOOTEXEC
	jeql		bootexec
	PANIC("boot protocol error, invalid type")
bootdata:
	jsb		readmsgint
	jsb		readmsgint
	movl		r0,r9
	jsb		readmsgint
	movl		r0,r8
	jeql		bootloop
	jgtr		1f
	PANIC("boot protocol error, negative size")
1:	cmpl		r9,_maxcore
	jlssu		1f
2:	PANIC("program too large, would overrun boot")
1:	addl3		r8,r9,r0
	cmpl		r0,_maxcore
	jgtru		2b
	jsb		readmsgblock
	jsb		ringbell
	jbr		bootloop
bootexec:
	PRINT("Got EXEC message\r\n")
	jsb		readmsgint
	jsb		readmsgint
	jsb		ringbell
	jmp		(r0)

ringbell:
	bisw2		$KA_DBI,*$IPCR_BASE
	rsb

readmsgblock:
	movl		8(r11),r0
	subl3		r0,$KA_MSGDATASIZE,r6
	cmpl		r8,r6
	jgeq		1f
	movc3		r8,12(r11)[r0],(r9)
	addl2		r8,8(r11)
	rsb
1:	movc3		r6,12(r11)[r0],(r9)
	subl2		r6,r8
	jeql		1f
	movc3		r8,12(r11),(r9)[r6]
1:	movl		r8,8(r11)
	rsb

readmsgint:
	jsb		readmsgbyte
	insv		r0,$0,$8,r2
	jsb		readmsgbyte
	insv		r0,$8,$8,r2
	jsb		readmsgbyte
	insv		r0,$16,$8,r2
	jsb		readmsgbyte
	insv		r0,$24,$8,r2
	movl		r2,r0
	rsb

readmsgbyte:
	movl		8(r11),r1
	movzbl		12(r11)[r1],r0
	incl		r1
	cmpl		r1,$KA_MSGDATASIZE
	jlss		1f
	subl2		$KA_MSGDATASIZE,r1
1:	movl		r1,8(r11)
	rsb

/* Utility routines */

/* 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

	.align	2
_SCB_stray:
	PANIC("stray interrupt")
	.align	2
_SCB_accvio:
	PANIC("accvio")
	.align	2
_SCB_arithtrap:
	PANIC("arithtrap")
	.align	2
_SCB_bpt:
	PANIC("bpt")
	.align	2
_SCB_chme:
	PANIC("chme")
	.align	2
_SCB_chmk:
	PANIC("chmk")
	.align	2
_SCB_chms:
	PANIC("chms")
	.align	2
_SCB_chmu:
	PANIC("chmu")
	.align	2
_SCB_crx:
	PANIC("crx")
	.align	2
_SCB_ctx:
	PANIC("ctx")
	.align	2
_SCB_doorbell:
	PANIC("doorbell")
	.align	2
_SCB_emulate:
	PANIC("emulate")
	.align	2
_SCB_emulateFPD:
	PANIC("emulateFPD")
	.align	2
_SCB_kspinval:
	PANIC("kspinval")
	.align	2
_SCB_mchk:
	.data
mchk_expected:
	.long		0
	.text
	tstl		mchk_expected
	jneq		1f
	PANIC("mchk")
1:	addl2		(sp)+,sp
	movl		mchk_expected,(sp)
	rei
	.align	2
_SCB_powerfail:
	PANIC("powerfail")
	.align	2
_SCB_privinst:
	PANIC("privinst")
	.align	2
_SCB_radrmod:
	PANIC("radrmod")
	.align	2
_SCB_resoprnd:
	PANIC("resoprnd")
	.align	2
_SCB_soft1:
	PANIC("soft1")
	.align	2
_SCB_soft2:
	PANIC("soft2")
	.align	2
_SCB_soft3:
	PANIC("soft3")
	.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:
	PANIC("soft8")
	.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
_SCB_timer:
	PANIC("timer")
	.align	2
_SCB_tracepend:
	PANIC("tracepend")
	.align	2
_SCB_xfc:
	PANIC("xfc")
	.align	2
_SCB_xinval:
	PANIC("xinval")

	.align	2
	.globl	_halt
_halt:
	.word	0
	halt

	.align	2
	.globl	_panic
_panic:
	.word	0
	pushr		$0xfff
	.data
9:	.asciz		"panic: "
8:	.asciz		"\r\n"
	.text
	pushab		9b
	calls		$1,_dumpstr
	pushab		*4(ap)
	calls		$1,_dumpstr
	pushab		8b
	calls		$1,_dumpstr
	mtpr		$HIGH,$IPL
	popr		$0xfff
	halt

	.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
