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