NetBSD-5.0.2/sys/arch/powerpc/powerpc/trap_subr.S

Compare this file to the similar file:
Show the results in this format:

/*	$NetBSD: trap_subr.S,v 1.65 2008/08/01 16:32:03 matt Exp $	*/

/*
 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
 * Copyright (C) 1995, 1996 TooLs GmbH.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by TooLs GmbH.
 * 4. The name of TooLs GmbH may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * NOTICE: This is not a standalone file.  to use it, #include it in
 * your port's locore.S, like so:
 *
 *	#include <powerpc/powerpc/trap_subr.S>
 */
#include "opt_altivec.h"

/* LINTSTUB: include <sys/param.h> */
/* LINTSTUB: include <powerpc/oea/bat.h> */

#ifdef ALTIVEC
#define	SAVE_VRSAVE(tf,b)						\
	mfspr	b,SPR_VRSAVE;						\
	stint	b,(FRAME_VRSAVE+(2*SZREG))(tf);

#define RESTORE_VRSAVE(tf,b)						\
	ldint	b,(FRAME_VRSAVE+(2*SZREG))(tf);				\
	mtspr	SPR_VRSAVE,b;
#else
#define SAVE_VRSAVE(tf,b)
#define RESTORE_VRSAVE(tf,b)
#endif

#if defined (PPC_OEA64)
#define	RFI	rfid
#else
#define	RFI	rfi
#endif /* PPC_OEA64 */

#if defined(PPC_OEA64)
/*
 * User segment table is loaded through a pointer to the current pmap.
 */
#define RESTORE_USER_SRS(t0,t1)						\
	GET_CPUINFO(t0);						\
	ldptr	t0,CI_CURPM(t0);					\
	ldreg	t0,PM_STEG(t0);						\
	mtasr	t0

/*
 * Kernel segment table is loaded directly from kernel_pmap_
 */
#define RESTORE_KERN_SRS(t0,t1)						\
	lis	t0,_C_LABEL(kernel_pmap_)@ha;				\
	ldreg	t0,_C_LABEL(kernel_pmap_)+PM_STEG@l(t0);		\
	mtasr	t0

#else /* not OEA64 */

/*
 * Restore segment registers from array.
 */
#define	RESTORE_SRS(pmap,sr)	mtsr	0,sr; \
	ldreg	sr,4(pmap);	mtsr	1,sr; \
	ldreg	sr,8(pmap);	mtsr	2,sr; \
	ldreg	sr,12(pmap);	mtsr	3,sr; \
	ldreg	sr,16(pmap);	mtsr	4,sr; \
	ldreg	sr,20(pmap);	mtsr	5,sr; \
	ldreg	sr,24(pmap);	mtsr	6,sr; \
	ldreg	sr,28(pmap);	mtsr	7,sr; \
	ldreg	sr,32(pmap);	mtsr	8,sr; \
	ldreg	sr,36(pmap);	mtsr	9,sr; \
	ldreg	sr,40(pmap);	mtsr	10,sr; \
	ldreg	sr,44(pmap);	mtsr	11,sr; \
	ldreg	sr,48(pmap);	mtsr	12,sr; \
	ldreg	sr,52(pmap);	mtsr	13,sr; \
	ldreg	sr,56(pmap);	mtsr	14,sr; \
	ldreg	sr,60(pmap);	mtsr	15,sr; isync;

/*
 * User SRs are loaded through a pointer to the current pmap.
 * Note: oea_init() relies on the 601 instruction sequence.
 */
#define RESTORE_USER_SRS(pmap,sr)					\
	GET_CPUINFO(pmap);						\
	ldptr	pmap,CI_CURPM(pmap);					\
	ldregu	sr,PM_SR(pmap);						\
	RESTORE_SRS(pmap,sr);						\
	/* Obliterate BATs on 601; reuse temporary registers. */	\
	li	sr,0;							\
	mtibatl	0,sr;							\
	mtibatl	1,sr;							\
	mtibatl	2,sr;							\
	mtibatl	3,sr

/*
 * Kernel SRs are loaded directly from kernel_pmap_.
 * Note: oea_init() relies on the 601 instruction sequence.
 */
#define RESTORE_KERN_SRS(pmap,sr)					\
	lis	pmap,_C_LABEL(kernel_pmap_)@ha;				\
	ldregu	sr,_C_LABEL(kernel_pmap_)+PM_SR@l(pmap);		\
	RESTORE_SRS(pmap,sr);						\
	/* Restore fixed BATs on 601; reuse temporary registers. */	\
	lis	pmap,_C_LABEL(battable)@ha;				\
	ldregu	sr,_C_LABEL(battable)@l(pmap);				\
	mtibatu 0,sr;							\
	ldreg	sr,4(pmap);	mtibatl 0,sr;				\
	ldreg	sr,8(pmap);	mtibatu 1,sr;				\
	ldreg	sr,12(pmap);	mtibatl 1,sr
#endif /* (PPC_OEA64) */

/*
 * Save/restore MPC601 MQ register.
 * Note: oea_init() relies on this instruction sequence.
 */
#if defined(PPC_OEA601)
#define	SAVE_MQ(tf,b)							\
	mfspr	b,SPR_MQ;						\
	streg	b,(FRAME_MQ+(2*SZREG))(tf);

#define	RESTORE_MQ(tf,b)						\
	ldreg	b,(FRAME_MQ+(2*SZREG))(tf);				\
	mtspr	SPR_MQ,b;
#else
#define	SAVE_MQ(tf,b)
#define	RESTORE_MQ(tf,b)
#endif

/*
 * This code gets copied to all the trap vectors
 * (except ISI/DSI, ALI, the interrupts, and possibly the debugging
 * traps when using IPKDB).
 */

/* LINTSTUB: Var: int trapcode[1], trapsize[1]; */
	.text
	.globl	_C_LABEL(trapcode),_C_LABEL(trapsize)
_C_LABEL(trapcode):
	mtsprg1	%r1			/* save SP */
	GET_CPUINFO(%r1)
	streg	%r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1)	/* free r28 */
	streg	%r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1)	/* free r29 */
	streg	%r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1)	/* free r30 */
	streg	%r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1)	/* free r31 */
	mfsprg1	%r1			/* restore SP */
	mflr	%r28			/* save LR */
	mfcr	%r29			/* save CR */
/* Test whether we already had PR set */
	mfsrr1	%r31
	mtcr	%r31
#if defined(DISTANT_KERNEL)
	lis	%r31,s_trap@ha
	addi	%r31,%r31,s_trap@l
	mtlr	%r31
	blrl
#else
	bla	s_trap
#endif
_C_LABEL(trapsize) = .-_C_LABEL(trapcode)

/*
 * For ALI: has to save DSISR and DAR
 * Also used as dsitrap for BATless cpus.
 */
/* LINTSTUB: Var: int alicode[1], alisize[1]; */
	.globl	_C_LABEL(alitrap),_C_LABEL(alisize)
_C_LABEL(alitrap):
	mtsprg1	%r1			/* save SP */
	GET_CPUINFO(%r1)
	streg	%r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1) /* save r28 */
	streg	%r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1) /* save r29 */
	streg	%r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1) /* save r30 */
	streg	%r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1) /* save r31 */
	mfdar	%r30
	mfdsisr	%r31
	streg	%r30,(CI_TEMPSAVE+CPUSAVE_DAR)(%r1)	/* save dar */
	streg	%r31,(CI_TEMPSAVE+CPUSAVE_DSISR)(%r1)	/* save dsisr */
	mfsprg1	%r1			/* restore SP */
	mflr	%r28			/* save LR */
	mfcr	%r29			/* save CR */
/* Test whether we already had PR set */
	mfsrr1	%r31
	mtcr	%r31
#if defined(DISTANT_KERNEL)
	lis	%r31,s_trap@ha
	addi	%r31,%r31,s_trap@l
	mtlr	%r31
	blrl
