xref: /netbsd-src/sys/arch/powerpc/powerpc/trap_subr.S (revision d339aae03fba759372c457f57e3c514b7be60866)
1/*	$NetBSD: trap_subr.S,v 1.86 2022/05/18 13:56:32 andvar 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
290dsitrap_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),  follored 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 */
302dsitrap_fix_dbat5:
303	mtspr	SPR_DBAT5U,%r30
304	mtspr	SPR_DBAT5L,%r31
305	b	8f
306dsitrap_fix_dbat6:
307	bt	30,3f
308	mtspr	SPR_DBAT6U,%r30
309	mtspr	SPR_DBAT6L,%r31
310	b	8f
3113:
312dsitrap_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 */
3198:
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 */
3311:
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
3942:
395	mtibatu	3,%r31
396	mtibatl	3,%r30
3973:
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 */
4091:
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)
4461:
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)
4801:
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 */
5051:
506	mtctr	%r1			/* load counter */
5072:
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
5263:	/* 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
5344:	/* 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
5395:	/* 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 */
5436:
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 */
5661:
567	mtctr	%r1			/* load counter */
5682:
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
5853:	/* 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
5935:	/* 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 */
6221:
623	mtctr	%r1			/* load counter */
6242:
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
6325:
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
6413:	/* 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
6494:	/* 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
6549:	/* 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
6607:	/* 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 */
6678:	/* 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
6725:	/* 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 */
6771:
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
7291:
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);					\
8981:	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 */
911disitrap:
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):
958realtrap:
959/* Test whether we already had PR set */
960	mfsrr1	%r1
961	mtcr	%r1
962	mfsprg1	%r1			/* restore SP (might have been
963					   overwritten) */
964s_trap:
965	bf	MSR_PR,k_trap		/* branch if PSL_PR is false */
966	GET_CPUINFO(%r1)		/* get cpu_info for this cpu */
967u_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
977k_trap:
978	FRAME_SETUP(CI_TEMPSAVE)
979trapagain:
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
992trapexit:
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
1008trapleave:
1009	FRAME_RESTORE_CALLEE
1010intrleave:
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
1039s_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)
1131extintr:
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
1138intr_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 */
1190decrintr:
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 */
1226ddbtrap:
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