xref: /freebsd/sys/powerpc/aim/locore.S (revision 8fa113e5fc65fe6abc757f0089f477a87ee4d185)
1/* $FreeBSD$ */
2/* $NetBSD: locore.S,v 1.24 2000/05/31 05:09:17 thorpej Exp $ */
3
4/*
5 * Copyright (C) 2001 Benno Rice
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 *
17 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28/*
29 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
30 * Copyright (C) 1995, 1996 TooLs GmbH.
31 * All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 *    notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 *    notice, this list of conditions and the following disclaimer in the
40 *    documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 *    must display the following acknowledgement:
43 *	This product includes software developed by TooLs GmbH.
44 * 4. The name of TooLs GmbH may not be used to endorse or promote products
45 *    derived from this software without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
48 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
49 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
50 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
51 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
52 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
53 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
54 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
55 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
56 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 */
58
59#include "opt_ddb.h"
60#include "opt_ipkdb.h"
61#include "assym.s"
62
63#include <sys/syscall.h>
64
65#include <machine/trap.h>
66#include <machine/param.h>
67#include <machine/pmap.h>
68#include <machine/psl.h>
69#include <machine/asm.h>
70
71/*
72 * Some instructions gas doesn't understand (yet?)
73 */
74#define	bdneq	bdnzf 2,
75
76/*
77 * Globals
78 */
79	.data
80GLOBAL(tmpstk)
81	.space	8208
82GLOBAL(esym)
83	.long	0			/* end of symbol table */
84GLOBAL(proc0paddr)
85	.long	0			/* proc0 p_addr */
86GLOBAL(PTmap)
87	.long	0			/* PTmap */
88
89GLOBAL(intrnames)
90	.asciz	"irq0", "irq1", "irq2", "irq3"
91	.asciz	"irq4", "irq5", "irq6", "irq7"
92	.asciz	"irq8", "irq9", "irq10", "irq11"
93	.asciz	"irq12", "irq13", "irq14", "irq15"
94	.asciz	"irq16", "irq17", "irq18", "irq19"
95	.asciz	"irq20", "irq21", "irq22", "irq23"
96	.asciz	"irq24", "irq25", "irq26", "irq27"
97	.asciz	"irq28", "irq29", "irq30", "irq31"
98	.asciz	"irq32", "irq33", "irq34", "irq35"
99	.asciz	"irq36", "irq37", "irq38", "irq39"
100	.asciz	"irq40", "irq41", "irq42", "irq43"
101	.asciz	"irq44", "irq45", "irq46", "irq47"
102	.asciz	"irq48", "irq49", "irq50", "irq51"
103	.asciz	"irq52", "irq53", "irq54", "irq55"
104	.asciz	"irq56", "irq57", "irq58", "irq59"
105	.asciz	"irq60", "irq61", "irq62", "irq63"
106	.asciz	"clock", "softclock", "softnet", "softserial"
107GLOBAL(eintrnames)
108	.align	4
109GLOBAL(intrcnt)
110	.long	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
111	.long	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
112	.long	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
113	.long	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
114	.long	0,0,0,0
115GLOBAL(eintrcnt)
116
117GLOBAL(ofmsr)
118	.long	0			/* msr used in Open Firmware */
119
120GLOBAL(powersave)
121	.long	0
122
123/*
124 * File-scope for locore.S
125 */
126idle_u:
127	.long	0			/* fake uarea during idle after exit */
128openfirmware_entry:
129	.long	0			/* openfirmware entry point */
130srsave:
131	.long	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
132
133/*
134 * This symbol is here for the benefit of kvm_mkdb, and is supposed to
135 * mark the start of kernel text.
136 */
137	.text
138	.globl	kernel_text
139kernel_text:
140
141/*
142 * Startup entry.  Note, this must be the first thing in the text
143 * segment!
144 */
145	.text
146	.globl	__start
147__start:
148#ifdef	FIRMWORKSBUGS
149	mfmsr	0
150	andi.	0,0,PSL_IR|PSL_DR
151	beq	1f
152
153	bl	ofwr_init
1541:
155#endif
156	li	8,0
157	li	9,0x100
158	mtctr	9
1591:
160	dcbf	0,8
161	icbi	0,8
162	addi	8,8,0x20
163	bdnz	1b
164	sync
165	isync
166
167	mtibatu	0,0
168	mtibatu	1,0
169	mtibatu	2,0
170	mtibatu	3,0
171	mtdbatu	0,0
172	mtdbatu	1,0
173	mtdbatu	2,0
174	mtdbatu	3,0
175
176	li	9,0x12
177	mtibatl	0,9
178	mtdbatl	0,9
179	li	9,0x1ffe
180	mtibatu	0,9
181	mtdbatu	0,9
182	isync
183
184	lis	8,openfirmware_entry@ha
185	stw	5,openfirmware_entry@l(8) /* save client interface handler */
186	mr	3,5
187
188	lis	1,tmpstk@ha
189	addi	1,1,tmpstk@l
190	addi	1,1,8192
191
192	mfmsr	0
193	lis	9,ofmsr@ha
194	stw	0,ofmsr@l(9)
195
196	bl	OF_init
197
198	lis	4,end@ha
199	addi	4,4,end@l
200	mr	5,4
201	li	9,PAGE_MASK
202	add	4,4,9
203	andc	4,4,9
204	lis	9,OF_buf@ha
205	stw	4,OF_buf@l(9)
206	addi	4,4,PAGE_SIZE
207	lis	9,proc0paddr@ha
208	stw	4,proc0paddr@l(9)
209	addi	4,4,USPACE-FRAMELEN
210	mr	1,4
211	xor	0,0,0
212	stwu	0,-16(1)
213
214	lis	3,kernel_text@ha
215	addi	3,3,kernel_text@l
216#if 0
217	mr	5,6
218#endif
219
220	bl	powerpc_init
221	bl	mi_startup
222	b	OF_exit
223
224#if 0 /* XXX: We may switch back to this in the future. */
225/*
226 * OpenFirmware entry point
227 */
228ENTRY(openfirmware)
229	mflr	0			/* save return address */
230	stw	0,4(1)
231	stwu	1,-16(1)		/* setup stack frame */
232
233	mfmsr	4			/* save msr */
234	stw	4,8(1)
235
236	lis	4,openfirmware_entry@ha	/* get firmware entry point */
237	lwz	4,openfirmware_entry@l(4)
238	mtlr	4
239
240	li	0,0			/* clear battable translations */
241	mtdbatu	2,0
242	mtdbatu	3,0
243	mtibatu	2,0
244	mtibatu	3,0
245
246	lis	4,ofmsr@ha		/* Open Firmware msr */
247	lwz	4,ofmsr@l(4)
248	mtmsr	4
249	isync
250
251	lis	4,srsave@ha		/* save old SR */
252	addi	4,4,srsave@l
253	li	5,0
2541:	mfsrin	0,5
255	stw	0,0(4)
256	addi	4,4,4
257	addis	5,5,0x10000000@h
258	cmpwi	5,0
259	bne	1b
260
261	lis	4,ofw_pmap@ha		/* load OFW SR */
262	addi	4,4,ofw_pmap@l
263	lwz	0,PM_KERNELSR(4)
264	cmpwi	0,0			/* pm_sr[KERNEL_SR] == 0? */
265	beq	2f			/* then skip (not initialized yet) */
266	li	5,0
2671:	lwz	0,0(4)
268	mtsrin	0,5
269	addi	4,4,4
270	addis	5,5,0x10000000@h
271	cmpwi	5,0
272	bne	1b
2732:
274	blrl				/* call Open Firmware */
275
276	mfmsr	4
277	li	5,PSL_IR|PSL_DR
278	andc 	4,4,5
279	mtmsr	4
280	isync
281
282	lis	4,srsave@ha		/* restore saved SR */
283	addi	4,4,srsave@l
284	li	5,0
2851:	lwz	0,0(4)
286	mtsrin	0,5
287	addi	4,4,4
288	addis	5,5,0x10000000@h
289	cmpwi	5,0
290	bne	1b
291
292	lwz	4,8(1)			/* restore msr */
293	mtmsr	4
294	isync
295
296	lwz	1,0(1)			/* and return */
297	lwz	0,4(1)
298	mtlr	0
299	blr
300#endif
301
302/*
303 * Switch to/from OpenFirmware real mode stack
304 *
305 * Note: has to be called as the very first thing in OpenFirmware interface
306 * routines.
307 * E.g.:
308 * int
309 * OF_xxx(arg1, arg2)
310 * type arg1, arg2;
311 * {
312 *	static struct {
313 *		char *name;
314 *		int nargs;
315 *		int nreturns;
316 *		char *method;
317 *		int arg1;
318 *		int arg2;
319 *		int ret;
320 *	} args = {
321 *		"xxx",
322 *		2,
323 *		1,
324 *	};
325 *
326 *	ofw_stack();
327 *	args.arg1 = arg1;
328 *	args.arg2 = arg2;
329 *	if (openfirmware(&args) < 0)
330 *		return -1;
331 *	return args.ret;
332 * }
333 */
334
335	.local	firmstk
336	.comm	firmstk,PAGE_SIZE,8
337
338ENTRY(ofw_stack)
339	mfmsr	8			/* turn off interrupts */
340	andi.	0,8,~(PSL_EE|PSL_RI)@l
341	mtmsr	0
342	stw	8,4(1)			/* abuse return address slot */
343
344	lwz	5,0(1)			/* get length of stack frame */
345	subf	5,1,5
346
347	lis	7,firmstk+PAGE_SIZE-8@ha
348	addi	7,7,firmstk+PAGE_SIZE-8@l
349	lis	6,ofw_back@ha
350	addi	6,6,ofw_back@l
351	subf	4,5,7			/* make room for stack frame on
352					   new stack */
353	stw	6,-4(7)			/* setup return pointer */
354	stwu	1,-8(7)
355
356	stw	7,-8(4)
357
358	addi	3,1,8
359	addi	1,4,-8
360	subi	5,5,8
361
362	cmpw	3,4
363	beqlr
364
365	mr	0,5
366	addi	5,5,-1
367	cmpwi	0,0
368	beqlr
369
3701:	lwz	0,0(3)
371	stw	0,0(4)
372	addi	3,3,1
373	addi	4,4,1
374	mr	0,5
375	addi	5,5,-1
376	cmpwi	0,0
377	bne	1b
378	blr
379
380ofw_back:
381	lwz	1,0(1)			/* get callers original stack pointer */
382
383	lwz	0,4(1)			/* get saved msr from abused slot */
384	mtmsr	0
385
386	lwz	1,0(1)			/* return */
387	lwz	0,4(1)
388	mtlr	0
389	blr
390
391/*
392 * Data used during primary/secondary traps/interrupts
393 */
394#define	tempsave	0x2e0	/* primary save area for trap handling */
395#define	disisave	0x3e0	/* primary save area for dsi/isi traps */
396
397#define	INTSTK	(8*1024)	/* 8K interrupt stack */
398	.data
399	.align	4
400intstk:
401	.space	INTSTK		/* interrupt stack */
402
403GLOBAL(intr_depth)
404	.long	-1		/* in-use marker */
405
406#define	SPILLSTK 1024		/* 1K spill stack */
407
408	.comm	spillstk,SPILLSTK,8
409
410/*
411 * This code gets copied to all the trap vectors
412 * (except ISI/DSI, ALI, the interrupts, and possibly the debugging
413 * traps when using IPKDB).
414 */
415	.text
416	.globl	trapcode,trapsize
417trapcode:
418	mtsprg	1,1			/* save SP */
419	stmw	28,tempsave(0)		/* free r28-r31 */
420	mflr	28			/* save LR */
421	mfcr	29			/* save CR */
422/* Test whether we already had PR set */
423	mfsrr1	31
424	mtcr	31
425	bc	4,17,1f			/* branch if PSL_PR is clear */
426	mfsprg	1,0
427	lwz	1,GD_CURPCB(1)
428	addi	1,1,USPACE		/* stack is top of user struct */
4291:
430	bla	s_trap
431trapsize = .-trapcode
432
433/*
434 * For ALI: has to save DSISR and DAR
435 */
436	.globl	alitrap,alisize
437alitrap:
438	mtsprg	1,1			/* save SP */
439	stmw	28,tempsave(0)		/* free r28-r31 */
440	mfdar	30
441	mfdsisr	31
442	stmw	30,tempsave+16(0)
443	mflr	28			/* save LR */
444	mfcr	29			/* save CR */
445/* Test whether we already had PR set */
446	mfsrr1	31
447	mtcr	31
448	bc	4,17,1f			/* branch if PSL_PR is clear */
449	mfsprg	1,0
450	lwz	1,GD_CURPCB(1)
451	addi	1,1,USPACE		/* stack is top of user struct */
4521:
453	bla	s_trap
454alisize = .-alitrap
455
456/*
457 * Similar to the above for DSI
458 * Has to handle BAT spills
459 * and standard pagetable spills
460 */
461	.globl	dsitrap,dsisize
462dsitrap:
463	stmw	28,disisave(0)		/* free r28-r31 */
464	mfcr	29			/* save CR */
465	mfxer	30			/* save XER */
466	mtsprg	2,30			/* in SPRG2 */
467	mfsrr1	31			/* test kernel mode */
468	mtcr	31
469	bc	12,17,1f		/* branch if PSL_PR is set */
470	mfdar	31			/* get fault address */
471	rlwinm	31,31,7,25,28		/* get segment * 8 */
472
473	/* get batu */
474	addis	31,31,battable@ha
475	lwz	30,battable@l(31)
476	mtcr	30
477	bc	4,30,1f			/* branch if supervisor valid is
478					   false */
479	/* get batl */
480	lwz	31,battable+4@l(31)
481/* We randomly use the highest two bat registers here */
482	mftb	28
483	andi.	28,28,1
484	bne	2f
485	mtdbatu	2,30
486	mtdbatl	2,31
487	b	3f
4882:
489	mtdbatu	3,30
490	mtdbatl	3,31
4913:
492	mfsprg	30,2			/* restore XER */
493	mtxer	30
494	mtcr	29			/* restore CR */
495	lmw	28,disisave(0)		/* restore r28-r31 */
496	rfi				/* return to trapped code */
4971:
498	mflr	28			/* save LR */
499	bla	s_dsitrap
500dsisize = .-dsitrap
501
502/*
503 * Similar to the above for ISI
504 */
505	.globl	isitrap,isisize
506isitrap:
507	stmw	28,disisave(0)		/* free r28-r31 */
508	mflr	28			/* save LR */
509	mfcr	29			/* save CR */
510	mfsrr1	31			/* test kernel mode */
511	mtcr	31
512	bc	12,17,1f		/* branch if PSL_PR is set */
513	mfsrr0	31			/* get fault address */
514	rlwinm	31,31,7,25,28		/* get segment * 8 */
515
516	/* get batu */
517	addis	31,31,battable@ha
518	lwz	30,battable@l(31)
519	mtcr	30
520	bc	4,30,1f			/* branch if supervisor valid is
521					   false */
522	mtibatu	3,30
523
524	/* get batl */
525	lwz	30,battable+4@l(31)
526	mtibatl	3,30
527
528	mtcr	29			/* restore CR */
529	lmw	28,disisave(0)		/* restore r28-r31 */
530	rfi				/* return to trapped code */
5311:
532	bla	s_isitrap
533isisize = .-isitrap
534
535/*
536 * This one for the external interrupt handler.
537 */
538	.globl	extint,extsize
539extint:
540	mtsprg	1,1			/* save SP */
541	stmw	28,tempsave(0)		/* free r28-r31 */
542	mflr	28			/* save LR */
543	mfcr	29			/* save CR */
544	mfxer	30			/* save XER */
545	lis	1,intstk+INTSTK@ha	/* get interrupt stack */
546	addi	1,1,intstk+INTSTK@l
547	lwz	31,0(1)			/* were we already running on intstk? */
548	addic.	31,31,1
549	stw	31,0(1)
550	beq	1f
551	mfsprg	1,1			/* yes, get old SP */
5521:
553	ba	extintr
554extsize = .-extint
555
556/*
557 * And this one for the decrementer interrupt handler.
558 */
559	.globl	decrint,decrsize
560decrint:
561	mtsprg	1,1			/* save SP */
562	stmw	28,tempsave(0)		/* free r28-r31 */
563	mflr	28			/* save LR */
564	mfcr	29			/* save CR */
565	mfxer	30			/* save XER */
566	lis	1,intstk+INTSTK@ha	/* get interrupt stack */
567	addi	1,1,intstk+INTSTK@l
568	lwz	31,0(1)			/* were we already running on intstk? */
569	addic.	31,31,1
570	stw	31,0(1)
571	beq	1f
572	mfsprg	1,1			/* yes, get old SP */
5731:
574	ba	decrintr
575decrsize = .-decrint
576
577/*
578 * Now the tlb software load for 603 processors:
579 * (Code essentially from the 603e User Manual, Chapter 5, but
580 * corrected a lot.)
581 */
582#define	DMISS	976
583#define	DCMP	977
584#define	HASH1	978
585#define	HASH2	979
586#define	IMISS	980
587#define	ICMP	981
588#define	RPA	982
589
590	.globl	tlbimiss,tlbimsize
591tlbimiss:
592	mfspr	2,HASH1			/* get first pointer */
593	li	1,8
594	mfctr	0			/* save counter */
595	mfspr	3,ICMP			/* get first compare value */
596	addi	2,2,-8			/* predec pointer */
5971:
598	mtctr	1			/* load counter */
5992:
600	lwzu	1,8(2)			/* get next pte */
601	cmpl	0,1,3			/* see if found pte */
602	bdneq	2b			/* loop if not eq */
603	bne	3f			/* not found */
604	lwz	1,4(2)			/* load tlb entry lower word */
605	andi.	3,1,8			/* check G-bit */
606	bne	4f			/* if guarded, take ISI */
607	mtctr	0			/* restore counter */
608	mfspr	0,IMISS			/* get the miss address for the tlbli */
609	mfsrr1	3			/* get the saved cr0 bits */
610	mtcrf	0x80,3			/* and restore */
611	ori	1,1,0x100		/* set the reference bit */
612	mtspr	RPA,1			/* set the pte */
613	srwi	1,1,8			/* get byte 7 of pte */
614	tlbli	0			/* load the itlb */
615	stb	1,6(2)			/* update page table */
616	rfi
617
6183:	/* not found in pteg */
619	andi.	1,3,0x40		/* have we already done second hash? */
620	bne	5f
621	mfspr	2,HASH2			/* get the second pointer */
622	ori	3,3,0x40		/* change the compare value */
623	li	1,8
624	addi	2,2,-8			/* predec pointer */
625	b	1b
6264:	/* guarded */
627	mfsrr1	3
628	andi.	2,3,0xffff		/* clean upper srr1 */
629	oris	2,2,0x8000000@h		/* set srr<4> to flag prot violation */
630	b	6f
6315:	/* not found anywhere */
632	mfsrr1	3
633	andi.	2,3,0xffff		/* clean upper srr1 */
634	oris	2,2,0x40000000@h	/* set srr1<1> to flag pte not found */
6356:
636	mtctr	0			/* restore counter */
637	mtsrr1	2
638	mfmsr	0
639	xoris	0,0,0x20000@h		/* flip the msr<tgpr> bit */
640	mtcrf	0x80,3			/* restore cr0 */
641	mtmsr	0			/* now with native gprs */
642	isync
643	ba	EXC_ISI
644tlbimsize = .-tlbimiss
645
646	.globl	tlbdlmiss,tlbdlmsize
647tlbdlmiss:
648	mfspr	2,HASH1			/* get first pointer */
649	li	1,8
650	mfctr	0			/* save counter */
651	mfspr	3,DCMP			/* get first compare value */
652	addi	2,2,-8			/* predec pointer */
6531:
654	mtctr	1			/* load counter */
6552:
656	lwzu	1,8(2)			/* get next pte */
657	cmpl	0,1,3			/* see if found pte */
658	bdneq	2b			/* loop if not eq */
659	bne	3f			/* not found */
660	lwz	1,4(2)			/* load tlb entry lower word */
661	mtctr	0			/* restore counter */
662	mfspr	0,DMISS			/* get the miss address for the tlbld */
663	mfsrr1	3			/* get the saved cr0 bits */
664	mtcrf	0x80,3			/* and restore */
665	ori	1,1,0x100		/* set the reference bit */
666	mtspr	RPA,1			/* set the pte */
667	srwi	1,1,8			/* get byte 7 of pte */
668	tlbld	0			/* load the dtlb */
669	stb	1,6(2)			/* update page table */
670	rfi
671
6723:	/* not found in pteg */
673	andi.	1,3,0x40		/* have we already done second hash? */
674	bne	5f
675	mfspr	2,HASH2			/* get the second pointer */
676	ori	3,3,0x40		/* change the compare value */
677	li	1,8
678	addi	2,2,-8			/* predec pointer */
679	b	1b
6805:	/* not found anywhere */
681	mfsrr1	3
682	lis	1,0x40000000@h		/* set dsisr<1> to flag pte not found */
683	mtctr	0			/* restore counter */
684	andi.	2,3,0xffff		/* clean upper srr1 */
685	mtsrr1	2
686	mtdsisr	1			/* load the dsisr */
687	mfspr	1,DMISS			/* get the miss address */
688	mtdar	1			/* put in dar */
689	mfmsr	0
690	xoris	0,0,0x20000@h		/* flip the msr<tgpr> bit */
691	mtcrf	0x80,3			/* restore cr0 */
692	mtmsr	0			/* now with native gprs */
693	isync
694	ba	EXC_DSI
695tlbdlmsize = .-tlbdlmiss
696
697	.globl	tlbdsmiss,tlbdsmsize
698tlbdsmiss:
699	mfspr	2,HASH1			/* get first pointer */
700	li	1,8
701	mfctr	0			/* save counter */
702	mfspr	3,DCMP			/* get first compare value */
703	addi	2,2,-8			/* predec pointer */
7041:
705	mtctr	1			/* load counter */
7062:
707	lwzu	1,8(2)			/* get next pte */
708	cmpl	0,1,3			/* see if found pte */
709	bdneq	2b			/* loop if not eq */
710	bne	3f			/* not found */
711	lwz	1,4(2)			/* load tlb entry lower word */
712	andi.	3,1,0x80		/* check the C-bit */
713	beq	4f
7145:
715	mtctr	0			/* restore counter */
716	mfspr	0,DMISS			/* get the miss address for the tlbld */
717	mfsrr1	3			/* get the saved cr0 bits */
718	mtcrf	0x80,3			/* and restore */
719	mtspr	RPA,1			/* set the pte */
720	tlbld	0			/* load the dtlb */
721	rfi
722
7233:	/* not found in pteg */
724	andi.	1,3,0x40		/* have we already done second hash? */
725	bne	5f
726	mfspr	2,HASH2			/* get the second pointer */
727	ori	3,3,0x40		/* change the compare value */
728	li	1,8
729	addi	2,2,-8			/* predec pointer */
730	b	1b
7314:	/* found, but C-bit = 0 */
732	rlwinm.	3,1,30,0,1		/* test PP */
733	bge-	7f
734	andi.	3,1,1
735	beq+	8f
7369:	/* found, but protection violation (PP==00)*/
737	mfsrr1	3
738	lis	1,0xa000000@h		/* indicate protection violation
739					   on store */
740	b	1f
7417:	/* found, PP=1x */
742	mfspr	3,DMISS			/* get the miss address */
743	mfsrin	1,3			/* get the segment register */
744	mfsrr1	3
745	rlwinm	3,3,18,31,31		/* get PR-bit */
746	rlwnm.	2,2,3,1,1		/* get the key */
747	bne-	9b			/* protection violation */
7488:	/* found, set reference/change bits */
749	lwz	1,4(2)			/* reload tlb entry */
750	ori	1,1,0x180
751	sth	1,6(2)
752	b	5b
7535:	/* not found anywhere */
754	mfsrr1	3
755	lis	1,0x42000000@h		/* set dsisr<1> to flag pte not found */
756					/* dsisr<6> to flag store */
7571:
758	mtctr	0			/* restore counter */
759	andi.	2,3,0xffff		/* clean upper srr1 */
760	mtsrr1	2
761	mtdsisr	1			/* load the dsisr */
762	mfspr	1,DMISS			/* get the miss address */
763	mtdar	1			/* put in dar */
764	mfmsr	0
765	xoris	0,0,0x20000@h		/* flip the msr<tgpr> bit */
766	mtcrf	0x80,3			/* restore cr0 */
767	mtmsr	0			/* now with native gprs */
768	isync
769	ba	EXC_DSI
770tlbdsmsize = .-tlbdsmiss
771
772#ifdef DDB
773#define	ddbsave	0xde0		/* primary save area for DDB */
774/*
775 * In case of DDB we want a separate trap catcher for it
776 */
777	.local	ddbstk
778	.comm	ddbstk,INTSTK,8		/* ddb stack */
779
780	.globl	ddblow,ddbsize
781ddblow:
782	mtsprg	1,1			/* save SP */
783	stmw	28,ddbsave(0)		/* free r28-r31 */
784	mflr	28			/* save LR */
785	mfcr	29			/* save CR */
786	lis	1,ddbstk+INTSTK@ha	/* get new SP */
787	addi	1,1,ddbstk+INTSTK@l
788	bla	ddbtrap
789ddbsize = .-ddblow
790#endif	/* DDB */
791
792#ifdef IPKDB
793#define	ipkdbsave	0xde0		/* primary save area for IPKDB */
794/*
795 * In case of IPKDB we want a separate trap catcher for it
796 */
797
798	.local	ipkdbstk
799	.comm	ipkdbstk,INTSTK,8		/* ipkdb stack */
800
801	.globl	ipkdblow,ipkdbsize
802ipkdblow:
803	mtsprg	1,1			/* save SP */
804	stmw	28,ipkdbsave(0)		/* free r28-r31 */
805	mflr	28			/* save LR */
806	mfcr	29			/* save CR */
807	lis	1,ipkdbstk+INTSTK@ha	/* get new SP */
808	addi	1,1,ipkdbstk+INTSTK@l
809	bla	ipkdbtrap
810ipkdbsize = .-ipkdblow
811#endif	/* IPKDB */
812
813/*
814 * FRAME_SETUP assumes:
815 *	SPRG1		SP (1)
816 *	savearea	r28-r31,DAR,DSISR	(DAR & DSISR only for DSI traps)
817 *	28		LR
818 *	29		CR
819 *	1		kernel stack
820 *	LR		trap type
821 *	SRR0/1		as at start of trap
822 */
823#define	FRAME_SETUP(savearea)						\
824/* Have to enable translation to allow access of kernel stack: */	\
825	mfsrr0	30;							\
826	mfsrr1	31;							\
827	stmw	30,savearea+24(0);					\
828	mfmsr	30;							\
829	ori	30,30,(PSL_DR|PSL_IR);					\
830	mtmsr	30;							\
831	isync;								\
832	mfsprg	31,1;							\
833	stwu	31,-FRAMELEN(1);					\
834	stw	0,FRAME_0+8(1);						\
835	stw	31,FRAME_1+8(1);					\
836	stw	28,FRAME_LR+8(1);					\
837	stw	29,FRAME_CR+8(1);					\
838	lmw	28,savearea(0);						\
839	stmw	2,FRAME_2+8(1);						\
840	lmw	28,savearea+16(0);					\
841	mfxer	3;							\
842	mfctr	4;							\
843	mflr	5;							\
844	andi.	5,5,0xff00;						\
845	stw	3,FRAME_XER+8(1);					\
846	stw	4,FRAME_CTR+8(1);					\
847	stw	5,FRAME_EXC+8(1);					\
848	stw	28,FRAME_DAR+8(1);					\
849	stw	29,FRAME_DSISR+8(1);					\
850	stw	30,FRAME_SRR0+8(1);					\
851	stw	31,FRAME_SRR1+8(1)
852
853#define	FRAME_LEAVE(savearea)						\
854/* Now restore regs: */							\
855	lwz	2,FRAME_SRR0+8(1);					\
856	lwz	3,FRAME_SRR1+8(1);					\
857	lwz	4,FRAME_CTR+8(1);					\
858	lwz	5,FRAME_XER+8(1);					\
859	lwz	6,FRAME_LR+8(1);					\
860	lwz	7,FRAME_CR+8(1);					\
861	stw	2,savearea(0);						\
862	stw	3,savearea+4(0);					\
863	mtctr	4;							\
864	mtxer	5;							\
865	mtlr	6;							\
866	mtsprg	1,7;			/* save cr */			\
867	lmw	2,FRAME_2+8(1);						\
868	lwz	0,FRAME_0+8(1);						\
869	lwz	1,FRAME_1+8(1);						\
870	mtsprg	2,2;			/* save r2 & r3 */		\
871	mtsprg	3,3;							\
872/* Disable translation, machine check and recoverability: */		\
873	mfmsr	2;							\
874	andi.	2,2,~(PSL_DR|PSL_IR|PSL_ME|PSL_RI)@l;			\
875	mtmsr	2;							\
876	isync;								\
877/* Decide whether we return to user mode: */				\
878	lwz	3,savearea+4(0);					\
879	mtcr	3;							\
880	bc	4,17,1f;		/* branch if PSL_PR is false */	\
881/* Restore user & kernel access SR: */					\
882/*	lis	2,curpm@ha;		get real address of pmap */	\
883/*	lwz	2,curpm@l(2);					*/	\
884/*	lwz	3,PM_USRSR(2);					*/	\
885/*	mtsr	USER_SR,3;					*/	\
886/*	lwz	3,PM_KERNELSR(2);				*/	\
887/*	mtsr	KERNEL_SR,3;					*/	\
8881:	mfsprg	2,1;			/* restore cr */		\
889	mtcr	2;							\
890	lwz	2,savearea(0);						\
891	lwz	3,savearea+4(0);					\
892	mtsrr0	2;							\
893	mtsrr1	3;							\
894	mfsprg	2,2;			/* restore r2 & r3 */		\
895	mfsprg	3,3
896
897/*
898 * Preamble code for DSI/ISI traps
899 */
900disitrap:
901	lmw	30,disisave(0)
902	stmw	30,tempsave(0)
903	lmw	30,disisave+8(0)
904	stmw	30,tempsave+8(0)
905	mfdar	30
906	mfdsisr	31
907	stmw	30,tempsave+16(0)
908realtrap:
909/* Test whether we already had PR set */
910	mfsrr1	1
911	mtcr	1
912	mfsprg	1,1			/* restore SP (might have been
913					   overwritten) */
914	bc	4,17,s_trap		/* branch if PSL_PR is false */
915	mfsprg	1,0
916	lwz	1,GD_CURPCB(1)
917	addi	1,1,USPACE		/* stack is top of user struct */
918
919/*
920 * Now the common trap catching code.
921 */
922s_trap:
923/* First have to enable KERNEL mapping */
924	lis	31,KERNEL_SEGMENT@h
925	ori	31,31,KERNEL_SEGMENT@l
926	mtsr	KERNEL_SR,31
927	FRAME_SETUP(tempsave)
928/* Now we can recover interrupts again: */
929	mfmsr	7
930	ori	7,7,(PSL_EE|PSL_FP|PSL_ME|PSL_RI)@l
931	mtmsr	7
932	isync
933/* Call C trap code: */
934	addi	3,1,8
935	mr	30,3
936	bl	trap
937	mr	3,30
938	bl	ast
939	FRAME_LEAVE(tempsave)
940	rfi
941
942/*
943 * Child comes here at the end of a fork.
944 * Mostly similar to the above.
945 */
946	.globl	fork_trampoline
947fork_trampoline:
948	xor	3,3,3
949#if 0 /* XXX */
950	bl	lcsplx
951#endif
952	mtlr	31
953	mr	3,30
954	blrl				/* jump indirect to r31 */
955	mr	3,30
956	bl	ast
957	FRAME_LEAVE(tempsave)
958	rfi
959
960/*
961 * DSI second stage fault handler
962 */
963s_dsitrap:
964	mfdsisr	31			/* test whether this may be a
965					   spill fault */
966	mtcr	31
967	mtsprg	1,1			/* save SP */
968	bc	4,1,disitrap		/* branch if table miss is false */
969	lis	1,spillstk+SPILLSTK@ha
970	addi	1,1,spillstk+SPILLSTK@l	/* get spill stack */
971	stwu	1,-52(1)
972	stw	0,48(1)			/* save non-volatile registers */
973	stw	3,44(1)
974	stw	4,40(1)
975	stw	5,36(1)
976	stw	6,32(1)
977	stw	7,28(1)
978	stw	8,24(1)
979	stw	9,20(1)
980	stw	10,16(1)
981	stw	11,12(1)
982	stw	12,8(1)
983	mflr	30			/* save trap type */
984	mfctr	31			/* & CTR */
985	mfdar	3
986s_pte_spill:
987	bl	pte_spill		/* try a spill */
988	or.	3,3,3
989	mtctr	31			/* restore CTR */
990	mtlr	30			/* and trap type */
991	mfsprg	31,2			/* get saved XER */
992	mtxer	31			/* restore XER */
993	lwz	12,8(1)			/* restore non-volatile registers */
994	lwz	11,12(1)
995	lwz	10,16(1)
996	lwz	9,20(1)
997	lwz	8,24(1)
998	lwz	7,28(1)
999	lwz	6,32(1)
1000	lwz	5,36(1)
1001	lwz	4,40(1)
1002	lwz	3,44(1)
1003	lwz	0,48(1)
1004	beq	disitrap
1005	mfsprg	1,1			/* restore SP */
1006	mtcr	29			/* restore CR */
1007	mtlr	28			/* restore LR */
1008	lmw	28,disisave(0)		/* restore r28-r31 */
1009	rfi				/* return to trapped code */
1010
1011/*
1012 * ISI second stage fault handler
1013 */
1014s_isitrap:
1015	mfsrr1	31			/* test whether this may be a
1016					   spill fault */
1017	mtcr	31
1018	mtsprg	1,1			/* save SP */
1019	bc	4,1,disitrap		/* branch if table miss is false */
1020	lis	1,spillstk+SPILLSTK@ha
1021	addi	1,1,spillstk+SPILLSTK@l	/* get spill stack */
1022	stwu	1,-52(1)
1023	stw	0,48(1)			/* save non-volatile registers */
1024	stw	3,44(1)
1025	stw	4,40(1)
1026	stw	5,36(1)
1027	stw	6,32(1)
1028	stw	7,28(1)
1029	stw	8,24(1)
1030	stw	9,20(1)
1031	stw	10,16(1)
1032	stw	11,12(1)
1033	stw	12,8(1)
1034	mfxer	30			/* save XER */
1035	mtsprg	2,30
1036	mflr	30			/* save trap type */
1037	mfctr	31			/* & ctr */
1038	mfsrr0	3
1039	b	s_pte_spill		/* above */
1040
1041/*
1042 * External interrupt second level handler
1043 */
1044#define	INTRENTER							\
1045/* Save non-volatile registers: */					\
1046	stwu	1,-88(1);		/* temporarily */		\
1047	stw	0,84(1);						\
1048	mfsprg	0,1;			/* get original SP */		\
1049	stw	0,0(1);			/* and store it */		\
1050	stw	3,80(1);						\
1051	stw	4,76(1);						\
1052	stw	5,72(1);						\
1053	stw	6,68(1);						\
1054	stw	7,64(1);						\
1055	stw	8,60(1);						\
1056	stw	9,56(1);						\
1057	stw	10,52(1);						\
1058	stw	11,48(1);						\
1059	stw	12,44(1);						\
1060	stw	28,40(1);		/* saved LR */			\
1061	stw	29,36(1);		/* saved CR */			\
1062	stw	30,32(1);		/* saved XER */			\
1063	lmw	28,tempsave(0);		/* restore r28-r31 */		\
1064	mfctr	6;							\
1065	lis	5,intr_depth@ha;					\
1066	lwz	5,intr_depth@l(5);					\
1067	mfsrr0	4;							\
1068	mfsrr1	3;							\
1069	stw	6,28(1);						\
1070	stw	5,20(1);						\
1071	stw	4,12(1);						\
1072	stw	3,8(1);							\
1073/* interrupts are recoverable here, and enable translation */		\
1074	lis	3,(KERNEL_SEGMENT|SR_SUKEY|SR_PRKEY)@h;			\
1075	ori	3,3,(KERNEL_SEGMENT|SR_SUKEY|SR_PRKEY)@l;		\
1076	mtsr	KERNEL_SR,3;						\
1077	mfmsr	5;							\
1078	ori	5,5,(PSL_IR|PSL_DR|PSL_RI);				\
1079	mtmsr	5;							\
1080	isync
1081
1082	.globl	extint_call
1083extintr:
1084	INTRENTER
1085extint_call:
1086	bl	extint_call		/* to be filled in later */
1087
1088intr_exit:
1089/* Disable interrupts (should already be disabled) and MMU here: */
1090	mfmsr	3
1091	andi.	3,3,~(PSL_EE|PSL_ME|PSL_RI|PSL_DR|PSL_IR)@l
1092	mtmsr	3
1093	isync
1094/* restore possibly overwritten registers: */
1095	lwz	12,44(1)
1096	lwz	11,48(1)
1097	lwz	10,52(1)
1098	lwz	9,56(1)
1099	lwz	8,60(1)
1100	lwz	7,64(1)
1101	lwz	6,8(1)
1102	lwz	5,12(1)
1103	lwz	4,28(1)
1104	lwz	3,32(1)
1105	mtsrr1	6
1106	mtsrr0	5
1107	mtctr	4
1108	mtxer	3
1109/* Returning to user mode? */
1110	mtcr	6			/* saved SRR1 */
1111	bc	4,17,1f			/* branch if PSL_PR is false */
1112	mfsprg	3,0			/* get globaldata */
1113	lwz	3,GD_CURPCB(3)		/* get curpcb from globaldata */
1114	lwz	3,PCB_PMR(3)		/* get pmap real address from curpcb */
1115	mtsr	KERNEL_SR,3
1116/* Setup for entry to realtrap: */
1117	lwz	3,0(1)			/* get saved SP */
1118	mtsprg	1,3
1119#if 0 /* XXX */
1120	li	6,EXC_AST
1121#endif
1122	stmw	28,tempsave(0)		/* establish tempsave again */
1123	mtlr	6
1124	lwz	28,40(1)		/* saved LR */
1125	lwz	29,36(1)		/* saved CR */
1126	lwz	6,68(1)
1127	lwz	5,72(1)
1128	lwz	4,76(1)
1129	lwz	3,80(1)
1130	lwz	0,84(1)
1131	lis	30,intr_depth@ha	 /* adjust reentrancy count */
1132	lwz	31,intr_depth@l(30)
1133	addi	31,31,-1
1134	stw	31,intr_depth@l(30)
1135	b	realtrap		/* XXX:	should call ast(frame ptr) */
11361:
1137/* Here is the normal exit of extintr: */
1138	lwz	5,36(1)
1139	lwz	6,40(1)
1140	mtcr	5
1141	mtlr	6
1142	lwz	6,68(1)
1143	lwz	5,72(1)
1144	lis	3,intr_depth@ha		/* adjust reentrancy count */
1145	lwz	4,intr_depth@l(3)
1146	addi	4,4,-1
1147	stw	4,intr_depth@l(3)
1148	lwz	4,76(1)
1149	lwz	3,80(1)
1150	lwz	0,84(1)
1151	lwz	1,0(1)
1152	rfi
1153
1154/*
1155 * Decrementer interrupt second level handler
1156 */
1157decrintr:
1158	INTRENTER
1159	addi	3,1,8			/* intr frame */
1160	bl	decr_intr
1161	b	intr_exit
1162
1163#ifdef DDB
1164/*
1165 * Deliberate entry to ddbtrap
1166 */
1167	.globl	ddb_trap
1168ddb_trap:
1169	mtsprg	1,1
1170	mfmsr	3
1171	mtsrr1	3
1172	andi.	3,3,~(PSL_EE|PSL_ME)@l
1173	mtmsr	3			/* disable interrupts */
1174	isync
1175	stmw	28,ddbsave(0)
1176	mflr	28
1177	li	29,EXC_BPT
1178	mtlr	29
1179	mfcr	29
1180	mtsrr0	28
1181
1182/*
1183 * Now the ddb trap catching code.
1184 */
1185ddbtrap:
1186	FRAME_SETUP(ddbsave)
1187/* Call C trap code: */
1188	addi	3,1,8
1189	bl	ddb_trap_glue
1190	or.	3,3,3
1191	bne	ddbleave
1192/* This wasn't for DDB, so switch to real trap: */
1193	lwz	3,FRAME_EXC+8(1)	/* save exception */
1194	stw	3,ddbsave+8(0)
1195	FRAME_LEAVE(ddbsave)
1196	mtsprg	1,1			/* prepare for entrance to realtrap */
1197	stmw	28,tempsave(0)
1198	mflr	28
1199	mfcr	29
1200	lwz	31,ddbsave+8(0)
1201	mtlr	31
1202	b	realtrap
1203ddbleave:
1204	FRAME_LEAVE(ddbsave)
1205	rfi
1206#endif /* DDB */
1207
1208#ifdef IPKDB
1209/*
1210 * Deliberate entry to ipkdbtrap
1211 */
1212	.globl	ipkdb_trap
1213ipkdb_trap:
1214	mtsprg	1,1
1215	mfmsr	3
1216	mtsrr1	3
1217	andi.	3,3,~(PSL_EE|PSL_ME)@l
1218	mtmsr	3			/* disable interrupts */
1219	isync
1220	stmw	28,ipkdbsave(0)
1221	mflr	28
1222	li	29,EXC_BPT
1223	mtlr	29
1224	mfcr	29
1225	mtsrr0	28
1226
1227/*
1228 * Now the ipkdb trap catching code.
1229 */
1230ipkdbtrap:
1231	FRAME_SETUP(ipkdbsave)
1232/* Call C trap code: */
1233	addi	3,1,8
1234	bl	ipkdb_trap_glue
1235	or.	3,3,3
1236	bne	ipkdbleave
1237/* This wasn't for IPKDB, so switch to real trap: */
1238	lwz	3,FRAME_EXC+8(1)	/* save exception */
1239	stw	3,ipkdbsave+8(0)
1240	FRAME_LEAVE(ipkdbsave)
1241	mtsprg	1,1			/* prepare for entrance to realtrap */
1242	stmw	28,tempsave(0)
1243	mflr	28
1244	mfcr	29
1245	lwz	31,ipkdbsave+8(0)
1246	mtlr	31
1247	b	realtrap
1248ipkdbleave:
1249	FRAME_LEAVE(ipkdbsave)
1250	rfi
1251
1252ipkdbfault:
1253	ba	_ipkdbfault
1254_ipkdbfault:
1255	mfsrr0	3
1256	addi	3,3,4
1257	mtsrr0	3
1258	li	3,-1
1259	rfi
1260
1261/*
1262 * int ipkdbfbyte(unsigned char *p)
1263 */
1264	.globl	ipkdbfbyte
1265ipkdbfbyte:
1266	li	9,EXC_DSI		/* establish new fault routine */
1267	lwz	5,0(9)
1268	lis	6,ipkdbfault@ha
1269	lwz	6,ipkdbfault@l(6)
1270	stw	6,0(9)
1271#ifdef	IPKDBUSERHACK
1272	lis	8,ipkdbsr@ha
1273	lwz	8,ipkdbsr@l(8)
1274	mtsr	USER_SR,8
1275	isync
1276#endif
1277	dcbst	0,9			/* flush data... */
1278	sync
1279	icbi	0,9			/* and instruction caches */
1280	lbz	3,0(3)			/* fetch data */
1281	stw	5,0(9)			/* restore previous fault handler */
1282	dcbst	0,9			/* and flush data... */
1283	sync
1284	icbi	0,9			/* and instruction caches */
1285	blr
1286
1287/*
1288 * int ipkdbsbyte(unsigned char *p, int c)
1289 */
1290	.globl	ipkdbsbyte
1291ipkdbsbyte:
1292	li	9,EXC_DSI		/* establish new fault routine */
1293	lwz	5,0(9)
1294	lis	6,ipkdbfault@ha
1295	lwz	6,ipkdbfault@l(6)
1296	stw	6,0(9)
1297#ifdef	IPKDBUSERHACK
1298	lis	8,ipkdbsr@ha
1299	lwz	8,ipkdbsr@l(8)
1300	mtsr	USER_SR,8
1301	isync
1302#endif
1303	dcbst	0,9			/* flush data... */
1304	sync
1305	icbi	0,9			/* and instruction caches */
1306	mr	6,3
1307	xor	3,3,3
1308	stb	4,0(6)
1309	dcbst	0,6			/* Now do appropriate flushes
1310					   to data... */
1311	sync
1312	icbi	0,6			/* and instruction caches */
1313	stw	5,0(9)			/* restore previous fault handler */
1314	dcbst	0,9			/* and flush data... */
1315	sync
1316	icbi	0,9			/* and instruction caches */
1317	blr
1318#endif	/* IPKDB */
1319
1320/*
1321 * int setfault()
1322 *
1323 * Similar to setjmp to setup for handling faults on accesses to user memory.
1324 * Any routine using this may only call bcopy, either the form below,
1325 * or the (currently used) C code optimized, so it doesn't use any non-volatile
1326 * registers.
1327 */
1328	.globl	setfault
1329setfault:
1330	mflr	0
1331	mfcr	12
1332	mfsprg	4,0
1333	lwz	4,GD_CURPCB(4)
1334	stw	3,PCB_ONFAULT(4)
1335	stw	0,0(3)
1336	stw	1,4(3)
1337	stw	2,8(3)
1338	stmw	12,12(3)
1339	xor	3,3,3
1340	blr
1341
1342/*
1343 * Signal "trampoline" code.
1344 */
1345	.globl	sigcode
1346sigcode:
1347	b	sys_exit
1348esigcode:
1349	.data
1350GLOBAL(szsigcode)
1351	.long	esigcode-sigcode
1352	.text
1353
1354