#else
	bla	s_trap
#endif
_C_LABEL(alisize) = .-_C_LABEL(alitrap)

/*
 * Similar to the above for DSI
 * Has to handle BAT spills
 * and standard pagetable spills
 */
/* LINTSTUB: Var: int dsicode[1], dsisize[1]; */
	.globl	_C_LABEL(dsitrap),_C_LABEL(dsisize)
_C_LABEL(dsitrap):
	mtsprg1	%r1
	GET_CPUINFO(%r1)
	streg	%r28,(CI_DISISAVE+CPUSAVE_R28)(%r1)	/* save r28 */
	streg	%r29,(CI_DISISAVE+CPUSAVE_R29)(%r1)	/* save r29 */
	streg	%r30,(CI_DISISAVE+CPUSAVE_R30)(%r1)	/* save r30 */
	streg	%r31,(CI_DISISAVE+CPUSAVE_R31)(%r1)	/* save r31 */
	mfsprg1	%r1
	mfcr	%r29			/* save CR */
	mfxer	%r30			/* save XER */
	mtsprg2	%r30			/* in SPRG2 */
	mfsrr1	%r31			/* test kernel mode */
	mtcr	%r31
	bt	17,1f			/* branch if PSL_PR is set */
	mfdar	%r31			/* get fault address */
	rlwinm	%r31,%r31,7,25,28	/* get segment * 8 */

	/* get batu */
	addis	%r31,%r31,_C_LABEL(battable)@ha
	ldreg	%r30,_C_LABEL(battable)@l(%r31)
	mtcr	%r30
	bf	30,1f			/* branch if supervisor valid is
					   false */
	/* get batl */
	ldreg	%r31,_C_LABEL(battable)+SZREG@l(%r31)
/* We randomly use the highest two bat registers here */
	mftb	%r28
	andi.	%r28,%r28,1
	bne	2f
	mtdbatu	2,%r30
	mtdbatl	2,%r31
	b	3f
2:
	mtdbatu	3,%r30
	mtdbatl	3,%r31
3:
	mfsprg2	%r30			/* restore XER */
	mtxer	%r30
	mtcr	%r29			/* restore CR */
	mtsprg1	%r1
	GET_CPUINFO(%r1)
	ldreg	%r28,(CI_DISISAVE+CPUSAVE_R28)(%r1)	/* restore r28 */
	ldreg	%r29,(CI_DISISAVE+CPUSAVE_R29)(%r1)	/* restore r29 */
	ldreg	%r30,(CI_DISISAVE+CPUSAVE_R30)(%r1)	/* restore r30 */
	ldreg	%r31,(CI_DISISAVE+CPUSAVE_R31)(%r1)	/* restore r31 */
	mfsprg1	%r1
	RFI				/* return to trapped code */
1:
	mflr	%r28			/* save LR */
	mtsprg1	%r1			/* save SP */
#if defined(DISTANT_KERNEL)
	lis	%r31,disitrap@ha
	addi	%r31,%r31,disitrap@l
	mtlr	%r31
	blrl
#else
	bla	disitrap
#endif
_C_LABEL(dsisize) = .-_C_LABEL(dsitrap)

#if defined(PPC_OEA601)
/*
 * Dedicated MPC601 version of the above.
 * Considers different BAT format and combined implementation
 * (being addressed as I-BAT).
 */
/* LINTSTUB: Var: int dsi601code[1], dsi601size[1]; */
	.globl	_C_LABEL(dsi601trap),_C_LABEL(dsi601size)
_C_LABEL(dsi601trap):
	mtsprg1	%r1
	GET_CPUINFO(%r1)
	streg	%r28,(CI_DISISAVE+CPUSAVE_R28)(%r1)	/* save r28 */
	streg	%r29,(CI_DISISAVE+CPUSAVE_R29)(%r1)	/* save r29 */
	streg	%r30,(CI_DISISAVE+CPUSAVE_R30)(%r1)	/* save r30 */
	streg	%r31,(CI_DISISAVE+CPUSAVE_R31)(%r1)	/* save r31 */
	mfsprg1	%r1
	mfcr	%r29			/* save CR */
	mfxer	%r30			/* save XER */
	mtsprg2	%r30			/* in SPRG2 */
	mfsrr1	%r31			/* test kernel mode */
	mtcr	%r31
	bt	17,1f			/* branch if PSL_PR is set */
	mfdar	%r31			/* get fault address */
	rlwinm	%r31,%r31,12,20,28	/* get "segment" battable offset */

	/* get batl */
	addis	%r31,%r31,_C_LABEL(battable)@ha
	ldreg	%r30,_C_LABEL(battable)+SZREG@l(%r31)
	mtcr	%r30
	bf	25,1f			/* branch if Valid is is false,
					   presently assumes supervisor only */

	/* get batu */
	ldreg	%r31,_C_LABEL(battable)@l(%r31)
/* We randomly use the highest two bat registers here */
	mfspr	%r28,SPR_RTCL_R
	andi.	%r28,%r28,128
	bne	2f
	mtibatu	2,%r31
	mtibatl	2,%r30
	b	3f
2:
	mtibatu	3,%r31
	mtibatl	3,%r30
3:
	mfsprg2	%r30			/* restore XER */
	mtxer	%r30
	mtcr	%r29			/* restore CR */
	mtsprg1	%r1
	GET_CPUINFO(%r1)
	ldreg	%r28,(CI_DISISAVE+CPUSAVE_R28)(%r1)	/* restore r28 */
	ldreg	%r29,(CI_DISISAVE+CPUSAVE_R29)(%r1)	/* restore r29 */
	ldreg	%r30,(CI_DISISAVE+CPUSAVE_R30)(%r1)	/* restore r30 */
	ldreg	%r31,(CI_DISISAVE+CPUSAVE_R31)(%r1)	/* restore r31 */
	mfsprg1	%r1
	RFI				/* return to trapped code */
1:
	mflr	%r28			/* save LR */
	mtsprg1	%r1
#if defined(DISTANT_KERNEL)
	lis	%r31,disitrap@ha
	addi	%r31,%r31,disitrap@l
	mtlr	%r31
	blrl
#else
	bla	disitrap
#endif
_C_LABEL(dsi601size) = .-_C_LABEL(dsi601trap)
#endif /* defined(PPC_OEA601) */

/*
 * This one for the external interrupt handler.
 */
/* LINTSTUB: Var: int extint[1], extsize[1]; */
	.globl	_C_LABEL(extint),_C_LABEL(extsize)
_C_LABEL(extint):
	mtsprg1	%r1			/* save SP */
	GET_CPUINFO(%r1)
	streg	%r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1)	/* save r28 */
	streg	%r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1)	/* save r29 */
	streg	%r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1)	/* save r30 */
	streg	%r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1)	/* save r31 */
	mflr	%r28			/* save LR */
	mfcr	%r29			/* save CR */
	mfxer	%r30			/* save XER */
	ldint	%r31,CI_INTRDEPTH(%r1)	/* were we already running on intstk? */
	addic.	%r31,%r31,1
	stint	%r31,CI_INTRDEPTH(%r1)
	ldptr	%r1,CI_INTSTK(%r1)	/* get interrupt stack */
	beq	1f
	mfsprg1	%r1			/* yes, get old SP */
1:
#if defined(DISTANT_KERNEL)
	lis	%r31,extintr@ha
	addi	%r31,%r31,extintr@l
	mtlr	%r31
	blr
#else
	ba	extintr
#endif
_C_LABEL(extsize) = .-_C_LABEL(extint)

/*
 * And this one for the decrementer interrupt handler.
 */
/* LINTSTUB: Var: int decrint[1], decrsize[1]; */
	.globl	_C_LABEL(decrint),_C_LABEL(decrsize)
