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