trap_subr32.S revision 111551
1/* $FreeBSD: head/sys/powerpc/aim/trap_subr.S 111551 2003-02-26 14:41:39Z grehan $ */
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
49cpassert:
50	.asciz	"attempting to return from kernel with no current pmap"
51
52/*
53 * Data used during primary/secondary traps/interrupts
54 */
55#define	tempsave	EXC_MCHK+0xe0 /* primary save area for trap handling */
56#define	disisave	EXC_DSI+0xe0  /* primary save area for dsi/isi traps */
57
58/*
59 * XXX Interrupt and spill stacks need to be per-CPU.
60 */
61	.data
62	.align	4
63intstk:
64	.space	INTSTK		/* interrupt stack */
65
66GLOBAL(intr_depth)
67	.long	-1		/* in-use marker */
68
69	.comm	spillstk,SPILLSTK,8
70
71/*
72 * This code gets copied to all the trap vectors
73 * (except ISI/DSI, ALI, the interrupts, and possibly the debugging
74 * traps when using IPKDB).
75 */
76	.text
77	.globl	CNAME(trapcode),CNAME(trapsize)
78CNAME(trapcode):
79	mtsprg	1,1			/* save SP */
80	stmw	28,tempsave(0)		/* free r28-r31 */
81	mflr	28			/* save LR */
82	mfcr	29			/* save CR */
83/* Test whether we already had PR set */
84	mfsrr1	31
85	mtcr	31
86	bc	4,17,1f			/* branch if PSL_PR is clear */
87	mfsprg	31,0
88	lwz	1,PC_CURPCB(31)
891:
90	bla	s_trap
91CNAME(trapsize) = .-CNAME(trapcode)
92
93/*
94 * For ALI: has to save DSISR and DAR
95 */
96	.globl	CNAME(alitrap),CNAME(alisize)
97CNAME(alitrap):
98	mtsprg	1,1			/* save SP */
99	stmw	28,tempsave(0)		/* free r28-r31 */
100	mfdar	30
101	mfdsisr	31
102	stmw	30,tempsave+16(0)
103	mflr	28			/* save LR */
104	mfcr	29			/* save CR */
105/* Test whether we already had PR set */
106	mfsrr1	31
107	mtcr	31
108	bc	4,17,1f			/* branch if PSL_PR is clear */
109	mfsprg	31,0
110	lwz	1,PC_CURPCB(31)
1111:
112	bla	s_trap
113CNAME(alisize) = .-CNAME(alitrap)
114
115/*
116 * Similar to the above for DSI
117 * Has to handle BAT spills
118 * and standard pagetable spills
119 */
120	.globl	CNAME(dsitrap),CNAME(dsisize)
121CNAME(dsitrap):
122	stmw	28,disisave(0)		/* free r28-r31 */
123	mfcr	29			/* save CR */
124	mfxer	30			/* save XER */
125	mtsprg	2,30			/* in SPRG2 */
126	mfsrr1	31			/* test kernel mode */
127	mtcr	31
128	bc	12,17,1f		/* branch if PSL_PR is set */
129	mfdar	31			/* get fault address */
130	rlwinm	31,31,7,25,28		/* get segment * 8 */
131
132	/* get batu */
133	addis	31,31,CNAME(battable)@ha
134	lwz	30,CNAME(battable)@l(31)
135	mtcr	30
136	bc	4,30,1f			/* branch if supervisor valid is
137					   false */
138	/* get batl */
139	lwz	31,CNAME(battable)+4@l(31)
140/* We randomly use the highest two bat registers here */
141	mftb	28
142	andi.	28,28,1
143	bne	2f
144	mtdbatu	2,30
145	mtdbatl	2,31
146	b	3f
1472:
148	mtdbatu	3,30
149	mtdbatl	3,31
1503:
151	mfsprg	30,2			/* restore XER */
152	mtxer	30
153	mtcr	29			/* restore CR */
154	lmw	28,disisave(0)		/* restore r28-r31 */
155	rfi				/* return to trapped code */
1561:
157	mflr	28			/* save LR */
158	bla	s_dsitrap
159CNAME(dsisize) = .-CNAME(dsitrap)
160
161/*
162 * Dedicated MPC601 version of the above.
163 * Considers different BAT format and combined implementation
164 * (being addressed as I-BAT).
165 */
166	.globl	CNAME(dsitrap601),CNAME(dsi601size)
167CNAME(dsitrap601):
168	stmw	28,disisave(0)		/* free r28-r31 */
169	mfcr	29			/* save CR */
170	mfxer	30			/* save XER */
171	mtsprg	2,30			/* in SPRG2 */
172	mfsrr1	31			/* test kernel mode */
173	mtcr	31
174	bc	12,17,1f		/* branch if PSL_PR is set */
175	mfdar	31			/* get fault address */
176	rlwinm	31,31,12,20,28		/* get "segment" battable offset */
177
178	/* get batl */
179	addis	31,31,CNAME(battable)@ha
180	lwz	30,CNAME(battable)+4@l(31)
181	mtcr	30
182	bc	4,25,1f			/* branch if Valid is is false,
183					   presently assumes supervisor only */
184
185	/* get batu */
186	lwz	31,CNAME(battable)@l(31)
187/* We randomly use the highest two bat registers here */
188	mfspr	28,SPR_RTCL_R
189	andi.	28,28,128
190	bne	2f
191	mtibatu	2,31
192	mtibatl	2,30
193	b	3f
1942:
195	mtibatu	3,31
196	mtibatl	3,30
1973:
198	mfsprg	30,2			/* restore XER */
199	mtxer	30
200	mtcr	29			/* restore CR */
201	lmw	28,disisave(0)		/* restore r28-r31 */
202	rfi				/* return to trapped code */
2031:
204	mflr	28			/* save LR */
205	bla	s_dsitrap
206CNAME(dsi601size) = .-CNAME(dsitrap601)
207
208/*
209 * Similar to the above for ISI
210 */
211	.globl	CNAME(isitrap),CNAME(isisize)
212CNAME(isitrap):
213	stmw	28,disisave(0)		/* free r28-r31 */
214	mflr	28			/* save LR */
215	mfcr	29			/* save CR */
216	mfsrr1	31			/* test kernel mode */
217	mtcr	31
218	bc	12,17,1f		/* branch if PSL_PR is set */
219	mfsrr0	31			/* get fault address */
220	rlwinm	31,31,7,25,28		/* get segment * 8 */
221
222	/* get batu */
223	addis	31,31,CNAME(battable)@ha
224	lwz	30,CNAME(battable)@l(31)
225	mtcr	30
226	bc	4,30,1f			/* branch if supervisor valid is
227					   false */
228	mtibatu	3,30
229
230	/* get batl */
231	lwz	30,CNAME(battable)+4@l(31)
232	mtibatl	3,30
233
234	mtcr	29			/* restore CR */
235	lmw	28,disisave(0)		/* restore r28-r31 */
236	rfi				/* return to trapped code */
2371:
238	bla	s_isitrap
239CNAME(isisize)= .-CNAME(isitrap)
240
241/*
242 * Dedicated MPC601 version of the above.
243 * Considers different BAT format.
244 */
245	.globl	CNAME(isitrap601),CNAME(isi601size)
246CNAME(isitrap601):
247	stmw	28,disisave(0)		/* free r28-r31 */
248	mflr	28			/* save LR */
249	mfcr	29			/* save CR */
250	mfsrr1	31			/* test kernel mode */
251	mtcr	31
252	bc	12,17,1f		/* branch if PSL_PR is set */
253	mfsrr0	31			/* get fault address */
254	rlwinm	31,31,12,20,28		/* get "segment" battable offset */
255
256	/* get batl */
257	addis	31,31,CNAME(battable)@ha
258	lwz	30,CNAME(battable)+4@l(31)
259	mtcr	30
260	bc	4,25,1f			/* branch if Valid is is false,
261					   presently assumes supervisor only */
262	/* get batu */
263	lwz	31,CNAME(battable)@l(31)
264
265	mtibatu	3,31
266	mtibatl	3,30
267
268	mtcr	29			/* restore CR */
269	lmw	28,disisave(0)		/* restore r28-r31 */
270	rfi				/* return to trapped code */
2711:
272	bla	s_isitrap
273CNAME(isi601size)= .-CNAME(isitrap601)
274
275/*
276 * Now the tlb software load for 603 processors:
277 * (Code essentially from the 603e User Manual, Chapter 5, but
278 * corrected a lot.)
279 */
280
281	.globl	CNAME(tlbimiss),CNAME(tlbimsize)
282CNAME(tlbimiss):
283#ifdef PMAPDEBUG
284	mfspr	2,SPR_IMISS		/* exception address */
285	li	1,24			/* get rid of the lower */
286	srw	2,2,1			/*   24 bits */
287	li	1,1			/* Load 1 */
288	cmpl	2,1,1			/* is it > 16MB */
289	blt	99f			/* nope, skip saving these SPRs */
290	li	1,0xc0			/* arbitrary */
291	mfspr	2,SPR_HASH1
292	stw	2,0(1)
293	mfspr	2,SPR_HASH2
294	stw	2,4(1)
295	mfspr	2,SPR_IMISS
296	stw	2,8(1)
297	mfspr	2,SPR_ICMP
298	stw	2,12(1)
29999:
300#endif /* PMAPDEBUG */
301	mfspr	2,SPR_HASH1		/* get first pointer */
302	li	1,8
303	mfctr	0			/* save counter */
304	mfspr	3,SPR_ICMP		/* get first compare value */
305	addi	2,2,-8			/* predec pointer */
3061:
307	mtctr	1			/* load counter */
3082:
309	lwzu	1,8(2)			/* get next pte */
310	cmpl	0,1,3			/* see if found pte */
311	bdneq	2b			/* loop if not eq */
312	bne	3f			/* not found */
313	lwz	1,4(2)			/* load tlb entry lower word */
314	andi.	3,1,8			/* check G-bit */
315	bne	4f			/* if guarded, take ISI */
316	mtctr	0			/* restore counter */
317	mfspr	0,SPR_IMISS		/* get the miss address for the tlbli */
318	mfsrr1	3			/* get the saved cr0 bits */
319	mtcrf	0x80,3			/* and restore */
320	ori	1,1,0x100		/* set the reference bit */
321	mtspr	SPR_RPA,1		/* set the pte */
322	srwi	1,1,8			/* get byte 7 of pte */
323	tlbli	0			/* load the itlb */
324	stb	1,6(2)			/* update page table */
325	rfi
326
3273:	/* not found in pteg */
328	andi.	1,3,0x40		/* have we already done second hash? */
329	bne	5f
330	mfspr	2,SPR_HASH2		/* get the second pointer */
331	ori	3,3,0x40		/* change the compare value */
332	li	1,8
333	addi	2,2,-8			/* predec pointer */
334	b	1b
3354:	/* guarded */
336	mfsrr1	3
337	andi.	2,3,0xffff		/* clean upper srr1 */
338	oris	2,2,0x8000000@h		/* set srr<4> to flag prot violation */
339	b	6f
3405:	/* not found anywhere */
341	mfsrr1	3
342	andi.	2,3,0xffff		/* clean upper srr1 */
343	oris	2,2,0x40000000@h	/* set srr1<1> to flag pte not found */
3446:
345	mtctr	0			/* restore counter */
346	mtsrr1	2
347	mfmsr	0
348	xoris	0,0,0x20000@h		/* flip the msr<tgpr> bit */
349	mtcrf	0x80,3			/* restore cr0 */
350	mtmsr	0			/* now with native gprs */
351	isync
352	ba	EXC_ISI
353CNAME(tlbimsize) = .-CNAME(tlbimiss)
354
355	.globl	CNAME(tlbdlmiss),CNAME(tlbdlmsize)
356CNAME(tlbdlmiss):
357	mfspr	2,SPR_HASH1		/* get first pointer */
358	li	1,8
359	mfctr	0			/* save counter */
360	mfspr	3,SPR_DCMP		/* get first compare value */
361	addi	2,2,-8			/* predec pointer */
3621:
363	mtctr	1			/* load counter */
3642:
365	lwzu	1,8(2)			/* get next pte */
366	cmpl	0,1,3			/* see if found pte */
367	bdneq	2b			/* loop if not eq */
368	bne	3f			/* not found */
369	lwz	1,4(2)			/* load tlb entry lower word */
370	mtctr	0			/* restore counter */
371	mfspr	0,SPR_DMISS		/* get the miss address for the tlbld */
372	mfsrr1	3			/* get the saved cr0 bits */
373	mtcrf	0x80,3			/* and restore */
374	ori	1,1,0x100		/* set the reference bit */
375	mtspr	SPR_RPA,1			/* set the pte */
376	srwi	1,1,8			/* get byte 7 of pte */
377	tlbld	0			/* load the dtlb */
378	stb	1,6(2)			/* update page table */
379	rfi
380
3813:	/* not found in pteg */
382	andi.	1,3,0x40		/* have we already done second hash? */
383	bne	5f
384	mfspr	2,SPR_HASH2		/* get the second pointer */
385	ori	3,3,0x40		/* change the compare value */
386	li	1,8
387	addi	2,2,-8			/* predec pointer */
388	b	1b
3895:	/* not found anywhere */
390	mfsrr1	3
391	lis	1,0x40000000@h		/* set dsisr<1> to flag pte not found */
392	mtctr	0			/* restore counter */
393	andi.	2,3,0xffff		/* clean upper srr1 */
394	mtsrr1	2
395	mtdsisr	1			/* load the dsisr */
396	mfspr	1,SPR_DMISS		/* get the miss address */
397	mtdar	1			/* put in dar */
398	mfmsr	0
399	xoris	0,0,0x20000@h		/* flip the msr<tgpr> bit */
400	mtcrf	0x80,3			/* restore cr0 */
401	mtmsr	0			/* now with native gprs */
402	isync
403	ba	EXC_DSI
404CNAME(tlbdlmsize) = .-CNAME(tlbdlmiss)
405
406	.globl	CNAME(tlbdsmiss),CNAME(tlbdsmsize)
407CNAME(tlbdsmiss):
408	mfspr	2,SPR_HASH1		/* get first pointer */
409	li	1,8
410	mfctr	0			/* save counter */
411	mfspr	3,SPR_DCMP		/* get first compare value */
412	addi	2,2,-8			/* predec pointer */
4131:
414	mtctr	1			/* load counter */
4152:
416	lwzu	1,8(2)			/* get next pte */
417	cmpl	0,1,3			/* see if found pte */
418	bdneq	2b			/* loop if not eq */
419	bne	3f			/* not found */
420	lwz	1,4(2)			/* load tlb entry lower word */
421	andi.	3,1,0x80		/* check the C-bit */
422	beq	4f
4235:
424	mtctr	0			/* restore counter */
425	mfspr	0,SPR_DMISS		/* get the miss address for the tlbld */
426	mfsrr1	3			/* get the saved cr0 bits */
427	mtcrf	0x80,3			/* and restore */
428	mtspr	SPR_RPA,1		/* set the pte */
429	tlbld	0			/* load the dtlb */
430	rfi
431
4323:	/* not found in pteg */
433	andi.	1,3,0x40		/* have we already done second hash? */
434	bne	5f
435	mfspr	2,SPR_HASH2		/* get the second pointer */
436	ori	3,3,0x40		/* change the compare value */
437	li	1,8
438	addi	2,2,-8			/* predec pointer */
439	b	1b
4404:	/* found, but C-bit = 0 */
441	rlwinm.	3,1,30,0,1		/* test PP */
442	bge-	7f
443	andi.	3,1,1
444	beq+	8f
4459:	/* found, but protection violation (PP==00)*/
446	mfsrr1	3
447	lis	1,0xa000000@h		/* indicate protection violation
448					   on store */
449	b	1f
4507:	/* found, PP=1x */
451	mfspr	3,SPR_DMISS		/* get the miss address */
452	mfsrin	1,3			/* get the segment register */
453	mfsrr1	3
454	rlwinm	3,3,18,31,31		/* get PR-bit */
455	rlwnm.	2,2,3,1,1		/* get the key */
456	bne-	9b			/* protection violation */
4578:	/* found, set reference/change bits */
458	lwz	1,4(2)			/* reload tlb entry */
459	ori	1,1,0x180
460	sth	1,6(2)
461	b	5b
4625:	/* not found anywhere */
463	mfsrr1	3
464	lis	1,0x42000000@h		/* set dsisr<1> to flag pte not found */
465					/* dsisr<6> to flag store */
4661:
467	mtctr	0			/* restore counter */
468	andi.	2,3,0xffff		/* clean upper srr1 */
469	mtsrr1	2
470	mtdsisr	1			/* load the dsisr */
471	mfspr	1,SPR_DMISS		/* get the miss address */
472	mtdar	1			/* put in dar */
473	mfmsr	0
474	xoris	0,0,0x20000@h		/* flip the msr<tgpr> bit */
475	mtcrf	0x80,3			/* restore cr0 */
476	mtmsr	0			/* now with native gprs */
477	isync
478	ba	EXC_DSI
479CNAME(tlbdsmsize) = .-CNAME(tlbdsmiss)
480
481#if defined(DDB) || defined(KGDB)
482#define	ddbsave	0xde0		/* primary save area for DDB */
483/*
484 * In case of DDB we want a separate trap catcher for it
485 */
486	.local	ddbstk
487	.comm	ddbstk,INTSTK,8		/* ddb stack */
488
489	.globl	CNAME(ddblow),CNAME(ddbsize)
490CNAME(ddblow):
491	mtsprg	1,1			/* save SP */
492	stmw	28,ddbsave(0)		/* free r28-r31 */
493	mflr	28			/* save LR */
494	mfcr	29			/* save CR */
495	lis	1,ddbstk+INTSTK@ha	/* get new SP */
496	addi	1,1,ddbstk+INTSTK@l
497	bla	ddbtrap
498CNAME(ddbsize) = .-CNAME(ddblow)
499#endif	/* DDB | KGDB */
500
501#ifdef IPKDB
502#define	ipkdbsave	0xde0		/* primary save area for IPKDB */
503/*
504 * In case of IPKDB we want a separate trap catcher for it
505 */
506
507	.local	ipkdbstk
508	.comm	ipkdbstk,INTSTK,8		/* ipkdb stack */
509
510	.globl	CNAME(ipkdblow),CNAME(ipkdbsize)
511CNAME(ipkdblow):
512	mtsprg	1,1			/* save SP */
513	stmw	28,ipkdbsave(0)		/* free r28-r31 */
514	mflr	28			/* save LR */
515	mfcr	29			/* save CR */
516	lis	1,ipkdbstk+INTSTK@ha	/* get new SP */
517	addi	1,1,ipkdbstk+INTSTK@l
518	bla	ipkdbtrap
519CNAME(ipkdbsize) = .-CNAME(ipkdblow)
520#endif	/* IPKDB */
521
522/*
523 * FRAME_SETUP assumes:
524 *	SPRG1		SP (1)
525 *	savearea	r28-r31,DAR,DSISR	(DAR & DSISR only for DSI traps)
526 *	28		LR
527 *	29		CR
528 *	1		kernel stack
529 *	LR		trap type
530 *	SRR0/1		as at start of trap
531 */
532#define	FRAME_SETUP(savearea)						\
533/* Have to enable translation to allow access of kernel stack: */	\
534	mfsrr0	30;							\
535	mfsrr1	31;							\
536	stmw	30,savearea+24(0);					\
537	mfmsr	30;							\
538	ori	30,30,(PSL_DR|PSL_IR|PSL_RI)@l;				\
539	mtmsr	30;							\
540	isync;								\
541	mfsprg	31,1;							\
542	stwu	31,-FRAMELEN(1);					\
543	stw	0,FRAME_0+8(1);						\
544	stw	31,FRAME_1+8(1);					\
545	stw	28,FRAME_LR+8(1);					\
546	stw	29,FRAME_CR+8(1);					\
547	lmw	28,savearea(0);						\
548	stmw	2,FRAME_2+8(1);						\
549	lmw	28,savearea+16(0);					\
550	mfxer	3;							\
551	mfctr	4;							\
552	mflr	5;							\
553	andi.	5,5,0xff00;						\
554	stw	3,FRAME_XER+8(1);					\
555	stw	4,FRAME_CTR+8(1);					\
556	stw	5,FRAME_EXC+8(1);					\
557	stw	28,FRAME_DAR+8(1);					\
558	stw	29,FRAME_DSISR+8(1);					\
559	stw	30,FRAME_SRR0+8(1);					\
560	stw	31,FRAME_SRR1+8(1)
561
562#define	FRAME_LEAVE(savearea)						\
563/* Now restore regs: */							\
564	lwz	2,FRAME_SRR0+8(1);					\
565	lwz	3,FRAME_SRR1+8(1);					\
566	lwz	4,FRAME_CTR+8(1);					\
567	lwz	5,FRAME_XER+8(1);					\
568	lwz	6,FRAME_LR+8(1);					\
569	lwz	7,FRAME_CR+8(1);					\
570	stw	2,savearea(0);						\
571	stw	3,savearea+4(0);					\
572	mtctr	4;							\
573	mtxer	5;							\
574	mtlr	6;							\
575	mtsprg	1,7;			/* save cr */			\
576	lmw	2,FRAME_2+8(1);						\
577	lwz	0,FRAME_0+8(1);						\
578	lwz	1,FRAME_1+8(1);						\
579	mtsprg	2,2;			/* save r2 & r3 */		\
580	mtsprg	3,3;							\
581/* Disable translation, machine check and recoverability: */		\
582	mfmsr	2;							\
583	andi.	2,2,~(PSL_DR|PSL_IR|PSL_EE|PSL_ME|PSL_RI)@l;		\
584	mtmsr	2;							\
585	isync;								\
586/* Decide whether we return to user mode: */				\
587	lwz	3,savearea+4(0);					\
588	mtcr	3;							\
589	bc	4,17,1f;		/* branch if PSL_PR is false */	\
590/* Restore user & kernel access SR: */					\
591	mfsprg	2,0;							\
592	lwz	2,PC_CURPMAP(2);					\
593	cmpwi	cr4,2,0;		/* is curpmap NULL? */		\
594	bne	cr4,2f;							\
595	lis	3,cpassert@ha;		/* if it is, panic */		\
596	addi	3,3,cpassert@l;						\
597	b	panic;							\
5982:	lwz	3,PM_SR+0(2);						\
599	mtsr	0,3;			/* restore SR0 */		\
600	lwz	3,PM_SR+4(2);						\
601	mtsr	1,3;			/* restore SR1 */		\
602	lwz	3,PM_SR+8(2);						\
603	mtsr	2,3;			/* restore SR2 */		\
604	lwz	3,PM_SR+12(2);						\
605	mtsr	3,3;			/* restore SR3 */		\
606	lwz	3,PM_SR+16(2);						\
607	mtsr	4,3;			/* restore SR4 */		\
608	lwz	3,PM_SR+20(2);						\
609	mtsr	5,3;			/* restore SR5 */		\
610	lwz	3,PM_SR+24(2);						\
611	mtsr	6,3;			/* restore SR6 */		\
612	lwz	3,PM_SR+28(2);						\
613	mtsr	7,3;			/* restore SR7 */		\
614	lwz	3,PM_USRSR(2);						\
615	mtsr	USER_SR,3;						\
616	lwz	3,PM_KERNELSR(2);					\
617	mtsr	KERNEL_SR,3;						\
6181:	mfsprg	2,1;			/* restore cr */		\
619	mtcr	2;							\
620	lwz	2,savearea(0);						\
621	lwz	3,savearea+4(0);					\
622	mtsrr0	2;							\
623	mtsrr1	3;							\
624	mfsprg	2,2;			/* restore r2 & r3 */		\
625	mfsprg	3,3
626
627/*
628 * Preamble code for DSI/ISI traps
629 */
630disitrap:
631	lmw	30,disisave(0)
632	stmw	30,tempsave(0)
633	lmw	30,disisave+8(0)
634	stmw	30,tempsave+8(0)
635	mfdar	30
636	mfdsisr	31
637	stmw	30,tempsave+16(0)
638realtrap:
639/* Test whether we already had PR set */
640	mfsrr1	1
641	mtcr	1
642	mfsprg	1,1			/* restore SP (might have been
643					   overwritten) */
644	bc	4,17,s_trap		/* branch if PSL_PR is false */
645	mfsprg	31,0
646	lwz	1,PC_CURPCB(31)
647
648/*
649 * Now the common trap catching code.
650 */
651s_trap:
652/* First have to enable KERNEL mapping */
653	lis	31,KERNEL_SEGMENT@h
654	ori	31,31,KERNEL_SEGMENT@l
655	mtsr	KERNEL_SR,31
656/* Obliterate SRs so BAT spills work correctly */
657	lis	31,EMPTY_SEGMENT@h
658	ori	31,31,EMPTY_SEGMENT@l
659	mtsr	0,31
660	mtsr	1,31
661	mtsr	2,31
662	mtsr	3,31
663	mtsr	4,31
664	mtsr	5,31
665	mtsr	6,31
666	mtsr	7,31
667	FRAME_SETUP(tempsave)
668/* Now we can recover interrupts again: */
669#if 0
670	mfmsr	7
671	ori	7,7,(PSL_EE|PSL_ME|PSL_RI)@l
672	mtmsr	7
673	isync
674#endif
675/* Call C interrupt dispatcher: */
676trapagain:
677	addi	3,1,8
678	bl	CNAME(powerpc_interrupt)
679	.globl	CNAME(trapexit)
680CNAME(trapexit):
681
682/* Disable interrupts: */
683	mfmsr	3
684	andi.	3,3,~PSL_EE@l
685	mtmsr	3
686/* Test AST pending: */
687	lwz	5,FRAME_SRR1+8(1)
688	mtcr	5
689	bc	4,17,1f			/* branch if PSL_PR is false */
690
691	mfsprg	3, 0			/* get per-CPU pointer */
692	lwz	4, PC_CURTHREAD(3)	/* deref to get curthread */
693	lwz	4, TD_FLAGS(4)		/* get thread flags value */
694	lis	5, (TDF_ASTPENDING|TDF_NEEDRESCHED)@h
695	ori	5,5, (TDF_ASTPENDING|TDF_NEEDRESCHED)@l
696	and.	4,4,5
697	beq	1f
698	mfmsr	3			/* re-enable interrupts */
699	ori	3,3,PSL_EE@l
700	mtmsr	3
701	isync
702	addi	3,1,8
703	bl	CNAME(ast)
704	b	trapexit		/* test ast ret value ? */
7051:
706	FRAME_LEAVE(tempsave)
707	rfi
708
709/*
710 * DSI second stage fault handler
711 */
712s_dsitrap:
713	mfdsisr	31			/* test whether this may be a
714					   spill fault */
715	mtcr	31
716	mtsprg	1,1			/* save SP */
717	bc	4,1,disitrap		/* branch if table miss is false */
718	lis	1,spillstk+SPILLSTK@ha
719	addi	1,1,spillstk+SPILLSTK@l	/* get spill stack */
720	stwu	1,-SPFRAMELEN(1)
721	stw	0,SPFRAME_R0(1)		/* save non-volatile registers */
722	stw	3,SPFRAME_R3(1)
723	stw	4,SPFRAME_R4(1)
724	stw	5,SPFRAME_R5(1)
725	stw	6,SPFRAME_R6(1)
726	stw	7,SPFRAME_R7(1)
727	stw	8,SPFRAME_R8(1)
728	stw	9,SPFRAME_R9(1)
729	stw	10,SPFRAME_R10(1)
730	stw	11,SPFRAME_R11(1)
731	stw	12,SPFRAME_R12(1)
732	mflr	30			/* save trap type */
733	mfctr	31			/* & CTR */
734	mfdar	3
735s_pte_spill:
736	bl	CNAME(pmap_pte_spill)	/* try a spill */
737	or.	3,3,3
738	mtctr	31			/* restore CTR */
739	mtlr	30			/* and trap type */
740	mfsprg	31,2			/* get saved XER */
741	mtxer	31			/* restore XER */
742	lwz	12,SPFRAME_R12(1)	/* restore non-volatile registers */
743	lwz	11,SPFRAME_R11(1)
744	lwz	10,SPFRAME_R10(1)
745	lwz	9,SPFRAME_R9(1)
746	lwz	8,SPFRAME_R8(1)
747	lwz	7,SPFRAME_R7(1)
748	lwz	6,SPFRAME_R6(1)
749	lwz	5,SPFRAME_R5(1)
750	lwz	4,SPFRAME_R4(1)
751	lwz	3,SPFRAME_R3(1)
752	lwz	0,SPFRAME_R0(1)
753	beq	disitrap
754	mfsprg	1,1			/* restore SP */
755	mtcr	29			/* restore CR */
756	mtlr	28			/* restore LR */
757	lmw	28,disisave(0)		/* restore r28-r31 */
758	rfi				/* return to trapped code */
759
760/*
761 * ISI second stage fault handler
762 */
763s_isitrap:
764	mfsrr1	31			/* test whether this may be a
765					   spill fault */
766	mtcr	31
767	mtsprg	1,1			/* save SP */
768	bc	4,1,disitrap		/* branch if table miss is false */
769	lis	1,spillstk+SPILLSTK@ha
770	addi	1,1,spillstk+SPILLSTK@l	/* get spill stack */
771	stwu	1,-SPFRAMELEN(1)
772	stw	0,SPFRAME_R0(1)		/* save non-volatile registers */
773	stw	3,SPFRAME_R3(1)
774	stw	4,SPFRAME_R4(1)
775	stw	5,SPFRAME_R5(1)
776	stw	6,SPFRAME_R6(1)
777	stw	7,SPFRAME_R7(1)
778	stw	8,SPFRAME_R8(1)
779	stw	9,SPFRAME_R9(1)
780	stw	10,SPFRAME_R10(1)
781	stw	11,SPFRAME_R11(1)
782	stw	12,SPFRAME_R12(1)
783	mfxer	30			/* save XER */
784	mtsprg	2,30
785	mflr	30			/* save trap type */
786	mfctr	31			/* & ctr */
787	mfsrr0	3
788	b	s_pte_spill		/* above */
789
790
791#if defined(DDB)
792/*
793 * Deliberate entry to ddbtrap
794 */
795	.globl	CNAME(ddb_trap)
796CNAME(ddb_trap):
797	mtsprg	1,1
798	mfmsr	3
799	mtsrr1	3
800	andi.	3,3,~(PSL_EE|PSL_ME)@l
801	mtmsr	3			/* disable interrupts */
802	isync
803	stmw	28,ddbsave(0)
804	mflr	28
805	li	29,EXC_BPT
806	mtlr	29
807	mfcr	29
808	mtsrr0	28
809#endif /* DDB */
810
811#if defined(DDB) || defined(KGDB)
812/*
813 * Now the ddb trap catching code.
814 */
815ddbtrap:
816	FRAME_SETUP(ddbsave)
817/* Call C trap code: */
818	addi	3,1,8
819	bl	CNAME(ddb_trap_glue)
820	or.	3,3,3
821	bne	ddbleave
822/* This wasn't for DDB, so switch to real trap: */
823	lwz	3,FRAME_EXC+8(1)	/* save exception */
824	stw	3,ddbsave+8(0)
825	FRAME_LEAVE(ddbsave)
826	mtsprg	1,1			/* prepare for entrance to realtrap */
827	stmw	28,tempsave(0)
828	mflr	28
829	mfcr	29
830	lwz	31,ddbsave+8(0)
831	mtlr	31
832	b	realtrap
833ddbleave:
834	FRAME_LEAVE(ddbsave)
835	rfi
836#endif /* DDB || KGDB */
837
838#ifdef IPKDB
839/*
840 * Deliberate entry to ipkdbtrap
841 */
842	.globl	CNAME(ipkdb_trap)
843CNAME(ipkdb_trap):
844	mtsprg	1,1
845	mfmsr	3
846	mtsrr1	3
847	andi.	3,3,~(PSL_EE|PSL_ME)@l
848	mtmsr	3			/* disable interrupts */
849	isync
850	stmw	28,ipkdbsave(0)
851	mflr	28
852	li	29,EXC_BPT
853	mtlr	29
854	mfcr	29
855	mtsrr0	28
856
857/*
858 * Now the ipkdb trap catching code.
859 */
860ipkdbtrap:
861	FRAME_SETUP(ipkdbsave)
862/* Call C trap code: */
863	addi	3,1,8
864	bl	CNAME(ipkdb_trap_glue)
865	or.	3,3,3
866	bne	ipkdbleave
867/* This wasn't for IPKDB, so switch to real trap: */
868	lwz	3,FRAME_EXC+8(1)	/* save exception */
869	stw	3,ipkdbsave+8(0)
870	FRAME_LEAVE(ipkdbsave)
871	mtsprg	1,1			/* prepare for entrance to realtrap */
872	stmw	28,tempsave(0)
873	mflr	28
874	mfcr	29
875	lwz	31,ipkdbsave+8(0)
876	mtlr	31
877	b	realtrap
878ipkdbleave:
879	FRAME_LEAVE(ipkdbsave)
880	rfi
881
882ipkdbfault:
883	ba	_ipkdbfault
884_ipkdbfault:
885	mfsrr0	3
886	addi	3,3,4
887	mtsrr0	3
888	li	3,-1
889	rfi
890
891/*
892 * int ipkdbfbyte(unsigned char *p)
893 */
894	.globl	CNAME(ipkdbfbyte)
895CNAME(ipkdbfbyte):
896	li	9,EXC_DSI		/* establish new fault routine */
897	lwz	5,0(9)
898	lis	6,ipkdbfault@ha
899	lwz	6,ipkdbfault@l(6)
900	stw	6,0(9)
901#ifdef	IPKDBUSERHACK
902	lis	8,CNAME(ipkdbsr)@ha
903	lwz	8,CNAME(ipkdbsr)@l(8)
904	mtsr	USER_SR,8
905	isync
906#endif
907	dcbst	0,9			/* flush data... */
908	sync
909	icbi	0,9			/* and instruction caches */
910	lbz	3,0(3)			/* fetch data */
911	stw	5,0(9)			/* restore previous fault handler */
912	dcbst	0,9			/* and flush data... */
913	sync
914	icbi	0,9			/* and instruction caches */
915	blr
916
917/*
918 * int ipkdbsbyte(unsigned char *p, int c)
919 */
920	.globl	CNAME(ipkdbsbyte)
921CNAME(ipkdbsbyte):
922	li	9,EXC_DSI		/* establish new fault routine */
923	lwz	5,0(9)
924	lis	6,ipkdbfault@ha
925	lwz	6,ipkdbfault@l(6)
926	stw	6,0(9)
927#ifdef	IPKDBUSERHACK
928	lis	8,CNAME(ipkdbsr)@ha
929	lwz	8,CNAME(ipkdbsr)@l(8)
930	mtsr	USER_SR,8
931	isync
932#endif
933	dcbst	0,9			/* flush data... */
934	sync
935	icbi	0,9			/* and instruction caches */
936	mr	6,3
937	xor	3,3,3
938	stb	4,0(6)
939	dcbst	0,6			/* Now do appropriate flushes
940					   to data... */
941	sync
942	icbi	0,6			/* and instruction caches */
943	stw	5,0(9)			/* restore previous fault handler */
944	dcbst	0,9			/* and flush data... */
945	sync
946	icbi	0,9			/* and instruction caches */
947	blr
948#endif	/* IPKDB */
949