_C_LABEL(decrint):
	mtsprg1	%r1			/* save SP */
	GET_CPUINFO(%r1)
	streg	%r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1)	/* save r28 */
	streg	%r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1)	/* save r29 */
	streg	%r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1)	/* save r30 */
	streg	%r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1)	/* save r31 */
	mflr	%r28			/* save LR */
	mfcr	%r29			/* save CR */
	mfxer	%r30			/* save XER */
	ldint	%r31,CI_INTRDEPTH(%r1)	/* were we already running on intstk? */
	addic.	%r31,%r31,1
	stint	%r31,CI_INTRDEPTH(%r1)
	ldptr	%r1,CI_INTSTK(%r1)	/* get interrupt stack */
	beq	1f
	mfsprg1	%r1			/* yes, get old SP */
1:
#if defined(DISTANT_KERNEL)
	lis	%r31,decrintr@ha
	addi	%r31,%r31,decrintr@l
	mtlr	%r31
	blr
#else
	ba	decrintr
#endif
_C_LABEL(decrsize) = .-_C_LABEL(decrint)

#if !defined(PPC_OEA64)
/*
 * Now the tlb software load for 603 processors:
 * (Code essentially from the 603e User Manual, Chapter 5, but
 * corrected a lot.)
 */
/* LINTSTUB: Var: int tlbimiss[1], tlbimsize[1]; */
	.globl	_C_LABEL(tlbimiss),_C_LABEL(tlbimsize)
_C_LABEL(tlbimiss):
	mfspr	%r2,SPR_HASH1		/* get first pointer */
	li	%r1,8
	mfctr	%r0			/* save counter */
	mfspr	%r3,SPR_ICMP		/* get first compare value */
	addi	%r2,%r2,-8		/* predec pointer */
1:
	mtctr	%r1			/* load counter */
2:
	ldregu	%r1,8(%r2)		/* get next pte */
	cmpl	%cr0,%r1,%r3		/* see if found pte */
	bdneq	2b			/* loop if not eq */
	bne	3f			/* not found */
	ldreg	%r1,4(%r2)		/* load tlb entry lower word */
	andi.	%r3,%r1,PTE_G		/* check G-bit */
	bne	4f			/* if guarded, take ISI */
	mtctr	%r0			/* restore counter */
	mfspr	%r0,SPR_IMISS		/* get the miss address for the tlbli */
	mfsrr1	%r3			/* get the saved cr0 bits */
	mtcrf	0x80,%r3		/* and restore */
	ori	%r1,%r1,PTE_REF		/* set the reference bit */
	mtspr	SPR_RPA,1		/* set the pte */
	srwi	%r1,%r1,8		/* get byte 7 of pte */
	tlbli	%r0			/* load the itlb */
	stb	%r1,6(%r2)		/* update page table */
	RFI

3:	/* not found in pteg */
	andi.	%r1,%r3,PTE_HID		/* have we already done second hash? */
	bne	5f
	mfspr	%r2,SPR_HASH2		/* get the second pointer */
	ori	%r3,%r3,PTE_HID		/* change the compare value */
	li	%r1,8
	addi	%r2,%r2,-8		/* predec pointer */
	b	1b
4:	/* guarded */
	mfsrr1	%r3
	andi.	%r2,%r3,0xffff		/* clean upper srr1 */
	oris	%r2,%r2,DSISR_PROTECT@h	/* set srr<4> to flag prot violation */
	b	6f
5:	/* not found anywhere */
	mfsrr1	%r3
	andi.	%r2,%r3,0xffff		/* clean upper srr1 */
	oris	%r2,%r2,DSISR_NOTFOUND@h /* set srr1<1> to flag pte not found */
6:
	mtctr	%r0			/* restore counter */
	mtsrr1	%r2
	mfmsr	%r0
	xoris	%r0,%r0,PSL_TGPR@h	/* flip the msr<tgpr> bit */
	mtcrf	0x80,%r3		/* restore cr0 */
	mtmsr	%r0			/* now with native gprs */
	isync
#if defined(PPC_HIGH_VEC)
	ba	EXC_HIGHVEC+EXC_ISI
#else
	ba	EXC_ISI
#endif
_C_LABEL(tlbimsize) = .-_C_LABEL(tlbimiss)

/* LINTSTUB: Var: int tlbdlmiss[1], tlbdlmsize[1]; */
	.globl	_C_LABEL(tlbdlmiss),_C_LABEL(tlbdlmsize)
_C_LABEL(tlbdlmiss):
	mfspr	%r2,SPR_HASH1		/* get first pointer */
	li	%r1,8
	mfctr	%r0			/* save counter */
	mfspr	%r3,SPR_DCMP		/* get first compare value */
	addi	%r2,%r2,-8		/* predec pointer */
1:
	mtctr	%r1			/* load counter */
2:
	ldregu	%r1,8(%r2)		/* get next pte */
	cmpl	%cr0,%r1,%r3		/* see if found pte */
	bdneq	2b			/* loop if not eq */
	bne	3f			/* not found */
	ldreg	%r1,4(%r2)		/* load tlb entry lower word */
	mtctr	%r0			/* restore counter */
	mfspr	%r0,SPR_DMISS		/* get the miss address for the tlbld */
	mfsrr1	%r3			/* get the saved cr0 bits */
	mtcrf	0x80,%r3		/* and restore */
	ori	%r1,%r1,PTE_REF		/* set the reference bit */
	mtspr	SPR_RPA,%r1		/* set the pte */
	srwi	%r1,%r1,8		/* get byte 7 of pte */
	tlbld	%r0			/* load the dtlb */
	stb	%r1,6(%r2)		/* update page table */
	RFI

3:	/* not found in pteg */
	andi.	%r1,%r3,PTE_HID		/* have we already done second hash? */
	bne	5f
	mfspr	%r2,SPR_HASH2		/* get the second pointer */
	ori	%r3,%r3,PTE_HID		/* change the compare value */
	li	%r1,8
	addi	%r2,%r2,-8		/* predec pointer */
	b	1b
5:	/* not found anywhere */
	mfsrr1	%r3
	lis	%r1,DSISR_NOTFOUND@h	/* set dsisr<1> to flag pte not found */
	mtctr	%r0			/* restore counter */
	andi.	%r2,%r3,0xffff		/* clean upper srr1 */
	mtsrr1	%r2
	mtdsisr	%r1			/* load the dsisr */
	mfspr	%r1,SPR_DMISS		/* get the miss address */
	mtdar	%r1			/* put in dar */
	mfmsr	%r0
	xoris	%r0,%r0,PSL_TGPR@h	/* flip the msr<tgpr> bit */
	mtcrf	0x80,%r3		/* restore cr0 */
	mtmsr	%r0			/* now with native gprs */
	isync
#if defined(PPC_HIGH_VEC)
	ba	EXC_HIGHVEC+EXC_DSI
#else
	ba	EXC_DSI
#endif
_C_LABEL(tlbdlmsize) = .-_C_LABEL(tlbdlmiss)

/* LINTSTUB: Var: int tlbdsmiss[1], tlbdsmsize[1]; */
	.globl	_C_LABEL(tlbdsmiss),_C_LABEL(tlbdsmsize)
_C_LABEL(tlbdsmiss):
	mfspr	%r2,SPR_HASH1		/* get first pointer */
	li	%r1,%r8
	mfctr	%r0			/* save counter */
	mfspr	%r3,SPR_DCMP		/* get first compare value */
	addi	%r2,%r2,-8		/* predec pointer */
1:
	mtctr	%r1			/* load counter */
2:
	ldregu	%r1,8(%r2)		/* get next pte */
	cmpl	%cr0,%r1,%r3		/* see if found pte */
	bdneq	2b			/* loop if not eq */
	bne	3f			/* not found */
	ldreg	%r1,4(%r2)		/* load tlb entry lower word */
	andi.	%r3,%r1,PTE_CHG		/* check the C-bit */
	beq	4f
