#include <machine/param.h>
#include <machine/mmu.h>
#include <machine/asm_linkage.h>
#include <machine/psl.h>
#include <rciext/assym.s>

	.global _kentucky_fp_enable
	.global	_kentucky_fp_save
	.global	_kentucky_fp_restore
	.global	_kentucky_switchto
	.global	_kentucky_switchback
	.global _uunix

	.seg	"data"
	.align	4
_kps_uarea:
	.word		1
_uunix_save:
	.word		1
_kps_uto:
	.word		1

	.seg	"text"

_kentucky_switchto:
	/* C call is kentucky_switchto(savearea,proc).  proc is "struct
	   proc *"; savearea is int[UPAGES+1].  savearea is where old
	   context number and u area pmes are saved. */
	save		%sp,-SA(MINFRAME),%sp
	/* check that we're on the interrupt stack */
	set		intstack,%l0
	subcc		%sp,%l0,%g0
	blu		notintstack
	.empty
	set		eintstack,%l0
	subcc		%sp,%l0,%g0
	bgu		notintstack
	nop
	/* flush windows to stack, in case of user frames in windows */
	/* _flush_user_windows may be enough, but I'm being paranoid */
	call		_flush_windows
	nop
	/* save old context number */
	set		CONTEXT_REG,%l0
	lduba		[%l0]ASI_CTL,%l1
	st		%l1,[%i0]

	/* has u area switching been disabled? */
	sethi		%hi(_kps_uarea),%l0
	ld		[%l0+%lo(_kps_uarea)],%l1
	tst		%l1
	bz		skip_uarea__to
	nop

#if 0 	/* OLD U AREA SWITCH CODE */

#ifdef VAC
	/* check for existence of cache */
	sethi		%hi(_vac),%l0
	ld		[%l0+%lo(_vac)],%l0
	tst		%l0
	be		1f
	.empty
	/* flush old u area from cache */
	/* don't try to be clever yet */
	set		UPAGES*NBPG,%o1
	set		_uunix,%o0
	ld		[%o0],%o0
	call		_vac_flush
	nop
1:
#endif
	!
	! Switch to new u area.
	!
	set	CONTEXT_REG, %l3	! setup kernel context (0)
	stba	%g0, [%l3]ASI_CTL
	set     _uunix, %l0		! virtual address of first page of u
	ld 	[%l0],%l0
#if UPAGES == 1
	lda		[%l0]ASI_PM,%l1	! pick up old pte
	st		%l1,[%i0+4]	! dump it in the save array
	ld	[%i1 + P_USEG], %g1	! get u pte
	ld	[%g1 + SU_UADDR], %g1
	sta	%g1, [%l0]ASI_PM	! set u pte in page map
#endif /* UPAGES == 1 */
#if UPAGES > 1
	set	UPAGES, %l2
	set	NBPG, %l4
	add		%i0,4,%l3	! set up ptr to save array
	ld	[%i1 + P_USEG], %l1
	add	%l1, SU_UADDR, %l1
0:
					! save old pte first
	lda		[%l0]ASI_PM,%l5	! pick up old pte
	st		%l5,[%l3]	! drop it in the array
	add		%l3,4,%l3	! inc save-array ptr
	ld      [%l1], %g1		! get first u pte
	add     %l1, 4, %l1		! point at next u pte
	sta     %g1, [%l0]ASI_PM	! set first u pte in page map
	deccc	%l2			! last u page?
	bg,a	0b
	add	%l0, %l4, %l0		! next u page
#endif /* UPAGES > 1 */


#else	/* NEW U AREA SWITCH CODE */
	set	_uunix, %l0	
	ld	[%l0], %l1
	set	_uunix_save, %l2
	st	%l1, [%l2]		! uunix_save = uunix
	ld	[%i1 + P_UAREA], %l1
	set	_kps_uto,%l2
	st	%l1, [%l0]		! uunix = p->p_uarea
	st	%l1,[%l2]
#endif
skip_uarea__to:
	!
	! Switch to the procs context.
	!
	set	CONTEXT_REG, %l3
	ld	[%i1 + P_AS], %l0
	ld	[%l0 + A_HAT_CTX], %l0
	ldub	[%l0 + C_NUM], %g1	! get context number
	stba	%g1, [%l3]ASI_CTL	! set it up
	ret
	restore

_kentucky_switchback:
	/* C call is kentucky_switchback(savearea).  savearea is a save
	   area filled in by kentucky_switchto().  we assume kps_uarea hasn't
	   been changed since the call to switchto (since the entire time is
	   spent at splhigh(), you'd need the monitor - or cooperation from
	   the user function - to break this). */
	save		%sp,-SA(MINFRAME),%sp
	/* sanity - check that we're on the interrupt stack */
	set		intstack,%l0
	subcc		%sp,%l0,%g0
	blu		notintstack
	.empty
	set		eintstack,%l0
	subcc		%sp,%l0,%g0
	bgu		notintstack
	nop
	/* flush windows to stack, just in case (paranoia again) */
	call		_flush_windows
	nop
	/* has u area switching been disabled? */
	sethi		%hi(_kps_uarea),%l0
	ld		[%l0+%lo(_kps_uarea)],%l1
	tst		%l1
	bz		skip_uarea__back
	nop

#if 0	/* OLD U AREA SWITCH BACK CODE */

