xref: /netbsd-src/sys/arch/ofppc/ofppc/locore.S (revision e4d7c2e329d54c97e0c0bd3016bbe74f550c3d5e)
1/*	$NetBSD: locore.S,v 1.14 2000/01/19 03:28:23 danw 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#include "opt_ddb.h"
35#include "ipkdb.h"
36#include "assym.h"
37
38#include <sys/syscall.h>
39
40#include <machine/param.h>
41#include <machine/pmap.h>
42#include <machine/psl.h>
43#include <machine/trap.h>
44#include <machine/asm.h>
45
46/*
47 * Some instructions gas doesn't understand (yet?)
48 */
49#define	bdneq	bdnzf 2,
50
51/*
52 * Globals
53 */
54GLOBAL(esym)
55	.long	0			/* end of symbol table */
56GLOBAL(proc0paddr)
57	.long	0			/* proc0 p_addr */
58
59/*
60 * File-scope for locore.S
61 */
62	.data
63idle_u:
64	.long	0			/* fake uarea during idle after exit */
65openfirmware_entry:
66	.long	0			/* openfirmware entry point */
67
68/*
69 * This symbol is here for the benefit of kvm_mkdb, and is supposed to
70 * mark the start of kernel text.
71 */
72	.text
73	.globl	_C_LABEL(kernel_text)
74_C_LABEL(kernel_text):
75
76/*
77 * Startup entry.  Note, this must be the first thing in the text
78 * segment!
79 */
80	.text
81	.globl	__start
82__start:
83#ifdef	FIRMWORKSBUGS
84	mfmsr	0
85	andi.	0,0,PSL_IR|PSL_DR
86	beq	1f
87
88	bl	_C_LABEL(ofwr_init)
891:
90#endif
91	li	0,0
92	mtmsr	0			/* Disable FPU/MMU/exceptions */
93	isync
94
95/* compute end of kernel memory */
96	lis	8,_C_LABEL(end)@ha
97	addi	8,8,_C_LABEL(end)@l
98#ifdef DDB
99	/*
100	 * XXX Account for symbols.
101	 */
102#endif
103	li	9,PGOFSET
104	add	8,8,9
105	andc	8,8,9
106	lis	9,_C_LABEL(OF_buf)@ha
107	stw	8,_C_LABEL(OF_buf)@l(9)
108	addi	8,8,NBPG
109	lis	9,idle_u@ha
110	stw	8,idle_u@l(9)
111	addi	8,8,USPACE		/* space for idle_u */
112	lis	9,_C_LABEL(proc0paddr)@ha
113	stw	8,_C_LABEL(proc0paddr)@l(9)
114	addi	1,8,USPACE-FRAMELEN	/* stackpointer for proc0 */
115	mr	4,1			/* end of mem reserved for kernel */
116	xor	0,0,0
117	stwu	0,-16(1)		/* end of stack chain */
118
119	lis	8,openfirmware_entry@ha
120	stw	5,openfirmware_entry@l(8) /* save client interface handler */
121	lis	3,__start@ha
122	addi	3,3,__start@l
123	mr	5,6			/* args string */
124	bl	_C_LABEL(initppc)
125	bl	_C_LABEL(main)
126	b	_C_LABEL(OF_exit)
127
128/*
129 * OpenFirmware entry point
130 */
131ENTRY(openfirmware)
132	mflr	0			/* save return address */
133	stw	0,4(1)
134	stwu	1,-16(1)		/* setup stack frame */
135
136	mfmsr	4			/* save msr */
137	stw	4,8(1)
138
139	lis	4,openfirmware_entry@ha	/* get firmware entry point */
140	lwz	4,openfirmware_entry@l(4)
141	mtlr	4
142
143	li	0,0			/* turn off any ints/mmu/etc. */
144	mtmsr	0
145	isync
146
147	blrl				/* call OpenFirmware */
148
149	lwz	4,8(1)			/* restore msr */
150	mtmsr	4
151	isync
152
153	lwz	1,0(1)			/* and return */
154	lwz	0,4(1)
155	mtlr	0
156	blr
157
158/*
159 * Switch to/from OpenFirmware real mode stack
160 *
161 * Note: has to be called as the very first thing in OpenFirmware interface
162 * routines.
163 * E.g.:
164 * int
165 * OF_xxx(arg1, arg2)
166 * type arg1, arg2;
167 * {
168 *	static struct {
169 *		char *name;
170 *		int nargs;
171 *		int nreturns;
172 *		char *method;
173 *		int arg1;
174 *		int arg2;
175 *		int ret;
176 *	} args = {
177 *		"xxx",
178 *		2,
179 *		1,
180 *	};
181 *
182 *	ofw_stack();
183 *	args.arg1 = arg1;
184 *	args.arg2 = arg2;
185 *	if (openfirmware(&args) < 0)
186 *		return -1;
187 *	return args.ret;
188 * }
189 */
190
191	.local	firmstk
192	.comm	firmstk,NBPG,8
193
194ENTRY(ofw_stack)
195	mfmsr	8			/* turn off interrupts */
196	andi.	0,8,~(PSL_EE|PSL_RI)@l
197	mtmsr	0
198	stw	8,4(1)			/* abuse return address slot */
199
200	lwz	5,0(1)			/* get length of stack frame */
201	subf	5,1,5
202
203	lis	7,firmstk+NBPG-8@ha
204	addi	7,7,firmstk+NBPG-8@l
205	lis	6,ofw_back@ha
206	addi	6,6,ofw_back@l
207	subf	4,5,7			/* make room for stack frame on
208					   new stack */
209	stw	6,-4(7)			/* setup return pointer */
210	stwu	1,-8(7)
211
212	stw	7,-8(4)
213
214	addi	3,1,8
215	addi	1,4,-8
216	subi	5,5,8
217
218	b	_C_LABEL(ofbcopy)	/* and copy it */
219
220ofw_back:
221	lwz	1,0(1)			/* get callers original stack pointer */
222
223	lwz	0,4(1)			/* get saved msr from abused slot */
224	mtmsr	0
225
226	lwz	1,0(1)			/* return */
227	lwz	0,4(1)
228	mtlr	0
229	blr
230
231
232/*
233 * No processes are runnable, so loop waiting for one.
234 * Separate label here for accounting purposes.
235 */
236ASENTRY(Idle)
237	mfmsr	3
238	andi.	3,3,~PSL_EE@l		/* disable interrupts while
239					   manipulating runque */
240	mtmsr	3
241
242	lis	8,_C_LABEL(whichqs)@ha
243	lwz	9,_C_LABEL(whichqs)@l(8)
244
245	or.	9,9,9
246	bne-	.Lsw1			/* at least one queue non-empty */
247
248	ori	3,3,PSL_EE@l		/* reenable ints again */
249	mtmsr	3
250	isync
251
252/* May do some power saving here? */
253
254	b	_ASM_LABEL(Idle)
255
256/*
257 * switchexit gets called from cpu_exit to complete the exit procedure.
258 */
259ENTRY(switchexit)
260/* First switch to the idle pcb/kernel stack */
261	lis	6,idle_u@ha
262	lwz	6,idle_u@l(6)
263	lis	7,_C_LABEL(curpcb)@ha
264	stw	6,_C_LABEL(curpcb)@l(7)
265	addi	1,6,USPACE-16		/* 16 bytes are reserved at stack top */
266	/*
267	 * Schedule the vmspace and stack to be freed (the proc arg is
268	 * already in r3).
269	 */
270	bl	_C_LABEL(exit2)
271
272/* Fall through to cpu_switch to actually select another proc */
273	li	3,0			/* indicate exited process */
274
275/*
276 * void cpu_switch(struct proc *p)
277 * Find a runnable process and switch to it.
278 */
279/* XXX noprofile?  --thorpej@netbsd.org */
280ENTRY(cpu_switch)
281	mflr	0			/* save lr */
282	stw	0,4(1)
283	stwu	1,-16(1)
284	stw	31,12(1)
285	stw	30,8(1)
286
287	mr	30,3
288	lis	3,_C_LABEL(curproc)@ha
289	xor	31,31,31
290	stw	31,_C_LABEL(curproc)@l(3) /* Zero to not accumulate cpu time */
291	lis	3,_C_LABEL(curpcb)@ha
292	lwz	31,_C_LABEL(curpcb)@l(3)
293
294	xor	3,3,3
295	lis	4,_C_LABEL(machine_interface)+SPLX@ha
296	lwz	0,_C_LABEL(machine_interface)+SPLX@l(4)
297	mtlr	0
298	blrl
299	stw	3,PCB_SPL(31)		/* save spl */
300
301/* Find a new process */
302	mfmsr	3
303	andi.	3,3,~PSL_EE@l		/* disable interrupts while
304					   manipulating runque */
305	mtmsr	3
306	isync
307
308	lis	8,_C_LABEL(whichqs)@ha
309	lwz	9,_C_LABEL(whichqs)@l(8)
310
311	or.	9,9,9
312	beq-	_ASM_LABEL(Idle)	/* all queues empty */
313.Lsw1:
314	cntlzw	10,9
315	lis	4,_C_LABEL(qs)@ha
316	addi	4,4,_C_LABEL(qs)@l
317	slwi	3,10,3
318	add	3,3,4			/* select queue */
319
320	lwz	31,P_FORW(3)		/* unlink first proc from queue */
321	lwz	4,P_FORW(31)
322	stw	4,P_FORW(3)
323	stw	3,P_BACK(4)
324
325	cmpl	0,3,4			/* queue empty? */
326	bne	1f
327
328	lis	3,0x80000000@h
329	srw	3,3,10
330	andc	9,9,3
331	stw	9,_C_LABEL(whichqs)@l(8) /* mark it empty */
332
3331:
334	/* just did this resched thing */
335	xor	3,3,3
336	lis	4,_C_LABEL(want_resched)@ha
337	stw	3,_C_LABEL(want_resched)@l(4)
338
339	stw	3,P_BACK(31)		/* probably superfluous */
340
341	/* record new process */
342	lis	4,_C_LABEL(curproc)@ha
343	stw	31,_C_LABEL(curproc)@l(4)
344
345	mfmsr	3
346	ori	3,3,PSL_EE@l		/* Now we can interrupt again */
347	mtmsr	3
348
349	cmpl	0,31,30			/* is it the same process? */
350	beq	switch_return
351
352	or.	30,30,30		/* old process was exiting? */
353	beq	switch_exited
354
355	mfsr	10,USER_SR		/* save USER_SR for copyin/copyout */
356	mfcr	11			/* save cr */
357	mr	12,2			/* save r2 */
358	stwu	1,-SFRAMELEN(1)		/* still running on old stack */
359	stmw	10,8(1)
360	lwz	3,P_ADDR(30)
361	stw	1,PCB_SP(3)		/* save SP */
362
363switch_exited:
364	mfmsr	3
365	andi.	3,3,~PSL_EE@l		/* disable interrupts while
366					   actually switching */
367	mtmsr	3
368
369	/* indicate new pcb */
370	lwz	4,P_ADDR(31)
371	lis	5,_C_LABEL(curpcb)@ha
372	stw	4,_C_LABEL(curpcb)@l(5)
373
374	/* save real pmap pointer for spill fill */
375	lwz	5,PCB_PMR(4)
376	lis	6,_C_LABEL(curpm)@ha
377	stwu	5,_C_LABEL(curpm)@l(6)
378	stwcx.	5,0,6			/* clear possible reservation */
379
380	addic.	5,5,64
381	li	6,0
382	mfsr	8,KERNEL_SR		/* save kernel SR */
3831:
384	addis	6,6,-0x10000000@ha	/* set new procs segment registers */
385	or.	6,6,6			/* This is done from the real
386					   address pmap */
387	lwzu	7,-4(5)			/* so we don't have to worry */
388	mtsrin	7,6			/* about accessibility */
389	bne	1b
390	mtsr	KERNEL_SR,8		/* restore kernel SR */
391	isync
392
393	lwz	1,PCB_SP(4)		/* get new procs SP */
394
395	ori	3,3,PSL_EE@l		/* interrupts are okay again */
396	mtmsr	3
397
398	lmw	10,8(1)			/* get other regs */
399	lwz	1,0(1)			/* get saved SP */
400	mr	2,12			/* get saved r2 */
401	mtcr	11			/* get saved cr */
402	isync
403	mtsr	USER_SR,10		/* get saved USER_SR */
404	isync
405
406switch_return:
407	mr	30,7			/* save proc pointer */
408	lwz	3,PCB_SPL(4)
409	lis	4,_C_LABEL(machine_interface)+SPLX@ha
410	lwz	0,_C_LABEL(machine_interface)+SPLX@l(4)
411	mtlr	0
412	blrl
413
414	mr	3,30			/* get curproc for special fork
415					   returns */
416
417	lwz	31,12(1)
418	lwz	30,8(1)
419	addi	1,1,16
420	lwz	0,4(1)
421	mtlr	0
422	blr
423
424
425/*
426 * Data used during primary/secondary traps/interrupts
427 */
428#define	tempsave	0x2e0	/* primary save area for trap handling */
429#define	disisave	0x3e0	/* primary save area for dsi/isi traps */
430
431#define	INTSTK	(8*1024)	/* 8K interrupt stack */
432	.data
433	.align	4
434intstk:
435	.space	INTSTK		/* interrupt stack */
436
437GLOBAL(intr_depth)
438	.long	-1		/* in-use marker */
439
440#define	SPILLSTK 1024		/* 1K spill stack */
441
442	.comm	spillstk,SPILLSTK,8
443
444/*
445 * This code gets copied to all the trap vectors
446 * (except ISI/DSI, ALI, the interrupts, and possibly the debugging
447 * traps when using IPKDB).
448 */
449	.text
450	.globl	_C_LABEL(trapcode),_C_LABEL(trapsize)
451_C_LABEL(trapcode):
452	mtsprg	1,1			/* save SP */
453	stmw	28,tempsave(0)		/* free r28-r31 */
454	mflr	28			/* save LR */
455	mfcr	29			/* save CR */
456/* Test whether we already had PR set */
457	mfsrr1	31
458	mtcr	31
459	bc	4,17,1f			/* branch if PSL_PR is clear */
460	lis	1,_C_LABEL(curpcb)@ha
461	lwz	1,_C_LABEL(curpcb)@l(1)
462	addi	1,1,USPACE		/* stack is top of user struct */
4631:
464	bla	s_trap
465_C_LABEL(trapsize) = .-_C_LABEL(trapcode)
466
467/*
468 * For ALI: has to save DSISR and DAR
469 */
470	.globl	_C_LABEL(alitrap),_C_LABEL(alisize)
471_C_LABEL(alitrap):
472	mtsprg	1,1			/* save SP */
473	stmw	28,tempsave(0)		/* free r28-r31 */
474	mfdar	30
475	mfdsisr	31
476	stmw	30,tempsave+16(0)
477	mflr	28			/* save LR */
478	mfcr	29			/* save CR */
479/* Test whether we already had PR set */
480	mfsrr1	31
481	mtcr	31
482	bc	4,17,1f			/* branch if PSL_PR is clear */
483	lis	1,_C_LABEL(curpcb)@ha
484	lwz	1,_C_LABEL(curpcb)@l(1)
485	addi	1,1,USPACE		/* stack is top of user struct */
4861:
487	bla	s_trap
488_C_LABEL(alisize) = .-_C_LABEL(alitrap)
489
490/*
491 * Similar to the above for DSI
492 * Has to handle BAT spills
493 * and standard pagetable spills
494 */
495	.globl	_C_LABEL(dsitrap),_C_LABEL(dsisize)
496_C_LABEL(dsitrap):
497	stmw	28,disisave(0)		/* free r28-r31 */
498	mfcr	29			/* save CR */
499	mfxer	30			/* save XER */
500	mtsprg	2,30			/* in SPRG2 */
501	mfsrr1	31			/* test kernel mode */
502	mtcr	31
503	bc	12,17,1f		/* branch if PSL_PR is set */
504	mfdar	31			/* get fault address */
505	rlwinm	31,31,7,25,28		/* get segment * 8 */
506
507	/* get batu */
508	addis	31,31,_C_LABEL(battable)@ha
509	lwz	30,_C_LABEL(battable)@l(31)
510	mtcr	30
511	bc	4,30,1f			/* branch if supervisor valid is
512					   false */
513	/* get batl */
514	lwz	31,_C_LABEL(battable)+4@l(31)
515/* We randomly use the highest two bat registers here */
516	mftb	28
517	andi.	28,28,1
518	bne	2f
519	mtdbatu	2,30
520	mtdbatl	2,31
521	b	3f
5222:
523	mtdbatu	3,30
524	mtdbatl	3,31
5253:
526	mfsprg	30,2			/* restore XER */
527	mtxer	30
528	mtcr	29			/* restore CR */
529	lmw	28,disisave(0)		/* restore r28-r31 */
530	rfi				/* return to trapped code */
5311:
532	mflr	28			/* save LR */
533	bla	s_dsitrap
534_C_LABEL(dsisize) = .-_C_LABEL(dsitrap)
535
536/*
537 * Similar to the above for ISI
538 */
539	.globl	_C_LABEL(isitrap),_C_LABEL(isisize)
540_C_LABEL(isitrap):
541	stmw	28,disisave(0)		/* free r28-r31 */
542	mflr	28			/* save LR */
543	mfcr	29			/* save CR */
544	mfsrr1	31			/* test kernel mode */
545	mtcr	31
546	bc	12,17,1f		/* branch if PSL_PR is set */
547	mfsrr0	31			/* get fault address */
548	rlwinm	31,31,7,25,28		/* get segment * 8 */
549
550	/* get batu */
551	addis	31,31,_C_LABEL(battable)@ha
552	lwz	30,_C_LABEL(battable)@l(31)
553	mtcr	30
554	bc	4,30,1f			/* branch if supervisor valid is
555					   false */
556	mtibatu	3,30
557
558	/* get batl */
559	lwz	30,_C_LABEL(battable)+4@l(31)
560	mtibatl	3,30
561
562	mtcr	29			/* restore CR */
563	lmw	28,disisave(0)		/* restore r28-r31 */
564	rfi				/* return to trapped code */
5651:
566	bla	s_isitrap
567_C_LABEL(isisize)= .-_C_LABEL(isitrap)
568
569/*
570 * This one for the external interrupt handler.
571 */
572	.globl	_C_LABEL(extint),_C_LABEL(extsize)
573_C_LABEL(extint):
574	mtsprg	1,1			/* save SP */
575	stmw	28,tempsave(0)		/* free r28-r31 */
576	mflr	28			/* save LR */
577	mfcr	29			/* save CR */
578	mfxer	30			/* save XER */
579	lis	1,intstk+INTSTK@ha	/* get interrupt stack */
580	addi	1,1,intstk+INTSTK@l
581	lwz	31,0(1)			/* were we already running on intstk? */
582	addic.	31,31,1
583	stw	31,0(1)
584	beq	1f
585	mfsprg	1,1			/* yes, get old SP */
5861:
587	ba	extintr
588_C_LABEL(extsize) = .-_C_LABEL(extint)
589
590/*
591 * And this one for the decrementer interrupt handler.
592 */
593	.globl	_C_LABEL(decrint),_C_LABEL(decrsize)
594_C_LABEL(decrint):
595	mtsprg	1,1			/* save SP */
596	stmw	28,tempsave(0)		/* free r28-r31 */
597	mflr	28			/* save LR */
598	mfcr	29			/* save CR */
599	mfxer	30			/* save XER */
600	lis	1,intstk+INTSTK@ha	/* get interrupt stack */
601	addi	1,1,intstk+INTSTK@l
602	lwz	31,0(1)			/* were we already running on intstk? */
603	addic.	31,31,1
604	stw	31,0(1)
605	beq	1f
606	mfsprg	1,1			/* yes, get old SP */
6071:
608	ba	decrintr
609_C_LABEL(decrsize) = .-_C_LABEL(decrint)
610
611/*
612 * Now the tlb software load for 603 processors:
613 * (Code essentially from the 603e User Manual, Chapter 5, but
614 * corrected a lot.)
615 */
616#define	DMISS	976
617#define	DCMP	977
618#define	HASH1	978
619#define	HASH2	979
620#define	IMISS	980
621#define	ICMP	981
622#define	RPA	982
623
624	.globl	_C_LABEL(tlbimiss),_C_LABEL(tlbimsize)
625_C_LABEL(tlbimiss):
626	mfspr	2,HASH1			/* get first pointer */
627	li	1,8
628	mfctr	0			/* save counter */
629	mfspr	3,ICMP			/* get first compare value */
630	addi	2,2,-8			/* predec pointer */
6311:
632	mtctr	1			/* load counter */
6332:
634	lwzu	1,8(2)			/* get next pte */
635	cmpl	0,1,3			/* see if found pte */
636	bdneq	2b			/* loop if not eq */
637	bne	3f			/* not found */
638	lwz	1,4(2)			/* load tlb entry lower word */
639	andi.	3,1,8			/* check G-bit */
640	bne	4f			/* if guarded, take ISI */
641	mtctr	0			/* restore counter */
642	mfspr	0,IMISS			/* get the miss address for the tlbli */
643	mfsrr1	3			/* get the saved cr0 bits */
644	mtcrf	0x80,3			/* and restore */
645	ori	1,1,0x100		/* set the reference bit */
646	mtspr	RPA,1			/* set the pte */
647	srwi	1,1,8			/* get byte 7 of pte */
648	tlbli	0			/* load the itlb */
649	stb	1,6(2)			/* update page table */
650	rfi
651
6523:	/* not found in pteg */
653	andi.	1,3,0x40		/* have we already done second hash? */
654	bne	5f
655	mfspr	2,HASH2			/* get the second pointer */
656	ori	3,3,0x40		/* change the compare value */
657	li	1,8
658	addi	2,2,-8			/* predec pointer */
659	b	1b
6604:	/* guarded */
661	mfsrr1	3
662	andi.	2,3,0xffff		/* clean upper srr1 */
663	oris	2,2,0x8000000@h		/* set srr<4> to flag prot violation */
664	b	6f
6655:	/* not found anywhere */
666	mfsrr1	3
667	andi.	2,3,0xffff		/* clean upper srr1 */
668	oris	2,2,0x40000000@h	/* set srr1<1> to flag pte not found */
6696:
670	mtctr	0			/* restore counter */
671	mtsrr1	2
672	mfmsr	0
673	xoris	0,0,0x20000@h		/* flip the msr<tgpr> bit */
674	mtcrf	0x80,3			/* restore cr0 */
675	mtmsr	0			/* now with native gprs */
676	isync
677	ba	EXC_ISI
678_C_LABEL(tlbimsize) = .-_C_LABEL(tlbimiss)
679
680	.globl	_C_LABEL(tlbdlmiss),_C_LABEL(tlbdlmsize)
681_C_LABEL(tlbdlmiss):
682	mfspr	2,HASH1			/* get first pointer */
683	li	1,8
684	mfctr	0			/* save counter */
685	mfspr	3,DCMP			/* get first compare value */
686	addi	2,2,-8			/* predec pointer */
6871:
688	mtctr	1			/* load counter */
6892:
690	lwzu	1,8(2)			/* get next pte */
691	cmpl	0,1,3			/* see if found pte */
692	bdneq	2b			/* loop if not eq */
693	bne	3f			/* not found */
694	lwz	1,4(2)			/* load tlb entry lower word */
695	mtctr	0			/* restore counter */
696	mfspr	0,DMISS			/* get the miss address for the tlbld */
697	mfsrr1	3			/* get the saved cr0 bits */
698	mtcrf	0x80,3			/* and restore */
699	ori	1,1,0x100		/* set the reference bit */
700	mtspr	RPA,1			/* set the pte */
701	srwi	1,1,8			/* get byte 7 of pte */
702	tlbld	0			/* load the dtlb */
703	stb	1,6(2)			/* update page table */
704	rfi
705
7063:	/* not found in pteg */
707	andi.	1,3,0x40		/* have we already done second hash? */
708	bne	5f
709	mfspr	2,HASH2			/* get the second pointer */
710	ori	3,3,0x40		/* change the compare value */
711	li	1,8
712	addi	2,2,-8			/* predec pointer */
713	b	1b
7145:	/* not found anywhere */
715	mfsrr1	3
716	lis	1,0x40000000@h		/* set dsisr<1> to flag pte not found */
717	mtctr	0			/* restore counter */
718	andi.	2,3,0xffff		/* clean upper srr1 */
719	mtsrr1	2
720	mtdsisr	1			/* load the dsisr */
721	mfspr	1,DMISS			/* get the miss address */
722	mtdar	1			/* put in dar */
723	mfmsr	0
724	xoris	0,0,0x20000@h		/* flip the msr<tgpr> bit */
725	mtcrf	0x80,3			/* restore cr0 */
726	mtmsr	0			/* now with native gprs */
727	isync
728	ba	EXC_DSI
729_C_LABEL(tlbdlmsize) = .-_C_LABEL(tlbdlmiss)
730
731	.globl	_C_LABEL(tlbdsmiss),_C_LABEL(tlbdsmsize)
732_C_LABEL(tlbdsmiss):
733	mfspr	2,HASH1			/* get first pointer */
734	li	1,8
735	mfctr	0			/* save counter */
736	mfspr	3,DCMP			/* get first compare value */
737	addi	2,2,-8			/* predec pointer */
7381:
739	mtctr	1			/* load counter */
7402:
741	lwzu	1,8(2)			/* get next pte */
742	cmpl	0,1,3			/* see if found pte */
743	bdneq	2b			/* loop if not eq */
744	bne	3f			/* not found */
745	lwz	1,4(2)			/* load tlb entry lower word */
746	andi.	3,1,0x80		/* check the C-bit */
747	beq	4f
7485:
749	mtctr	0			/* restore counter */
750	mfspr	0,DMISS			/* get the miss address for the tlbld */
751	mfsrr1	3			/* get the saved cr0 bits */
752	mtcrf	0x80,3			/* and restore */
753	mtspr	RPA,1			/* set the pte */
754	tlbld	0			/* load the dtlb */
755	rfi
756
7573:	/* not found in pteg */
758	andi.	1,3,0x40		/* have we already done second hash? */
759	bne	5f
760	mfspr	2,HASH2			/* get the second pointer */
761	ori	3,3,0x40		/* change the compare value */
762	li	1,8
763	addi	2,2,-8			/* predec pointer */
764	b	1b
7654:	/* found, but C-bit = 0 */
766	rlwinm.	3,1,30,0,1		/* test PP */
767	bge-	7f
768	andi.	3,1,1
769	beq+	8f
7709:	/* found, but protection violation (PP==00)*/
771	mfsrr1	3
772	lis	1,0xa000000@h		/* indicate protection violation
773					   on store */
774	b	1f
7757:	/* found, PP=1x */
776	mfspr	3,DMISS			/* get the miss address */
777	mfsrin	1,3			/* get the segment register */
778	mfsrr1	3
779	rlwinm	3,3,18,31,31		/* get PR-bit */
780	rlwnm.	2,2,3,1,1		/* get the key */
781	bne-	9b			/* protection violation */
7828:	/* found, set reference/change bits */
783	lwz	1,4(2)			/* reload tlb entry */
784	ori	1,1,0x180
785	sth	1,6(2)
786	b	5b
7875:	/* not found anywhere */
788	mfsrr1	3
789	lis	1,0x42000000@h		/* set dsisr<1> to flag pte not found */
790					/* dsisr<6> to flag store */
7911:
792	mtctr	0			/* restore counter */
793	andi.	2,3,0xffff		/* clean upper srr1 */
794	mtsrr1	2
795	mtdsisr	1			/* load the dsisr */
796	mfspr	1,DMISS			/* get the miss address */
797	mtdar	1			/* put in dar */
798	mfmsr	0
799	xoris	0,0,0x20000@h		/* flip the msr<tgpr> bit */
800	mtcrf	0x80,3			/* restore cr0 */
801	mtmsr	0			/* now with native gprs */
802	isync
803	ba	EXC_DSI
804_C_LABEL(tlbdsmsize) = .-_C_LABEL(tlbdsmiss)
805
806#ifdef DDB
807#define	ddbsave	0xde0		/* primary save area for DDB */
808/*
809 * In case of DDB we want a separate trap catcher for it
810 */
811	.local	ddbstk
812	.comm	ddbstk,INTSTK,8		/* ddb stack */
813
814	.globl	_C_LABEL(ddblow),_C_LABEL(ddbsize)
815_C_LABEL(ddblow):
816	mtsprg	1,1			/* save SP */
817	stmw	28,ddbsave(0)		/* free r28-r31 */
818	mflr	28			/* save LR */
819	mfcr	29			/* save CR */
820	lis	1,ddbstk+INTSTK@ha	/* get new SP */
821	addi	1,1,ddbstk+INTSTK@l
822	bla	ddbtrap
823_C_LABEL(ddbsize) = .-_C_LABEL(ddblow)
824#endif	/* DDB */
825
826#if NIPKDB > 0
827#define	ipkdbsave	0xde0		/* primary save area for IPKDB */
828/*
829 * In case of IPKDB we want a separate trap catcher for it
830 */
831
832	.local	ipkdbstk
833	.comm	ipkdbstk,INTSTK,8		/* ipkdb stack */
834
835	.globl	_C_LABEL(ipkdblow),_C_LABEL(ipkdbsize)
836_C_LABEL(ipkdblow):
837	mtsprg	1,1			/* save SP */
838	stmw	28,ipkdbsave(0)		/* free r28-r31 */
839	mflr	28			/* save LR */
840	mfcr	29			/* save CR */
841	lis	1,ipkdbstk+INTSTK@ha	/* get new SP */
842	addi	1,1,ipkdbstk+INTSTK@l
843	bla	ipkdbtrap
844_C_LABEL(ipkdbsize) = .-_C_LABEL(ipkdblow)
845#endif	/* NIPKDB > 0 */
846
847/*
848 * FRAME_SETUP assumes:
849 *	SPRG1		SP (1)
850 *	savearea	r28-r31,DAR,DSISR	(DAR & DSISR only for DSI traps)
851 *	28		LR
852 *	29		CR
853 *	1		kernel stack
854 *	LR		trap type
855 *	SRR0/1		as at start of trap
856 */
857#define	FRAME_SETUP(savearea)						\
858/* Have to enable translation to allow access of kernel stack: */	\
859	mfsrr0	30;							\
860	mfsrr1	31;							\
861	stmw	30,savearea+24(0);					\
862	mfmsr	30;							\
863	ori	30,30,(PSL_DR|PSL_IR);					\
864	mtmsr	30;							\
865	isync;								\
866	mfsprg	31,1;							\
867	stwu	31,-FRAMELEN(1);					\
868	stw	0,FRAME_0+8(1);						\
869	stw	31,FRAME_1+8(1);					\
870	stw	28,FRAME_LR+8(1);					\
871	stw	29,FRAME_CR+8(1);					\
872	lmw	28,savearea(0);						\
873	stmw	2,FRAME_2+8(1);						\
874	lmw	28,savearea+16(0);					\
875	mfxer	3;							\
876	mfctr	4;							\
877	mflr	5;							\
878	andi.	5,5,0xff00;						\
879	stw	3,FRAME_XER+8(1);					\
880	stw	4,FRAME_CTR+8(1);					\
881	stw	5,FRAME_EXC+8(1);					\
882	stw	28,FRAME_DAR+8(1);					\
883	stw	29,FRAME_DSISR+8(1);					\
884	stw	30,FRAME_SRR0+8(1);					\
885	stw	31,FRAME_SRR1+8(1)
886
887#define	FRAME_LEAVE(savearea)						\
888/* Now restore regs: */							\
889	lwz	2,FRAME_SRR0+8(1);					\
890	lwz	3,FRAME_SRR1+8(1);					\
891	lwz	4,FRAME_CTR+8(1);					\
892	lwz	5,FRAME_XER+8(1);					\
893	lwz	6,FRAME_LR+8(1);					\
894	lwz	7,FRAME_CR+8(1);					\
895	stw	2,savearea(0);						\
896	stw	3,savearea+4(0);					\
897	mtctr	4;							\
898	mtxer	5;							\
899	mtlr	6;							\
900	mtsprg	1,7;			/* save cr */			\
901	lmw	2,FRAME_2+8(1);						\
902	lwz	0,FRAME_0+8(1);						\
903	lwz	1,FRAME_1+8(1);						\
904	mtsprg	2,2;			/* save r2 & r3 */		\
905	mtsprg	3,3;							\
906/* Disable translation, machine check and recoverability: */		\
907	mfmsr	2;							\
908	andi.	2,2,~(PSL_DR|PSL_IR|PSL_ME|PSL_RI)@l;			\
909	mtmsr	2;							\
910	isync;								\
911/* Decide whether we return to user mode: */				\
912	lwz	3,savearea+4(0);					\
913	mtcr	3;							\
914	bc	4,17,1f;		/* branch if PSL_PR is false */	\
915/* Restore user & kernel access SR: */					\
916	lis	2,_C_LABEL(curpm)@ha;	/* get real address of pmap */	\
917	lwz	2,_C_LABEL(curpm)@l(2);					\
918	lwz	3,PM_USRSR(2);						\
919	mtsr	USER_SR,3;						\
920	lwz	3,PM_KERNELSR(2);					\
921	mtsr	KERNEL_SR,3;						\
9221:	mfsprg	2,1;			/* restore cr */		\
923	mtcr	2;							\
924	lwz	2,savearea(0);						\
925	lwz	3,savearea+4(0);					\
926	mtsrr0	2;							\
927	mtsrr1	3;							\
928	mfsprg	2,2;			/* restore r2 & r3 */		\
929	mfsprg	3,3
930
931/*
932 * Preamble code for DSI/ISI traps
933 */
934disitrap:
935	lmw	30,disisave(0)
936	stmw	30,tempsave(0)
937	lmw	30,disisave+8(0)
938	stmw	30,tempsave+8(0)
939	mfdar	30
940	mfdsisr	31
941	stmw	30,tempsave+16(0)
942realtrap:
943/* Test whether we already had PR set */
944	mfsrr1	1
945	mtcr	1
946	mfsprg	1,1			/* restore SP (might have been
947					   overwritten) */
948	bc	4,17,s_trap		/* branch if PSL_PR is false */
949	lis	1,_C_LABEL(curpcb)@ha
950	lwz	1,_C_LABEL(curpcb)@l(1)
951	addi	1,1,USPACE		/* stack is top of user struct */
952
953/*
954 * Now the common trap catching code.
955 */
956s_trap:
957/* First have to enable KERNEL mapping */
958	lis	31,KERNEL_SEGMENT@h
959	ori	31,31,KERNEL_SEGMENT@l
960	mtsr	KERNEL_SR,31
961	FRAME_SETUP(tempsave)
962/* Now we can recover interrupts again: */
963	mfmsr	7
964	ori	7,7,(PSL_EE|PSL_ME|PSL_RI)@l
965	mtmsr	7
966	isync
967/* Call C trap code: */
968trapagain:
969	addi	3,1,8
970	bl	_C_LABEL(trap)
971trapexit:
972/* Disable interrupts: */
973	mfmsr	3
974	andi.	3,3,~PSL_EE@l
975	mtmsr	3
976/* Test AST pending: */
977	lwz	5,FRAME_SRR1+8(1)
978	mtcr	5
979	bc	4,17,1f			/* branch if PSL_PR is false */
980	lis	3,_C_LABEL(astpending)@ha
981	lwz	4,_C_LABEL(astpending)@l(3)
982	andi.	4,4,1
983	beq	1f
984	li	6,EXC_AST
985	stw	6,FRAME_EXC+8(1)
986	b	trapagain
9871:
988	FRAME_LEAVE(tempsave)
989	rfi
990
991/*
992 * Child comes here at the end of a fork.
993 * Mostly similar to the above.
994 */
995	.globl	_C_LABEL(fork_trampoline)
996_C_LABEL(fork_trampoline):
997	xor	3,3,3
998	lis	4,_C_LABEL(machine_interface)+SPLX@ha
999	lwz	0,_C_LABEL(machine_interface)+SPLX@l(4)
1000	mtlr	0
1001	blrl
1002	mtlr	31
1003	mr	3,30
1004	blrl				/* jump indirect to r31 */
1005	b	trapexit
1006
1007/*
1008 * DSI second stage fault handler
1009 */
1010s_dsitrap:
1011	mfdsisr	31			/* test whether this may be a
1012					   spill fault */
1013	mtcr	31
1014	mtsprg	1,1			/* save SP */
1015	bc	4,1,disitrap		/* branch if table miss is false */
1016	lis	1,spillstk+SPILLSTK@ha
1017	addi	1,1,spillstk+SPILLSTK@l	/* get spill stack */
1018	stwu	1,-52(1)
1019	stw	0,48(1)			/* save non-volatile registers */
1020	stw	3,44(1)
1021	stw	4,40(1)
1022	stw	5,36(1)
1023	stw	6,32(1)
1024	stw	7,28(1)
1025	stw	8,24(1)
1026	stw	9,20(1)
1027	stw	10,16(1)
1028	stw	11,12(1)
1029	stw	12,8(1)
1030	mflr	30			/* save trap type */
1031	mfctr	31			/* & CTR */
1032	mfdar	3
1033s_pte_spill:
1034	bl	_C_LABEL(pte_spill)	/* try a spill */
1035	or.	3,3,3
1036	mtctr	31			/* restore CTR */
1037	mtlr	30			/* and trap type */
1038	mfsprg	31,2			/* get saved XER */
1039	mtxer	31			/* restore XER */
1040	lwz	12,8(1)			/* restore non-volatile registers */
1041	lwz	11,12(1)
1042	lwz	10,16(1)
1043	lwz	9,20(1)
1044	lwz	8,24(1)
1045	lwz	7,28(1)
1046	lwz	6,32(1)
1047	lwz	5,36(1)
1048	lwz	4,40(1)
1049	lwz	3,44(1)
1050	lwz	0,48(1)
1051	beq	disitrap
1052	mfsprg	1,1			/* restore SP */
1053	mtcr	29			/* restore CR */
1054	mtlr	28			/* restore LR */
1055	lmw	28,disisave(0)		/* restore r28-r31 */
1056	rfi				/* return to trapped code */
1057
1058/*
1059 * ISI second stage fault handler
1060 */
1061s_isitrap:
1062	mfsrr1	31			/* test whether this may be a
1063					   spill fault */
1064	mtcr	31
1065	mtsprg	1,1			/* save SP */
1066	bc	4,1,disitrap		/* branch if table miss is false */
1067	lis	1,spillstk+SPILLSTK@ha
1068	addi	1,1,spillstk+SPILLSTK@l	/* get spill stack */
1069	stwu	1,-52(1)
1070	stw	0,48(1)			/* save non-volatile registers */
1071	stw	3,44(1)
1072	stw	4,40(1)
1073	stw	5,36(1)
1074	stw	6,32(1)
1075	stw	7,28(1)
1076	stw	8,24(1)
1077	stw	9,20(1)
1078	stw	10,16(1)
1079	stw	11,12(1)
1080	stw	12,8(1)
1081	mfxer	30			/* save XER */
1082	mtsprg	2,30
1083	mflr	30			/* save trap type */
1084	mfctr	31			/* & ctr */
1085	mfsrr0	3
1086	b	s_pte_spill		/* above */
1087
1088/*
1089 * External interrupt second level handler
1090 */
1091#define	INTRENTER							\
1092/* Save non-volatile registers: */					\
1093	stwu	1,-88(1);		/* temporarily */		\
1094	stw	0,84(1);						\
1095	mfsprg	0,1;			/* get original SP */		\
1096	stw	0,0(1);			/* and store it */		\
1097	stw	3,80(1);						\
1098	stw	4,76(1);						\
1099	stw	5,72(1);						\
1100	stw	6,68(1);						\
1101	stw	7,64(1);						\
1102	stw	8,60(1);						\
1103	stw	9,56(1);						\
1104	stw	10,52(1);						\
1105	stw	11,48(1);						\
1106	stw	12,44(1);						\
1107	stw	28,40(1);		/* saved LR */			\
1108	stw	29,36(1);		/* saved CR */			\
1109	stw	30,32(1);		/* saved XER */			\
1110	lmw	28,tempsave(0);		/* restore r28-r31 */		\
1111	mfctr	6;							\
1112	lis	5,_C_LABEL(intr_depth)@ha;				\
1113	lwz	5,_C_LABEL(intr_depth)@l(5);				\
1114	mfsrr0	4;							\
1115	mfsrr1	3;							\
1116	stw	6,28(1);						\
1117	stw	5,20(1);						\
1118	stw	4,12(1);						\
1119	stw	3,8(1);							\
1120/* interrupts are recoverable here, and enable translation */		\
1121	lis	3,(KERNEL_SEGMENT|SR_SUKEY|SR_PRKEY)@h;			\
1122	ori	3,3,(KERNEL_SEGMENT|SR_SUKEY|SR_PRKEY)@l;		\
1123	mtsr	KERNEL_SR,3;						\
1124	mfmsr	5;							\
1125	ori	5,5,(PSL_IR|PSL_DR|PSL_RI);				\
1126	mtmsr	5;							\
1127	isync
1128
1129	.globl	_C_LABEL(extint_call)
1130extintr:
1131	INTRENTER
1132_C_LABEL(extint_call):
1133	bl	_C_LABEL(extint_call)	/* to be filled in later */
1134
1135intr_exit:
1136/* Disable interrupts (should already be disabled) and MMU here: */
1137	mfmsr	3
1138	andi.	3,3,~(PSL_EE|PSL_ME|PSL_RI|PSL_DR|PSL_IR)@l
1139	mtmsr	3
1140	isync
1141/* restore possibly overwritten registers: */
1142	lwz	12,44(1)
1143	lwz	11,48(1)
1144	lwz	10,52(1)
1145	lwz	9,56(1)
1146	lwz	8,60(1)
1147	lwz	7,64(1)
1148	lwz	6,8(1)
1149	lwz	5,12(1)
1150	lwz	4,28(1)
1151	lwz	3,32(1)
1152	mtsrr1	6
1153	mtsrr0	5
1154	mtctr	4
1155	mtxer	3
1156/* Returning to user mode? */
1157	mtcr	6			/* saved SRR1 */
1158	bc	4,17,1f			/* branch if PSL_PR is false */
1159	lis	3,_C_LABEL(curpm)@ha	/* get current pmap real address */
1160	lwz	3,_C_LABEL(curpm)@l(3)
1161	lwz	3,PM_KERNELSR(3)
1162	mtsr	KERNEL_SR,3		/* Restore kernel SR */
1163	lis	3,_C_LABEL(astpending)@ha /* Test AST pending */
1164	lwz	4,_C_LABEL(astpending)@l(3)
1165	andi.	4,4,1
1166	beq	1f
1167/* Setup for entry to realtrap: */
1168	lwz	3,0(1)			/* get saved SP */
1169	mtsprg	1,3
1170	li	6,EXC_AST
1171	stmw	28,tempsave(0)		/* establish tempsave again */
1172	mtlr	6
1173	lwz	28,40(1)		/* saved LR */
1174	lwz	29,36(1)		/* saved CR */
1175	lwz	6,68(1)
1176	lwz	5,72(1)
1177	lwz	4,76(1)
1178	lwz	3,80(1)
1179	lwz	0,84(1)
1180	lis	30,_C_LABEL(intr_depth)@ha /* adjust reentrancy count */
1181	lwz	31,_C_LABEL(intr_depth)@l(30)
1182	addi	31,31,-1
1183	stw	31,_C_LABEL(intr_depth)@l(30)
1184	b	realtrap
11851:
1186/* Here is the normal exit of extintr: */
1187	lwz	5,36(1)
1188	lwz	6,40(1)
1189	mtcr	5
1190	mtlr	6
1191	lwz	6,68(1)
1192	lwz	5,72(1)
1193	lis	3,_C_LABEL(intr_depth)@ha /* adjust reentrancy count */
1194	lwz	4,_C_LABEL(intr_depth)@l(3)
1195	addi	4,4,-1
1196	stw	4,_C_LABEL(intr_depth)@l(3)
1197	lwz	4,76(1)
1198	lwz	3,80(1)
1199	lwz	0,84(1)
1200	lwz	1,0(1)
1201	rfi
1202
1203/*
1204 * Decrementer interrupt second level handler
1205 */
1206decrintr:
1207	INTRENTER
1208	addi	3,1,8			/* intr frame */
1209	bl	_C_LABEL(decr_intr)
1210	b	intr_exit
1211
1212#ifdef DDB
1213/*
1214 * Deliberate entry to ddbtrap
1215 */
1216	.globl	_C_LABEL(ddb_trap)
1217_C_LABEL(ddb_trap):
1218	mtsprg	1,1
1219	mfmsr	3
1220	mtsrr1	3
1221	andi.	3,3,~(PSL_EE|PSL_ME)@l
1222	mtmsr	3			/* disable interrupts */
1223	isync
1224	stmw	28,ddbsave(0)
1225	mflr	28
1226	li	29,EXC_BPT
1227	mtlr	29
1228	mfcr	29
1229	mtsrr0	28
1230
1231/*
1232 * Now the ddb trap catching code.
1233 */
1234ddbtrap:
1235	FRAME_SETUP(ddbsave)
1236/* Call C trap code: */
1237	addi	3,1,8
1238	bl	_C_LABEL(ddb_trap_glue)
1239	or.	3,3,3
1240	bne	ddbleave
1241/* This wasn't for DDB, so switch to real trap: */
1242	lwz	3,FRAME_EXC+8(1)	/* save exception */
1243	stw	3,ddbsave+8(0)
1244	FRAME_LEAVE(ddbsave)
1245	mtsprg	1,1			/* prepare for entrance to realtrap */
1246	stmw	28,tempsave(0)
1247	mflr	28
1248	mfcr	29
1249	lwz	31,ddbsave+8(0)
1250	mtlr	31
1251	b	realtrap
1252ddbleave:
1253	FRAME_LEAVE(ddbsave)
1254	rfi
1255#endif /* DDB */
1256
1257#if NIPKDB > 0
1258/*
1259 * Deliberate entry to ipkdbtrap
1260 */
1261	.globl	_C_LABEL(ipkdb_trap)
1262_C_LABEL(ipkdb_trap):
1263	mtsprg	1,1
1264	mfmsr	3
1265	mtsrr1	3
1266	andi.	3,3,~(PSL_EE|PSL_ME)@l
1267	mtmsr	3			/* disable interrupts */
1268	isync
1269	stmw	28,ipkdbsave(0)
1270	mflr	28
1271	li	29,EXC_BPT
1272	mtlr	29
1273	mfcr	29
1274	mtsrr0	28
1275
1276/*
1277 * Now the ipkdb trap catching code.
1278 */
1279ipkdbtrap:
1280	FRAME_SETUP(ipkdbsave)
1281/* Call C trap code: */
1282	addi	3,1,8
1283	bl	_C_LABEL(ipkdb_trap_glue)
1284	or.	3,3,3
1285	bne	ipkdbleave
1286/* This wasn't for IPKDB, so switch to real trap: */
1287	lwz	3,FRAME_EXC+8(1)	/* save exception */
1288	stw	3,ipkdbsave+8(0)
1289	FRAME_LEAVE(ipkdbsave)
1290	mtsprg	1,1			/* prepare for entrance to realtrap */
1291	stmw	28,tempsave(0)
1292	mflr	28
1293	mfcr	29
1294	lwz	31,ipkdbsave+8(0)
1295	mtlr	31
1296	b	realtrap
1297ipkdbleave:
1298	FRAME_LEAVE(ipkdbsave)
1299	rfi
1300
1301ipkdbfault:
1302	ba	_ipkdbfault
1303_ipkdbfault:
1304	mfsrr0	3
1305	addi	3,3,4
1306	mtsrr0	3
1307	li	3,-1
1308	rfi
1309
1310/*
1311 * int ipkdbfbyte(unsigned char *p)
1312 */
1313	.globl	_C_LABEL(ipkdbfbyte)
1314_C_LABEL(ipkdbfbyte):
1315	li	9,EXC_DSI		/* establish new fault routine */
1316	lwz	5,0(9)
1317	lis	6,ipkdbfault@ha
1318	lwz	6,ipkdbfault@l(6)
1319	stw	6,0(9)
1320#ifdef	IPKDBUSERHACK
1321	lis	8,_C_LABEL(ipkdbsr)@ha
1322	lwz	8,_C_LABEL(ipkdbsr)@l(8)
1323	mtsr	USER_SR,8
1324	isync
1325#endif
1326	dcbst	0,9			/* flush data... */
1327	sync
1328	icbi	0,9			/* and instruction caches */
1329	lbz	3,0(3)			/* fetch data */
1330	stw	5,0(9)			/* restore previous fault handler */
1331	dcbst	0,9			/* and flush data... */
1332	sync
1333	icbi	0,9			/* and instruction caches */
1334	blr
1335
1336/*
1337 * int ipkdbsbyte(unsigned char *p, int c)
1338 */
1339	.globl	_C_LABEL(ipkdbsbyte)
1340_C_LABEL(ipkdbsbyte):
1341	li	9,EXC_DSI		/* establish new fault routine */
1342	lwz	5,0(9)
1343	lis	6,ipkdbfault@ha
1344	lwz	6,ipkdbfault@l(6)
1345	stw	6,0(9)
1346#ifdef	IPKDBUSERHACK
1347	lis	8,_C_LABEL(ipkdbsr)@ha
1348	lwz	8,_C_LABEL(ipkdbsr)@l(8)
1349	mtsr	USER_SR,8
1350	isync
1351#endif
1352	dcbst	0,9			/* flush data... */
1353	sync
1354	icbi	0,9			/* and instruction caches */
1355	mr	6,3
1356	xor	3,3,3
1357	stb	4,0(6)
1358	dcbst	0,6			/* Now do appropriate flushes
1359					   to data... */
1360	sync
1361	icbi	0,6			/* and instruction caches */
1362	stw	5,0(9)			/* restore previous fault handler */
1363	dcbst	0,9			/* and flush data... */
1364	sync
1365	icbi	0,9			/* and instruction caches */
1366	blr
1367#endif	/* NIPKDB > 0 */
1368
1369/*
1370 * int setfault()
1371 *
1372 * Similar to setjmp to setup for handling faults on accesses to user memory.
1373 * Any routine using this may only call bcopy, either the form below,
1374 * or the (currently used) C code optimized, so it doesn't use any non-volatile
1375 * registers.
1376 */
1377	.globl	_C_LABEL(setfault)
1378_C_LABEL(setfault):
1379	mflr	0
1380	mfcr	12
1381	lis	4,_C_LABEL(curpcb)@ha
1382	lwz	4,_C_LABEL(curpcb)@l(4)
1383	stw	3,PCB_FAULT(4)
1384	stw	0,0(3)
1385	stw	1,4(3)
1386	stw	2,8(3)
1387	stmw	12,12(3)
1388	xor	3,3,3
1389	blr
1390