5:
	mtctr	%r0			/* restore counter */
	mfspr	%r0,SPR_DMISS		/* get the miss address for the tlbld */
	mfsrr1	%r3			/* get the saved cr0 bits */
	mtcrf	0x80,%r3		/* and restore */
	mtspr	SPR_RPA,%r1		/* set the pte */
	tlbld	%r0			/* load the dtlb */
	RFI

3:	/* not found in pteg */
	andi.	%r1,%r3,PTE_HID		/* have we already done second hash? */
	bne	5f
	mfspr	%r2,SPR_HASH2		/* get the second pointer */
	ori	%r3,%r3,PTE_HID		/* change the compare value */
	li	%r1,8
	addi	%r2,%r2,-8		/* predec pointer */
	b	1b
4:	/* found, but C-bit = 0 */
	rlwinm.	%r3,%r1,30,0,1		/* test PP */
	bge-	7f
	andi.	%r3,%r1,1
	beq+	8f
9:	/* found, but protection violation (PP==00)*/
	mfsrr1	%r3
	lis	%r1,(DSISR_PROTECT|DSISR_STORE)@h
					/* indicate protection violation
					   on store */
	b	1f
7:	/* found, PP=1x */
	mfspr	%r3,SPR_DMISS		/* get the miss address */
	mfsrin	%r1,%r3			/* get the segment register */
	mfsrr1	%r3
	rlwinm	%r3,%r3,18,31,31	/* get PR-bit */
	rlwnm.	%r1,%r1,%r3,1,1		/* get the key */
	bne-	9b			/* protection violation */
8:	/* found, set reference/change bits */
	ldreg	%r1,4(%r2)		/* reload tlb entry */
	ori	%r1,%r1,(PTE_REF|PTE_CHG)
	sth	%r1,6(%r2)
	b	5b
5:	/* not found anywhere */
	mfsrr1	%r3
	lis	%r1,(DSISR_NOTFOUND|DSISR_STORE)@h
					/* set dsisr<1> to flag pte not found */
					/* dsisr<6> to flag store */
1:
	mtctr	%r0			/* restore counter */
	andi.	%r2,%r3,0xffff		/* clean upper srr1 */
	mtsrr1	%r2
	mtdsisr	%r1			/* load the dsisr */
	mfspr	%r1,SPR_DMISS		/* get the miss address */
	mtdar	%r1			/* put in dar */
	mfmsr	%r0
	xoris	%r0,%r0,PSL_TGPR@h	/* flip the msr<tgpr> bit */
	mtcrf	0x80,%r3		/* restore cr0 */
	mtmsr	%r0			/* now with native gprs */
	isync
#if defined(PPC_HIGH_VEC)
	ba	EXC_HIGHVEC+EXC_DSI
#else
	ba	EXC_DSI
#endif
_C_LABEL(tlbdsmsize) = .-_C_LABEL(tlbdsmiss)
#endif /* !defined(PPC_OEA64) */

#if defined(DDB) || defined(KGDB)
/*
 * In case of DDB we want a separate trap catcher for it
 */
	.local	ddbstk
	.comm	ddbstk,INTSTK,8		/* ddb stack */

/* LINTSTUB: Var: int ddblow[1], ddbsize[1]; */
	.globl	_C_LABEL(ddblow),_C_LABEL(ddbsize)
_C_LABEL(ddblow):
	mtsprg1	%r1			/* save SP */
	mtsprg2 %r29			/* save r29 */
	mfcr	%r29			/* save CR in r29 */
	mfsrr1	%r1
	mtcr	%r1
	GET_CPUINFO(%r1)
	bf	17,1f			/* branch if privileged */
	streg	%r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1)	/* free r28 */
	mfsprg2	%r28
	streg	%r28,(CI_TEMPSAVE+CPUSAVE_R29)(%r1)	/* free r29 */
	streg	%r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1)	/* free r30 */
	streg	%r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1)	/* free r31 */
	mflr	%r28			/* save LR */
#if defined(DISTANT_KERNEL)
	lis	%r31,u_trap@ha
	addi	%r31,%r31,u_trap@l
	mtlr	%r31
	blrl
#else
	bla	u_trap
#endif
1:
	streg	%r28,(CI_DDBSAVE+CPUSAVE_R28)(%r1) /* save r28 */
	mfsprg2	%r28
	streg	%r28,(CI_DDBSAVE+CPUSAVE_R29)(%r1) /* save r29 */
	streg	%r30,(CI_DDBSAVE+CPUSAVE_R30)(%r1) /* save r30 */
	streg	%r31,(CI_DDBSAVE+CPUSAVE_R31)(%r1) /* save r31 */
	mflr	%r28			/* save LR */
	lis	%r1,ddbstk+INTSTK@ha	/* get new SP */
	addi	%r1,%r1,ddbstk+INTSTK@l
#if defined(DISTANT_KERNEL)
	lis	%r31,ddbtrap@ha
	addi	%r31,%r31,ddbtrap@l
	mtlr	%r31
	blrl
#else
	bla	ddbtrap
#endif
_C_LABEL(ddbsize) = .-_C_LABEL(ddblow)
#endif	/* DDB || KGDB */

#if defined(IPKDB) && !defined(DISTANT_KERNEL)
/* IPKDB doesn't work together with DISTANT_KERNEL at the moment! */

#define	ipkdbsave	0xde0		/* primary save area for IPKDB */
/*
 * In case of IPKDB we want a separate trap catcher for it
 */

	.local	ipkdbstk
	.comm	ipkdbstk,INTSTK,8		/* ipkdb stack */

/* LINTSTUB: Var: int ipkdblow[1], ipkdbsize[1]; */
	.globl	_C_LABEL(ipkdblow),_C_LABEL(ipkdbsize)
_C_LABEL(ipkdblow):
	mtsprg1	%r1			/* save SP */
	GET_CPUINFO(%r1)
	streg	%r28,(CI_IPKDBSAVE+CPUSAVE_R28)(%r1) /* save r28 */
	streg	%r29,(CI_IPKDBSAVE+CPUSAVE_R29)(%r1) /* save r29 */
	streg	%r30,(CI_IPKDBSAVE+CPUSAVE_R30)(%r1) /* save r30 */
	streg	%r31,(CI_IPKDBSAVE+CPUSAVE_R31)(%r1) /* save r31 */
	mflr	%r28			/* save LR */
	mfcr	%r29			/* save CR */
	lis	%r1,ipkdbstk+INTSTK@ha	/* get new SP */
	addi	%r1,%r1,ipkdbstk+INTSTK@l
#if defined(DISTANT_KERNEL)
	lis	%r31,ipkdbtrap@ha
	addi	%r31,%r31,ipkdbtrap@l
	mtlr	%r31
	blrl
#else
	bla	ipkdbtrap
#endif
_C_LABEL(ipkdbsize) = .-_C_LABEL(ipkdblow)
#endif	/* IPKDB */

/*
 * FRAME_SETUP assumes:
 *	SPRG1		SP (%r1)
 *	savearea	r28-r31,DAR,DSISR	(DAR & DSISR only for DSI traps)
 *	28		LR
 *	29		CR
 *	30		scratch
 *	31		scratch
 *	1		kernel stack
 *	LR		trap type
 *	SRR0/1		as at start of trap
 */