#ifdef VAC
	/* check for existence of cache */
	sethi		%hi(_vac),%l0
	ld		[%l0+%lo(_vac)],%l0
	tst		%l0
	be		1f
	.empty
	/* flush old u area from cache */
	/* don't try to be clever yet */
	set		UPAGES*NBPG,%o1
	set		_uunix,%o0
	ld		[%o0],%o0
	call		_vac_flush
	nop
1:
#endif
	/* switch back to old u area */
	set		CONTEXT_REG,%l3
	stba		%g0,[%l3]ASI_CTL
	set		_uunix,%l0
	ld		[%l0],%l0
#if UPAGES == 1
	ld		[%i0+4],%l5
	sta		%l5,[%l0]ASI_PM
#else
	mov		%i0,%i2
	set		UPAGES,%l2
	set		NBPG,%l4
0:	add		%i2,4,%i2
	ld		[%i2],%l5
	sta		%l5,[%l0]ASI_PM
	deccc		%l2
	bg,a		0b
	add		%l0,%l4,%l0
#endif
	
#else	/* NEW U AREA SWITCH BACK CODE */
	set	_uunix_save, %l0
	ld	[%l0], %l1		
	set	_uunix, %l0
	st	%l1, [%l0]		! uunix = uunix_save
#endif	
skip_uarea__back:
	/* switch back to the old context */
	set		CONTEXT_REG,%l0
	ld		[%i0],%l1
	stba		%l1,[%l0]ASI_CTL
	/* done */
	ret
	restore

notintstack:
	set		notispanic,%o0
	call		_panic
	nop
notispanic:
	.asciz		"kentucky: not on interrupt stack"
	.align	4

_kentucky_fp_enable:
	set	PSR_EF, %o0
	mov	%psr, %o1
	or	%o1, %o0, %o1
	mov	%o1, %psr
	nop; nop; nop
	retl
	nop

_kentucky_fp_save:
	st		%fsr,[%o0+(32*4)]
	std		%f0,[%o0+(0*4)]
	std		%f2,[%o0+(2*4)]
	std		%f4,[%o0+(4*4)]
	std		%f6,[%o0+(6*4)]
	std		%f8,[%o0+(8*4)]
	std		%f10,[%o0+(10*4)]
	std		%f12,[%o0+(12*4)]
	std		%f14,[%o0+(14*4)]
	std		%f16,[%o0+(16*4)]
	std		%f18,[%o0+(18*4)]
	std		%f20,[%o0+(20*4)]
	std		%f22,[%o0+(22*4)]
	std		%f24,[%o0+(24*4)]
	std		%f26,[%o0+(26*4)]
	std		%f28,[%o0+(28*4)]
	std		%f30,[%o0+(30*4)]
	retl
	nop

_kentucky_fp_restore:
	ld		[%o0+(32*4)],%fsr
	ldd		[%o0+(0*4)],%f0
	ldd		[%o0+(2*4)],%f2
	ldd		[%o0+(4*4)],%f4
	ldd		[%o0+(6*4)],%f6
	ldd		[%o0+(8*4)],%f8
	ldd		[%o0+(10*4)],%f10
	ldd		[%o0+(12*4)],%f12
	ldd		[%o0+(14*4)],%f14
	ldd		[%o0+(16*4)],%f16
	ldd		[%o0+(18*4)],%f18
	ldd		[%o0+(20*4)],%f20
	ldd		[%o0+(22*4)],%f22
	ldd		[%o0+(24*4)],%f24
	ldd		[%o0+(26*4)],%f26
	ldd		[%o0+(28*4)],%f28
	ldd		[%o0+(30*4)],%f30
	retl
	nop

	.seg	"data"
	.align	4
saved_ksp:
	.long		1
	.seg	"text"
	.align 	4
	.global	_intstkcall
_intstkcall:
	save		%sp,-SA(MINFRAME),%sp

	/* check that we're on the interrupt stack */
	set		intstack,%o0
	subcc		%sp,%o0,%g0
	blu		notonstack
	.empty
	set		eintstack,%o0
	subcc		%sp,%o0,%g0
	bgu		notonstack
	nop

	/* we are on the interrupt stack, so just call the function */
	call		%i0
	mov		%i1,%o0
	mov		%o0,%i0
	ret
	restore
notonstack:
	/* we are not on the interrupt stack, so go there and then call */
	/* the function */

	set	saved_ksp,%l0
	st	%sp,[%l0]
	sethi	%hi(eintstack-SA(MINFRAME)), %g1 ! get on instack
	add	%g1, %lo(eintstack-SA(MINFRAME)), %sp
	call	%i0
	mov	%i1,%o0
	mov	%o0,%i0
	ld	[%l0],%sp
	ret
	restore

	.seg	"data"
tempstack:
	.skip	2048
etempstack:
savedsp:
	.skip	4

	.seg	"text"
	.global	_dumpstack
_dumpstack:
	mov		%sp,%l0
	sethi		%hi(savedsp),%l1
	st		%l0,[%l1+%lo(savedsp)]
	mov		%g0,%wim
	mov		%psr,%l0
	andn		%l0,PSR_CWP,%l0
	mov		%l0,%psr
	nop
	nop
	nop
	set		2,%l0
	mov		%l0,%wim
	set		etempstack-SA(MINFRAME),%sp
1:	mov		%psr,%l0
	set		PSR_PIL|PSR_ET,%l1
	or		%l1,%l0,%l2
	mov		%l2,%psr
	nop
	nop
	nop
	call		_traceback
	mov		savedsp,%o0
0:	nop
	b		0b
	nop
