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