#define	FRAME_SETUP(savearea)						\
/* Have to enable translation to allow access of kernel stack: */	\
	GET_CPUINFO(%r31);						\
	mfsrr0	%r30;							\
	streg	%r30,(savearea+CPUSAVE_SRR0)(%r31);	/* save SRR0 */	\
	mfsrr1	%r30;							\
	streg	%r30,(savearea+CPUSAVE_SRR1)(%r31);	/* save SRR1 */	\
	mfmsr	%r30;							\
	ori	%r30,%r30,(PSL_DR|PSL_IR);	/* turn on relocation */ \
	mtmsr	%r30;			/* stack can be accesed now */	\
	isync;								\
	mfsprg1	%r31;			/* get saved SP */		\
	stregu	%r31,-FRAMELEN(%r1);	/* save it in the callframe */	\
	streg	%r0,(FRAME_0+(2*SZREG))(%r1);	/* save R0 in the trapframe */ \
	streg	%r31,(FRAME_1+(2*SZREG))(%r1);	/* save SP in the trapframe */ \
	streg	%r2,(FRAME_2+(2*SZREG))(%r1);	/* save R2 in the trapframe */ \
	streg	%r28,(FRAME_LR+(2*SZREG))(%r1);				\
	stint	%r29,(FRAME_CR+(2*SZREG))(%r1);				\
	GET_CPUINFO(%r2);						\
	ldreg	%r31,(savearea+CPUSAVE_R31)(%r2); /* get saved r31 */	\
	ldreg	%r30,(savearea+CPUSAVE_R30)(%r2); /* get saved r30 */	\
	ldreg	%r29,(savearea+CPUSAVE_R29)(%r2); /* get saved r29 */	\
	ldreg	%r28,(savearea+CPUSAVE_R28)(%r2); /* get saved r28 */	\
	streg	%r3,(FRAME_3+(2*SZREG))(%r1);	/* save r3 */		\
	streg	%r4,(FRAME_4+(2*SZREG))(%r1);	/* save r4 */		\
	streg	%r5,(FRAME_5+(2*SZREG))(%r1);	/* save r5 */		\
	streg	%r6,(FRAME_6+(2*SZREG))(%r1);	/* save r6 */		\
	streg	%r7,(FRAME_7+(2*SZREG))(%r1);	/* save r7 */		\
	streg	%r8,(FRAME_8+(2*SZREG))(%r1);	/* save r8 */		\
	streg	%r9,(FRAME_9+(2*SZREG))(%r1);	/* save r9 */		\
	streg	%r10,(FRAME_10+(2*SZREG))(%r1);	/* save r10 */		\
	streg	%r11,(FRAME_11+(2*SZREG))(%r1);	/* save r11 */		\
	streg	%r12,(FRAME_12+(2*SZREG))(%r1);	/* save r12 */		\
	streg	%r13,(FRAME_13+(2*SZREG))(%r1);	/* save r13 */		\
	streg	%r14,(FRAME_14+(2*SZREG))(%r1);	/* save r14 */		\
	streg	%r15,(FRAME_15+(2*SZREG))(%r1);	/* save r15 */		\
	streg	%r16,(FRAME_16+(2*SZREG))(%r1);	/* save r16 */		\
	streg	%r17,(FRAME_17+(2*SZREG))(%r1);	/* save r17 */		\
	streg	%r18,(FRAME_18+(2*SZREG))(%r1);	/* save r18 */		\
	streg	%r19,(FRAME_19+(2*SZREG))(%r1);	/* save r19 */		\
	streg	%r20,(FRAME_20+(2*SZREG))(%r1);	/* save r20 */		\
	streg	%r21,(FRAME_21+(2*SZREG))(%r1);	/* save r21 */		\
	streg	%r22,(FRAME_22+(2*SZREG))(%r1);	/* save r22 */		\
	streg	%r23,(FRAME_23+(2*SZREG))(%r1);	/* save r23 */		\
	streg	%r24,(FRAME_24+(2*SZREG))(%r1);	/* save r24 */		\
	streg	%r25,(FRAME_25+(2*SZREG))(%r1);	/* save r25 */		\
	streg	%r26,(FRAME_26+(2*SZREG))(%r1);	/* save r26 */		\
	streg	%r27,(FRAME_27+(2*SZREG))(%r1);	/* save r27 */		\
	streg	%r28,(FRAME_28+(2*SZREG))(%r1);	/* save r28 */		\
	streg	%r29,(FRAME_29+(2*SZREG))(%r1);	/* save r29 */		\
	streg	%r30,(FRAME_30+(2*SZREG))(%r1);	/* save r30 */		\
	streg	%r31,(FRAME_31+(2*SZREG))(%r1);	/* save r31 */		\
	ldreg	%r28,(savearea+CPUSAVE_DAR)(%r2); /* get saved DAR */	\
	ldreg	%r29,(savearea+CPUSAVE_DSISR)(%r2); /* get saved DSISR */ \
	ldreg	%r30,(savearea+CPUSAVE_SRR0)(%r2); /* get saved SRR0 */	\
	ldreg	%r31,(savearea+CPUSAVE_SRR1)(%r2); /* get saved SRR1 */	\
	mfxer	%r3;							\
	mfctr	%r4;							\
	mflr	%r5;							\
	andi.	%r5,%r5,0xff00;						\
	stint	%r3,(FRAME_XER+(2*SZREG))(%r1);				\
	streg	%r4,(FRAME_CTR+(2*SZREG))(%r1);				\
	streg	%r30,(FRAME_SRR0+(2*SZREG))(%r1);			\
	streg	%r31,(FRAME_SRR1+(2*SZREG))(%r1);			\
	streg	%r28,(FRAME_DAR+(2*SZREG))(%r1);			\
	stint	%r29,(FRAME_DSISR+(2*SZREG))(%r1);			\
	stint	%r5,(FRAME_EXC+(2*SZREG))(%r1);				\
	SAVE_VRSAVE(%r1,%r6);						\
	SAVE_MQ(%r1,%r7)

#define	FRAME_LEAVE(savearea)						\
/* Now restore regs: */							\
	ldreg	%r2,(FRAME_SRR0+(2*SZREG))(%r1);			\
	ldreg	%r3,(FRAME_SRR1+(2*SZREG))(%r1);			\
	ldreg	%r4,(FRAME_CTR+(2*SZREG))(%r1);				\
	ldint	%r5,(FRAME_XER+(2*SZREG))(%r1);				\
	ldreg	%r6,(FRAME_LR+(2*SZREG))(%r1);				\
	RESTORE_MQ(%r1,%r8);						\
	RESTORE_VRSAVE(%r1,%r9);					\
	GET_CPUINFO(%r7);						\
	streg	%r2,(savearea+CPUSAVE_SRR0)(%r7); /* save SRR0 */	\
	streg	%r3,(savearea+CPUSAVE_SRR1)(%r7); /* save SRR1 */	\
	ldint	%r7,(FRAME_CR+(2*SZREG))(%r1);				\
	mtctr	%r4;							\
	mtxer	%r5;							\
	mtlr	%r6;							\
	mtsprg1	%r7;			/* save cr */			\
	ldreg	%r31,(FRAME_31+(2*SZREG))(%r1);	/* restore r31 */	\
	ldreg	%r30,(FRAME_30+(2*SZREG))(%r1);	/* restore r30 */	\
	ldreg	%r29,(FRAME_29+(2*SZREG))(%r1);	/* restore r29 */	\
	ldreg	%r28,(FRAME_28+(2*SZREG))(%r1);	/* restore r28 */	\
	ldreg	%r27,(FRAME_27+(2*SZREG))(%r1);	/* restore r27 */	\
	ldreg	%r26,(FRAME_26+(2*SZREG))(%r1);	/* restore r26 */	\
	ldreg	%r25,(FRAME_25+(2*SZREG))(%r1);	/* restore r25 */	\
	ldreg	%r24,(FRAME_24+(2*SZREG))(%r1);	/* restore r24 */	\
	ldreg	%r23,(FRAME_23+(2*SZREG))(%r1);	/* restore r23 */	\
	ldreg	%r22,(FRAME_22+(2*SZREG))(%r1);	/* restore r22 */	\
	ldreg	%r21,(FRAME_21+(2*SZREG))(%r1);	/* restore r21 */	\
	ldreg	%r20,(FRAME_20+(2*SZREG))(%r1);	/* restore r20 */	\
	ldreg	%r19,(FRAME_19+(2*SZREG))(%r1);	/* restore r19 */	\
	ldreg	%r18,(FRAME_18+(2*SZREG))(%r1);	/* restore r18 */	\
	ldreg	%r17,(FRAME_17+(2*SZREG))(%r1);	/* restore r17 */	\
	ldreg	%r16,(FRAME_16+(2*SZREG))(%r1);	/* restore r16 */	\
	ldreg	%r15,(FRAME_15+(2*SZREG))(%r1);	/* restore r15 */	\
	ldreg	%r14,(FRAME_14+(2*SZREG))(%r1);	/* restore r14 */	\
	ldreg	%r13,(FRAME_13+(2*SZREG))(%r1);	/* restore r13 */	\
	ldreg	%r12,(FRAME_12+(2*SZREG))(%r1);	/* restore r12 */	\
	ldreg	%r11,(FRAME_11+(2*SZREG))(%r1);	/* restore r11 */	\
	ldreg	%r10,(FRAME_10+(2*SZREG))(%r1);	/* restore r10 */	\
	ldreg	%r9,(FRAME_9+(2*SZREG))(%r1);	/* restore r9 */	\
	ldreg	%r8,(FRAME_8+(2*SZREG))(%r1);	/* restore r8 */	\
	ldreg	%r7,(FRAME_7+(2*SZREG))(%r1);	/* restore r7 */	\
	ldreg	%r6,(FRAME_6+(2*SZREG))(%r1);	/* restore r6 */	\
	ldreg	%r5,(FRAME_5+(2*SZREG))(%r1);	/* restore r5 */	\
	ldreg	%r4,(FRAME_4+(2*SZREG))(%r1);	/* restore r4 */	\
	ldreg	%r3,(FRAME_3+(2*SZREG))(%r1);	/* restore r3 */	\
	ldreg	%r2,(FRAME_2+(2*SZREG))(%r1);	/* restore r2 */	\
	ldreg	%r0,(FRAME_0+(2*SZREG))(%r1);	/* restore r0 */	\
	ldreg	%r1,(FRAME_1+(2*SZREG))(%r1);	/* restore old sp in r1 */ \
