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