trap_subr64.S revision 96253
1/* $FreeBSD: head/sys/powerpc/aim/trap_subr.S 96253 2002-05-09 14:15:51Z benno $ */
2/* $NetBSD: trap_subr.S,v 1.20 2002/04/22 23:20:08 kleink Exp $	*/
3
4/*
5 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
6 * Copyright (C) 1995, 1996 TooLs GmbH.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *	This product includes software developed by TooLs GmbH.
20 * 4. The name of TooLs GmbH may not be used to endorse or promote products
21 *    derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35/*
36 * NOTICE: This is not a standalone file.  to use it, #include it in
37 * your port's locore.S, like so:
38 *
39 *	#include <powerpc/powerpc/trap_subr.S>
40 */
41
42/*
43 * XXX Fake AST trap vector.  This is here until we work out how to safely
44 * remove the AST code.
45 */
46#define	EXC_AST	0x3000
47	.data
48	.align	4
49astpending:
50	.long	0
51cpassert:
52	.asciz	"attempting to return from kernel with no current pmap"
53
54/*
55 * Data used during primary/secondary traps/interrupts
56 */
57#define	tempsave	EXC_MCHK+0xe0 /* primary save area for trap handling */
58#define	disisave	EXC_DSI+0xe0  /* primary save area for dsi/isi traps */
59
60/*
61 * XXX Interrupt and spill stacks need to be per-CPU.
62 */
63	.data
64	.align	4
65intstk:
66	.space	INTSTK		/* interrupt stack */
67
68GLOBAL(intr_depth)
69	.long	-1		/* in-use marker */
70
71	.comm	spillstk,SPILLSTK,8
72
73/*
74 * This code gets copied to all the trap vectors
75 * (except ISI/DSI, ALI, the interrupts, and possibly the debugging
76 * traps when using IPKDB).
77 */
78	.text
79	.globl	_C_LABEL(trapcode),_C_LABEL(trapsize)
80_C_LABEL(trapcode):
81	mtsprg	1,1			/* save SP */
82	stmw	28,tempsave(0)		/* free r28-r31 */
83	mflr	28			/* save LR */
84	mfcr	29			/* save CR */
85/* Test whether we already had PR set */
86	mfsrr1	31
87	mtcr	31
88	bc	4,17,1f			/* branch if PSL_PR is clear */
89	mfsprg	31,0
90	lwz	1,PC_CURPCB(31)
91	addi	1,1,USPACE		/* stack is top of user struct */
921:
93	bla	s_trap
94_C_LABEL(trapsize) = .-_C_LABEL(trapcode)
95
96/*
97 * For ALI: has to save DSISR and DAR
98 */
99	.globl	_C_LABEL(alitrap),_C_LABEL(alisize)
100_C_LABEL(alitrap):
101	mtsprg	1,1			/* save SP */
102	stmw	28,tempsave(0)		/* free r28-r31 */
103	mfdar	30
104	mfdsisr	31
105	stmw	30,tempsave+16(0)
106	mflr	28			/* save LR */
107	mfcr	29			/* save CR */
108/* Test whether we already had PR set */
109	mfsrr1	31
110	mtcr	31
111	bc	4,17,1f			/* branch if PSL_PR is clear */
112	mfsprg	31,0
113	lwz	1,PC_CURPCB(31)
114	addi	1,1,USPACE		/* stack is top of user struct */
1151:
116	bla	s_trap
117_C_LABEL(alisize) = .-_C_LABEL(alitrap)
118
119/*
120 * Similar to the above for DSI
121 * Has to handle BAT spills
122 * and standard pagetable spills
123 */
124	.globl	_C_LABEL(dsitrap),_C_LABEL(dsisize)
125_C_LABEL(dsitrap):
126	stmw	28,disisave(0)		/* free r28-r31 */
127	mfcr	29			/* save CR */
128	mfxer	30			/* save XER */
129	mtsprg	2,30			/* in SPRG2 */
130	mfsrr1	31			/* test kernel mode */
131	mtcr	31
132	bc	12,17,1f		/* branch if PSL_PR is set */
133	mfdar	31			/* get fault address */
134	rlwinm	31,31,7,25,28		/* get segment * 8 */
135
136	/* get batu */
137	addis	31,31,_C_LABEL(battable)@ha
138	lwz	30,_C_LABEL(battable)@l(31)
139	mtcr	30
140	bc	4,30,1f			/* branch if supervisor valid is
141					   false */
142	/* get batl */
143	lwz	31,_C_LABEL(battable)+4@l(31)
144/* We randomly use the highest two bat registers here */
145	mftb	28
146	andi.	28,28,1
147	bne	2f
148	mtdbatu	2,30
149	mtdbatl	2,31
150	b	3f
1512:
152	mtdbatu	3,30
153	mtdbatl	3,31
1543:
155	mfsprg	30,2			/* restore XER */
156	mtxer	30
157	mtcr	29			/* restore CR */
158	lmw	28,disisave(0)		/* restore r28-r31 */
159	rfi				/* return to trapped code */
1601:
161	mflr	28			/* save LR */
162	bla	s_dsitrap
163_C_LABEL(dsisize) = .-_C_LABEL(dsitrap)
164
165/*
166 * Dedicated MPC601 version of the above.
167 * Considers different BAT format and combined implementation
168 * (being addressed as I-BAT).
169 */
170	.globl	_C_LABEL(dsitrap601),_C_LABEL(dsi601size)
171_C_LABEL(dsitrap601):
172	stmw	28,disisave(0)		/* free r28-r31 */
173	mfcr	29			/* save CR */
174	mfxer	30			/* save XER */
175	mtsprg	2,30			/* in SPRG2 */
176	mfsrr1	31			/* test kernel mode */
177	mtcr	31
178	bc	12,17,1f		/* branch if PSL_PR is set */
179	mfdar	31			/* get fault address */
180	rlwinm	31,31,12,20,28		/* get "segment" battable offset */
181
182	/* get batl */
183	addis	31,31,_C_LABEL(battable)@ha
184	lwz	30,_C_LABEL(battable)+4@l(31)
185	mtcr	30
186	bc	4,25,1f			/* branch if Valid is is false,
187					   presently assumes supervisor only */
188
189	/* get batu */
190	lwz	31,_C_LABEL(battable)@l(31)
191/* We randomly use the highest two bat registers here */
192	mfspr	28,SPR_RTCL_R
193	andi.	28,28,128
194	bne	2f
195	mtibatu	2,31
196	mtibatl	2,30
197	b	3f
1982:
199	mtibatu	3,31
200	mtibatl	3,30
2013:
202	mfsprg	30,2			/* restore XER */
203	mtxer	30
204	mtcr	29			/* restore CR */
205	lmw	28,disisave(0)		/* restore r28-r31 */
206	rfi				/* return to trapped code */
2071:
208	mflr	28			/* save LR */
209	bla	s_dsitrap
210_C_LABEL(dsi601size) = .-_C_LABEL(dsitrap601)
211
212/*
213 * Similar to the above for ISI
214 */
215	.globl	_C_LABEL(isitrap),_C_LABEL(isisize)
216_C_LABEL(isitrap):
217	stmw	28,disisave(0)		/* free r28-r31 */
218	mflr	28			/* save LR */
219	mfcr	29			/* save CR */
220	mfsrr1	31			/* test kernel mode */
221	mtcr	31
222	bc	12,17,1f		/* branch if PSL_PR is set */
223	mfsrr0	31			/* get fault address */
224	rlwinm	31,31,7,25,28		/* get segment * 8 */
225
226	/* get batu */
227	addis	31,31,_C_LABEL(battable)@ha
228	lwz	30,_C_LABEL(battable)@l(31)
229	mtcr	30
230	bc	4,30,1f			/* branch if supervisor valid is
231					   false */
232	mtibatu	3,30
233
234	/* get batl */
235	lwz	30,_C_LABEL(battable)+4@l(31)
236	mtibatl	3,30
237
238	mtcr	29			/* restore CR */
239	lmw	28,disisave(0)		/* restore r28-r31 */
240	rfi				/* return to trapped code */
2411:
242	bla	s_isitrap
243_C_LABEL(isisize)= .-_C_LABEL(isitrap)
244
245/*
246 * Dedicated MPC601 version of the above.
247 * Considers different BAT format.
248 */
249	.globl	_C_LABEL(isitrap601),_C_LABEL(isi601size)
250_C_LABEL(isitrap601):
251	stmw	28,disisave(0)		/* free r28-r31 */
252	mflr	28			/* save LR */
253	mfcr	29			/* save CR */
254	mfsrr1	31			/* test kernel mode */
255	mtcr	31
256	bc	12,17,1f		/* branch if PSL_PR is set */
257	mfsrr0	31			/* get fault address */
258	rlwinm	31,31,12,20,28		/* get "segment" battable offset */
259
260	/* get batl */
261	addis	31,31,_C_LABEL(battable)@ha
262	lwz	30,_C_LABEL(battable)+4@l(31)
263	mtcr	30
264	bc	4,25,1f			/* branch if Valid is is false,
265					   presently assumes supervisor only */
266	/* get batu */
267	lwz	31,_C_LABEL(battable)@l(31)
268
269	mtibatu	3,31
270	mtibatl	3,30
271
272	mtcr	29			/* restore CR */
273	lmw	28,disisave(0)		/* restore r28-r31 */
274	rfi				/* return to trapped code */
2751:
276	bla	s_isitrap
277_C_LABEL(isi601size)= .-_C_LABEL(isitrap601)
278
279/*
280 * This one for the external interrupt handler.
281 */
282	.globl	_C_LABEL(extint),_C_LABEL(extsize)
283_C_LABEL(extint):
284	mtsprg	1,1			/* save SP */
285	stmw	28,tempsave(0)		/* free r28-r31 */
286	mflr	28			/* save LR */
287	mfcr	29			/* save CR */
288	mfxer	30			/* save XER */
289	lis	1,intstk+INTSTK@ha	/* get interrupt stack */
290	addi	1,1,intstk+INTSTK@l	/* this is really intr_depth! */
291	lwz	31,0(1)			/* were we already running on intstk? */
292	addic.	31,31,1
293	stw	31,0(1)
294	beq	1f
295	mfsprg	1,1			/* yes, get old SP */
2961:
297	ba	extintr
298_C_LABEL(extsize) = .-_C_LABEL(extint)
299
300/*
301 * And this one for the decrementer interrupt handler.
302 */
303	.globl	_C_LABEL(decrint),_C_LABEL(decrsize)
304_C_LABEL(decrint):
305	mtsprg	1,1			/* save SP */
306	stmw	28,tempsave(0)		/* free r28-r31 */
307	mflr	28			/* save LR */
308	mfcr	29			/* save CR */
309	mfxer	30			/* save XER */
310	lis	1,intstk+INTSTK@ha	/* get interrupt stack */
311	addi	1,1,intstk+INTSTK@l
312	lwz	31,0(1)			/* were we already running on intstk? */
313	addic.	31,31,1
314	stw	31,0(1)
315	beq	1f
316	mfsprg	1,1			/* yes, get old SP */
3171:
318	ba	decrintr
319_C_LABEL(decrsize) = .-_C_LABEL(decrint)
320
321/*
322 * Now the tlb software load for 603 processors:
323 * (Code essentially from the 603e User Manual, Chapter 5, but
324 * corrected a lot.)
325 */
326
327	.globl	_C_LABEL(tlbimiss),_C_LABEL(tlbimsize)
328_C_LABEL(tlbimiss):
329#ifdef PMAPDEBUG
330	mfspr	2,SPR_IMISS		/* exception address */
331	li	1,24			/* get rid of the lower */
332	srw	2,2,1			/*   24 bits */
333	li	1,1			/* Load 1 */
334	cmpl	2,1,1			/* is it > 16MB */
335	blt	99f			/* nope, skip saving these SPRs */
336	li	1,0xc0			/* arbitrary */
337	mfspr	2,SPR_HASH1
338	stw	2,0(1)
339	mfspr	2,SPR_HASH2
340	stw	2,4(1)
341	mfspr	2,SPR_IMISS
342	stw	2,8(1)
343	mfspr	2,SPR_ICMP
344	stw	2,12(1)
34599:
346#endif /* PMAPDEBUG */
347	mfspr	2,SPR_HASH1		/* get first pointer */
348	li	1,8
349	mfctr	0			/* save counter */
350	mfspr	3,SPR_ICMP		/* get first compare value */
351	addi	2,2,-8			/* predec pointer */
3521:
353	mtctr	1			/* load counter */
3542:
355	lwzu	1,8(2)			/* get next pte */
356	cmpl	0,1,3			/* see if found pte */
357	bdneq	2b			/* loop if not eq */
358	bne	3f			/* not found */
359	lwz	1,4(2)			/* load tlb entry lower word */
360	andi.	3,1,8			/* check G-bit */
361	bne	4f			/* if guarded, take ISI */
362	mtctr	0			/* restore counter */
363	mfspr	0,SPR_IMISS		/* get the miss address for the tlbli */
364	mfsrr1	3			/* get the saved cr0 bits */
365	mtcrf	0x80,3			/* and restore */
366	ori	1,1,0x100		/* set the reference bit */
367	mtspr	SPR_RPA,1		/* set the pte */
368	srwi	1,1,8			/* get byte 7 of pte */
369	tlbli	0			/* load the itlb */
370	stb	1,6(2)			/* update page table */
371	rfi
372
3733:	/* not found in pteg */
374	andi.	1,3,0x40		/* have we already done second hash? */
375	bne	5f
376	mfspr	2,SPR_HASH2		/* get the second pointer */
377	ori	3,3,0x40		/* change the compare value */
378	li	1,8
379	addi	2,2,-8			/* predec pointer */
380	b	1b
3814:	/* guarded */
382	mfsrr1	3
383	andi.	2,3,0xffff		/* clean upper srr1 */
384	oris	2,2,0x8000000@h		/* set srr<4> to flag prot violation */
385	b	6f
3865:	/* not found anywhere */
387	mfsrr1	3
388	andi.	2,3,0xffff		/* clean upper srr1 */
389	oris	2,2,0x40000000@h	/* set srr1<1> to flag pte not found */
3906:
391	mtctr	0			/* restore counter */
392	mtsrr1	2
393	mfmsr	0
394	xoris	0,0,0x20000@h		/* flip the msr<tgpr> bit */
395	mtcrf	0x80,3			/* restore cr0 */
396	mtmsr	0			/* now with native gprs */
397	isync
398	ba	EXC_ISI
399_C_LABEL(tlbimsize) = .-_C_LABEL(tlbimiss)
400
401	.globl	_C_LABEL(tlbdlmiss),_C_LABEL(tlbdlmsize)
402_C_LABEL(tlbdlmiss):
403	mfspr	2,SPR_HASH1		/* get first pointer */
404	li	1,8
405	mfctr	0			/* save counter */
406	mfspr	3,SPR_DCMP		/* get first compare value */
407	addi	2,2,-8			/* predec pointer */
4081:
409	mtctr	1			/* load counter */
4102:
411	lwzu	1,8(2)			/* get next pte */
412	cmpl	0,1,3			/* see if found pte */
413	bdneq	2b			/* loop if not eq */
414	bne	3f			/* not found */
415	lwz	1,4(2)			/* load tlb entry lower word */
416	mtctr	0			/* restore counter */
417	mfspr	0,SPR_DMISS		/* get the miss address for the tlbld */
418	mfsrr1	3			/* get the saved cr0 bits */
419	mtcrf	0x80,3			/* and restore */
420	ori	1,1,0x100		/* set the reference bit */
421	mtspr	SPR_RPA,1			/* set the pte */
422	srwi	1,1,8			/* get byte 7 of pte */
423	tlbld	0			/* load the dtlb */
424	stb	1,6(2)			/* update page table */
425	rfi
426
4273:	/* not found in pteg */
428	andi.	1,3,0x40		/* have we already done second hash? */
429	bne	5f
430	mfspr	2,SPR_HASH2		/* get the second pointer */
431	ori	3,3,0x40		/* change the compare value */
432	li	1,8
433	addi	2,2,-8			/* predec pointer */
434	b	1b
4355:	/* not found anywhere */
436	mfsrr1	3
437	lis	1,0x40000000@h		/* set dsisr<1> to flag pte not found */
438	mtctr	0			/* restore counter */
439	andi.	2,3,0xffff		/* clean upper srr1 */
440	mtsrr1	2
441	mtdsisr	1			/* load the dsisr */
442	mfspr	1,SPR_DMISS		/* get the miss address */
443	mtdar	1			/* put in dar */
444	mfmsr	0
445	xoris	0,0,0x20000@h		/* flip the msr<tgpr> bit */
446	mtcrf	0x80,3			/* restore cr0 */
447	mtmsr	0			/* now with native gprs */
448	isync
449	ba	EXC_DSI
450_C_LABEL(tlbdlmsize) = .-_C_LABEL(tlbdlmiss)
451
452	.globl	_C_LABEL(tlbdsmiss),_C_LABEL(tlbdsmsize)
453_C_LABEL(tlbdsmiss):
454	mfspr	2,SPR_HASH1		/* get first pointer */
455	li	1,8
456	mfctr	0			/* save counter */
457	mfspr	3,SPR_DCMP		/* get first compare value */
458	addi	2,2,-8			/* predec pointer */
4591:
460	mtctr	1			/* load counter */
4612:
462	lwzu	1,8(2)			/* get next pte */
463	cmpl	0,1,3			/* see if found pte */
464	bdneq	2b			/* loop if not eq */
465	bne	3f			/* not found */
466	lwz	1,4(2)			/* load tlb entry lower word */
467	andi.	3,1,0x80		/* check the C-bit */
468	beq	4f
4695:
470	mtctr	0			/* restore counter */
471	mfspr	0,SPR_DMISS		/* get the miss address for the tlbld */
472	mfsrr1	3			/* get the saved cr0 bits */
473	mtcrf	0x80,3			/* and restore */
474	mtspr	SPR_RPA,1		/* set the pte */
475	tlbld	0			/* load the dtlb */
476	rfi
477
4783:	/* not found in pteg */
479	andi.	1,3,0x40		/* have we already done second hash? */
480	bne	5f
481	mfspr	2,SPR_HASH2		/* get the second pointer */
482	ori	3,3,0x40		/* change the compare value */
483	li	1,8
484	addi	2,2,-8			/* predec pointer */
485	b	1b
4864:	/* found, but C-bit = 0 */
487	rlwinm.	3,1,30,0,1		/* test PP */
488	bge-	7f
489	andi.	3,1,1
490	beq+	8f
4919:	/* found, but protection violation (PP==00)*/
492	mfsrr1	3
493	lis	1,0xa000000@h		/* indicate protection violation
494					   on store */
495	b	1f
4967:	/* found, PP=1x */
497	mfspr	3,SPR_DMISS		/* get the miss address */
498	mfsrin	1,3			/* get the segment register */
499	mfsrr1	3
500	rlwinm	3,3,18,31,31		/* get PR-bit */
501	rlwnm.	2,2,3,1,1		/* get the key */
502	bne-	9b			/* protection violation */
5038:	/* found, set reference/change bits */
504	lwz	1,4(2)			/* reload tlb entry */
505	ori	1,1,0x180
506	sth	1,6(2)
507	b	5b
5085:	/* not found anywhere */
509	mfsrr1	3
510	lis	1,0x42000000@h		/* set dsisr<1> to flag pte not found */
511					/* dsisr<6> to flag store */
5121:
513	mtctr	0			/* restore counter */
514	andi.	2,3,0xffff		/* clean upper srr1 */
515	mtsrr1	2
516	mtdsisr	1			/* load the dsisr */
517	mfspr	1,SPR_DMISS		/* get the miss address */
518	mtdar	1			/* put in dar */
519	mfmsr	0
520	xoris	0,0,0x20000@h		/* flip the msr<tgpr> bit */
521	mtcrf	0x80,3			/* restore cr0 */
522	mtmsr	0			/* now with native gprs */
523	isync
524	ba	EXC_DSI
525_C_LABEL(tlbdsmsize) = .-_C_LABEL(tlbdsmiss)
526
527#if defined(DDB) || defined(KGDB)
528#define	ddbsave	0xde0		/* primary save area for DDB */
529/*
530 * In case of DDB we want a separate trap catcher for it
531 */
532	.local	ddbstk
533	.comm	ddbstk,INTSTK,8		/* ddb stack */
534
535	.globl	_C_LABEL(ddblow),_C_LABEL(ddbsize)
536_C_LABEL(ddblow):
537	mtsprg	1,1			/* save SP */
538	stmw	28,ddbsave(0)		/* free r28-r31 */
539	mflr	28			/* save LR */
540	mfcr	29			/* save CR */
541	lis	1,ddbstk+INTSTK@ha	/* get new SP */
542	addi	1,1,ddbstk+INTSTK@l
543	bla	ddbtrap
544_C_LABEL(ddbsize) = .-_C_LABEL(ddblow)
545#endif	/* DDB | KGDB */
546
547#ifdef IPKDB
548#define	ipkdbsave	0xde0		/* primary save area for IPKDB */
549/*
550 * In case of IPKDB we want a separate trap catcher for it
551 */
552
553	.local	ipkdbstk
554	.comm	ipkdbstk,INTSTK,8		/* ipkdb stack */
555
556	.globl	_C_LABEL(ipkdblow),_C_LABEL(ipkdbsize)
557_C_LABEL(ipkdblow):
558	mtsprg	1,1			/* save SP */
559	stmw	28,ipkdbsave(0)		/* free r28-r31 */
560	mflr	28			/* save LR */
561	mfcr	29			/* save CR */
562	lis	1,ipkdbstk+INTSTK@ha	/* get new SP */
563	addi	1,1,ipkdbstk+INTSTK@l
564	bla	ipkdbtrap
565_C_LABEL(ipkdbsize) = .-_C_LABEL(ipkdblow)
566#endif	/* IPKDB */
567
568/*
569 * FRAME_SETUP assumes:
570 *	SPRG1		SP (1)
571 *	savearea	r28-r31,DAR,DSISR	(DAR & DSISR only for DSI traps)
572 *	28		LR
573 *	29		CR
574 *	1		kernel stack
575 *	LR		trap type
576 *	SRR0/1		as at start of trap
577 */
578#define	FRAME_SETUP(savearea)						\
579/* Have to enable translation to allow access of kernel stack: */	\
580	mfsrr0	30;							\
581	mfsrr1	31;							\
582	stmw	30,savearea+24(0);					\
583	mfmsr	30;							\
584	ori	30,30,(PSL_DR|PSL_IR);					\
585	mtmsr	30;							\
586	isync;								\
587	mfsprg	31,1;							\
588	stwu	31,-FRAMELEN(1);					\
589	stw	0,FRAME_0+8(1);						\
590	stw	31,FRAME_1+8(1);					\
591	stw	28,FRAME_LR+8(1);					\
592	stw	29,FRAME_CR+8(1);					\
593	lmw	28,savearea(0);						\
594	stmw	2,FRAME_2+8(1);						\
595	lmw	28,savearea+16(0);					\
596	mfxer	3;							\
597	mfctr	4;							\
598	mflr	5;							\
599	andi.	5,5,0xff00;						\
600	stw	3,FRAME_XER+8(1);					\
601	stw	4,FRAME_CTR+8(1);					\
602	stw	5,FRAME_EXC+8(1);					\
603	stw	28,FRAME_DAR+8(1);					\
604	stw	29,FRAME_DSISR+8(1);					\
605	stw	30,FRAME_SRR0+8(1);					\
606	stw	31,FRAME_SRR1+8(1)
607
608#define	FRAME_LEAVE(savearea)						\
609/* Now restore regs: */							\
610	lwz	2,FRAME_SRR0+8(1);					\
611	lwz	3,FRAME_SRR1+8(1);					\
612	lwz	4,FRAME_CTR+8(1);					\
613	lwz	5,FRAME_XER+8(1);					\
614	lwz	6,FRAME_LR+8(1);					\
615	lwz	7,FRAME_CR+8(1);					\
616	stw	2,savearea(0);						\
617	stw	3,savearea+4(0);					\
618	mtctr	4;							\
619	mtxer	5;							\
620	mtlr	6;							\
621	mtsprg	1,7;			/* save cr */			\
622	lmw	2,FRAME_2+8(1);						\
623	lwz	0,FRAME_0+8(1);						\
624	lwz	1,FRAME_1+8(1);						\
625	mtsprg	2,2;			/* save r2 & r3 */		\
626	mtsprg	3,3;							\
627/* Disable translation, machine check and recoverability: */		\
628	mfmsr	2;							\
629	andi.	2,2,~(PSL_DR|PSL_IR|PSL_ME|PSL_RI)@l;			\
630	mtmsr	2;							\
631	isync;								\
632/* Decide whether we return to user mode: */				\
633	lwz	3,savearea+4(0);					\
634	mtcr	3;							\
635	bc	4,17,1f;		/* branch if PSL_PR is false */	\
636/* Restore user & kernel access SR: */					\
637	mfsprg	2,0;							\
638	lwz	2,PC_CURPMAP(2);					\
639	cmpwi	cr4,2,0;		/* is curpmap NULL? */		\
640	bne	cr4,2f;							\
641	lis	3,cpassert@ha;		/* if it is, panic */		\
642	addi	3,3,cpassert@l;						\
643	b	panic;							\
6442:	lwz	3,PM_SR+0(2);						\
645	mtsr	0,3;			/* restore SR0 */		\
646	lwz	3,PM_SR+4(2);						\
647	mtsr	1,3;			/* restore SR1 */		\
648	lwz	3,PM_SR+8(2);						\
649	mtsr	2,3;			/* restore SR2 */		\
650	lwz	3,PM_SR+12(2);						\
651	mtsr	3,3;			/* restore SR3 */		\
652	lwz	3,PM_SR+16(2);						\
653	mtsr	4,3;			/* restore SR4 */		\
654	lwz	3,PM_SR+20(2);						\
655	mtsr	5,3;			/* restore SR5 */		\
656	lwz	3,PM_SR+24(2);						\
657	mtsr	6,3;			/* restore SR6 */		\
658	lwz	3,PM_SR+28(2);						\
659	mtsr	7,3;			/* restore SR7 */		\
660	lwz	3,PM_USRSR(2);						\
661	mtsr	USER_SR,3;						\
662	lwz	3,PM_KERNELSR(2);					\
663	mtsr	KERNEL_SR,3;						\
6641:	mfsprg	2,1;			/* restore cr */		\
665	mtcr	2;							\
666	lwz	2,savearea(0);						\
667	lwz	3,savearea+4(0);					\
668	mtsrr0	2;							\
669	mtsrr1	3;							\
670	mfsprg	2,2;			/* restore r2 & r3 */		\
671	mfsprg	3,3
672
673/*
674 * Preamble code for DSI/ISI traps
675 */
676disitrap:
677	lmw	30,disisave(0)
678	stmw	30,tempsave(0)
679	lmw	30,disisave+8(0)
680	stmw	30,tempsave+8(0)
681	mfdar	30
682	mfdsisr	31
683	stmw	30,tempsave+16(0)
684realtrap:
685/* Test whether we already had PR set */
686	mfsrr1	1
687	mtcr	1
688	mfsprg	1,1			/* restore SP (might have been
689					   overwritten) */
690	bc	4,17,s_trap		/* branch if PSL_PR is false */
691	mfsprg	31,0
692	lwz	1,PC_CURPCB(31)
693	addi	1,1,USPACE		/* stack is top of user struct */
694
695/*
696 * Now the common trap catching code.
697 */
698s_trap:
699/* First have to enable KERNEL mapping */
700	lis	31,KERNEL_SEGMENT@h
701	ori	31,31,KERNEL_SEGMENT@l
702	mtsr	KERNEL_SR,31
703/* Obliterate SRs so BAT spills work correctly */
704	lis	31,EMPTY_SEGMENT@h
705	ori	31,31,EMPTY_SEGMENT@l
706	mtsr	0,31
707	mtsr	1,31
708	mtsr	2,31
709	mtsr	3,31
710	mtsr	4,31
711	mtsr	5,31
712	mtsr	6,31
713	mtsr	7,31
714	FRAME_SETUP(tempsave)
715/* Now we can recover interrupts again: */
716	mfmsr	7
717	ori	7,7,(PSL_EE|PSL_ME|PSL_RI)@l
718	mtmsr	7
719	isync
720/* Call C trap code: */
721trapagain:
722	addi	3,1,8
723	bl	_C_LABEL(trap)
724	.globl	_C_LABEL(trapexit)
725_C_LABEL(trapexit):
726/* Disable interrupts: */
727	mfmsr	3
728	andi.	3,3,~PSL_EE@l
729	mtmsr	3
730/* Test AST pending: */
731	lwz	5,FRAME_SRR1+8(1)
732	mtcr	5
733	bc	4,17,1f			/* branch if PSL_PR is false */
734	lis	3,_C_LABEL(astpending)@ha
735	lwz	4,_C_LABEL(astpending)@l(3)
736	andi.	4,4,1
737	beq	1f
738	li	6,EXC_AST
739	stw	6,FRAME_EXC+8(1)
740	b	trapagain
7411:
742	FRAME_LEAVE(tempsave)
743	rfi
744
745/*
746 * DSI second stage fault handler
747 */
748s_dsitrap:
749	mfdsisr	31			/* test whether this may be a
750					   spill fault */
751	mtcr	31
752	mtsprg	1,1			/* save SP */
753	bc	4,1,disitrap		/* branch if table miss is false */
754	lis	1,spillstk+SPILLSTK@ha
755	addi	1,1,spillstk+SPILLSTK@l	/* get spill stack */
756	stwu	1,-SPFRAMELEN(1)
757	stw	0,SPFRAME_R0(1)		/* save non-volatile registers */
758	stw	3,SPFRAME_R3(1)
759	stw	4,SPFRAME_R4(1)
760	stw	5,SPFRAME_R5(1)
761	stw	6,SPFRAME_R6(1)
762	stw	7,SPFRAME_R7(1)
763	stw	8,SPFRAME_R8(1)
764	stw	9,SPFRAME_R9(1)
765	stw	10,SPFRAME_R10(1)
766	stw	11,SPFRAME_R11(1)
767	stw	12,SPFRAME_R12(1)
768	mflr	30			/* save trap type */
769	mfctr	31			/* & CTR */
770	mfdar	3
771s_pte_spill:
772	bl	_C_LABEL(pmap_pte_spill)	/* try a spill */
773	or.	3,3,3
774	mtctr	31			/* restore CTR */
775	mtlr	30			/* and trap type */
776	mfsprg	31,2			/* get saved XER */
777	mtxer	31			/* restore XER */
778	lwz	12,SPFRAME_R12(1)	/* restore non-volatile registers */
779	lwz	11,SPFRAME_R11(1)
780	lwz	10,SPFRAME_R10(1)
781	lwz	9,SPFRAME_R9(1)
782	lwz	8,SPFRAME_R8(1)
783	lwz	7,SPFRAME_R7(1)
784	lwz	6,SPFRAME_R6(1)
785	lwz	5,SPFRAME_R5(1)
786	lwz	4,SPFRAME_R4(1)
787	lwz	3,SPFRAME_R3(1)
788	lwz	0,SPFRAME_R0(1)
789	beq	disitrap
790	mfsprg	1,1			/* restore SP */
791	mtcr	29			/* restore CR */
792	mtlr	28			/* restore LR */
793	lmw	28,disisave(0)		/* restore r28-r31 */
794	rfi				/* return to trapped code */
795
796/*
797 * ISI second stage fault handler
798 */
799s_isitrap:
800	mfsrr1	31			/* test whether this may be a
801					   spill fault */
802	mtcr	31
803	mtsprg	1,1			/* save SP */
804	bc	4,1,disitrap		/* branch if table miss is false */
805	lis	1,spillstk+SPILLSTK@ha
806	addi	1,1,spillstk+SPILLSTK@l	/* get spill stack */
807	stwu	1,-SPFRAMELEN(1)
808	stw	0,SPFRAME_R0(1)		/* save non-volatile registers */
809	stw	3,SPFRAME_R3(1)
810	stw	4,SPFRAME_R4(1)
811	stw	5,SPFRAME_R5(1)
812	stw	6,SPFRAME_R6(1)
813	stw	7,SPFRAME_R7(1)
814	stw	8,SPFRAME_R8(1)
815	stw	9,SPFRAME_R9(1)
816	stw	10,SPFRAME_R10(1)
817	stw	11,SPFRAME_R11(1)
818	stw	12,SPFRAME_R12(1)
819	mfxer	30			/* save XER */
820	mtsprg	2,30
821	mflr	30			/* save trap type */
822	mfctr	31			/* & ctr */
823	mfsrr0	3
824	b	s_pte_spill		/* above */
825
826/*
827 * External interrupt second level handler
828 */
829#define	INTRENTER							\
830/* Save non-volatile registers: */					\
831	stwu	1,-IFRAMELEN(1);	/* temporarily */		\
832	stw	0,IFRAME_R0(1);						\
833	mfsprg	0,1;			/* get original SP */		\
834	stw	0,IFRAME_R1(1);		/* and store it */		\
835	stw	3,IFRAME_R3(1);						\
836	stw	4,IFRAME_R4(1);						\
837	stw	5,IFRAME_R5(1);						\
838	stw	6,IFRAME_R6(1);						\
839	stw	7,IFRAME_R7(1);						\
840	stw	8,IFRAME_R8(1);						\
841	stw	9,IFRAME_R9(1);						\
842	stw	10,IFRAME_R10(1);					\
843	stw	11,IFRAME_R11(1);					\
844	stw	12,IFRAME_R12(1);					\
845	stw	28,IFRAME_LR(1);	/* saved LR */			\
846	stw	29,IFRAME_CR(1);	/* saved CR */			\
847	stw	30,IFRAME_XER(1);	/* saved XER */			\
848	lmw	28,tempsave(0);		/* restore r28-r31 */		\
849	mfctr	6;							\
850	lis	5,_C_LABEL(intr_depth)@ha;				\
851	lwz	5,_C_LABEL(intr_depth)@l(5);				\
852	mfsrr0	4;							\
853	mfsrr1	3;							\
854	stw	6,IFRAME_CTR(1);					\
855	stw	5,IFRAME_INTR_DEPTH(1);					\
856	stw	4,IFRAME_SRR0(1);					\
857	stw	3,IFRAME_SRR1(1);					\
858	mtcr	3;							\
859	bc	4,17,99f;	/* branch if PSL_PR is false */		\
860	lis	3,EMPTY_SEGMENT@h;					\
861	ori	3,3,EMPTY_SEGMENT@l;					\
862	mtsr	0,3;		/* reset SRs so BAT spills work */	\
863	mtsr	1,3;							\
864	mtsr	2,3;							\
865	mtsr	3,3;							\
866	mtsr	4,3;							\
867	mtsr	5,3;							\
868	mtsr	6,3;							\
869	mtsr	7,3;							\
870/* interrupts are recoverable here, and enable translation */		\
871	lis	3,(KERNEL_SEGMENT|SR_KS|SR_KP)@h;			\
872	ori	3,3,(KERNEL_SEGMENT|SR_KS|SR_KP)@l;			\
873	mtsr	KERNEL_SR,3;						\
87499:	mfmsr	5;							\
875	ori	5,5,(PSL_IR|PSL_DR|PSL_RI);				\
876	mtmsr	5;							\
877	isync
878
879	.globl	_C_LABEL(extint_call)
880extintr:
881	INTRENTER
882_C_LABEL(extint_call):
883	bl	_C_LABEL(extint_call)	/* to be filled in later */
884
885intr_exit:
886/* Disable interrupts (should already be disabled) and MMU here: */
887	mfmsr	3
888	andi.	3,3,~(PSL_EE|PSL_ME|PSL_RI|PSL_DR|PSL_IR)@l
889	mtmsr	3
890	isync
891/* restore possibly overwritten registers: */
892	lwz	12,IFRAME_R12(1)
893	lwz	11,IFRAME_R11(1)
894	lwz	10,IFRAME_R10(1)
895	lwz	9,IFRAME_R9(1)
896	lwz	8,IFRAME_R8(1)
897	lwz	7,IFRAME_R7(1)
898	lwz	6,IFRAME_SRR1(1)
899	lwz	5,IFRAME_SRR0(1)
900	lwz	4,IFRAME_CTR(1)
901	lwz	3,IFRAME_XER(1)
902	mtsrr1	6
903	mtsrr0	5
904	mtctr	4
905	mtxer	3
906/* Returning to user mode? */
907	mtcr	6			/* saved SRR1 */
908	bc	4,17,1f			/* branch if PSL_PR is false */
909	mfsprg	31,0
910	lwz	3,PC_CURPMAP(31)
911	lwz	4,PM_SR+0(3)
912	mtsr	0,4			/* Restore SR0 */
913	lwz	4,PM_SR+4(3)
914	mtsr	1,4			/* Restore SR1 */
915	lwz	4,PM_SR+8(3)
916	mtsr	2,4			/* Restore SR2 */
917	lwz	4,PM_SR+12(3)
918	mtsr	3,4			/* Restore SR3 */
919	lwz	4,PM_SR+16(3)
920	mtsr	4,4			/* Restore SR4 */
921	lwz	4,PM_SR+20(3)
922	mtsr	5,4			/* Restore SR5 */
923	lwz	4,PM_SR+24(3)
924	mtsr	6,4			/* Restore SR6 */
925	lwz	4,PM_SR+28(3)
926	mtsr	7,4			/* Restore SR7 */
927	lwz	3,PM_KERNELSR(3)
928	mtsr	KERNEL_SR,3		/* Restore kernel SR */
929	lis	3,_C_LABEL(astpending)@ha /* Test AST pending */
930	lwz	4,_C_LABEL(astpending)@l(3)
931	andi.	4,4,1
932	beq	1f
933/* Setup for entry to realtrap: */
934	lwz	3,IFRAME_R1(1)		/* get saved SP */
935	mtsprg	1,3
936	li	6,EXC_AST
937	stmw	28,tempsave(0)		/* establish tempsave again */
938	mtlr	6
939	lwz	28,IFRAME_LR(1)		/* saved LR */
940	lwz	29,IFRAME_CR(1)		/* saved CR */
941	lwz	6,IFRAME_R6(1)
942	lwz	5,IFRAME_R5(1)
943	lwz	4,IFRAME_R4(1)
944	lwz	3,IFRAME_R3(1)
945	lwz	0,IFRAME_R0(1)
946	lis	30,_C_LABEL(intr_depth)@ha /* adjust reentrancy count */
947	lwz	31,_C_LABEL(intr_depth)@l(30)
948	addi	31,31,-1
949	stw	31,_C_LABEL(intr_depth)@l(30)
950	b	realtrap
9511:
952/* Here is the normal exit of extintr: */
953	lwz	5,IFRAME_CR(1)
954	lwz	6,IFRAME_LR(1)
955	mtcr	5
956	mtlr	6
957	lwz	6,IFRAME_R6(1)
958	lwz	5,IFRAME_R5(1)
959	lis	3,_C_LABEL(intr_depth)@ha /* adjust reentrancy count */
960	lwz	4,_C_LABEL(intr_depth)@l(3)
961	addi	4,4,-1
962	stw	4,_C_LABEL(intr_depth)@l(3)
963	lwz	4,IFRAME_R4(1)
964	lwz	3,IFRAME_R3(1)
965	lwz	0,IFRAME_R0(1)
966	lwz	1,IFRAME_R1(1)
967	rfi
968
969/*
970 * Decrementer interrupt second level handler
971 */
972decrintr:
973	INTRENTER
974	addi	3,1,8			/* intr frame -> clock frame */
975	bl	_C_LABEL(decr_intr)
976	b	intr_exit
977
978#if defined(DDB)
979/*
980 * Deliberate entry to ddbtrap
981 */
982	.globl	_C_LABEL(ddb_trap)
983_C_LABEL(ddb_trap):
984	mtsprg	1,1
985	mfmsr	3
986	mtsrr1	3
987	andi.	3,3,~(PSL_EE|PSL_ME)@l
988	mtmsr	3			/* disable interrupts */
989	isync
990	stmw	28,ddbsave(0)
991	mflr	28
992	li	29,EXC_BPT
993	mtlr	29
994	mfcr	29
995	mtsrr0	28
996#endif /* DDB */
997
998#if defined(DDB) || defined(KGDB)
999/*
1000 * Now the ddb trap catching code.
1001 */
1002ddbtrap:
1003	FRAME_SETUP(ddbsave)
1004/* Call C trap code: */
1005	addi	3,1,8
1006	bl	_C_LABEL(ddb_trap_glue)
1007	or.	3,3,3
1008	bne	ddbleave
1009/* This wasn't for DDB, so switch to real trap: */
1010	lwz	3,FRAME_EXC+8(1)	/* save exception */
1011	stw	3,ddbsave+8(0)
1012	FRAME_LEAVE(ddbsave)
1013	mtsprg	1,1			/* prepare for entrance to realtrap */
1014	stmw	28,tempsave(0)
1015	mflr	28
1016	mfcr	29
1017	lwz	31,ddbsave+8(0)
1018	mtlr	31
1019	b	realtrap
1020ddbleave:
1021	FRAME_LEAVE(ddbsave)
1022	rfi
1023#endif /* DDB || KGDB */
1024
1025#ifdef IPKDB
1026/*
1027 * Deliberate entry to ipkdbtrap
1028 */
1029	.globl	_C_LABEL(ipkdb_trap)
1030_C_LABEL(ipkdb_trap):
1031	mtsprg	1,1
1032	mfmsr	3
1033	mtsrr1	3
1034	andi.	3,3,~(PSL_EE|PSL_ME)@l
1035	mtmsr	3			/* disable interrupts */
1036	isync
1037	stmw	28,ipkdbsave(0)
1038	mflr	28
1039	li	29,EXC_BPT
1040	mtlr	29
1041	mfcr	29
1042	mtsrr0	28
1043
1044/*
1045 * Now the ipkdb trap catching code.
1046 */
1047ipkdbtrap:
1048	FRAME_SETUP(ipkdbsave)
1049/* Call C trap code: */
1050	addi	3,1,8
1051	bl	_C_LABEL(ipkdb_trap_glue)
1052	or.	3,3,3
1053	bne	ipkdbleave
1054/* This wasn't for IPKDB, so switch to real trap: */
1055	lwz	3,FRAME_EXC+8(1)	/* save exception */
1056	stw	3,ipkdbsave+8(0)
1057	FRAME_LEAVE(ipkdbsave)
1058	mtsprg	1,1			/* prepare for entrance to realtrap */
1059	stmw	28,tempsave(0)
1060	mflr	28
1061	mfcr	29
1062	lwz	31,ipkdbsave+8(0)
1063	mtlr	31
1064	b	realtrap
1065ipkdbleave:
1066	FRAME_LEAVE(ipkdbsave)
1067	rfi
1068
1069ipkdbfault:
1070	ba	_ipkdbfault
1071_ipkdbfault:
1072	mfsrr0	3
1073	addi	3,3,4
1074	mtsrr0	3
1075	li	3,-1
1076	rfi
1077
1078/*
1079 * int ipkdbfbyte(unsigned char *p)
1080 */
1081	.globl	_C_LABEL(ipkdbfbyte)
1082_C_LABEL(ipkdbfbyte):
1083	li	9,EXC_DSI		/* establish new fault routine */
1084	lwz	5,0(9)
1085	lis	6,ipkdbfault@ha
1086	lwz	6,ipkdbfault@l(6)
1087	stw	6,0(9)
1088#ifdef	IPKDBUSERHACK
1089	lis	8,_C_LABEL(ipkdbsr)@ha
1090	lwz	8,_C_LABEL(ipkdbsr)@l(8)
1091	mtsr	USER_SR,8
1092	isync
1093#endif
1094	dcbst	0,9			/* flush data... */
1095	sync
1096	icbi	0,9			/* and instruction caches */
1097	lbz	3,0(3)			/* fetch data */
1098	stw	5,0(9)			/* restore previous fault handler */
1099	dcbst	0,9			/* and flush data... */
1100	sync
1101	icbi	0,9			/* and instruction caches */
1102	blr
1103
1104/*
1105 * int ipkdbsbyte(unsigned char *p, int c)
1106 */
1107	.globl	_C_LABEL(ipkdbsbyte)
1108_C_LABEL(ipkdbsbyte):
1109	li	9,EXC_DSI		/* establish new fault routine */
1110	lwz	5,0(9)
1111	lis	6,ipkdbfault@ha
1112	lwz	6,ipkdbfault@l(6)
1113	stw	6,0(9)
1114#ifdef	IPKDBUSERHACK
1115	lis	8,_C_LABEL(ipkdbsr)@ha
1116	lwz	8,_C_LABEL(ipkdbsr)@l(8)
1117	mtsr	USER_SR,8
1118	isync
1119#endif
1120	dcbst	0,9			/* flush data... */
1121	sync
1122	icbi	0,9			/* and instruction caches */
1123	mr	6,3
1124	xor	3,3,3
1125	stb	4,0(6)
1126	dcbst	0,6			/* Now do appropriate flushes
1127					   to data... */
1128	sync
1129	icbi	0,6			/* and instruction caches */
1130	stw	5,0(9)			/* restore previous fault handler */
1131	dcbst	0,9			/* and flush data... */
1132	sync
1133	icbi	0,9			/* and instruction caches */
1134	blr
1135#endif	/* IPKDB */
1136