/* Can't touch %r1 from here on */					\
	mtsprg2	%r2;			/* save r2 & r3 */		\
	mtsprg3	%r3;							\
/* Disable translation, machine check and recoverability: */		\
	mfmsr	%r2;							\
	andi.	%r2,%r2,~(PSL_DR|PSL_IR|PSL_ME|PSL_RI)@l;		\
	mtmsr	%r2;							\
	isync;								\
/* Decide whether we return to user mode: */				\
	GET_CPUINFO(%r2);						\
	ldreg	%r3,(savearea+CPUSAVE_SRR1)(%r2);			\
	mtcr	%r3;							\
	bf	17,1f;			/* branch if PSL_PR is false */	\
/* Restore user SRs */							\
	RESTORE_USER_SRS(%r2,%r3);					\
1:	mfsprg1	%r2;			/* restore cr */		\
	mtcr	%r2;							\
	GET_CPUINFO(%r2);						\
	ldreg	%r3,(savearea+CPUSAVE_SRR0)(%r2);			\
	mtsrr0	%r3;							\
	ldreg	%r3,(savearea+CPUSAVE_SRR1)(%r2);			\
	mtsrr1	%r3;							\
	mfsprg2	%r2;			/* restore r2 & r3 */		\
	mfsprg3	%r3

/*
 * Preamble code for DSI/ISI traps
 */
disitrap:
	GET_CPUINFO(%r1)
	ldreg	%r30,(CI_DISISAVE+CPUSAVE_R28)(%r1)
	streg	%r30,(CI_TEMPSAVE+CPUSAVE_R28)(%r1)
	ldreg	%r31,(CI_DISISAVE+CPUSAVE_R29)(%r1)
	streg	%r31,(CI_TEMPSAVE+CPUSAVE_R29)(%r1)
	ldreg	%r30,(CI_DISISAVE+CPUSAVE_R30)(%r1)
	streg	%r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1)
	ldreg	%r31,(CI_DISISAVE+CPUSAVE_R31)(%r1)
	streg	%r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1)
	mfdar	%r30
	mfdsisr	%r31
	streg	%r30,(CI_TEMPSAVE+CPUSAVE_DAR)(%r1)
	streg	%r31,(CI_TEMPSAVE+CPUSAVE_DSISR)(%r1)

#ifdef DDB
	mfsrr1	%r31
	mtcr	%r31
	bt	17,trapstart		/* branch is user mode */
	mfsprg1	%r31			/* get old SP */
#if 0
	subf	%r30,%r30,%r31		/* subtract DAR from it */
	addi	%r30,%r30,2048		/* offset result 1/2 page */
	cmplwi	%cr0,%r30,4096		/* is DAR +- 1/2 page of SP? */
#else
	xor.	%r30,%r30,%r31		/* try xor most significant bits */
	cmplwi	%cr0,%r30,4096		/* is DAR on same page as SP? */
#endif
	bge	%cr0,trapstart		/* no, too far away. */
	/* Now convert this DSI into a DDB trap.  */
	GET_CPUINFO(%r1)
	ldreg	%r30,(CI_DISISAVE+CPUSAVE_R28)(%r1) /* get  r28 */
	streg	%r30,(CI_DDBSAVE +CPUSAVE_R28)(%r1) /* save r28 */
	ldreg	%r31,(CI_DISISAVE+CPUSAVE_R29)(%r1) /* get  r29 */
	streg	%r31,(CI_DDBSAVE +CPUSAVE_R29)(%r1) /* save r29 */
	ldreg	%r30,(CI_DISISAVE+CPUSAVE_R30)(%r1) /* get  r30 */
	streg	%r30,(CI_DDBSAVE +CPUSAVE_R30)(%r1) /* save r30 */
	ldreg	%r31,(CI_DISISAVE+CPUSAVE_R31)(%r1) /* get  r31 */
	streg	%r31,(CI_DDBSAVE +CPUSAVE_R31)(%r1) /* save r31 */
	lis	%r1,ddbstk+INTSTK@ha	/* get new SP */
	addi	%r1,%r1,ddbstk+INTSTK@l
	b	ddbtrap
#endif

	.globl	_C_LABEL(trapstart)
	.type	_C_LABEL(trapstart),@function
_C_LABEL(trapstart):
realtrap:
/* Test whether we already had PR set */
	mfsrr1	%r1
	mtcr	%r1
	mfsprg1	%r1			/* restore SP (might have been
					   overwritten) */
s_trap:
	bf	17,k_trap		/* branch if PSL_PR is false */
	GET_CPUINFO(%r1)		/* get cpu_info for this cpu */
u_trap:
	ldptr	%r1,CI_CURPCB(%r1)
	addi	%r1,%r1,USPACE		/* stack is top of user struct */

/*
 * Now the common trap catching code.
 */

	RESTORE_KERN_SRS(%r30,%r31)	/* First enable KERNEL mapping */

k_trap:
	FRAME_SETUP(CI_TEMPSAVE)
trapagain:
/* Now we can recover interrupts again: */
	mfmsr	%r7
	ldreg	%r6, (FRAME_SRR1+(2*SZREG))(%r1)
	andi.	%r6,%r6,(PSL_EE|PSL_ME|PSL_RI)@l
	or	%r7,%r7,%r6
	mtmsr	%r7
	isync
/* Call C trap code: */
	addi	%r3,%r1,(2*SZREG)
	bl	_C_LABEL(trap)
/* LINTSTUB: Var: int trapexit[1]; */
	.globl	trapexit
trapexit:
/* Disable interrupts: */
	mfmsr	%r3
	andi.	%r3,%r3,~PSL_EE@l
	mtmsr	%r3
/* Test AST pending: */
	ldreg	%r5,(FRAME_SRR1+(2*SZREG))(%r1)
	mtcr	%r5
	bf	17,1f			/* branch if PSL_PR is false */
	GET_CPUINFO(%r3)
	ldint	%r4,CI_ASTPENDING(%r3)
	andi.	%r4,%r4,1
	beq	1f
	li	%r6,EXC_AST
	stint	%r6,(FRAME_EXC+(2*SZREG))(%r1)
	b	trapagain
