Home | History | Annotate | Line # | Download | only in powerpc
      1 /*	$NetBSD: trap_subr.S,v 1.87 2025/04/29 14:33:26 tsutsui Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
      5  * Copyright (C) 1995, 1996 TooLs GmbH.
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *	This product includes software developed by TooLs GmbH.
     19  * 4. The name of TooLs GmbH may not be used to endorse or promote products
     20  *    derived from this software without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
     23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     25  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 /*
     35  * NOTICE: This is not a standalone file.  to use it, #include it in
     36  * your port's locore.S, like so:
     37  *
     38  *	#include <powerpc/powerpc/trap_subr.S>
     39  */
     40 
     41 #ifdef _KERNEL_OPT
     42 #include "opt_altivec.h"
     43 #include "opt_ddb.h"
     44 #include "opt_kgdb.h"
     45 #include "opt_ppcarch.h"
     46 #endif
     47 
     48 /* LINTSTUB: include <sys/param.h> */
     49 /* LINTSTUB: include <powerpc/oea/bat.h> */
     50 
     51 #ifdef ALTIVEC
     52 #define	SAVE_VRSAVE(tf,b)						\
     53 	mfspr	b,SPR_VRSAVE;						\
     54 	stint	b,FRAME_VRSAVE(tf);
     55 
     56 #define RESTORE_VRSAVE(tf,b)						\
     57 	ldint	b,FRAME_VRSAVE(tf);					\
     58 	mtspr	SPR_VRSAVE,b;
     59 #else
     60 #define SAVE_VRSAVE(tf,b)
     61 #define RESTORE_VRSAVE(tf,b)
     62 #endif
     63 
     64 #if defined (PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
     65 #define	RFI	rfid
     66 #else
     67 #define	RFI	rfi
     68 #endif /* PPC_OEA64 || PPC_OEA64_BRIDGE*/
     69 
     70 #if defined (PPC_OEA64_BRIDGE)
     71 #define ENABLE_64BIT_BRIDGE(t0)						\
     72 	mfmsr	t0;							\
     73 	clrldi	t0,t0,1;						\
     74 	mtmsrd	t0;
     75 #else
     76 #define ENABLE_64BIT_BRIDGE(t0)
     77 #endif /* PPC_OEA64_BRIDGE */
     78 
     79 #if defined(PPC_OEA64)
     80 /*
     81  * User segment table is loaded through a pointer to the current pmap.
     82  */
     83 #define RESTORE_USER_SRS(t0,t1)						\
     84 	GET_CPUINFO(t0);						\
     85 	ldptr	t0,CI_CURPM(t0);					\
     86 	ldreg	t0,PM_STEG(t0);						\
     87 	mtasr	t0
     88 
     89 /*
     90  * Kernel segment table is loaded directly from kernel_pmap_
     91  */
     92 #define RESTORE_KERN_SRS(t0,t1)						\
     93 	lis	t0,_C_LABEL(kernel_pmap_)@ha;				\
     94 	ldreg	t0,_C_LABEL(kernel_pmap_)+PM_STEG@l(t0);		\
     95 	mtasr	t0
     96 
     97 #elif defined(PPC_MPC8XX)
     98 
     99 /*
    100  * PPC_MPC8XX don't have SRs to load
    101  */
    102 #define RESTORE_USER_SRS(t0,t1)
    103 #define RESTORE_KERN_SRS(t0,t1)
    104 
    105 #else /* not OEA64 */
    106 
    107 /*
    108  * Restore segment registers from array.
    109  */
    110 #define	RESTORE_SRS(pmap,sr)	mtsr	0,sr; \
    111 	ldreg	sr,4(pmap);	mtsr	1,sr; \
    112 	ldreg	sr,8(pmap);	mtsr	2,sr; \
    113 	ldreg	sr,12(pmap);	mtsr	3,sr; \
    114 	ldreg	sr,16(pmap);	mtsr	4,sr; \
    115 	ldreg	sr,20(pmap);	mtsr	5,sr; \
    116 	ldreg	sr,24(pmap);	mtsr	6,sr; \
    117 	ldreg	sr,28(pmap);	mtsr	7,sr; \
    118 	ldreg	sr,32(pmap);	mtsr	8,sr; \
    119 	ldreg	sr,36(pmap);	mtsr	9,sr; \
    120 	ldreg	sr,40(pmap);	mtsr	10,sr; \
    121 	ldreg	sr,44(pmap);	mtsr	11,sr; \
    122 	ldreg	sr,48(pmap);	mtsr	12,sr; \
    123 	ldreg	sr,52(pmap);	mtsr	13,sr; \
    124 	ldreg	sr,56(pmap);	mtsr	14,sr; \
    125 	ldreg	sr,60(pmap);	mtsr	15,sr; isync;
    126 
    127 /*
    128  * User SRs are loaded through a pointer to the current pmap.
    129  * Note: oea_init() relies on the 601 instruction sequence.
    130  */
    131 #define RESTORE_USER_SRS(pmap,sr)					\
    132 	GET_CPUINFO(pmap);						\
    133 	ldptr	pmap,CI_CURPM(pmap);					\
    134 	ldregu	sr,PM_SR(pmap);						\
    135 	RESTORE_SRS(pmap,sr);						\
    136 	/* Obliterate BATs on 601; reuse temporary registers. */	\
    137 	li	sr,0;							\
    138 	mtibatl	0,sr;							\
    139 	mtibatl	1,sr;							\
    140 	mtibatl	2,sr;							\
    141 	mtibatl	3,sr
    142 
    143 /*
    144  * Kernel SRs are loaded directly from kernel_pmap_.
    145  * Note: oea_init() relies on the 601 instruction sequence.
    146  */
    147 #define RESTORE_KERN_SRS(pmap,sr)					\
    148 	lis	pmap,_C_LABEL(kernel_pmap_)@ha;				\
    149 	ldregu	sr,_C_LABEL(kernel_pmap_)+PM_SR@l(pmap);		\
    150 	RESTORE_SRS(pmap,sr);						\
    151 	/* Restore fixed BATs on 601; reuse temporary registers. */	\
    152 	lis	pmap,_C_LABEL(battable)@ha;				\
    153 	ldregu	sr,_C_LABEL(battable)@l(pmap);				\
    154 	mtibatu 0,sr;							\
    155 	ldreg	sr,4(pmap);	mtibatl 0,sr;				\
    156 	ldreg	sr,8(pmap);	mtibatu 1,sr;				\
    157 	ldreg	sr,12(pmap);	mtibatl 1,sr
    158 #endif /* (PPC_OEA64) */
    159 
    160 /*
    161  * Save/restore MPC601 MQ register.
    162  * Note: oea_init() relies on this instruction sequence.
    163  */
    164 #if defined(PPC_OEA601)
    165 #define	SAVE_MQ(tf,b)							\
    166 	mfspr	b,SPR_MQ;						\
    167 	streg	b,FRAME_MQ(tf);
    168 
    169 #define	RESTORE_MQ(tf,b)						\
    170 	ldreg	b,FRAME_MQ(tf);						\
    171 	mtspr	SPR_MQ,b;
    172 #else
    173 #define	SAVE_MQ(tf,b)
    174 #define	RESTORE_MQ(tf,b)
    175 #endif
    176 
    177 /*
    178  * This code gets copied to all the trap vectors
    179  * (except ISI/DSI, ALI, the interrupts).
    180  */
    181 
    182 /* LINTSTUB: Var: int trapcode[1], trapsize[1]; */
    183 	.text
    184 	.globl	_C_LABEL(trapcode),_C_LABEL(trapsize)
    185 _C_LABEL(trapcode):
    186 	mtsprg1	%r1			/* save SP */
    187 	ENABLE_64BIT_BRIDGE(%r1)
    188 	GET_CPUINFO(%r1)
    189 	streg	%r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1)	/* free r28 */
    190 	streg	%r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1)	/* free r29 */
    191 	streg	%r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1)	/* free r30 */
    192 	streg	%r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1)	/* free r31 */
    193 	mfsprg1	%r1			/* restore SP */
    194 	mflr	%r28			/* save LR */
    195 	mfcr	%r29			/* save CR */
    196 /* Test whether we already had PR set */
    197 	mfsrr1	%r31
    198 	mtcr	%r31
    199 #if defined(DISTANT_KERNEL)
    200 	lis	%r31,s_trap@ha
    201 	addi	%r31,%r31,s_trap@l
    202 	mtlr	%r31
    203 	blrl
    204 #else
    205 	bla	s_trap
    206 #endif
    207 _C_LABEL(trapsize) = .-_C_LABEL(trapcode)
    208 
    209 /*
    210  * For ALI: has to save DSISR and DAR
    211  * Also used as dsitrap for BATless cpus.
    212  */
    213 /* LINTSTUB: Var: int alicode[1], alisize[1]; */
    214 	.globl	_C_LABEL(alitrap),_C_LABEL(alisize)
    215 _C_LABEL(alitrap):
    216 	mtsprg1	%r1			/* save SP */
    217 	ENABLE_64BIT_BRIDGE(%r1)
    218 	GET_CPUINFO(%r1)
    219 	streg	%r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1) /* save r28 */
    220 	streg	%r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1) /* save r29 */
    221 	streg	%r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1) /* save r30 */
    222 	streg	%r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1) /* save r31 */
    223 	mfdar	%r30
    224 	mfdsisr	%r31
    225 	streg	%r30,(CI_TEMPSAVE+CPUSAVE_DAR)(%r1)	/* save dar */
    226 	streg	%r31,(CI_TEMPSAVE+CPUSAVE_DSISR)(%r1)	/* save dsisr */
    227 	mfsprg1	%r1			/* restore SP */
    228 	mflr	%r28			/* save LR */
    229 	mfcr	%r29			/* save CR */
    230 /* Test whether we already had PR set */
    231 	mfsrr1	%r31
    232 	mtcr	%r31
    233 #if defined(DISTANT_KERNEL)
    234 	lis	%r31,s_trap@ha
    235 	addi	%r31,%r31,s_trap@l
    236 	mtlr	%r31
    237 	blrl
    238 #else
    239 	bla	s_trap
    240 #endif
    241 _C_LABEL(alisize) = .-_C_LABEL(alitrap)
    242 
    243 #if !defined(PPC_MPC8XX)
    244 /*
    245  * Similar to the above for DSI
    246  * Has to handle BAT spills
    247  * and standard pagetable spills
    248  */
    249 /* LINTSTUB: Var: int dsicode[1], dsisize[1]; */
    250 	.globl	_C_LABEL(dsitrap),_C_LABEL(dsisize)
    251 _C_LABEL(dsitrap):
    252 	mtsprg1	%r1
    253 	ENABLE_64BIT_BRIDGE(%r1)
    254 	GET_CPUINFO(%r1)
    255 	streg	%r28,(CI_DISISAVE+CPUSAVE_R28)(%r1)	/* save r28 */
    256 	streg	%r29,(CI_DISISAVE+CPUSAVE_R29)(%r1)	/* save r29 */
    257 	streg	%r30,(CI_DISISAVE+CPUSAVE_R30)(%r1)	/* save r30 */
    258 	streg	%r31,(CI_DISISAVE+CPUSAVE_R31)(%r1)	/* save r31 */
    259 	mfsprg1	%r1
    260 	mfcr	%r29			/* save CR */
    261 	mfsrr1	%r31			/* test kernel mode */
    262 	mtcr	%r31
    263 #if !defined(PPC_MPC8XX)
    264 	mfxer	%r30			/* save XER */
    265 	mtsprg2	%r30			/* in SPRG2 */
    266 	bt	MSR_PR,1f		/* branch if PSL_PR is set */
    267 	mfdar	%r31			/* get fault address */
    268 	rlwinm	%r31,%r31,3+(32-BAT_ADDR_SHIFT),BAT_ADDR_SHIFT-3,28
    269 					/* get segment * 8 */
    270 
    271 	/* Get address of this CPU's current battable */
    272 	GET_CPUINFO(%r30)
    273 	ldreg	%r30,CI_BATTABLE(%r30)
    274 
    275 	/* Add offset to the slot we care about. */
    276 	add	%r31,%r31,%r30
    277 
    278 	/* get batu */
    279 	ldreg	%r30,0(%r31)
    280 	mtcr	%r30
    281 	bf	30,1f			/* branch if supervisor valid is
    282 					   false */
    283 	/* get batl */
    284 	ldreg	%r31,SZREG(%r31)
    285 /* We randomly use the highest two bat registers here */
    286 	mftb	%r28
    287 	mtcr	%r28
    288 	.globl	dsitrap_fix_dbat4, dsitrap_fix_dbat5
    289 	.globl	dsitrap_fix_dbat6, dsitrap_fix_dbat7
    290 dsitrap_fix_dbat4:
    291 	bt	31,3f
    292 	/*
    293 	 * If we are running on a CPU that has HIGHBAT, these will be replaced
    294 	 * by instructions to test bit 30 (aka bit 1 for normal people) and if
    295 	 * set skip ahead to 5f (4 instructions),  followed by instructions to
    296 	 * update BAT4.
    297 	 */
    298 	mtspr	SPR_DBAT2U,%r30		/*	bt	30,dsitrap_fix_dbat5 */
    299 	mtspr	SPR_DBAT2L,%r31		/*	mtspr	SPR_DBAT4U,%r30 */
    300 	b	8f			/*	mtspr	SPR_DBAT4L,%r31 */
    301 	b	8f			/*	do not remove */
    302 dsitrap_fix_dbat5:
    303 	mtspr	SPR_DBAT5U,%r30
    304 	mtspr	SPR_DBAT5L,%r31
    305 	b	8f
    306 dsitrap_fix_dbat6:
    307 	bt	30,3f
    308 	mtspr	SPR_DBAT6U,%r30
    309 	mtspr	SPR_DBAT6L,%r31
    310 	b	8f
    311 3:
    312 dsitrap_fix_dbat7:
    313 	/*
    314 	 * If we are running on a CPU that has HIGHBAT, these will be replaced
    315 	 * by instructions to update BAT7.
    316 	 */
    317 	mtspr	SPR_DBAT3U,%r30		/*	mtspr	SPR_DBAT7U,%r30 */
    318 	mtspr	SPR_DBAT3L,%r31		/*	mtspr	SPR_DBAT7L,%r31 */
    319 8:
    320 	mfsprg2	%r30			/* restore XER */
    321 	mtxer	%r30
    322 	mtcr	%r29			/* restore CR */
    323 	mtsprg1	%r1
    324 	GET_CPUINFO(%r1)
    325 	ldreg	%r28,(CI_DISISAVE+CPUSAVE_R28)(%r1)	/* restore r28 */
    326 	ldreg	%r29,(CI_DISISAVE+CPUSAVE_R29)(%r1)	/* restore r29 */
    327 	ldreg	%r30,(CI_DISISAVE+CPUSAVE_R30)(%r1)	/* restore r30 */
    328 	ldreg	%r31,(CI_DISISAVE+CPUSAVE_R31)(%r1)	/* restore r31 */
    329 	mfsprg1	%r1
    330 	RFI				/* return to trapped code */
    331 1:
    332 #endif	/* !PPC_MPC8XX */
    333 	mflr	%r28			/* save LR */
    334 	mtsprg1	%r1			/* save SP */
    335 #if defined(DISTANT_KERNEL)
    336 	lis	%r31,disitrap@ha
    337 	addi	%r31,%r31,disitrap@l
    338 	mtlr	%r31
    339 	blrl
    340 #else
    341 	bla	disitrap
    342 #endif
    343 _C_LABEL(dsisize) = .-_C_LABEL(dsitrap)
    344 #endif /* !PPC_MPC8XX */
    345 
    346 #if defined(PPC_OEA601)
    347 /*
    348  * Dedicated MPC601 version of the above.
    349  * Considers different BAT format and combined implementation
    350  * (being addressed as I-BAT).
    351  */
    352 /* LINTSTUB: Var: int dsi601code[1], dsi601size[1]; */
    353 	.globl	_C_LABEL(dsi601trap),_C_LABEL(dsi601size)
    354 _C_LABEL(dsi601trap):
    355 	mtsprg1	%r1
    356 	ENABLE_64BIT_BRIDGE(%r1)
    357 	GET_CPUINFO(%r1)
    358 	streg	%r28,(CI_DISISAVE+CPUSAVE_R28)(%r1)	/* save r28 */
    359 	streg	%r29,(CI_DISISAVE+CPUSAVE_R29)(%r1)	/* save r29 */
    360 	streg	%r30,(CI_DISISAVE+CPUSAVE_R30)(%r1)	/* save r30 */
    361 	streg	%r31,(CI_DISISAVE+CPUSAVE_R31)(%r1)	/* save r31 */
    362 	mfsprg1	%r1
    363 	mfcr	%r29			/* save CR */
    364 	mfxer	%r30			/* save XER */
    365 	mtsprg2	%r30			/* in SPRG2 */
    366 	mfsrr1	%r31			/* test kernel mode */
    367 	mtcr	%r31
    368 	bt	MSR_PR,1f		/* branch if PSL_PR is set */
    369 	mfdar	%r31			/* get fault address */
    370 	rlwinm	%r31,%r31,12,20,28	/* get "segment" battable offset */
    371 
    372 	/* Get address of this CPU's current battable */
    373 	GET_CPUINFO(%r30)
    374 	ldreg	%r30,CI_BATTABLE(%r30)
    375 
    376 	/* Add offset to the slot we care about. */
    377 	add	%r31,%r31,%r30
    378 
    379 	/* get batl */
    380 	ldreg	%r30,SZREG(%r31)
    381 	mtcr	%r30
    382 	bf	25,1f			/* branch if Valid is false,
    383 					   presently assumes supervisor only */
    384 
    385 	/* get batu */
    386 	ldreg	%r31,0(%r31)
    387 /* We randomly use the highest two bat registers here */
    388 	mfspr	%r28,SPR_RTCL_R
    389 	andi.	%r28,%r28,128
    390 	bne	2f
    391 	mtibatu	2,%r31
    392 	mtibatl	2,%r30
    393 	b	3f
    394 2:
    395 	mtibatu	3,%r31
    396 	mtibatl	3,%r30
    397 3:
    398 	mfsprg2	%r30			/* restore XER */
    399 	mtxer	%r30
    400 	mtcr	%r29			/* restore CR */
    401 	mtsprg1	%r1
    402 	GET_CPUINFO(%r1)
    403 	ldreg	%r28,(CI_DISISAVE+CPUSAVE_R28)(%r1)	/* restore r28 */
    404 	ldreg	%r29,(CI_DISISAVE+CPUSAVE_R29)(%r1)	/* restore r29 */
    405 	ldreg	%r30,(CI_DISISAVE+CPUSAVE_R30)(%r1)	/* restore r30 */
    406 	ldreg	%r31,(CI_DISISAVE+CPUSAVE_R31)(%r1)	/* restore r31 */
    407 	mfsprg1	%r1
    408 	RFI				/* return to trapped code */
    409 1:
    410 	mflr	%r28			/* save LR */
    411 	mtsprg1	%r1
    412 #if defined(DISTANT_KERNEL)
    413 	lis	%r31,disitrap@ha
    414 	addi	%r31,%r31,disitrap@l
    415 	mtlr	%r31
    416 	blrl
    417 #else
    418 	bla	disitrap
    419 #endif
    420 _C_LABEL(dsi601size) = .-_C_LABEL(dsi601trap)
    421 #endif /* defined(PPC_OEA601) */
    422 
    423 /*
    424  * This one for the external interrupt handler.
    425  */
    426 /* LINTSTUB: Var: int extint[1], extsize[1]; */
    427 	.globl	_C_LABEL(extint),_C_LABEL(extsize)
    428 _C_LABEL(extint):
    429 	mtsprg1	%r1			/* save SP */
    430 	ENABLE_64BIT_BRIDGE(%r1)
    431 	GET_CPUINFO(%r1)
    432 	streg	%r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1)	/* save r28 */
    433 	streg	%r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1)	/* save r29 */
    434 	streg	%r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1)	/* save r30 */
    435 	streg	%r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1)	/* save r31 */
    436 	mflr	%r28			/* save LR */
    437 	mfcr	%r29			/* save CR */
    438 	mfsrr1	%r31
    439 	mtcr	%r31
    440 	mr	%r30,%r1
    441 	mfsprg1	%r1			/* get old SP */
    442 	bf	MSR_PR,1f		/* branch if PSL_PR is true */
    443 	ldptr	%r1,CI_CURPCB(%r30)	/* get kernel stack */
    444 	addi	%r1,%r1,USPACE-CALLFRAMELEN /* stack is top of user struct */
    445 	RESTORE_KERN_SRS(%r30, %r31)
    446 1:
    447 #if defined(DISTANT_KERNEL)
    448 	lis	%r31,extintr@ha
    449 	addi	%r31,%r31,extintr@l
    450 	mtlr	%r31
    451 	blr
    452 #else
    453 	ba	extintr
    454 #endif
    455 _C_LABEL(extsize) = .-_C_LABEL(extint)
    456 
    457 /*
    458  * And this one for the decrementer interrupt handler.
    459  */
    460 /* LINTSTUB: Var: int decrint[1], decrsize[1]; */
    461 	.globl	_C_LABEL(decrint),_C_LABEL(decrsize)
    462 _C_LABEL(decrint):
    463 	mtsprg1	%r1			/* save SP */
    464 	ENABLE_64BIT_BRIDGE(%r1)
    465 	GET_CPUINFO(%r1)
    466 	streg	%r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1)	/* save r28 */
    467 	streg	%r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1)	/* save r29 */
    468 	streg	%r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1)	/* save r30 */
    469 	streg	%r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1)	/* save r31 */
    470 	mflr	%r28			/* save LR */
    471 	mfcr	%r29			/* save CR */
    472 	mfsrr1	%r31
    473 	mtcr	%r31
    474 	mr	%r30,%r1
    475 	mfsprg1	%r1			/* yes, get old SP */
    476 	bf	MSR_PR,1f		/* branch if PSL_PR is true */
    477 	ldptr	%r1,CI_CURPCB(%r30)	/* get kernel stack */
    478 	addi	%r1,%r1,USPACE-CALLFRAMELEN /* stack is top of user struct */
    479 	RESTORE_KERN_SRS(%r30, %r31)
    480 1:
    481 #if defined(DISTANT_KERNEL)
    482 	lis	%r31,decrintr@ha
    483 	addi	%r31,%r31,decrintr@l
    484 	mtlr	%r31
    485 	blr
    486 #else
    487 	ba	decrintr
    488 #endif
    489 _C_LABEL(decrsize) = .-_C_LABEL(decrint)
    490 
    491 #if !defined(PPC_OEA64) && !defined(PPC_MPC8XX)
    492 /*
    493  * Now the tlb software load for 603 processors:
    494  * (Code essentially from the 603e User Manual, Chapter 5, but
    495  * corrected a lot.)
    496  */
    497 /* LINTSTUB: Var: int tlbimiss[1], tlbimsize[1]; */
    498 	.globl	_C_LABEL(tlbimiss),_C_LABEL(tlbimsize)
    499 _C_LABEL(tlbimiss):
    500 	mfspr	%r2,SPR_HASH1		/* get first pointer */
    501 	li	%r1,8
    502 	mfctr	%r0			/* save counter */
    503 	mfspr	%r3,SPR_ICMP		/* get first compare value */
    504 	addi	%r2,%r2,-8		/* predec pointer */
    505 1:
    506 	mtctr	%r1			/* load counter */
    507 2:
    508 	ldregu	%r1,8(%r2)		/* get next pte */
    509 	cmplw	%r1,%r3			/* see if found pte */
    510 	bdneq	2b			/* loop if not eq */
    511 	bne	3f			/* not found */
    512 	ldreg	%r1,4(%r2)		/* load tlb entry lower word */
    513 	andi.	%r3,%r1,PTE_G		/* check G-bit */
    514 	bne	4f			/* if guarded, take ISI */
    515 	mtctr	%r0			/* restore counter */
    516 	mfspr	%r0,SPR_IMISS		/* get the miss address for the tlbli */
    517 	mfsrr1	%r3			/* get the saved cr0 bits */
    518 	mtcrf	0x80,%r3		/* and restore */
    519 	ori	%r1,%r1,PTE_REF		/* set the reference bit */
    520 	mtspr	SPR_RPA,1		/* set the pte */
    521 	srwi	%r1,%r1,8		/* get byte 7 of pte */
    522 	tlbli	%r0			/* load the itlb */
    523 	stb	%r1,6(%r2)		/* update page table */
    524 	RFI
    525 
    526 3:	/* not found in pteg */
    527 	andi.	%r1,%r3,PTE_HID		/* have we already done second hash? */
    528 	bne	5f
    529 	mfspr	%r2,SPR_HASH2		/* get the second pointer */
    530 	ori	%r3,%r3,PTE_HID		/* change the compare value */
    531 	li	%r1,8
    532 	addi	%r2,%r2,-8		/* predec pointer */
    533 	b	1b
    534 4:	/* guarded */
    535 	mfsrr1	%r3
    536 	andi.	%r2,%r3,0xffff		/* clean upper srr1 */
    537 	oris	%r2,%r2,DSISR_PROTECT@h	/* set srr<4> to flag prot violation */
    538 	b	6f
    539 5:	/* not found anywhere */
    540 	mfsrr1	%r3
    541 	andi.	%r2,%r3,0xffff		/* clean upper srr1 */
    542 	oris	%r2,%r2,DSISR_NOTFOUND@h /* set srr1<1> to flag pte not found */
    543 6:
    544 	mtctr	%r0			/* restore counter */
    545 	mtsrr1	%r2
    546 	mfmsr	%r0
    547 	xoris	%r0,%r0,PSL_TGPR@h	/* flip the msr<tgpr> bit */
    548 	mtcrf	0x80,%r3		/* restore cr0 */
    549 	mtmsr	%r0			/* now with native gprs */
    550 	isync
    551 #if defined(PPC_HIGH_VEC)
    552 	ba	EXC_HIGHVEC+EXC_ISI
    553 #else
    554 	ba	EXC_ISI
    555 #endif
    556 _C_LABEL(tlbimsize) = .-_C_LABEL(tlbimiss)
    557 
    558 /* LINTSTUB: Var: int tlbdlmiss[1], tlbdlmsize[1]; */
    559 	.globl	_C_LABEL(tlbdlmiss),_C_LABEL(tlbdlmsize)
    560 _C_LABEL(tlbdlmiss):
    561 	mfspr	%r2,SPR_HASH1		/* get first pointer */
    562 	li	%r1,8
    563 	mfctr	%r0			/* save counter */
    564 	mfspr	%r3,SPR_DCMP		/* get first compare value */
    565 	addi	%r2,%r2,-8		/* predec pointer */
    566 1:
    567 	mtctr	%r1			/* load counter */
    568 2:
    569 	ldregu	%r1,8(%r2)		/* get next pte */
    570 	cmplw	%r1,%r3			/* see if found pte */
    571 	bdneq	2b			/* loop if not eq */
    572 	bne	3f			/* not found */
    573 	ldreg	%r1,4(%r2)		/* load tlb entry lower word */
    574 	mtctr	%r0			/* restore counter */
    575 	mfspr	%r0,SPR_DMISS		/* get the miss address for the tlbld */
    576 	mfsrr1	%r3			/* get the saved cr0 bits */
    577 	mtcrf	0x80,%r3		/* and restore */
    578 	ori	%r1,%r1,PTE_REF		/* set the reference bit */
    579 	mtspr	SPR_RPA,%r1		/* set the pte */
    580 	srwi	%r1,%r1,8		/* get byte 7 of pte */
    581 	tlbld	%r0			/* load the dtlb */
    582 	stb	%r1,6(%r2)		/* update page table */
    583 	RFI
    584 
    585 3:	/* not found in pteg */
    586 	andi.	%r1,%r3,PTE_HID		/* have we already done second hash? */
    587 	bne	5f
    588 	mfspr	%r2,SPR_HASH2		/* get the second pointer */
    589 	ori	%r3,%r3,PTE_HID		/* change the compare value */
    590 	li	%r1,8
    591 	addi	%r2,%r2,-8		/* predec pointer */
    592 	b	1b
    593 5:	/* not found anywhere */
    594 	mfsrr1	%r3
    595 	lis	%r1,DSISR_NOTFOUND@h	/* set dsisr<1> to flag pte not found */
    596 	mtctr	%r0			/* restore counter */
    597 	andi.	%r2,%r3,0xffff		/* clean upper srr1 */
    598 	mtsrr1	%r2
    599 	mtdsisr	%r1			/* load the dsisr */
    600 	mfspr	%r1,SPR_DMISS		/* get the miss address */
    601 	mtdar	%r1			/* put in dar */
    602 	mfmsr	%r0
    603 	xoris	%r0,%r0,PSL_TGPR@h	/* flip the msr<tgpr> bit */
    604 	mtcrf	0x80,%r3		/* restore cr0 */
    605 	mtmsr	%r0			/* now with native gprs */
    606 	isync
    607 #if defined(PPC_HIGH_VEC)
    608 	ba	EXC_HIGHVEC+EXC_DSI
    609 #else
    610 	ba	EXC_DSI
    611 #endif
    612 _C_LABEL(tlbdlmsize) = .-_C_LABEL(tlbdlmiss)
    613 
    614 /* LINTSTUB: Var: int tlbdsmiss[1], tlbdsmsize[1]; */
    615 	.globl	_C_LABEL(tlbdsmiss),_C_LABEL(tlbdsmsize)
    616 _C_LABEL(tlbdsmiss):
    617 	mfspr	%r2,SPR_HASH1		/* get first pointer */
    618 	li	%r1,8
    619 	mfctr	%r0			/* save counter */
    620 	mfspr	%r3,SPR_DCMP		/* get first compare value */
    621 	addi	%r2,%r2,-8		/* predec pointer */
    622 1:
    623 	mtctr	%r1			/* load counter */
    624 2:
    625 	ldregu	%r1,8(%r2)		/* get next pte */
    626 	cmplw	%r1,%r3			/* see if found pte */
    627 	bdneq	2b			/* loop if not eq */
    628 	bne	3f			/* not found */
    629 	ldreg	%r1,4(%r2)		/* load tlb entry lower word */
    630 	andi.	%r3,%r1,PTE_CHG		/* check the C-bit */
    631 	beq	4f
    632 5:
    633 	mtctr	%r0			/* restore counter */
    634 	mfspr	%r0,SPR_DMISS		/* get the miss address for the tlbld */
    635 	mfsrr1	%r3			/* get the saved cr0 bits */
    636 	mtcrf	0x80,%r3		/* and restore */
    637 	mtspr	SPR_RPA,%r1		/* set the pte */
    638 	tlbld	%r0			/* load the dtlb */
    639 	RFI
    640 
    641 3:	/* not found in pteg */
    642 	andi.	%r1,%r3,PTE_HID		/* have we already done second hash? */
    643 	bne	5f
    644 	mfspr	%r2,SPR_HASH2		/* get the second pointer */
    645 	ori	%r3,%r3,PTE_HID		/* change the compare value */
    646 	li	%r1,8
    647 	addi	%r2,%r2,-8		/* predec pointer */
    648 	b	1b
    649 4:	/* found, but C-bit = 0 */
    650 	rlwinm.	%r3,%r1,30,0,1		/* test PP */
    651 	bge-	7f
    652 	andi.	%r3,%r1,1
    653 	beq+	8f
    654 9:	/* found, but protection violation (PP==00)*/
    655 	mfsrr1	%r3
    656 	lis	%r1,(DSISR_PROTECT|DSISR_STORE)@h
    657 					/* indicate protection violation
    658 					   on store */
    659 	b	1f
    660 7:	/* found, PP=1x */
    661 	mfspr	%r3,SPR_DMISS		/* get the miss address */
    662 	mfsrin	%r1,%r3			/* get the segment register */
    663 	mfsrr1	%r3
    664 	rlwinm	%r3,%r3,18,31,31	/* get PR-bit */
    665 	rlwnm.	%r1,%r1,%r3,1,1		/* get the key */
    666 	bne-	9b			/* protection violation */
    667 8:	/* found, set reference/change bits */
    668 	ldreg	%r1,4(%r2)		/* reload tlb entry */
    669 	ori	%r1,%r1,(PTE_REF|PTE_CHG)
    670 	sth	%r1,6(%r2)
    671 	b	5b
    672 5:	/* not found anywhere */
    673 	mfsrr1	%r3
    674 	lis	%r1,(DSISR_NOTFOUND|DSISR_STORE)@h
    675 					/* set dsisr<1> to flag pte not found */
    676 					/* dsisr<6> to flag store */
    677 1:
    678 	mtctr	%r0			/* restore counter */
    679 	andi.	%r2,%r3,0xffff		/* clean upper srr1 */
    680 	mtsrr1	%r2
    681 	mtdsisr	%r1			/* load the dsisr */
    682 	mfspr	%r1,SPR_DMISS		/* get the miss address */
    683 	mtdar	%r1			/* put in dar */
    684 	mfmsr	%r0
    685 	xoris	%r0,%r0,PSL_TGPR@h	/* flip the msr<tgpr> bit */
    686 	mtcrf	0x80,%r3		/* restore cr0 */
    687 	mtmsr	%r0			/* now with native gprs */
    688 	isync
    689 #if defined(PPC_HIGH_VEC)
    690 	ba	EXC_HIGHVEC+EXC_DSI
    691 #else
    692 	ba	EXC_DSI
    693 #endif
    694 _C_LABEL(tlbdsmsize) = .-_C_LABEL(tlbdsmiss)
    695 #endif /* !PPC_OEA64 && !PPC_MPC8XX */
    696 
    697 #if defined(DDB) || defined(KGDB)
    698 /*
    699  * In case of DDB we want a separate trap catcher for it
    700  */
    701 	.local	ddbstk
    702 	.comm	ddbstk,INTSTK,8		/* ddb stack */
    703 
    704 /* LINTSTUB: Var: int ddblow[1], ddbsize[1]; */
    705 	.globl	_C_LABEL(ddblow),_C_LABEL(ddbsize)
    706 _C_LABEL(ddblow):
    707 	mtsprg1	%r1			/* save SP */
    708 	ENABLE_64BIT_BRIDGE(%r1)
    709 	mtsprg2 %r29			/* save r29 */
    710 	mfcr	%r29			/* save CR in r29 */
    711 	mfsrr1	%r1
    712 	mtcr	%r1
    713 	GET_CPUINFO(%r1)
    714 	bf	MSR_PR,1f		/* branch if privileged */
    715 	streg	%r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1)	/* free r28 */
    716 	mfsprg2	%r28
    717 	streg	%r28,(CI_TEMPSAVE+CPUSAVE_R29)(%r1)	/* free r29 */
    718 	streg	%r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1)	/* free r30 */
    719 	streg	%r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1)	/* free r31 */
    720 	mflr	%r28			/* save LR */
    721 #if defined(DISTANT_KERNEL)
    722 	lis	%r31,u_trap@ha
    723 	addi	%r31,%r31,u_trap@l
    724 	mtlr	%r31
    725 	blrl
    726 #else
    727 	bla	u_trap
    728 #endif
    729 1:
    730 	streg	%r28,(CI_DDBSAVE+CPUSAVE_R28)(%r1) /* save r28 */
    731 	mfsprg2	%r28
    732 	streg	%r28,(CI_DDBSAVE+CPUSAVE_R29)(%r1) /* save r29 */
    733 	streg	%r30,(CI_DDBSAVE+CPUSAVE_R30)(%r1) /* save r30 */
    734 	streg	%r31,(CI_DDBSAVE+CPUSAVE_R31)(%r1) /* save r31 */
    735 	mflr	%r28			/* save LR */
    736 	lis	%r1,ddbstk+INTSTK@ha	/* get new SP */
    737 	addi	%r1,%r1,ddbstk+INTSTK@l
    738 #if defined(DISTANT_KERNEL)
    739 	lis	%r31,ddbtrap@ha
    740 	addi	%r31,%r31,ddbtrap@l
    741 	mtlr	%r31
    742 	blrl
    743 #else
    744 	bla	ddbtrap
    745 #endif
    746 _C_LABEL(ddbsize) = .-_C_LABEL(ddblow)
    747 #endif	/* DDB || KGDB */
    748 
    749 /*
    750  * FRAME_SETUP assumes:
    751  *	SPRG1		SP (%r1)
    752  *	savearea	r28-r31,DAR,DSISR	(DAR & DSISR only for DSI traps)
    753  *	28		LR
    754  *	29		CR
    755  *	30		scratch
    756  *	31		scratch
    757  *	1		kernel stack
    758  *	LR		trap type
    759  *	SRR0/1		as at start of trap
    760  */
    761 #define	FRAME_SETUP(savearea)						\
    762 /* Have to enable translation to allow access of kernel stack: */	\
    763 	GET_CPUINFO(%r31);						\
    764 	mfsrr0	%r30;							\
    765 	streg	%r30,(savearea+CPUSAVE_SRR0)(%r31);	/* save SRR0 */	\
    766 	mfsrr1	%r30;							\
    767 	streg	%r30,(savearea+CPUSAVE_SRR1)(%r31);	/* save SRR1 */	\
    768 	mfmsr	%r30;							\
    769 	ori	%r30,%r30,(PSL_DR|PSL_IR);	/* turn on relocation */ \
    770 	mtmsr	%r30;			/* stack can be accessed now */	\
    771 	isync;								\
    772 	mfsprg1	%r31;			/* get saved SP */		\
    773 	stregu	%r31,-FRAMELEN(%r1);	/* save it in the callframe */	\
    774 	streg	%r0,FRAME_R0(%r1);	/* save R0 in the trapframe */ \
    775 	streg	%r31,FRAME_R1(%r1);	/* save SP in the trapframe */ \
    776 	streg	%r2,FRAME_R2(%r1);	/* save R2 in the trapframe */ \
    777 	streg	%r28,FRAME_LR(%r1);				\
    778 	stint	%r29,FRAME_CR(%r1);				\
    779 	GET_CPUINFO(%r2);						\
    780 	ldreg	%r31,(savearea+CPUSAVE_R31)(%r2); /* get saved r31 */	\
    781 	ldreg	%r30,(savearea+CPUSAVE_R30)(%r2); /* get saved r30 */	\
    782 	ldreg	%r29,(savearea+CPUSAVE_R29)(%r2); /* get saved r29 */	\
    783 	ldreg	%r28,(savearea+CPUSAVE_R28)(%r2); /* get saved r28 */	\
    784 	streg	%r3,FRAME_R3(%r1);	/* save r3 */		\
    785 	streg	%r4,FRAME_R4(%r1);	/* save r4 */		\
    786 	streg	%r5,FRAME_R5(%r1);	/* save r5 */		\
    787 	streg	%r6,FRAME_R6(%r1);	/* save r6 */		\
    788 	streg	%r7,FRAME_R7(%r1);	/* save r7 */		\
    789 	streg	%r8,FRAME_R8(%r1);	/* save r8 */		\
    790 	streg	%r9,FRAME_R9(%r1);	/* save r9 */		\
    791 	streg	%r10,FRAME_R10(%r1);	/* save r10 */		\
    792 	streg	%r11,FRAME_R11(%r1);	/* save r11 */		\
    793 	streg	%r12,FRAME_R12(%r1);	/* save r12 */		\
    794 	streg	%r13,FRAME_R13(%r1);	/* save r13 */		\
    795 	streg	%r14,FRAME_R14(%r1);	/* save r14 */		\
    796 	streg	%r15,FRAME_R15(%r1);	/* save r15 */		\
    797 	streg	%r16,FRAME_R16(%r1);	/* save r16 */		\
    798 	streg	%r17,FRAME_R17(%r1);	/* save r17 */		\
    799 	streg	%r18,FRAME_R18(%r1);	/* save r18 */		\
    800 	streg	%r19,FRAME_R19(%r1);	/* save r19 */		\
    801 	streg	%r20,FRAME_R20(%r1);	/* save r20 */		\
    802 	streg	%r21,FRAME_R21(%r1);	/* save r21 */		\
    803 	streg	%r22,FRAME_R22(%r1);	/* save r22 */		\
    804 	streg	%r23,FRAME_R23(%r1);	/* save r23 */		\
    805 	streg	%r24,FRAME_R24(%r1);	/* save r24 */		\
    806 	streg	%r25,FRAME_R25(%r1);	/* save r25 */		\
    807 	streg	%r26,FRAME_R26(%r1);	/* save r26 */		\
    808 	streg	%r27,FRAME_R27(%r1);	/* save r27 */		\
    809 	streg	%r28,FRAME_R28(%r1);	/* save r28 */		\
    810 	streg	%r29,FRAME_R29(%r1);	/* save r29 */		\
    811 	streg	%r30,FRAME_R30(%r1);	/* save r30 */		\
    812 	streg	%r31,FRAME_R31(%r1);	/* save r31 */		\
    813 	ldreg	%r28,(savearea+CPUSAVE_DAR)(%r2); /* get saved DAR */	\
    814 	ldreg	%r29,(savearea+CPUSAVE_DSISR)(%r2); /* get saved DSISR */ \
    815 	ldreg	%r30,(savearea+CPUSAVE_SRR0)(%r2); /* get saved SRR0 */	\
    816 	ldreg	%r31,(savearea+CPUSAVE_SRR1)(%r2); /* get saved SRR1 */	\
    817 	ldptr	%r13,CI_CURLWP(%r2);	/* get curlwp */	\
    818 	mfxer	%r3;						\
    819 	mfctr	%r4;						\
    820 	mflr	%r5;						\
    821 	andi.	%r5,%r5,0xff00;					\
    822 	stint	%r3,FRAME_XER(%r1);				\
    823 	streg	%r4,FRAME_CTR(%r1);				\
    824 	streg	%r30,FRAME_SRR0(%r1);			\
    825 	streg	%r31,FRAME_SRR1(%r1);			\
    826 	streg	%r28,FRAME_DAR(%r1);			\
    827 	stint	%r29,FRAME_DSISR(%r1);			\
    828 	stint	%r5,FRAME_EXC(%r1);			\
    829 	SAVE_VRSAVE(%r1,%r6);				\
    830 	SAVE_MQ(%r1,%r7)
    831 
    832 #define	FRAME_RESTORE_CALLEE					\
    833 	ldreg	%r31,FRAME_R31(%r1);	/* restore r31 */	\
    834 	ldreg	%r30,FRAME_R30(%r1);	/* restore r30 */	\
    835 	ldreg	%r29,FRAME_R29(%r1);	/* restore r29 */	\
    836 	ldreg	%r28,FRAME_R28(%r1);	/* restore r28 */	\
    837 	ldreg	%r27,FRAME_R27(%r1);	/* restore r27 */	\
    838 	ldreg	%r26,FRAME_R26(%r1);	/* restore r26 */	\
    839 	ldreg	%r25,FRAME_R25(%r1);	/* restore r25 */	\
    840 	ldreg	%r24,FRAME_R24(%r1);	/* restore r24 */	\
    841 	ldreg	%r23,FRAME_R23(%r1);	/* restore r23 */	\
    842 	ldreg	%r22,FRAME_R22(%r1);	/* restore r22 */	\
    843 	ldreg	%r21,FRAME_R21(%r1);	/* restore r21 */	\
    844 	ldreg	%r20,FRAME_R20(%r1);	/* restore r20 */	\
    845 	ldreg	%r19,FRAME_R19(%r1);	/* restore r19 */	\
    846 	ldreg	%r18,FRAME_R18(%r1);	/* restore r18 */	\
    847 	ldreg	%r17,FRAME_R17(%r1);	/* restore r17 */	\
    848 	ldreg	%r16,FRAME_R16(%r1);	/* restore r16 */	\
    849 	ldreg	%r15,FRAME_R15(%r1);	/* restore r15 */	\
    850 	ldreg	%r14,FRAME_R14(%r1);	/* restore r14 */
    851 
    852 #define	FRAME_LEAVE(savearea)					\
    853 /* Now restore regs: */						\
    854 	ldreg	%r2,FRAME_SRR0(%r1);				\
    855 	ldreg	%r3,FRAME_SRR1(%r1);				\
    856 	ldreg	%r4,FRAME_CTR(%r1);				\
    857 	ldint	%r5,FRAME_XER(%r1);				\
    858 	ldreg	%r6,FRAME_LR(%r1);				\
    859 	RESTORE_MQ(%r1,%r8);						\
    860 	RESTORE_VRSAVE(%r1,%r9);					\
    861 	GET_CPUINFO(%r7);						\
    862 	streg	%r2,(savearea+CPUSAVE_SRR0)(%r7); /* save SRR0 */	\
    863 	streg	%r3,(savearea+CPUSAVE_SRR1)(%r7); /* save SRR1 */	\
    864 	ldint	%r7,FRAME_CR(%r1);				\
    865 	mtctr	%r4;							\
    866 	mtxer	%r5;							\
    867 	mtlr	%r6;							\
    868 	mtsprg1	%r7;			/* save cr */			\
    869 	ldreg	%r13,FRAME_R13(%r1);	/* restore r13 */	\
    870 	ldreg	%r12,FRAME_R12(%r1);	/* restore r12 */	\
    871 	ldreg	%r11,FRAME_R11(%r1);	/* restore r11 */	\
    872 	ldreg	%r10,FRAME_R10(%r1);	/* restore r10 */	\
    873 	ldreg	%r9,FRAME_R9(%r1);	/* restore r9 */	\
    874 	ldreg	%r8,FRAME_R8(%r1);	/* restore r8 */	\
    875 	ldreg	%r7,FRAME_R7(%r1);	/* restore r7 */	\
    876 	ldreg	%r6,FRAME_R6(%r1);	/* restore r6 */	\
    877 	ldreg	%r5,FRAME_R5(%r1);	/* restore r5 */	\
    878 	ldreg	%r4,FRAME_R4(%r1);	/* restore r4 */	\
    879 	ldreg	%r3,FRAME_R3(%r1);	/* restore r3 */	\
    880 	ldreg	%r2,FRAME_R2(%r1);	/* restore r2 */	\
    881 	ldreg	%r0,FRAME_R0(%r1);	/* restore r0 */	\
    882 	ldreg	%r1,FRAME_R1(%r1);	/* restore old sp in r1 */ \
    883 /* Can't touch %r1 from here on */					\
    884 	mtsprg2	%r2;			/* save r2 & r3 */		\
    885 	mtsprg3	%r3;							\
    886 /* Disable translation, machine check and recoverability: */		\
    887 	mfmsr	%r2;							\
    888 	andi.	%r2,%r2,~(PSL_DR|PSL_IR|PSL_ME|PSL_RI)@l;		\
    889 	mtmsr	%r2;							\
    890 	isync;								\
    891 /* Decide whether we return to user mode: */				\
    892 	GET_CPUINFO(%r2);						\
    893 	ldreg	%r3,(savearea+CPUSAVE_SRR1)(%r2);			\
    894 	mtcr	%r3;							\
    895 	bf	MSR_PR,1f;		/* branch if PSL_PR is false */	\
    896 /* Restore user SRs */							\
    897 	RESTORE_USER_SRS(%r2,%r3);					\
    898 1:	mfsprg1	%r2;			/* restore cr */		\
    899 	mtcr	%r2;							\
    900 	GET_CPUINFO(%r2);						\
    901 	ldreg	%r3,(savearea+CPUSAVE_SRR0)(%r2);			\
    902 	mtsrr0	%r3;							\
    903 	ldreg	%r3,(savearea+CPUSAVE_SRR1)(%r2);			\
    904 	mtsrr1	%r3;							\
    905 	mfsprg2	%r2;			/* restore r2 & r3 */		\
    906 	mfsprg3	%r3
    907 
    908 /*
    909  * Preamble code for DSI/ISI traps
    910  */
    911 disitrap:
    912 	GET_CPUINFO(%r1)
    913 	ldreg	%r30,(CI_DISISAVE+CPUSAVE_R28)(%r1)
    914 	streg	%r30,(CI_TEMPSAVE+CPUSAVE_R28)(%r1)
    915 	ldreg	%r31,(CI_DISISAVE+CPUSAVE_R29)(%r1)
    916 	streg	%r31,(CI_TEMPSAVE+CPUSAVE_R29)(%r1)
    917 	ldreg	%r30,(CI_DISISAVE+CPUSAVE_R30)(%r1)
    918 	streg	%r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1)
    919 	ldreg	%r31,(CI_DISISAVE+CPUSAVE_R31)(%r1)
    920 	streg	%r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1)
    921 	mfdar	%r30
    922 	mfdsisr	%r31
    923 	streg	%r30,(CI_TEMPSAVE+CPUSAVE_DAR)(%r1)
    924 	streg	%r31,(CI_TEMPSAVE+CPUSAVE_DSISR)(%r1)
    925 
    926 #ifdef DDB
    927 	mfsrr1	%r31
    928 	mtcr	%r31
    929 	bt	MSR_PR,trapstart	/* branch is user mode */
    930 	mfsprg1	%r31			/* get old SP */
    931 #if 0
    932 	subf	%r30,%r30,%r31		/* subtract DAR from it */
    933 	addi	%r30,%r30,2048		/* offset result 1/2 page */
    934 	cmplwi	%cr0,%r30,4096		/* is DAR +- 1/2 page of SP? */
    935 #else
    936 	xor.	%r30,%r30,%r31		/* try xor most significant bits */
    937 	cmplwi	%cr0,%r30,4096		/* is DAR on same page as SP? */
    938 #endif
    939 	bge	%cr0,trapstart		/* no, too far away. */
    940 	/* Now convert this DSI into a DDB trap.  */
    941 	GET_CPUINFO(%r1)
    942 	ldreg	%r30,(CI_DISISAVE+CPUSAVE_R28)(%r1) /* get  r28 */
    943 	streg	%r30,(CI_DDBSAVE +CPUSAVE_R28)(%r1) /* save r28 */
    944 	ldreg	%r31,(CI_DISISAVE+CPUSAVE_R29)(%r1) /* get  r29 */
    945 	streg	%r31,(CI_DDBSAVE +CPUSAVE_R29)(%r1) /* save r29 */
    946 	ldreg	%r30,(CI_DISISAVE+CPUSAVE_R30)(%r1) /* get  r30 */
    947 	streg	%r30,(CI_DDBSAVE +CPUSAVE_R30)(%r1) /* save r30 */
    948 	ldreg	%r31,(CI_DISISAVE+CPUSAVE_R31)(%r1) /* get  r31 */
    949 	streg	%r31,(CI_DDBSAVE +CPUSAVE_R31)(%r1) /* save r31 */
    950 	lis	%r1,ddbstk+INTSTK@ha	/* get new SP */
    951 	addi	%r1,%r1,ddbstk+INTSTK@l
    952 	b	ddbtrap
    953 #endif
    954 
    955 	.globl	_C_LABEL(trapstart)
    956 	.type	_C_LABEL(trapstart),@function
    957 _C_LABEL(trapstart):
    958 realtrap:
    959 /* Test whether we already had PR set */
    960 	mfsrr1	%r1
    961 	mtcr	%r1
    962 	mfsprg1	%r1			/* restore SP (might have been
    963 					   overwritten) */
    964 s_trap:
    965 	bf	MSR_PR,k_trap		/* branch if PSL_PR is false */
    966 	GET_CPUINFO(%r1)		/* get cpu_info for this cpu */
    967 u_trap:
    968 	ldptr	%r1,CI_CURPCB(%r1)
    969 	addi	%r1,%r1,USPACE-CALLFRAMELEN /* stack is top of user struct */
    970 
    971 /*
    972  * Now the common trap catching code.
    973  */
    974 
    975 	RESTORE_KERN_SRS(%r30,%r31)	/* First enable KERNEL mapping */
    976 
    977 k_trap:
    978 	FRAME_SETUP(CI_TEMPSAVE)
    979 trapagain:
    980 /* Now we can recover interrupts again: */
    981 	mfmsr	%r7
    982 	ldreg	%r6, FRAME_SRR1(%r1)
    983 	andi.	%r6,%r6,(PSL_EE|PSL_ME|PSL_RI)@l
    984 	or	%r7,%r7,%r6
    985 	mtmsr	%r7
    986 	isync
    987 /* Call C trap code: */
    988 	addi	%r3,%r1,FRAME_TF
    989 	bl	_C_LABEL(trap)
    990 /* LINTSTUB: Var: int trapexit[1]; */
    991 	.globl	trapexit
    992 trapexit:
    993 /* Disable interrupts: */
    994 	mfmsr	%r3
    995 	andi.	%r3,%r3,~PSL_EE@l
    996 	mtmsr	%r3
    997 /* Test AST pending: */
    998 	mtcr	%r31
    999 	bf	MSR_PR,trapleave	/* branch if PSL_PR is false */
   1000 	ldint	%r4,L_MD_ASTPENDING(%r13)
   1001 	andi.	%r4,%r4,1
   1002 	beq	trapleave
   1003 
   1004 	li	%r6,EXC_AST
   1005 	stint	%r6,FRAME_EXC(%r1)
   1006 	b	trapagain
   1007 
   1008 trapleave:
   1009 	FRAME_RESTORE_CALLEE
   1010 intrleave:
   1011 	FRAME_LEAVE(CI_TEMPSAVE)
   1012 	RFI
   1013 
   1014 /*
   1015  * Trap handler for syscalls (EXC_SC)
   1016  */
   1017 /* LINTSTUB: Var: int sctrap[1], scsize[1]; */
   1018 	.globl	_C_LABEL(sctrap),_C_LABEL(scsize),_C_LABEL(sctrapexit)
   1019 _C_LABEL(sctrap):
   1020 	mtsprg1	%r1			/* save SP */
   1021 	ENABLE_64BIT_BRIDGE(%r1)
   1022 	GET_CPUINFO(%r1)
   1023 	streg	%r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1) /* save r28 */
   1024 	streg	%r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1) /* save r20 */
   1025 	streg	%r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1) /* save r30 */
   1026 	streg	%r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1) /* save r31 */
   1027 	mflr	%r28			/* save LR */
   1028 	mfcr	%r29			/* save CR */
   1029 #if defined(DISTANT_KERNEL)
   1030 	lis	%r31,s_sctrap@ha
   1031 	addi	%r31,%r31,s_sctrap@l
   1032 	mtlr	%r31
   1033 	blrl
   1034 #else
   1035 	bla	s_sctrap
   1036 #endif
   1037 	_C_LABEL(scsize) = .-_C_LABEL(sctrap)
   1038 
   1039 s_sctrap:
   1040 	GET_CPUINFO(%r1)
   1041 	ldptr	%r1,CI_CURPCB(%r1)
   1042 	addi	%r1,%r1,USPACE-CALLFRAMELEN /* stack is top of user struct */
   1043 	RESTORE_KERN_SRS(%r30,%r31)	/* First enable KERNEL mapping */
   1044 	FRAME_SETUP(CI_TEMPSAVE)
   1045 /* Now we can recover interrupts again: */
   1046 	mfmsr	%r7
   1047 	ori	%r7,%r7,(PSL_EE|PSL_ME|PSL_RI)@l
   1048 	mtmsr	%r7
   1049 	isync
   1050 	addi	%r3,%r1,FRAME_TF
   1051 /* Call the appropriate syscall handler: */
   1052 	ldptr	%r4,L_PROC(%r13)
   1053 	ldptr	%r4,P_MD_SYSCALL(%r4)
   1054 	mtctr	%r4
   1055 	bctrl
   1056 _C_LABEL(sctrapexit):
   1057 	b	trapexit
   1058 
   1059 /*
   1060  * External interrupt second level handler
   1061  */
   1062 /*
   1063  * INTR_SETUP assumes:
   1064  *	SPRG1		SP (%r1)
   1065  *	savearea	r28-r31
   1066  *	28		LR
   1067  *	29		CR
   1068  *	30		scratch
   1069  *	31		scratch
   1070  *	1		kernel stack
   1071  *	SRR0/1		as at start of exception
   1072  */
   1073 #define	INTR_SETUP(savearea,exc)					\
   1074 /* Have to enable translation to allow access of kernel stack: */	\
   1075 	GET_CPUINFO(%r31);						\
   1076 	mfsrr0	%r30;							\
   1077 	streg	%r30,(savearea+CPUSAVE_SRR0)(%r31);	/* save SRR0 */	\
   1078 	mfsrr1	%r30;							\
   1079 	streg	%r30,(savearea+CPUSAVE_SRR1)(%r31);	/* save SRR1 */	\
   1080 	mfmsr	%r30;							\
   1081 	ori	%r30,%r30,(PSL_DR|PSL_IR);	/* turn on relocation */ \
   1082 	mtmsr	%r30;			/* stack can be accessed now */	\
   1083 	isync;								\
   1084 	mfsprg1	%r31;			/* get saved SP */		\
   1085 	stregu	%r31,-FRAMELEN(%r1);	/* save it in the callframe */	\
   1086 	streg	%r0,FRAME_R0(%r1);	/* save R0 in the trapframe */ \
   1087 	streg	%r31,FRAME_R1(%r1);	/* save SP in the trapframe */ \
   1088 	streg	%r2,FRAME_R2(%r1);	/* save R2 in the trapframe */ \
   1089 	streg	%r28,FRAME_LR(%r1);				\
   1090 	stint	%r29,FRAME_CR(%r1);				\
   1091 	GET_CPUINFO(%r2);						\
   1092 	ldreg	%r31,(savearea+CPUSAVE_R31)(%r2); /* get saved r31 */	\
   1093 	ldreg	%r30,(savearea+CPUSAVE_R30)(%r2); /* get saved r30 */	\
   1094 	ldreg	%r29,(savearea+CPUSAVE_R29)(%r2); /* get saved r29 */	\
   1095 	ldreg	%r28,(savearea+CPUSAVE_R28)(%r2); /* get saved r28 */	\
   1096 	streg	%r3,FRAME_R3(%r1);	/* save r3 */		\
   1097 	streg	%r4,FRAME_R4(%r1);	/* save r4 */		\
   1098 	streg	%r5,FRAME_R5(%r1);	/* save r5 */		\
   1099 	streg	%r6,FRAME_R6(%r1);	/* save r6 */		\
   1100 	streg	%r7,FRAME_R7(%r1);	/* save r7 */		\
   1101 	streg	%r8,FRAME_R8(%r1);	/* save r8 */		\
   1102 	streg	%r9,FRAME_R9(%r1);	/* save r9 */		\
   1103 	streg	%r10,FRAME_R10(%r1);	/* save r10 */		\
   1104 	streg	%r11,FRAME_R11(%r1);	/* save r11 */		\
   1105 	streg	%r12,FRAME_R12(%r1);	/* save r12 */		\
   1106 	streg	%r13,FRAME_R13(%r1);	/* save r13 */		\
   1107 	ldreg	%r11,(savearea+CPUSAVE_SRR0)(%r2); /* get saved SRR0 */	\
   1108 	ldreg	%r12,(savearea+CPUSAVE_SRR1)(%r2); /* get saved SRR1 */	\
   1109 	ldptr	%r13,CI_CURLWP(%r2);	/* get curlwp */	\
   1110 	ldint	%r3,CI_IDEPTH(%r2);					\
   1111 	stint	%r3,FRAME_IDEPTH(%r1);					\
   1112 	mfxer	%r3;							\
   1113 	mfctr	%r4;							\
   1114 	li	%r5,exc;						\
   1115 	stint	%r5,FRAME_EXC(%r1);					\
   1116 	stint	%r3,FRAME_XER(%r1);					\
   1117 	streg	%r4,FRAME_CTR(%r1);					\
   1118 	streg	%r11,FRAME_SRR0(%r1);					\
   1119 	streg	%r12,FRAME_SRR1(%r1);					\
   1120 	mfmsr	%r6;							\
   1121 	ori	%r6,%r6,PSL_RI;		/* turn on recovery interrupt */\
   1122 	mtmsr	%r6;							\
   1123 	SAVE_VRSAVE(%r1,%r6);						\
   1124 	SAVE_MQ(%r1,%r7)
   1125 
   1126 /* LINTSTUB: Var: int extint_call[1]; */
   1127 /*
   1128  * R1=sp, R28=LR, R29=CR, R30=scratch, R31=scratch
   1129  */
   1130 	.globl	_C_LABEL(extint_call)
   1131 extintr:
   1132 	INTR_SETUP(CI_TEMPSAVE, EXC_EXI)
   1133 					/* make trapframe available */
   1134 	addi	%r3,%r1,FRAME_TF	/* kern frame -> trap frame */
   1135 _C_LABEL(extint_call):
   1136 	bl	_C_LABEL(extint_call)	/* to be filled in later */
   1137 
   1138 intr_exit:
   1139 /* Disable interrupts (should already be disabled) but not MMU here: */
   1140 	mfmsr	%r3
   1141 	andi.	%r3,%r3,~(PSL_EE|PSL_ME|PSL_RI)@l
   1142 	mtmsr	%r3
   1143 	isync
   1144 
   1145 /* Returning to user mode? */
   1146 	ldreg	%r4,FRAME_SRR1(%r1)
   1147 	mtcr	%r4			/* saved SRR1 */
   1148 	bf	MSR_PR,intrleave	/* branch if PSL_PR is false */
   1149 
   1150 	ldint	%r3,L_MD_ASTPENDING(%r13) /* Test AST pending */
   1151 	andi.	%r3,%r3,1
   1152 	beq	intrleave		/* common frame exit */
   1153 
   1154 /*
   1155  * Since interrupts save their state in a std trapframe, all we need to do to
   1156  * process the AST is finish filling the trapframe with the rest of the fixed
   1157  * registers and let trap deal with it.
   1158  */
   1159 	streg	%r14,FRAME_R14(%r1)
   1160 	streg	%r15,FRAME_R15(%r1)
   1161 	streg	%r16,FRAME_R16(%r1)
   1162 	streg	%r17,FRAME_R17(%r1)
   1163 	streg	%r18,FRAME_R18(%r1)
   1164 	streg	%r19,FRAME_R19(%r1)
   1165 	streg	%r20,FRAME_R20(%r1)
   1166 	streg	%r21,FRAME_R21(%r1)
   1167 	streg	%r22,FRAME_R22(%r1)
   1168 	streg	%r23,FRAME_R23(%r1)
   1169 	streg	%r24,FRAME_R24(%r1)
   1170 	streg	%r25,FRAME_R25(%r1)
   1171 	streg	%r26,FRAME_R26(%r1)
   1172 	streg	%r27,FRAME_R27(%r1)
   1173 	streg	%r28,FRAME_R28(%r1)
   1174 	streg	%r29,FRAME_R29(%r1)
   1175 	streg	%r30,FRAME_R30(%r1)
   1176 	streg	%r31,FRAME_R31(%r1)
   1177 
   1178 	/*
   1179 	 * Tell trap we are doing an AST.
   1180 	 */
   1181 	li	%r6,EXC_AST
   1182 	stint	%r6,FRAME_EXC(%r1)
   1183 
   1184 	mr	%r31, %r4		/* trapagain wants SRR1 in %r31 */
   1185 	b	trapagain
   1186 
   1187 /*
   1188  * Decrementer interrupt second level handler
   1189  */
   1190 decrintr:
   1191 	INTR_SETUP(CI_TEMPSAVE, EXC_DECR)
   1192 
   1193 	addi	%r3,%r1,FRAME_CF	/* intr frame -> clock frame */
   1194 	bl	_C_LABEL(decr_intr)
   1195 	b	intr_exit
   1196 
   1197 #ifdef DDB
   1198 /*
   1199  * Deliberate entry to ddbtrap
   1200  */
   1201 	.globl	_C_LABEL(ddb_trap)
   1202 _C_LABEL(ddb_trap):
   1203 	mtsprg1	%r1
   1204 	mfmsr	%r3
   1205 	mtsrr1	%r3
   1206 	andi.	%r3,%r3,~(PSL_EE|PSL_ME)@l
   1207 	mtmsr	%r3			/* disable interrupts */
   1208 	isync
   1209 	ENABLE_64BIT_BRIDGE(%r3)
   1210 	GET_CPUINFO(%r3)
   1211 	streg	%r28,(CI_DDBSAVE+CPUSAVE_R28)(%r3)
   1212 	streg	%r29,(CI_DDBSAVE+CPUSAVE_R29)(%r3)
   1213 	streg	%r30,(CI_DDBSAVE+CPUSAVE_R30)(%r3)
   1214 	streg	%r31,(CI_DDBSAVE+CPUSAVE_R31)(%r3)
   1215 	mflr	%r28
   1216 	li	%r29,EXC_BPT
   1217 	mtlr	%r29
   1218 	mfcr	%r29
   1219 	mtsrr0	%r28
   1220 #endif /* DDB */
   1221 
   1222 #if defined(DDB) || defined(KGDB)
   1223 /*
   1224  * Now the ddb trap catching code.
   1225  */
   1226 ddbtrap:
   1227 	FRAME_SETUP(CI_DDBSAVE)
   1228 /* Call C trap code: */
   1229 	addi	%r3,%r1,FRAME_TF
   1230 	bl	_C_LABEL(ddb_trap_glue)
   1231 	or.	%r3,%r3,%r3
   1232 	beq	trapagain
   1233 	FRAME_RESTORE_CALLEE
   1234 	FRAME_LEAVE(CI_DDBSAVE)
   1235 	RFI
   1236 #endif /* DDB || KGDB */
   1237 
   1238 	.globl	_C_LABEL(trapend)
   1239 _C_LABEL(trapend):
   1240 
   1241 /*
   1242  * All OEA have FPUs so include this too.  Some OEA have AltiVec so include
   1243  * that too.
   1244  */
   1245 #if !defined(PPC_MPC8XX)
   1246 #include <powerpc/powerpc/fpu_subr.S>
   1247 #include <powerpc/oea/altivec_subr.S>
   1248 #endif
   1249