1:
	FRAME_LEAVE(CI_TEMPSAVE)
	RFI

/* 
 * Trap handler for syscalls (EXC_SC)
 */
/* LINTSTUB: Var: int sctrap[1], scsize[1]; */
	.globl	_C_LABEL(sctrap),_C_LABEL(scsize),_C_LABEL(sctrapexit)
_C_LABEL(sctrap):
	mtsprg1	%r1			/* save SP */
	GET_CPUINFO(%r1)
	streg	%r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1) /* save r28 */
	streg	%r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1) /* save r20 */
	streg	%r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1) /* save r30 */
	streg	%r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1) /* save r31 */
	mflr	%r28			/* save LR */
	mfcr	%r29			/* save CR */
#if defined(DISTANT_KERNEL)
	lis	%r31,s_sctrap@ha
	addi	%r31,%r31,s_sctrap@l
	mtlr	%r31
	blrl
#else
	bla	s_sctrap
#endif
	_C_LABEL(scsize) = .-_C_LABEL(sctrap)

s_sctrap:
	GET_CPUINFO(%r1)
	ldptr	%r1,CI_CURPCB(%r1)
	addi	%r1,%r1,USPACE		/* stack is top of user struct */
	RESTORE_KERN_SRS(%r30,%r31)	/* First enable KERNEL mapping */
	FRAME_SETUP(CI_TEMPSAVE)
/* Now we can recover interrupts again: */
	mfmsr	%r7
	ori	%r7,%r7,(PSL_EE|PSL_ME|PSL_RI)@l
	mtmsr	%r7
	isync
	addi	%r3,%r1,(2*SZREG)
/* Call the appropriate syscall handler: */
	GET_CPUINFO(%r4)
	ldptr	%r4,CI_CURLWP(%r4)
	ldptr	%r4,L_PROC(%r4)
	ldptr	%r4,P_MD_SYSCALL(%r4)
	mtctr	%r4
	bctrl
_C_LABEL(sctrapexit):
/* Disable interrupts: */
	mfmsr	%r3
	andi.	%r3,%r3,~PSL_EE@l
	mtmsr	%r3
/* Test AST pending: */
	GET_CPUINFO(%r3)
	ldint	%r4,CI_ASTPENDING(%r3)
	andi.	%r4,%r4,1
	beq	1f
	li	%r6,EXC_AST
	stint	%r6,(FRAME_EXC+(2*SZREG))(%r1)
	b	trapagain
1:
	FRAME_LEAVE(CI_TEMPSAVE)
	RFI

/*
 * External interrupt second level handler
 */
#define	INTRENTER							\
/* Save non-volatile registers: */					\
	stptru	%r1,-IFRAMELEN(%r1);	/* temporarily */		\
	streg	%r0,IFRAME_R0(%r1);					\
	mfsprg1	%r0;			/* get original SP */		\
	streg	%r0,IFRAME_R1(%r1);	/* and store it */		\
	streg	%r3,IFRAME_R3(%r1);					\
	streg	%r4,IFRAME_R4(%r1);					\
	streg	%r5,IFRAME_R5(%r1);					\
	streg	%r6,IFRAME_R6(%r1);					\
	streg	%r7,IFRAME_R7(%r1);					\
	streg	%r8,IFRAME_R8(%r1);					\
	streg	%r9,IFRAME_R9(%r1);					\
	streg	%r10,IFRAME_R10(%r1);					\
	streg	%r11,IFRAME_R11(%r1);					\
	streg	%r12,IFRAME_R12(%r1);					\
	streg	%r28,IFRAME_LR(%r1);	/* saved LR */			\
	stint	%r29,IFRAME_CR(%r1);	/* saved CR */			\
	stint	%r30,IFRAME_XER(%r1);	/* saved XER */			\
	GET_CPUINFO(%r4);						\
	ldreg	%r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r4); /* restore r28 */	\
	ldreg	%r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r4); /* restore r29 */	\
	ldreg	%r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r4); /* restore r30 */	\
	ldreg	%r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r4); /* restore r31 */	\
	mfctr	%r6;							\
	ldint	%r5,CI_INTRDEPTH(%r4);					\
	mfsrr0	%r4;							\
	mfsrr1	%r3;							\
	streg	%r6,IFRAME_CTR(%r1);					\
	stint	%r5,IFRAME_INTR_DEPTH(%r1);				\
	streg	%r4,IFRAME_SRR0(%r1);					\
	streg	%r3,IFRAME_SRR1(%r1);					\
	mtcr	%r3;							\
	bf	17,99f;	/* branch if PSL_PR is false */		\
/* interrupts are recoverable here, and enable translation */		\
	RESTORE_KERN_SRS(%r3,%r4);					\
99:	mfmsr	%r5;							\
	ori	%r5,%r5,(PSL_IR|PSL_DR|PSL_RI);				\
	mtmsr	%r5;							\
	isync

/* LINTSTUB: Var: int extint_call[1]; */
	.globl	_C_LABEL(extint_call)
extintr:
	INTRENTER
	mr	%r3,%r1			/* make intrframe available */
_C_LABEL(extint_call):
	bl	_C_LABEL(extint_call)	/* to be filled in later */

intr_exit:
/* Disable interrupts (should already be disabled) and MMU here: */
	mfmsr	%r3
	andi.	%r3,%r3,~(PSL_EE|PSL_ME|PSL_RI|PSL_DR|PSL_IR)@l
	mtmsr	%r3
	isync

/* restore possibly overwritten registers: */
	ldreg	%r12,IFRAME_R12(%r1)
	ldreg	%r11,IFRAME_R11(%r1)
	ldreg	%r10,IFRAME_R10(%r1)
	ldreg	%r9,IFRAME_R9(%r1)
	ldreg	%r8,IFRAME_R8(%r1)
	ldreg	%r7,IFRAME_R7(%r1)
	ldreg	%r6,IFRAME_SRR1(%r1)
	ldreg	%r5,IFRAME_SRR0(%r1)
	ldreg	%r4,IFRAME_CTR(%r1)
	ldint	%r3,IFRAME_XER(%r1)
	mtsrr1	%r6
	mtsrr0	%r5
	mtctr	%r4
	mtxer	%r3

	GET_CPUINFO(%r5)
	ldint	%r4,CI_INTRDEPTH(%r5)
	addi	%r4,%r4,-1		/* adjust reentrancy count */
	stint	%r4,CI_INTRDEPTH(%r5)

/* Returning to user mode? */
	mtcr	%r6			/* saved SRR1 */
	bf	17,1f			/* branch if PSL_PR is false */

	RESTORE_USER_SRS(%r3,%r4)
	ldint	%r3,CI_ASTPENDING(%r5)	/* Test AST pending */
	andi.	%r3,%r3,1
	beq	1f

/* Setup for entry to realtrap: */
	ldreg	%r3,IFRAME_R1(%r1)	/* get saved SP */
	mtsprg1	%r3
	li	%r6,EXC_AST
	streg	%r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r5) /* establish tempsave r28 */
	streg	%r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r5) /* establish tempsave r29 */
	streg	%r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r5) /* establish tempsave r30 */
	streg	%r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r5) /* establish tempsave r31 */
	mtlr	%r6
	ldreg	%r28,IFRAME_LR(%r1)	/* saved LR */
	ldint	%r29,IFRAME_CR(%r1)	/* saved CR */
	ldreg	%r6,IFRAME_R6(%r1)
	ldreg	%r5,IFRAME_R5(%r1)
	ldreg	%r4,IFRAME_R4(%r1)
	ldreg	%r3,IFRAME_R3(%r1)
	ldreg	%r0,IFRAME_R0(%r1)
	b	realtrap
1:
/* Here is the normal exit of extintr: */
	ldint	%r5,IFRAME_CR(%r1)
	ldreg	%r6,IFRAME_LR(%r1)
	mtcr	%r5
	mtlr	%r6
	ldreg	%r6,IFRAME_R6(%r1)
	ldreg	%r5,IFRAME_R5(%r1)
	ldreg	%r4,IFRAME_R4(%r1)
	ldreg	%r3,IFRAME_R3(%r1)
	ldreg	%r0,IFRAME_R0(%r1)
	ldreg	%r1,IFRAME_R1(%r1)
	RFI

/*
 * Decrementer interrupt second level handler
 */
decrintr:
	INTRENTER
	addi	%r3,%r1,(2*SZREG)	/* intr frame -> clock frame */
	bl	_C_LABEL(decr_intr)
	b	intr_exit

#ifdef DDB
/*
 * Deliberate entry to ddbtrap
 */
	.globl	_C_LABEL(ddb_trap)
_C_LABEL(ddb_trap):
	mtsprg1	%r1
	mfmsr	%r3
	mtsrr1	%r3
	andi.	%r3,%r3,~(PSL_EE|PSL_ME)@l
	mtmsr	%r3			/* disable interrupts */
	isync
	GET_CPUINFO(%r3)
	streg	%r28,(CI_DDBSAVE+CPUSAVE_R28)(%r3)
	streg	%r29,(CI_DDBSAVE+CPUSAVE_R29)(%r3)
	streg	%r30,(CI_DDBSAVE+CPUSAVE_R30)(%r3)
	streg	%r31,(CI_DDBSAVE+CPUSAVE_R31)(%r3)
	mflr	%r28
	li	%r29,EXC_BPT
	mtlr	%r29
	mfcr	%r29
	mtsrr0	%r28
#endif /* DDB */

#if defined(DDB) || defined(KGDB)
/*
 * Now the ddb trap catching code.
 */
ddbtrap:
	FRAME_SETUP(CI_DDBSAVE)
/* Call C trap code: */
	addi	%r3,%r1,(2*SZREG)
	bl	_C_LABEL(ddb_trap_glue)
	or.	%r3,%r3,%r3
	bne	ddbleave
/* This wasn't for DDB, so switch to real trap: */
	ldint	%r3,(FRAME_EXC+(2*SZREG))(%r1)	/* save exception */
	GET_CPUINFO(%r4)
	streg	%r3,(CI_DDBSAVE+CPUSAVE_R31)(%r4)
	FRAME_LEAVE(CI_DDBSAVE)
	mtsprg1	%r1			/* prepare for entrance to realtrap */
	GET_CPUINFO(%r1)
	streg	%r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1)
	streg	%r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1)
	streg	%r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1)
	streg	%r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1)
	mflr	%r28
	mfcr	%r29
	ldreg	%r31,(CI_DDBSAVE+CPUSAVE_R31)(%r1)
	mtlr	%r31
	mfsprg1	%r1
	b	realtrap
ddbleave:
	FRAME_LEAVE(CI_DDBSAVE)
	RFI
#endif /* DDB || KGDB */

#if defined(IPKDB) && !defined(DISTANT_KERNEL)
/*
 * Deliberate entry to ipkdbtrap
 */
	.globl	_C_LABEL(ipkdb_trap)
_C_LABEL(ipkdb_trap):
	mtsprg1	%r1
	mfmsr	%r3
	mtsrr1	%r3
	andi.	%r3,%r3,~(PSL_EE|PSL_ME)@l
	mtmsr	%r3			/* disable interrupts */
	isync
	GET_CPUINFO(%r3)
	streg	%r28,(CI_IPKDBSAVE+CPUSAVE_R28)(%r3)
	streg	%r29,(CI_IPKDBSAVE+CPUSAVE_R29)(%r3)
	streg	%r30,(CI_IPKDBSAVE+CPUSAVE_R30)(%r3)
	streg	%r31,(CI_IPKDBSAVE+CPUSAVE_R31)(%r3)
	mflr	%r28
	li	%r29,EXC_BPT
	mtlr	%r29
	mfcr	%r29
	mtsrr0	%r28

/*
 * Now the ipkdb trap catching code.
 */
ipkdbtrap:
	FRAME_SETUP(ipkdbsave)
/* Call C trap code: */
	addi	%r3,%r1,(2*SZREG)
	bl	_C_LABEL(ipkdb_trap_glue)
	or.	%r3,%r3,%r3
	bne	ipkdbleave
/* This wasn't for IPKDB, so switch to real trap: */
	ldint	%r3,(FRAME_EXC+(2*SZREG))(%r1)	/* save exception */
	GET_CPUINFO(%r4)
	streg	%r3,(CI_IPKDBSAVE+CPUSAVE_R31)(%r4)
	FRAME_LEAVE(CI_IPKDBSAVE)
	mtsprg1	%r1			/* prepare for entrance to realtrap */
	GET_CPUINFO(%r1)
	streg	%r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1)
	streg	%r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1)
	streg	%r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1)
	streg	%r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1)
	mflr	%r28
	mfcr	%r29
	ldreg	%r31,(CI_IPKDBSAVE+CPUSAVE_R31)(%r1)
	mtlr	%r31
	mfsprg1	%r1
	b	realtrap
ipkdbleave:
	FRAME_LEAVE(CI_IPKDBSAVE)
	RFI

ipkdbfault:
	ba	_ipkdbfault
_ipkdbfault:
	mfsrr0	%r3
	addi	%r3,%r3,4
	mtsrr0	%r3
	li	%r3,-1
	RFI

/*
 * int ipkdbfbyte(unsigned char *p)
 */
	.globl	_C_LABEL(ipkdbfbyte)
_C_LABEL(ipkdbfbyte):
	li	%r9,EXC_DSI		/* establish new fault routine */
	ldint	%r5,0(%r9)
	lis	%r6,ipkdbfault@ha
	ldint	%r6,ipkdbfault@l(%r6)
	stint	%r6,0(%r9)
#ifdef	IPKDBUSERHACK
	lis	%r8,_C_LABEL(ipkdbsr)@ha
	ldreg	%r8,_C_LABEL(ipkdbsr)@l(%r8)
	mtsr	USER_SR,8
	isync
#endif
	dcbst	%r0,%r9			/* flush data... */
	sync
	icbi	%r0,%r9			/* and instruction caches */
	lbz	%r3,0(%r3)		/* fetch data */
	stint	%r5,0(%r9)		/* restore previous fault handler */
	dcbst	%r0,%r9			/* and flush data... */
	sync
	icbi	%r0,%r9			/* and instruction caches */
	blr

/*
 * int ipkdbsbyte(unsigned char *p, int c)
 */
	.globl	_C_LABEL(ipkdbsbyte)
_C_LABEL(ipkdbsbyte):
	li	%r9,EXC_DSI		/* establish new fault routine */
	ldint	%r5,0(%r9)
	lis	%r6,ipkdbfault@ha
	ldint	%r6,ipkdbfault@l(%r6)
	stint	%r6,0(%r9)
#ifdef	IPKDBUSERHACK
	lis	%r8,_C_LABEL(ipkdbsr)@ha
	ldreg	%r8,_C_LABEL(ipkdbsr)@l(%r8)
	mtsr	USER_SR,%r8
	isync
#endif
	dcbst	%r0,%r9			/* flush data... */
	sync
	icbi	%r0,%r9			/* and instruction caches */
	mr	%r6,%r3
	li	%r3,0
	stb	%r4,0(%r6)
	dcbst	%r0,%r6			/* Now do appropriate flushes
					   to data... */
	sync
	icbi	%r0,%r6			/* and instruction caches */
	stint	%r5,0(%r9)		/* restore previous fault handler */
	dcbst	%r0,%r9			/* and flush data... */
	sync
	icbi	%r0,%r9			/* and instruction caches */
	blr
#endif	/* IPKDB */
	.globl	_C_LABEL(trapend)
_C_LABEL(trapend):