xref: /netbsd/sys/arch/hppa/hppa/trap.S (revision c4a72b64)
1/*	$NetBSD: trap.S,v 1.5 2002/08/25 20:19:59 fredette Exp $	*/
2
3/*-
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matthew Fredette.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *      This product includes software developed by the NetBSD
21 *      Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 *    contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39/*	$OpenBSD: locore.S,v 1.46 2001/09/20 18:33:03 mickey Exp $	*/
40
41/*
42 * Copyright (c) 1998-2001 Michael Shalayeff
43 * All rights reserved.
44 *
45 * Redistribution and use in source and binary forms, with or without
46 * modification, are permitted provided that the following conditions
47 * are met:
48 * 1. Redistributions of source code must retain the above copyright
49 *    notice, this list of conditions and the following disclaimer.
50 * 2. Redistributions in binary form must reproduce the above copyright
51 *    notice, this list of conditions and the following disclaimer in the
52 *    documentation and/or other materials provided with the distribution.
53 * 3. All advertising materials mentioning features or use of this software
54 *    must display the following acknowledgement:
55 *      This product includes software developed by Michael Shalayeff.
56 * 4. The name of the author may not be used to endorse or promote products
57 *    derived from this software without specific prior written permission.
58 *
59 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
60 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
61 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
62 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
63 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
64 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
65 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
67 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
68 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
69 * THE POSSIBILITY OF SUCH DAMAGE.
70 *
71 * Portitions of this file are derived from other sources, see
72 * the copyrights and acknowledgements below.
73 */
74/*
75 * Copyright (c) 1990,1991,1992,1994 The University of Utah and
76 * the Computer Systems Laboratory (CSL).  All rights reserved.
77 *
78 * THE UNIVERSITY OF UTAH AND CSL PROVIDE THIS SOFTWARE IN ITS "AS IS"
79 * CONDITION, AND DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
80 * WHATSOEVER RESULTING FROM ITS USE.
81 *
82 * CSL requests users of this software to return to csl-dist@cs.utah.edu any
83 * improvements that they make and grant CSL redistribution rights.
84 *
85 *	Utah $Hdr: locore.s 1.62 94/12/15$
86 */
87/*
88 *  (c) Copyright 1988 HEWLETT-PACKARD COMPANY
89 *
90 *  To anyone who acknowledges that this file is provided "AS IS"
91 *  without any express or implied warranty:
92 *      permission to use, copy, modify, and distribute this file
93 *  for any purpose is hereby granted without fee, provided that
94 *  the above copyright notice and this notice appears in all
95 *  copies, and that the name of Hewlett-Packard Company not be
96 *  used in advertising or publicity pertaining to distribution
97 *  of the software without specific, written prior permission.
98 *  Hewlett-Packard Company makes no representations about the
99 *  suitability of this software for any purpose.
100 */
101
102/*
103 * NOTICE: This is not a standalone file.  To use it, #include it in
104 * your port's locore.S, like so:
105 *
106 *	#include <hppa/hppa/trap.S>
107 */
108
109	.section .data
110	.align	2048
111$trap_tmp_save			/* XXX assumed to be aligned on 2048 */
112	.block	TF_PHYS		/* XXX must be aligned to 64 */
113	.align	64
114	.export emergency_stack_start, data
115emergency_stack_start
116	.block	32768		/* XXX must be aligned to 64 */
117	.export emergency_stack_end, data
118emergency_stack_end
119	.block	4
120
121	.text
122
123/*
124 * Kernel Gateway Page (must be at known address)
125 *	System Call Gate
126 *	Signal Return Gate
127 *
128 * GATEway instructions have to be at a fixed known locations
129 * because their addresses are hard coded in routines such as
130 * those in the C library.
131 */
132	.align	NBPG
133	.export	gateway_page, entry
134gateway_page
135	nop				/* @ 0.C0000000 (Nothing)  */
136	gate,n	$bsd_syscall,r0		/* @ 0.C0000004 (HPUX/BSD) */
137#ifdef COMPAT_OSF1
138	bl,n	$osf_syscall,r0
139	bl,n	$osf_syscall,r0
140#else
141	nop				/* @ 0.C0000008 (HPOSF UNIX) */
142	nop				/* @ 0.C000000C (HPOSF Mach) */
143#endif
144	nop
145	nop
146	nop
147	nop
148
149#ifdef COMPAT_OSF1
150$osf_syscall
151	/*
152	 * Ripped screaming from OSF/MkLinux:
153	 *
154	 * Convert HPOSF system call to a BSD one by stashing arg4 and arg5
155	 * back into the frame, and moving the system call number into r22.
156	 * Fortunately, the HPOSF compiler has a bigger stack frame, which
157	 * allows this horrible hack.
158	 *
159	 * We also need to save r29 (aka ret1) for the emulator since it may
160	 * get clobbered between here and there.
161	 */
162	stw	r22, HPPA_FRAME_ARG(4)(sp)
163	stw	r21, HPPA_FRAME_ARG(5)(sp)
164	stw	r29, HPPA_FRAME_SL(sp)
165	gate	$bsd_syscall,r0
166	copy	r1, r22
167#endif /* COMPAT_OSF1 */
168
169$bsd_syscall
170	/*
171	 * set up a space register and a protection id so that
172	 * we can access kernel memory
173	 */
174	mfctl	eiem, r1
175	mtctl	r0, eiem
176	mtsp	r0, sr1
177	mfctl	pidr1, r28
178	ldi	HPPA_PID_KERNEL, t2
179	mtctl	t2, pidr1
180
181	/*
182	 * now call the syscall handler
183	 */
184	.import $syscall,code
185	.call
186	ldil	L%$syscall, t2
187	be,n	R%$syscall(sr7, t2)
188	nop
189
190	.align	NBPG
191	.export	gateway_page_end, entry
192gateway_page_end
193
194	.export $syscall,entry
195	.proc
196	.callinfo calls
197	.entry
198$syscall
199	/*
200	 *
201	 * t1:	curproc
202	 * t2:	user
203	 * t3:	args
204	 * t4:	user stack
205	 *
206	 * N.B. we are trying to rely on the fact that bottom of kernel
207	 *	stack contains a print of some past trapframe, so
208	 *	we do not save hard to get information, but do restore
209	 *	the whole context later on return anyway.
210	 * XXXXXX this is very bad. everything must be saved
211	 */
212	ldil	L%curproc, t3
213	ldw	R%curproc(sr1, t3), t3
214	ldw	P_ADDR(sr1, t3), t2	/* XXX can use ,sl */
215
216	/* calculate kernel sp, load, create kernel stack frame */
217	/*
218	 * NB: Even though t4 is a caller-saved register, we
219	 * save it anyways, as a convenience to __vfork14 and
220	 * any other syscalls that absolutely must have a
221	 * register that is saved for it.
222	 */
223	ldo	NBPG+TRAPFRAME_SIZEOF(t2), t3
224	stw	t1, TF_R22 -TRAPFRAME_SIZEOF(sr1, t3)	/* syscall # */
225	stw	t4, TF_R19 -TRAPFRAME_SIZEOF(sr1, t3)	/* convenience */
226	copy	sp, t4
227	ldo	HPPA_FRAME_SIZE+HPPA_FRAME_MAXARGS(t3), sp
228	stw	t4, TF_R30 -TRAPFRAME_SIZEOF(sr1, t3)	/* user stack */
229	stw	r1, TF_CR15-TRAPFRAME_SIZEOF(sr1, t3)	/* eiem */
230	mtctl	r1, eiem
231
232	/*
233	 * Normally, we only have to save the caller-saved registers,
234	 * because the callee-saved registers will be naturally
235	 * saved and restored by our callee(s).  However, see the
236	 * longer comment in the trap handling code below for the
237	 * reasons why we need to save and restore all of them.
238	 */
239	stw	r27, TF_R27-TRAPFRAME_SIZEOF(sr1, t3)	/* dp */
240	stw	r3 , TF_R3 -TRAPFRAME_SIZEOF(sr1, t3)
241#if defined(DDB) || defined(KGDB) || defined(FPEMUL)
242	stw	r4 , TF_R4 -TRAPFRAME_SIZEOF(sr1, t3)
243	stw	r5 , TF_R5 -TRAPFRAME_SIZEOF(sr1, t3)
244	stw	r6 , TF_R6 -TRAPFRAME_SIZEOF(sr1, t3)
245	stw	r7 , TF_R7 -TRAPFRAME_SIZEOF(sr1, t3)
246	stw	r8 , TF_R8 -TRAPFRAME_SIZEOF(sr1, t3)
247	stw	r9 , TF_R9 -TRAPFRAME_SIZEOF(sr1, t3)
248	stw	r10, TF_R10-TRAPFRAME_SIZEOF(sr1, t3)
249	stw	r11, TF_R11-TRAPFRAME_SIZEOF(sr1, t3)
250	stw	r12, TF_R12-TRAPFRAME_SIZEOF(sr1, t3)
251	stw	r13, TF_R13-TRAPFRAME_SIZEOF(sr1, t3)
252	stw	r14, TF_R14-TRAPFRAME_SIZEOF(sr1, t3)
253	stw	r15, TF_R15-TRAPFRAME_SIZEOF(sr1, t3)
254	stw	r16, TF_R16-TRAPFRAME_SIZEOF(sr1, t3)
255	stw	r17, TF_R17-TRAPFRAME_SIZEOF(sr1, t3)
256	stw	r18, TF_R18-TRAPFRAME_SIZEOF(sr1, t3)
257#endif /* DDB || KGDB || FPEMUL */
258	stw	r0, 0(sr1, t3)	/* terminate frame */
259	copy	r0 , r3
260	stw	r0, HPPA_FRAME_PSP(sr1, sp)
261	stw	r0, HPPA_FRAME_CRP(sr1, sp)
262
263	/*
264	 * Copy Arguments
265	 * unfortunately mmap() under bsd requires 7 words;
266	 * linux is confined to 5, and hpux to 6.
267	 * assuming the `long' syscall it gives us the maximum
268	 * 9 words, which very much overkill for an average of 3.
269	 * we keep it at 10, since bundling will keep it
270	 * at the same speed as 9 anyway.
271	 */
272	/*
273	 * XXX fredette - possible security hole here.
274	 * What happens if the user hands us a stack
275	 * that points to nowhere, or to data that they
276	 * should not be reading?
277	 */
278	stw	arg0, 1*4(sr1, t3)	/* XXX can use ,bc */
279	stw	arg1, 2*4(sr1, t3)
280	stw	arg2, 3*4(sr1, t3)
281	stw	arg3, 4*4(sr1, t3)
282	ldw	HPPA_FRAME_ARG( 4)(t4), arg0
283	ldw	HPPA_FRAME_ARG( 5)(t4), arg1
284	ldw	HPPA_FRAME_ARG( 6)(t4), arg2
285	ldw	HPPA_FRAME_ARG( 7)(t4), arg3
286	stw	arg0, 5*4(sr1, t3)
287	stw	arg1, 6*4(sr1, t3)
288	stw	arg2, 7*4(sr1, t3)
289	stw	arg3, 8*4(sr1, t3)
290	ldw	HPPA_FRAME_ARG( 8)(t4), arg0
291	ldw	HPPA_FRAME_ARG( 9)(t4), arg1
292	stw	arg0, 9*4(sr1, t3)
293	stw	arg1,10*4(sr1, t3)
294
295	/*
296	 * Save the rest of the CPU context
297	 */
298
299	ldo	4(r31), arg1
300	stw	r31, TF_IIOQH-TRAPFRAME_SIZEOF(sr1, t3)
301	stw	arg1, TF_IIOQT-TRAPFRAME_SIZEOF(sr1, t3)
302
303	mfsp	sr0, arg0
304	stw	arg0, TF_IISQH-TRAPFRAME_SIZEOF(sr1, t3)
305	stw	arg0, TF_IISQT-TRAPFRAME_SIZEOF(sr1, t3)
306
307	stw	arg0, TF_CR20-TRAPFRAME_SIZEOF(sr1, t3)
308	stw	r31, TF_CR21-TRAPFRAME_SIZEOF(sr1, t3)
309
310	ldil	L%(PSW_Q | PSW_P | PSW_C | PSW_D | PSW_I), arg1
311	ldo	R%(PSW_Q | PSW_P | PSW_C | PSW_D | PSW_I)(arg1), arg1
312	mfsp	sr3, arg0
313	stw	arg1, TF_CR22-TRAPFRAME_SIZEOF(sr1, t3)
314	stw	arg0, TF_SR3-TRAPFRAME_SIZEOF(sr1, t3)
315	stw	r28, TF_CR8-TRAPFRAME_SIZEOF(sr1, t3)	/* pidr1 */
316
317	copy	r0, arg0
318	ldil	TFF_LAST|TFF_SYS, arg1
319	stw	arg0, TF_CR19-TRAPFRAME_SIZEOF(sr1, t3)
320	stw	arg1, TF_FLAGS-TRAPFRAME_SIZEOF(sr1, t3)
321
322	mfsp	sr0, arg0
323	copy	arg0, arg1	/* we overwrote sr1 earlier */
324	mfsp	sr2, arg2
325	mfsp	sr4, arg3
326	stw	arg0, TF_SR0-TRAPFRAME_SIZEOF(sr1, t3)
327	stw	arg1, TF_SR1-TRAPFRAME_SIZEOF(sr1, t3)
328	stw	arg2, TF_SR2-TRAPFRAME_SIZEOF(sr1, t3)
329	stw	arg3, TF_SR4-TRAPFRAME_SIZEOF(sr1, t3)
330
331	mfsp	sr5, arg0
332	mfsp	sr6, arg1
333	mfsp	sr7, arg2
334	mfctl	pidr2, arg3
335	stw	arg0, TF_SR5-TRAPFRAME_SIZEOF(sr1, t3)
336	stw	arg1, TF_SR6-TRAPFRAME_SIZEOF(sr1, t3)
337	stw	arg2, TF_SR7-TRAPFRAME_SIZEOF(sr1, t3)
338	stw	arg3, TF_CR9-TRAPFRAME_SIZEOF(sr1, t3)
339
340#if pbably_not_worth_it
341	mfctl	pidr3, arg2
342	mfctl	pidr4, arg3
343	stw	arg2, TF_CR12-TRAPFRAME_SIZEOF(sr1, t3)
344	stw	arg3, TF_CR13-TRAPFRAME_SIZEOF(sr1, t3)
345#endif
346
347#if defined(DDB) || defined(KGDB)
348	/*
349	 * Save hpt mask and v2p translation table pointer
350	 */
351	mfctl	eirr, arg0
352	mfctl	hptmask, arg1
353	stw	arg0, TF_CR23-TRAPFRAME_SIZEOF(sr1, t3)
354	stw	arg1, TF_CR24-TRAPFRAME_SIZEOF(sr1, t3)
355
356	mfctl	vtop, arg0
357	mfctl	cr28, arg1
358	stw	arg0, TF_CR25-TRAPFRAME_SIZEOF(sr1, t3)
359	stw	arg1, TF_CR28-TRAPFRAME_SIZEOF(sr1, t3)
360#endif
361
362	/* setup kernel context */
363	mtsp	r0, sr0
364	mtsp	r0, sr1
365	mtsp	r0, sr2
366	mtsp	r0, sr3
367	mtsp	r0, sr4
368	mtsp	r0, sr5
369	mtsp	r0, sr6
370	mtsp	r0, sr7
371
372	ldo	-TRAPFRAME_SIZEOF(t3), arg0
373	ldo	4(t3), arg1
374
375	ldil	L%$global$,dp
376	ldo	R%$global$(dp),dp
377
378	/* do a syscall */
379	.import	syscall,code
380	ldil	L%syscall, r1
381	ldo	R%syscall(r1), r1
382	.call
383	blr	r0, rp
384	bv,n	0(r1)
385	nop
386
387	ldil	L%curproc, r1
388	ldw	R%curproc(r1), r1
389	ldw	P_MD(r1), t3
390
391	.exit
392	.procend
393	/* FALLTHROUGH */
394
395	.export	$syscall_return, entry
396	.proc
397	.callinfo no_calls
398	.entry
399$syscall_return
400	/* t3 == VA trapframe */
401	/* check for AST ? XXX */
402
403	/* splhigh(), just in case */
404	mtctl	r0, eiem
405
406	/*
407	 * 1a. Copy a `phys' part of the frame into temp store
408	 *	(see a note for trapall)
409	 *	hopefully no page fault would happen on or after the copy,
410	 *	and interrupts are disabled.
411	 */
412	copy	t3, arg0
413	ldil	L%$trap_tmp_save, arg1
414	ldi	TF_PHYS - 4, arg2
415$syscall_return_copy_loop
416	ldwm	4(arg0), t1
417	addib,>= -4, arg2, $syscall_return_copy_loop
418	stwm	t1, 4(arg1)
419
420	/* 1b. restore most of the general registers */
421	ldw	TF_CR11(t3), t1
422	mtctl	t1, sar
423	ldw	TF_R1(t3), r1
424	ldw	TF_R2(t3), r2
425	ldw	TF_R3(t3), r3
426	/*
427	 * See the comment in the trap handling code below
428	 * about why we need to save and restore all general
429	 * registers under these cases.
430	 */
431#if defined(DDB) || defined(KGDB) || defined(FPEMUL)
432	ldw	TF_R4(t3), r4
433	ldw	TF_R5(t3), r5
434	ldw	TF_R6(t3), r6
435	ldw	TF_R7(t3), r7
436	ldw	TF_R8(t3), r8
437	ldw	TF_R9(t3), r9
438	ldw	TF_R10(t3), r10
439	ldw	TF_R11(t3), r11
440	ldw	TF_R12(t3), r12
441	ldw	TF_R13(t3), r13
442	ldw	TF_R14(t3), r14
443	ldw	TF_R15(t3), r15
444	ldw	TF_R16(t3), r16
445	ldw	TF_R17(t3), r17
446	ldw	TF_R18(t3), r18
447#endif /* DDB || KGDB || FPEMUL */
448	ldw	TF_R19(t3), t4
449	/*	r20(t3) is used as a temporary and will be restored later */
450	/*	r21(t2) is used as a temporary and will be restored later */
451	/*	r22(t1) is used as a temporary and will be restored later */
452	ldw	TF_R23(t3), r23
453	ldw	TF_R24(t3), r24
454	ldw	TF_R25(t3), r25
455	ldw	TF_R26(t3), r26
456	ldw	TF_R27(t3), r27
457	ldw	TF_R28(t3), r28
458	ldw	TF_R29(t3), r29
459	/*	r30 (sp) will be restored later */
460	ldw	TF_R31(t3), r31
461
462	/* 2. restore all the space regs and pid regs, except sr3, pidr1 */
463	ldw	TF_SR0(t3), t1
464	ldw	TF_SR1(t3), t2
465	mtsp	t1, sr0
466	mtsp	t2, sr1
467
468	ldw	TF_SR2(sr3, t3), t1
469	ldw	TF_SR4(sr3, t3), t2
470	mtsp	t1, sr2
471	mtsp	t2, sr4
472
473	ldw	TF_SR5(sr3, t3), t1
474	ldw	TF_SR6(sr3, t3), t2
475	mtsp	t1, sr5
476	mtsp	t2, sr6
477
478	ldw	TF_SR7(sr3, t3), t1
479	ldw	TF_CR9(sr3, t3), t2
480	mtsp	t1, sr7
481	mtctl	t2, pidr2
482
483#if pbably_not_worth_it
484	ldw	TF_CR12(sr3, t3), t1
485	ldw	TF_CR13(sr3, t3), t2
486	mtctl	t1, pidr3
487	mtctl	t2, pidr4
488#endif
489	ldw	TF_CR0(sr3, t3), t1
490	mtctl	t1, rctr
491	ldw	TF_CR30(sr3, t3), t1
492	mtctl	t1, cr30
493
494	/*
495	 * clear the system mask, this puts us back into physical mode.
496	 * reload trapframe pointer w/ correspondent PA value.
497	 * sp will be left in virtual until restored from trapframe,
498	 * since we don't use it anyway.
499	 */
500	rsm	RESET_PSW, r0
501	nop ! nop ! nop ! nop ! nop ! nop ! nop ! nop	/* XXX really? */
502$syscall_return_phys
503
504	ldil	L%$trap_tmp_save, t3
505
506	/* finally we can restore the space and offset queues and the ipsw */
507	ldw	TF_IISQH(t3), t1
508	ldw	TF_IISQT(t3), t2
509	mtctl	t1, pcsq
510	mtctl	t2, pcsq
511
512	ldw	TF_IIOQH(t3), t1
513	ldw	TF_IIOQT(t3), t2
514	mtctl	t1, pcoq
515	mtctl	t2, pcoq
516
517	ldw	TF_CR15(t3), t1
518	ldw	TF_CR22(t3), t2
519	mtctl	t1, eiem
520	mtctl	t2, ipsw
521
522	ldw	TF_SR3(t3), t1
523	ldw	TF_CR8(t3), t2
524	mtsp	t1, sr3
525	mtctl	t2, pidr1
526
527	ldw	TF_R22(t3), t1
528	ldw	TF_R21(t3), t2
529	ldw	TF_R30(t3), sp
530	ldw	TF_R20(t3), t3
531
532	rfi
533	nop
534	.exit
535	.procend
536$syscall_end
537
538/*
539 * interrupt vector table
540 */
541/* XXX - fredette changed sr4 to sr7 below: */
542#define	TLABEL(name)	$trap$name
543#define	TELABEL(num)	__CONCAT(trap_ep_,num)
544#define TRAP(name,num) \
545	.import TLABEL(name), code	! \
546	mtctl	r1, tr7			! \
547	ldil	L%TLABEL(name), r1	! \
548	.call				! \
549	be	R%TLABEL(name)(sr7, r1)	! \
550	ldi	num, r1			! \
551	.align	32
552
553#define	ATRAP(name,num) \
554	.export	TLABEL(name)$num, entry	! \
555	.label	TLABEL(name)$num	! \
556	TRAP(all,num)
557
558#define	CTRAP(name,num,pre) \
559	.export	TLABEL(name)$num, entry	! \
560	.label	TLABEL(name)$num	! \
561	pre				! \
562	TRAP(name,num)
563
564#define	STRAP(name,num,pre) \
565	.export	TLABEL(name)$num, entry	! \
566	.label	TLABEL(name)$num	! \
567	pre				! \
568	mtctl	r1, tr7			! \
569	.export	TELABEL(num), entry	! \
570	.label	TELABEL(num)		! \
571	ldil	0,r1			! \
572	ldo	0(r1), r1		! \
573	.call				! \
574	bv	0(r1)			! \
575	ldi	num, r1
576
577#define	LDILDO(name)			! \
578	.export	name, entry		! \
579	.label	name			! \
580	ldil	L%$name,%r1		! \
581	ldo	R%$name(%r1), %r1
582
583#ifdef HP7000_CPU
584LDILDO(itlb_x)
585LDILDO(dtlb_x)
586LDILDO(dtlbna_x)
587LDILDO(tlbd_x)
588
589LDILDO(itlb_s)
590LDILDO(dtlb_s)
591LDILDO(dtlbna_s)
592LDILDO(tlbd_s)
593#endif
594
595#ifdef HP7100_CPU
596LDILDO(itlb_t)
597LDILDO(dtlb_t)
598LDILDO(dtlbna_t)
599LDILDO(tlbd_t)
600#endif
601
602#ifdef HP7100LC_CPU
603LDILDO(itlb_l)
604LDILDO(dtlb_l)
605LDILDO(dtlbna_l)
606LDILDO(tlbd_l)
607#endif
608
609#define	ITLBPRE \
610	mfctl	pcoq,r9		/* Offset */			! \
611	mfctl	pcsq,r8		/* Space  */			! \
612	depi	0,31,PGSHIFT,r9	/* align offset to page */
613#define	DTLBPRE \
614	mfctl	ior, r9		/* Offset */			! \
615	mfctl	isr, r8		/* Space  */			! \
616	depi	0,31,PGSHIFT,r9	/* align offset to page */
617	/* CR28XXX according to a popular belief cr28 should be read here */
618#define	HPMCPRE	nop
619
620	.align NBPG
621	.export $ivaaddr, entry
622	.export os_hpmc, entry
623$ivaaddr
624	ATRAP(null,T_NONEXIST)		/*  0. invalid interrupt vector */
625os_hpmc
626	CTRAP(hpmc,T_HPMC,HPMCPRE)	/*  1. high priority machine check */
627	ATRAP(power,T_POWERFAIL)	/*  2. power failure */
628	ATRAP(recnt,T_RECOVERY)		/*  3. recovery counter trap */
629	ATRAP(intr,T_INTERRUPT)		/*  4. external interrupt */
630	ATRAP(lpmc,T_LPMC)		/*  5. low-priority machine check */
631	STRAP(itlb,T_ITLBMISS,ITLBPRE)	/*  6. instruction TLB miss fault */
632	ATRAP(iprot,T_IPROT)		/*  7. instruction protection trap */
633	ATRAP(ill,T_ILLEGAL)		/*  8. Illegal instruction trap */
634	CTRAP(ibrk,T_IBREAK,)		/*  9. break instruction trap */
635	ATRAP(privop,T_PRIV_OP)		/* 10. privileged operation trap */
636	ATRAP(privr,T_PRIV_REG)		/* 11. privileged register trap */
637	ATRAP(ovrfl,T_OVERFLOW)		/* 12. overflow trap */
638	ATRAP(cond,T_CONDITION)		/* 13. conditional trap */
639	ATRAP(excpt,T_EXCEPTION)	/* 14. assist exception trap */
640	STRAP(dtlb,T_DTLBMISS,DTLBPRE)	/* 15. data TLB miss fault */
641	STRAP(itlb,T_ITLBMISSNA,ITLBPRE)/* 16. ITLB non-access miss fault */
642	STRAP(dtlb,T_DTLBMISSNA,DTLBPRE)/* 17. DTLB non-access miss fault */
643	ATRAP(dprot,T_DPROT)		/* 18. data protection trap
644					      unalligned data reference trap */
645	ATRAP(dbrk,T_DBREAK)		/* 19. data break trap */
646	STRAP(tlbd,T_TLB_DIRTY,DTLBPRE)	/* 20. TLB dirty bit trap */
647	ATRAP(pgref,T_PAGEREF)		/* 21. page reference trap */
648	CTRAP(emu,T_EMULATION,)		/* 22. assist emulation trap */
649	ATRAP(hpl,T_HIGHERPL)		/* 23. higher-privelege transfer trap*/
650	ATRAP(lpl,T_LOWERPL)		/* 24. lower-privilege transfer trap */
651	ATRAP(tknbr,T_TAKENBR)		/* 25. taken branch trap */
652	ATRAP(dacc,T_DATACC)		/* 26. data access rights trap */
653	ATRAP(dpid,T_DATAPID)		/* 27. data protection ID trap */
654	ATRAP(dalgn,T_DATALIGN)		/* 28. unaligned data ref trap */
655	ATRAP(unk29,29)
656	ATRAP(unk30,30)
657	ATRAP(unk31,31)
658	ATRAP(unk32,32)
659	ATRAP(unk33,33)
660	ATRAP(unk34,34)
661	ATRAP(unk35,35)
662	ATRAP(unk36,36)
663	ATRAP(unk37,37)
664	ATRAP(unk38,38)
665	ATRAP(unk39,39)
666	ATRAP(unk40,40)
667	ATRAP(unk41,41)
668	ATRAP(unk42,42)
669	ATRAP(unk43,43)
670	ATRAP(unk44,44)
671	ATRAP(unk45,45)
672	ATRAP(unk46,46)
673	ATRAP(unk47,47)
674	ATRAP(unk48,48)
675	ATRAP(unk49,49)
676	ATRAP(unk50,50)
677	ATRAP(unk51,51)
678	ATRAP(unk52,52)
679	ATRAP(unk53,53)
680	ATRAP(unk54,54)
681	ATRAP(unk55,55)
682	ATRAP(unk56,56)
683	ATRAP(unk57,57)
684	ATRAP(unk58,58)
685	ATRAP(unk59,59)
686	ATRAP(unk60,60)
687	ATRAP(unk61,61)
688	ATRAP(unk62,62)
689	ATRAP(unk63,63)
690					/* 64 */
691
692/*
693 * This is the locore support for HPMC and TOC machine checks.
694 * In the HPMC case, this is a continuation of the HPMC handler
695 * that begins in the interrupt vector table.  In the TOC
696 * case, this is the handler installed in page zero.
697 *
698 * Notable points about the CPU state for the OS_TOC handler:
699 *
700 * - The PSW Q bit is 1, all other PSW bits are 0.
701 * - CR14 (IVA) does not point to our vector table.
702 * - CR22 (IPSW) is valid.
703 * - All other control registers HVERSION dependent.
704 * - The TLB is initialized and invalid.
705 *
706 * Notable points about the CPU state for the OS_HPMC handler:
707 *
708 * - The PSW M bit is 1, all other PSW bits are 0.
709 * - CR14 (IVA) does point to our vector table.
710 * - CR22 (IPSW) is valid.
711 * - All other control registers HVERSION dependent.
712 * - The TLB is unchanged.
713 *
714 * The TOC CPU state is actually trickier.  Whereas in the HPMC
715 * case, we can return to virtual mode right away, in the TOC
716 * case we can't return to virtual mode until the kernel mapping
717 * is reloaded into the BTLB.
718 *
719 * Otherwise, we set up the kernel context, move onto the
720 * emergency stack, and call hppa_machine_check.
721 */
722ENTRY(os_toc, 0)
723	/* This loads %arg0 and nullifies the next instruction. */
724	addi,tr	T_INTERRUPT, %r0, %arg0
725EXIT(os_toc)
726ENTRY(TLABEL(hpmc),0)
727ALTENTRY(os_hpmc_cont)
728	ldi	T_HPMC, %arg0
729
730	/* Disable interrupts. */
731	mtctl	%r0, eiem
732
733	/* Load protection and space registers for the kernel. */
734	ldi	HPPA_PID_KERNEL, %r1
735	mtctl	%r1, pidr1
736	ldi	HPPA_SID_KERNEL, %r1
737	mtsp	%r1, sr0
738	mtsp	%r1, sr1
739	mtsp	%r1, sr2
740	mtsp	%r1, sr3
741	mtsp	%r1, sr4
742	mtsp	%r1, sr5
743	mtsp	%r1, sr6
744	mtsp	%r1, sr7
745
746	/* Reload the Interruption Vector Address. */
747	ldil	L%$ivaaddr, %r1
748	ldo	R%$ivaaddr(%r1), %r1
749	mtctl	%r1, iva
750
751	/* Reload the HPT base and mask. */
752	ldil	L%hpt_base, %r1
753	ldw	R%hpt_base(%r1), %r1
754	mtctl	%r1, vtop
755	ldil	L%hpt_mask, %r1
756	ldw	R%hpt_mask(%r1), %r1
757	mtctl	%r1, hptmask
758
759	/* Disable interrupts for the long haul. */
760	ldil	L%kpsw, t1
761	ldw	R%kpsw(t1), %r1
762	depi	0, PSW_I_POS, 1, %r1
763	stw	%r1, R%kpsw(t1)
764
765	/* Reload the global data pointer. */
766	ldil	L%$global$, dp
767	ldo	R%$global$(dp), dp
768
769	/* Move onto the emergency stack. */
770	ldil	L%emergency_stack_start, %sp
771	ldo	R%emergency_stack_start(%sp), %sp
772	stw,ma	%r0, HPPA_FRAME_SIZE(%sp)
773	copy	%sp, %r3
774
775	/* Start stack calling convention. */
776	stw	%r0, HPPA_FRAME_CRP(%sp)
777	stw	%r0, HPPA_FRAME_PSP(%sp)
778	copy	%r3, %r1
779	copy	%sp, %r3
780	stw,ma	%r1, HPPA_FRAME_SIZE(%sp)
781
782	/* If this is a TOC, remap the kernel. */
783	comib,<>,n T_INTERRUPT, %arg0, $check_do_rfi
784
785	/* Clear kernelmapped. */
786	ldil	L%kernelmapped, %r1
787	stw	%r0, R%kernelmapped(%r1)
788
789	/* Call hppa_btlb_reload. */
790	ldil	L%hppa_btlb_reload, %r1
791	ldo	R%hppa_btlb_reload(%r1), %r1
792	blr	0, %rp
793	bv	%r0(%r1)
794	nop
795
796	/* Set kernelmapped. */
797	ldil	L%kernelmapped, %r1
798	stw	%r1, R%kernelmapped(%r1)
799
800	/* Reload %arg0 (it may have been destroyed). */
801	ldi	T_INTERRUPT, %arg0
802
803	/* Disable the interrupt queues. */
804	rsm	RESET_PSW, %r0
805
806$check_do_rfi
807
808	/* Load IPSW. */
809	ldil	L%kpsw, %r1
810	ldw	R%kpsw(%r1), %r1
811	mtctl	%r1, ipsw
812
813	/* Get the address of hppa_machine_check. */
814	ldil	L%hppa_machine_check, %r1
815	ldo	R%hppa_machine_check(%r1), %r1
816
817	/* Load the instruction address queues. */
818	mtctl	%r1, pcoq
819	ldo	4(%r1), %r1
820	mtctl	%r1, pcoq
821	ldi	HPPA_SID_KERNEL, %r1
822	mtctl	%r1, pcsq
823	mtctl	%r1, pcsq
824
825	blr	0, %rp
826	rfi
827	nop
828	nop
829	nop
830ALTENTRY(os_hpmc_cont_end)
831	nop
832ALTENTRY(os_toc_end)
833EXIT(TLABEL(hpmc))
834
835/*
836 * This handles all assist emulation traps.  We break
837 * these down into three categories: emulate special
838 * function unit, emulate non-FPU coprocessor, and
839 * emulate FPU coprocessor, and dispatch accordingly.
840 */
841	.export TLABEL(emu), entry
842LEAF_ENTRY(TLABEL(emu))
843
844	/*
845	 * Save %arg0 and load it with the instruction
846	 * that caused the emulation trap.
847	 */
848	mtctl	%arg0, tr2
849	mfctl	iir, %arg0
850
851	/*
852	 * If the opcode field in the instruction is 4,
853	 * indicating a special function unit SPOP
854	 * instruction, branch to emulate an sfu.
855	 */
856	extru	%arg0, 5, 6, %r1
857	comib,=,n 4, %r1, $emulate_sfu
858
859	/*
860	 * If the uid field in the instruction is not
861	 * zero or one, indicating a coprocessor other
862	 * than an FPU, branch to emulate a non-FPU
863	 * coprocessor.
864	 */
865	extru	%arg0, 25, 3, %r1
866	comib,<<,n 1, %r1, $emulate_coproc
867
868	/*
869	 * If we're still here, this is a FPU
870	 * coprocessor instruction.  That we trapped
871	 * to emulate it means one of three things.
872	 *
873	 * If we do not have a hardware FPU, we need
874	 * to emulate this instruction.
875	 *
876	 * If we do have a hardware FPU but it is
877	 * disabled, we trapped because the current
878	 * process' state is not loaded into the
879	 * FPU.  We load that state in, possibly
880	 * swapping out another process' state first.
881	 *
882	 * If we do have a hardware FPU and it is
883	 * enabled, we trapped because of an
884	 * instruction that isn't supported by this
885	 * FPU, and so we need to emulate it.
886	 */
887
888	/*
889	 * As an optimization, hppa_fpu_bootstrap
890	 * replaces this branch instruction with a
891	 * nop if there is a hardware FPU.
892	 *
893	 * Otherwise, this is the branch to emulate
894	 * an FPU coprocessor.
895	 */
896ALTENTRY(hppa_fpu_nop0)
897	b,n	$emulate_fpu
898
899	/*
900	 * We have a hardware FPU.  If it is enabled,
901	 * branch to emulate the instruction.
902	 */
903	mfctl	ccr, %arg0
904	extru,= %arg0, 25, 2, %r1
905	b,n	$emulate_fpu
906
907	/*
908	 * The hardware FPU is disabled, so we need to swap
909	 * in the FPU state of the process whose uspace
910	 * physical address in %cr30.  We may also need
911	 * to swap out the FPU state of any process whose
912	 * uspace physical address is in the fpu_cur_uspace
913	 * variable.
914	 */
915
916	/*
917	 * So far, the CTRAP() macro has saved %r1 in
918	 * %tr7, and the dispatching above has saved
919	 * %arg0 in tr2.  Save the other registers that
920	 * we want to use.  hppa_fpu_swap deliberately
921	 * uses only these registers and %r1 and %arg0.
922	 */
923	mtctl	%arg1, tr3
924	mtctl	%rp, tr5
925
926	/*
927	 * Call hppa_fpu_swap.
928	 */
929	ldil	L%fpu_cur_uspace, %arg0
930	ldw	R%fpu_cur_uspace(%arg0), %arg0
931	mfctl	cr30, %arg1
932	blr	0, %rp
933	b	hppa_fpu_swap
934	nop
935
936	/* Restore registers and rfi. */
937	mfctl	tr5, %rp
938	mfctl	tr3, %arg1
939	mfctl	tr2, %arg0
940	mfctl	tr7, %r1
941	rfi
942	nop
943
944	/*
945	 * We branch here to emulate a special function
946	 * unit instruction.  On entry, %r1 is saved in %tr7
947	 * (courtesy of CTRAP), and %arg0 is saved in %tr2
948	 * (courtesy of the sfu/coprocessor dispatcher).
949	 */
950$emulate_sfu
951	/*
952	 * Currently we just restore %arg0 and
953	 * trap with an illegal instruction.
954	 */
955	mfctl	tr2, %arg0
956	b	TLABEL(all)
957	ldi	T_ILLEGAL, %r1
958
959	/*
960	 * We branch here to emulate a non-FPU coprocessor
961	 * instruction.  On entry, %r1 is saved in %tr7
962	 * (courtesy of CTRAP), and %t1 is saved in %tr2
963	 * (courtesy of the sfu/coprocessor dispatcher).
964	 */
965$emulate_coproc
966	/*
967	 * Currently we just restore %arg0 and
968	 * trap with an illegal instruction.
969	 */
970	mfctl	tr2, %arg0
971	b	TLABEL(all)
972	ldi	T_ILLEGAL, %r1
973
974	/*
975	 * We branch here to emulate an FPU coprocessor
976	 * instruction.  On entry, %r1 is saved in %tr7
977	 * (courtesy of CTRAP), and %t1 is saved in %tr2
978	 * (courtesy of the sfu/coprocessor dispatcher).
979	 */
980$emulate_fpu
981	/*
982	 * We get back to C via the normal generic trap
983	 * mechanism, as opposed to switching to a special
984	 * stack, setting up a trapframe, etc., ourselves,
985	 * for three reasons.
986	 *
987	 * One, I want to turn interrupts back on, since
988	 * the emulation code might not be fast.  Two,
989	 * because the instruction to emulate might be
990	 * a load or a store, I need to turn address
991	 * translation back on (i.e., return to virtual
992	 * mode.)  Third, doing both of those plus
993	 * setting up a trapframe is a pain, and the
994	 * generic trap handling already does it all.
995	 *
996	 * To relieve trap() from having to check for
997	 * sfu and non-FPU instructions again, it assumes
998	 * that these kinds of instructions have already
999	 * been translated into some other trap type (as
1000	 * they have, by the above $emulate_sfu and
1001	 * $emulate_coproc), and all T_EMULATION | T_USER
1002	 * traps are FPU instructions that need emulating.
1003	 *
1004	 * So we just restore %arg0 and trap with
1005	 * T_EMULATION.
1006	 */
1007	mfctl	tr2, %arg0
1008	b	TLABEL(all)
1009	ldi	T_EMULATION, %r1
1010EXIT(TLABEL(emu))
1011
1012/*
1013 * void hppa_fpu_swap(struct user *user_out, struct user *user_in);
1014 */
1015LEAF_ENTRY(hppa_fpu_swap)
1016
1017	/*
1018	 * Note that this function must work in
1019	 * physical mode as well as virtual mode,
1020	 * because it can be called by a trap
1021	 * handler.  This also further restricts
1022	 * the registers we can use.  We can only
1023	 * use %arg0, %arg1, and %r1.
1024	 */
1025
1026	/*
1027	 * Assuming that user_out and user_in aren't
1028	 * both NULL, we will have to run coprocessor
1029	 * instructions, so we'd better enable it.
1030	 *
1031	 * Also, branch if there's no FPU state
1032	 * to swap out.
1033	 */
1034	mfctl	ccr, %r1
1035	depi	3, 25, 2, %r1
1036	comb,=	%r0, %arg0, $fpu_swap_in
1037	mtctl	%r1, ccr
1038
1039	/*
1040	 * Swap out the current FPU state.
1041	 */
1042	ldo	PCB_FPREGS(%arg0), %arg0
1043	fstds,ma fr0 , 8(%arg0)	/* fr0 must be saved first */
1044	fstds,ma fr1 , 8(%arg0)
1045	fstds,ma fr2 , 8(%arg0)
1046	fstds,ma fr3 , 8(%arg0)
1047	fstds,ma fr4 , 8(%arg0)
1048	fstds,ma fr5 , 8(%arg0)
1049	fstds,ma fr6 , 8(%arg0)
1050	fstds,ma fr7 , 8(%arg0)
1051	fstds,ma fr8 , 8(%arg0)
1052	fstds,ma fr9 , 8(%arg0)
1053	fstds,ma fr10, 8(%arg0)
1054	fstds,ma fr11, 8(%arg0)
1055	fstds,ma fr12, 8(%arg0)
1056	fstds,ma fr13, 8(%arg0)
1057	fstds,ma fr14, 8(%arg0)
1058	fstds,ma fr15, 8(%arg0)
1059	fstds,ma fr16, 8(%arg0)
1060	fstds,ma fr17, 8(%arg0)
1061	fstds,ma fr18, 8(%arg0)
1062	fstds,ma fr19, 8(%arg0)
1063	fstds,ma fr20, 8(%arg0)
1064	fstds,ma fr21, 8(%arg0)
1065	fstds,ma fr22, 8(%arg0)
1066	fstds,ma fr23, 8(%arg0)
1067	fstds,ma fr24, 8(%arg0)
1068	fstds,ma fr25, 8(%arg0)
1069	fstds,ma fr26, 8(%arg0)
1070	fstds,ma fr27, 8(%arg0)
1071	fstds,ma fr28, 8(%arg0)
1072	fstds,ma fr29, 8(%arg0)
1073	fstds,ma fr30, 8(%arg0)
1074	fstds    fr31, 0(%arg0)
1075
1076$fpu_swap_in
1077
1078	/*
1079	 * Stash the incoming user structure in
1080	 * fpu_cur_uspace.  Because this variable
1081	 * holds a physical address, this means
1082	 * that hppa_fpu_swap can only be called
1083	 * with a non-zero user_in from physical
1084	 * mode (i.e., from the emulation assist
1085	 * trap handler).  And that's exactly
1086	 * what happens now.
1087	 *
1088	 * So stash fpu_cur_uspace, branching
1089	 * past the swap-in code if it is zero.
1090	 */
1091	ldil	L%fpu_cur_uspace, %r1
1092	comb,=	%r0, %arg1, $fpu_no_swap_in
1093	stw	%arg1, R%fpu_cur_uspace(%r1)
1094
1095	/*
1096	 * Swap in the new FPU state.
1097	 */
1098	ldo	PCB_FPREGS+31*8(%arg1), %arg1
1099	fldds,ma -8(%arg1), fr31
1100	fldds,ma -8(%arg1), fr30
1101	fldds,ma -8(%arg1), fr29
1102	fldds,ma -8(%arg1), fr28
1103	fldds,ma -8(%arg1), fr27
1104	fldds,ma -8(%arg1), fr26
1105	fldds,ma -8(%arg1), fr25
1106	fldds,ma -8(%arg1), fr24
1107	fldds,ma -8(%arg1), fr23
1108	fldds,ma -8(%arg1), fr22
1109	fldds,ma -8(%arg1), fr21
1110	fldds,ma -8(%arg1), fr20
1111	fldds,ma -8(%arg1), fr19
1112	fldds,ma -8(%arg1), fr18
1113	fldds,ma -8(%arg1), fr17
1114	fldds,ma -8(%arg1), fr16
1115	fldds,ma -8(%arg1), fr15
1116	fldds,ma -8(%arg1), fr14
1117	fldds,ma -8(%arg1), fr13
1118	fldds,ma -8(%arg1), fr12
1119	fldds,ma -8(%arg1), fr11
1120	fldds,ma -8(%arg1), fr10
1121	fldds,ma -8(%arg1), fr9
1122	fldds,ma -8(%arg1), fr8
1123	fldds,ma -8(%arg1), fr7
1124	fldds,ma -8(%arg1), fr6
1125	fldds,ma -8(%arg1), fr5
1126	fldds,ma -8(%arg1), fr4
1127	fldds,ma -8(%arg1), fr3
1128	fldds,ma -8(%arg1), fr2
1129	fldds,ma -8(%arg1), fr1
1130	fldds     0(%arg1), fr0	/* fr0 must be restored last */
1131
1132$fpu_swap_done
1133
1134	/* Increment the switch count and return. */
1135	ldil	L%fpu_csw, %r1
1136	ldw	R%fpu_csw(%r1), %arg0
1137	ldo	1(%arg0), %arg0
1138	bv	%r0(%rp)
1139	stw	%arg0, R%fpu_csw(%r1)
1140
1141$fpu_no_swap_in
1142
1143	/* We didn't swap any FPU state in, so disable the FPU. */
1144	mfctl	ccr, %r1
1145	depi	0, 25, 2, %r1
1146	b	$fpu_swap_done
1147	mtctl	%r1, ccr
1148EXIT(hppa_fpu_swap)
1149
1150	/* Compute the hpt entry ptr */
1151#define	HPTENT \
1152	extru	r9, 23, 24, r16		/* r16 = (offset >> 8) */	! \
1153	zdep	r8, 22, 16, r24		/* r24 = (space << 9) */	! \
1154	mfctl	hptmask, r17		/* r17 = sizeof(HPT)-1 */	! \
1155	xor	r16, r24, r24		/* r24 ^= r16 */		! \
1156	and	r17, r24, r24		/* r24 &= r17 */		! \
1157	mfctl	vtop, r16		/* r16 = address of HPT table */! \
1158	or	r16, r24, r24		/* r24 = HPT entry */
1159
1160	/* Construct the virtual address tag. */
1161	/* NB: it is legal for off and t to be the same. */
1162#define VTAG(sp,off,t) \
1163	shd	%r0, off, 1, t		/* t[1..15] = off[0..14] */	! \
1164	dep	sp, 31, 16, t		/* put in the space id */	! \
1165	depi	1, 0, 1, t		/* and set the valid bit */
1166
1167#if defined(HP7000_CPU)
1168/*
1169 * int desidhash_s(void)
1170 */
1171	.align	64
1172LEAF_ENTRY(desidhash_s)
1173ALTENTRY(desidhash_x)
1174	MFCPU_T(DR_CPUCFG,22)	/* t1 */
1175	MFCPU_T(DR_CPUCFG,22)
1176	depi	0, DR0_PCXS_DHE, 3, t1	/* 3 4 DR0_PCXS_DOMAIN|DR0_PCXS_IHE */
1177	depi	1, DR0_PCXS_EQWSTO, 1, t1
1178	depi	0, DR0_PCXS_DHPMC, 1, t1
1179	depi	0, DR0_PCXS_ILPMC, 1, t1
1180	MTCPU_T(22,DR_CPUCFG)
1181	MTCPU_T(22,DR_CPUCFG)
1182	bv	0(rp)
1183	extru	t1, 4, 5, ret0	/* return chip revision */
1184EXIT(desidhash_s)
1185#endif /* HP7000_CPU */
1186
1187#ifdef HP7100_CPU
1188/*
1189 * int desidhash_t(void)
1190 */
1191	.align	64
1192LEAF_ENTRY(desidhash_t)
1193	MFCPU_T(DR_CPUCFG,22)	/* t1 */
1194	MFCPU_T(DR_CPUCFG,22)
1195	depi	0, DR0_PCXT_IHE, 1, t1
1196	depi	0, DR0_PCXT_DHE, 1, t1
1197	depi	0, DR0_PCXT_DHPMC, 1, t1
1198	depi	0, DR0_PCXT_ILPMC, 1, t1
1199	MTCPU_T(22,DR_CPUCFG)
1200	MTCPU_T(22,DR_CPUCFG)
1201	bv	0(rp)
1202	extru	t1, 4, 5, ret0	/* return chip revision */
1203EXIT(desidhash_t)
1204#endif
1205
1206/*
1207 * This is a handler for interruption 20, "TLB dirty bit trap".  It
1208 * is used on the PA7000 (PCX), PA7000 (PCX-S), and PA7100 (PCX-T).
1209 * Only shadowed registers are available, and they are:
1210 *
1211 * %r1 = C trap number
1212 * %r8 = data address space identifier
1213 * %r9 = data address offset
1214 * %r16 = undefined
1215 * %r17 = undefined
1216 * %r24 = undefined
1217 * %r25 = undefined
1218 */
1219$tlbd_x
1220$tlbd_s
1221$tlbd_t
1222	/*
1223	 * Calculate the offset of the HPT entry into %r24,
1224	 * and save it into %cr28 for recovery later, when
1225	 * we want to update the HPT.
1226	 */
1227	HPTENT
1228	mtctl	r24, cr28
1229
1230	/*
1231	 * Search the list of mappings attached to this
1232	 * HPT entry until we find the faulting mapping.
1233	 * If we don't find it, trap to C.
1234	 */
1235	ldw	HPT_ENTRY(r24), r24
1236$hash_loop_tlbd_t
1237	comb,=,n r0, r24, TLABEL(all)
1238	ldw	PV_VA(r24), r25
1239	ldw	PV_SPACE(r24), r17
1240	comb,<>,n r9, r25, $hash_loop_tlbd_t
1241	ldw	PV_HASH(r24), r24
1242	comb,<>,n r8, r17, $hash_loop_tlbd_t
1243	ldw	PV_HASH(r24), r24
1244
1245	/*
1246	 * We found the faulting mapping.  If it is not
1247	 * marked TLB_NO_RW_ALIAS, we have to flush all
1248	 * other mappings of this page.
1249	 */
1250	ldw	PV_TLBPROT(r24), r25
1251	bb,>=,n	%r25, TLB_NO_RW_ALIAS_POS, $flush_all_tlbd_t
1252
1253	/*
1254	 * Otherwise, just calculate the HPT tag, set the
1255	 * dirty bit on the mapping, and load it into the
1256	 * HPT and TLB.
1257	 */
1258$load_tlbd_t
1259	VTAG(%r8, %r9, %r16)
1260	b	$tlb_inshpt_t
1261	depi	1, TLB_DIRTY_POS, 1, r25
1262
1263	/*
1264	 * This flushes all other mappings of the page.  Since
1265	 * the flushing subroutine destroys %r8, %r9, and %r25,
1266	 * we have to reload them before we can continue.
1267	 */
1268$flush_all_tlbd_t
1269	bl	$flush_all_tlbd, %r1
1270	nop
1271	copy	%r0, %r1
1272	DTLBPRE
1273	ldw	PV_TLBPROT(%r24), %r25
1274	b	$load_tlbd_t
1275
1276/*
1277 * This is a handler for interruption 6, "Instruction TLB miss fault",
1278 * and interruption 16, "Non-access instruction TLB miss fault".  It
1279 * is used on the PA7000 (PCX), PA7000 (PCX-S), and PA7100 (PCX-T).
1280 * Only shadowed registers are available, and they are:
1281 *
1282 * %r1 = C trap number
1283 * %r8 = instruction address space identifier
1284 * %r9 = instruction address offset
1285 * %r16 = undefined
1286 * %r17 = undefined
1287 * %r24 = undefined
1288 * %r25 = undefined
1289 */
1290$itlb_x
1291$itlb_s
1292$itlb_t
1293	depi	1, TFF_ITLB_POS, 1, r1	/* mark for ITLB insert */
1294	/* FALLTHROUGH */
1295
1296/*
1297 * This is a handler for interruption 15, "Data TLB miss fault",
1298 * and interruption 17, "Non-access data TLB miss fault".  It is
1299 * used on the PA7000 (PCX), PA7000 (PCX-S), and PA7100 (PCX-T).
1300 * Only shadowed registers are available, and they are:
1301 *
1302 * %r1 = C trap number
1303 * %r8 = data address space identifier
1304 * %r9 = data address offset
1305 * %r16 = undefined
1306 * %r17 = undefined
1307 * %r24 = undefined
1308 * %r25 = undefined
1309 */
1310$dtlb_x
1311$dtlbna_x
1312$dtlb_s
1313$dtlbna_s
1314$dtlb_t
1315$dtlbna_t
1316	/*
1317	 * Calculate the offset of the HPT entry into %r24,
1318	 * and save it into %cr28 for recovery later, when
1319	 * we want to update the HPT.
1320	 */
1321	HPTENT
1322	mtctl	r24, cr28
1323
1324	/*
1325	 * Calculate the HPT tag for the faulting address
1326	 * and compare it against the one in the HPT entry.
1327	 * If they are different, we must find the mapping
1328	 * for the faulting address.
1329	 */
1330	ldw	HPT_TAG(r24),r17
1331	VTAG(%r8, %r9, %r16)
1332	comb,<>,n r16, r17, $tlb_gottalook_t
1333
1334	/*
1335	 * Otherwise, do the TLB insertion using the
1336	 * information in the HPT entry.
1337	 */
1338	ldw	HPT_TLBPAGE(r24), r17
1339	b	$tlb_gothpt_t
1340	ldw	HPT_TLBPROT(r24), r25
1341
1342$tlb_gottalook_t
1343	/*
1344	 * Search the list of mappings attached to this
1345	 * HPT entry until we find the faulting mapping.
1346	 * If we don't find it, branch to a subhandler
1347	 * that checks for a non-access fault caused by
1348	 * an LPA instruction.
1349	 */
1350	ldw	HPT_ENTRY(r24),r24
1351$hash_loop_t
1352	comb,=,n r0, r24, $tlbiflpa
1353	ldw	PV_VA(r24),r25
1354	ldw	PV_SPACE(r24),r17
1355	comb,<>,n r9,r25,$hash_loop_t
1356	ldw	PV_HASH(r24),r24
1357	comb,<>,n r8,r17,$hash_loop_t
1358	ldw	PV_HASH(r24),r24
1359
1360	/*
1361	 * If this mapping is not marked TLB_REF, and
1362	 * it isn't marked TLB_NO_RW_ALIAS, we have to
1363	 * flush any writable mapping for this page.
1364	 * Since TLB_REF and TLB_NO_RW_ALIAS are adjacent,
1365	 * we can test if they are both clear with one
1366	 * extru instruction.
1367	 */
1368	ldw	PV_TLBPROT(r24),r25
1369	extru,<> %r25, TLB_NO_RW_ALIAS_POS, 2, %r0
1370	b,n	$flush_writable_t
1371
1372	/* Mark this mapping as referenced. */
1373	depi	1, TLB_REF_POS, 1, r25
1374	/* FALLTHROUGH */
1375
1376/*
1377 * Load the HPT entry with a mapping.  On entry:
1378 *
1379 * %r1 = C trap number
1380 * %r8 = address space identifier
1381 * %r9 = address offset
1382 * %r16 = HPT tag
1383 * %r17 = undefined
1384 * %r24 = mapping
1385 * %r25 = TLB protection
1386 * %cr28 = HPT entry
1387 */
1388$tlb_inshpt_t
1389	stw	r25, PV_TLBPROT(r24)
1390	ldw	PV_TLBPAGE(r24),r17
1391	mfctl	cr28, r24
1392
1393	stw	r16, HPT_TAG(r24)
1394	stw	r25, HPT_TLBPROT(r24)
1395	stw	r17, HPT_TLBPAGE(r24)
1396	/* FALLTHROUGH */
1397
1398/*
1399 * Do the real TLB insertion.  On entry:
1400 *
1401 * %r1 = C trap number
1402 * %r8 = address space identifier
1403 * %r9 = address offset
1404 * %r16 = undefined
1405 * %r17 = TLB page
1406 * %r24 = undefined
1407 * %r25 = TLB protection
1408 */
1409$tlb_gothpt_t
1410	mfsp	sr1, r16
1411	bb,<	r1, TFF_ITLB_POS, $tlb_itlb_t
1412	mtsp	r8, sr1
1413
1414	idtlba	r17,(sr1, r9)
1415	idtlbp	r25,(sr1, r9)
1416	nop ! nop
1417	mtsp	r16, sr1
1418	rfir
1419	nop
1420
1421$tlb_itlb_t
1422	iitlba	r17,(sr1, r9)
1423	iitlbp	r25,(sr1, r9)
1424	nop ! nop
1425	mtsp	r16, sr1
1426	rfir
1427	nop
1428
1429/*
1430 * Flush any writable mapping in the TLB and cache, in order
1431 * to insert a readable mapping.  On entry:
1432 *
1433 * %r1 = C trap number
1434 * %r8 = undefined
1435 * %r9 = undefined
1436 * %r16 = undefined
1437 * %r17 = undefined
1438 * %r24 = struct pv_entry * of readable mapping
1439 * %r25 = undefined
1440 */
1441$flush_writable_t
1442	/*
1443	 * Branch if this was an ITLB fault.
1444	 */
1445	bb,<,n	%r1, TFF_ITLB_POS, $flush_writable_itlb_t
1446
1447	/*
1448	 * Flush any writable mapping, then reload registers
1449	 * for a DTLB insertion.
1450	 */
1451	bl	$flush_writable, %r1
1452	nop
1453	copy	%r0, %r1
1454	DTLBPRE
1455	VTAG(%r8, %r9, %r16)
1456	ldw	PV_TLBPROT(%r24), %r25
1457	b	$tlb_inshpt_t
1458	depi	1, TLB_REF_POS, 1, %r25
1459
1460$flush_writable_itlb_t
1461	/*
1462	 * Flush any writable mapping, then reload registers
1463	 * for an ITLB insertion.
1464	 */
1465	bl	$flush_writable, %r1
1466	nop
1467	ldil	L%TFF_ITLB, %r1
1468	ITLBPRE
1469	VTAG(%r8, %r9, %r16)
1470	ldw	PV_TLBPROT(%r24), %r25
1471	b	$tlb_inshpt_t
1472	depi	1, TLB_REF_POS, 1, %r25
1473
1474#ifdef HP7100LC_CPU
1475/*
1476 * int
1477 * ibtlb_l(int i, pa_space_t sp, vaddr_t va, paddr_t pa, vsize_t sz, u_int prot)
1478 */
1479LEAF_ENTRY(ibtlb_l)
1480	rsm	(PSW_R|PSW_I), t4
1481
1482	bv	0(rp)
1483	mtsm	t4
1484EXIT(ibtlb_l)
1485
1486/*
1487 * int
1488 * pbtlb_l(int i)
1489 */
1490LEAF_ENTRY(pbtlb_l)
1491	; DR_PAGE0
1492	rsm	(PSW_R|PSW_I), t4
1493	ldil	L%0xc041, t1
1494	dep	arg0, 30, 3, t1
1495	MTCPU_T(22,DR_DTLB)	/* t1 */
1496	mtsp	r0, sr1
1497	idtlba	r0,(sr1,r0)
1498	idtlbp	r0,(sr1,r0)
1499	zdepi	-1, 18, 1, t1
1500	MTCPU_T(22,DR_DTLB)
1501	bv	0(rp)
1502	mtsm	t4
1503EXIT(pbtlb_l)
1504
1505/*
1506 * int desidhash_l(void)
1507 */
1508LEAF_ENTRY(desidhash_l)
1509	MFCPU_C(DR_CPUCFG,22)	/* t1 */
1510	depi	0, DR0_PCXL_L2IHASH_EN, 2, t1	/* + DR0_PCXL_L2DHASH_EN */
1511	depi	0, DR0_PCXL_L2IHPMC, 1, t1	/* don't reset */
1512	depi	0, DR0_PCXL_L2DHPMC, 1, t1	/* don't reset */
1513	depi	0, DR0_PCXL_L1IHPMC, 1, t1	/* don't reset */
1514	depi	0, DR0_PCXL_L2PARERR,1, t1	/* don't reset */
1515		/* set DR0_PCXL_L1ICACHE_EN ??? */
1516	MTCPU_C(22,DR_CPUCFG)
1517	bv	0(rp)
1518	extru	t1, 4, 5, ret0	/* return chip revision */
1519EXIT(desidhash_l)
1520
1521
1522/*
1523 * This is a handler for interruption 20, "TLB dirty bit trap".  It
1524 * is used on the PA7100LC (PCX-L), PA7300LC (PCX-L2), PA8000 (PCX-U),
1525 * PA8200 (PCX-W), PA8500 (PCX-W), and PA8600 (PCX-W+).  Only shadowed
1526 * registers are available, and they are:
1527 *
1528 * %r1 = C trap number
1529 * %r8 = data address space identifier
1530 * %r9 = data address offset
1531 * %r16 = undefined
1532 * %r17 = undefined
1533 * %r24 = undefined
1534 * %r25 = undefined
1535 */
1536$tlbd_l
1537	/*
1538	 * Calculate the offset of the HPT entry into %r24,
1539	 * and save it into %cr28 for recovery later, when
1540	 * we want to update the HPT.
1541	 */
1542	HPTENT
1543	mtctl	%r24, %cr28
1544
1545	/*
1546	 * Search the list of mappings attached to this
1547	 * HPT entry until we find the faulting mapping.
1548	 * If we don't find it, trap to C.
1549	 */
1550	ldw	HPT_ENTRY(r24), r16
1551$hash_loop_tlbd_l
1552	comb,=,n r0, r16, TLABEL(all)
1553	ldw	PV_VA(r16), r25
1554	ldw	PV_SPACE(r16), r17
1555	comb,<>,n r9, r25, $hash_loop_tlbd_l
1556	ldw	PV_HASH(r16), r16
1557	comb,<>,n r8, r17, $hash_loop_tlbd_l
1558	ldw	PV_HASH(r16), r16
1559
1560	/*
1561	 * We found the faulting mapping.  If it is not
1562	 * marked TLB_NO_RW_ALIAS, we have to flush all
1563	 * other mappings of this page.
1564	 */
1565	ldw	PV_TLBPAGE(r16), r17
1566	ldw	PV_TLBPROT(r16), r25
1567	bb,>=,n	%r25, TLB_NO_RW_ALIAS_POS, $flush_all_tlbd_l
1568
1569	/*
1570	 * Otherwise, set the dirty bit on the mapping, and
1571	 * load it into the HPT and TLB.
1572	 */
1573	b	$tlb_inshpt_l
1574	depi	1, TLB_DIRTY_POS, 1, r25
1575
1576	/*
1577	 * This flushes all other mappings of the page.  Since
1578	 * the flushing subroutine destroys effectively preserves
1579	 * only the address of the writable mapping, we have to
1580	 * reload all other registers before we can continue.
1581	 */
1582$flush_all_tlbd_l
1583	bl	$flush_all_tlbd, %r1
1584	copy	%r16, %r24
1585	copy	%r0, %r1			/* reload %r1, 0 => DTLB */
1586	DTLBPRE					/* reload %r8, %r9 */
1587	copy	%r24, %r16			/* reload %r16 */
1588	mfctl	%cr28, %r24			/* reload %r24 */
1589	ldw	PV_TLBPAGE(%r16), %r17		/* reload %r17 */
1590	ldw	PV_TLBPROT(%r16), %r25		/* reload %r25 */
1591	b	$tlb_inshpt_l
1592	depi	1, TLB_DIRTY_POS, 1, %r25	/* set dirty bit */
1593
1594/*
1595 * This is a handler for interruption 6, "Instruction TLB miss fault",
1596 * and interruption 16, "Non-access instruction TLB miss fault".  It
1597 * is used on the PA7100LC (PCX-L), PA7300LC (PCX-L2), PA8000 (PCX-U),
1598 * PA8200 (PCX-W), PA8500 (PCX-W), and PA8600 (PCX-W+).  Only shadowed
1599 * registers are available, and they are:
1600 *
1601 * %r1 = C trap number
1602 * %r8 = instruction address space identifier
1603 * %r9 = instruction address offset
1604 * %r16 = undefined
1605 * %r17 = undefined
1606 * %r24 = undefined
1607 * %r25 = undefined
1608 */
1609$itlb_l
1610	depi	1, TFF_ITLB_POS, 1, r1	/* mark for ITLB insert */
1611	/* FALLTHROUGH */
1612
1613/*
1614 * This is a handler for interruption 17, "Non-access data TLB miss
1615 * fault".  It is used on the PA7100LC (PCX-L), PA7300LC (PCX-L2),
1616 * PA8000 (PCX-U), PA8200 (PCX-W), PA8500 (PCX-W), and PA8600 (PCX-W+).
1617 * Only shadowed registers are available, and they are:
1618 *
1619 * %r1 = C trap number
1620 * %r8 = data address space identifier
1621 * %r9 = data address offset
1622 * %r16 = undefined
1623 * %r17 = undefined
1624 * %r24 = undefined
1625 * %r25 = undefined
1626 */
1627$dtlbna_l
1628	/*
1629	 * Calculate the offset of the HPT entry into %r24,
1630	 * and save it into %cr28 for recovery later, when
1631	 * we want to update the HPT.
1632	 *
1633	 * XXX fredette: does the PA7100LC not provide the
1634	 * HPT entry in %cr28 for a non-access DTLB miss?
1635	 * What about an ITLB miss or non-access ITLB miss?
1636	 * Having this here, if unnecessary, hurts the
1637	 * performance of all of these faults.
1638	 */
1639	HPTENT
1640	mtctl	r24, cr28
1641	/* FALLTHROUGH */
1642
1643/*
1644 * This is a handler for interruption 15, "Data TLB miss fault".
1645 * It is used on the PA7100LC (PCX-L), PA7300LC (PCX-L2),
1646 * PA8000 (PCX-U), PA8200 (PCX-W), PA8500 (PCX-W), and PA8600 (PCX-W+).
1647 * Only shadowed registers are available, and they are:
1648 *
1649 * %r1 = C trap number
1650 * %r8 = data address space identifier
1651 * %r9 = data address offset
1652 * %r16 = undefined
1653 * %r17 = undefined
1654 * %r24 = undefined
1655 * %r25 = undefined
1656 */
1657$dtlb_l
1658	/*
1659	 * On entry, %cr28 contains the address of the
1660	 * relevant HPT entry, courtesy of hpti_g's call
1661	 * to PDC_TLB(8)/PDC_TLB_CONFIG(1) asking for
1662	 * PDC_TLB_CURRPDE.
1663	 */
1664	mfctl	cr28, r24
1665
1666	/*
1667	 * Search the list of mappings attached to this
1668	 * HPT entry until we find the faulting mapping.
1669	 * If we don't find it, branch to a subhandler
1670	 * that checks for a non-access fault caused by
1671	 * an LPA instruction.
1672	 */
1673	ldw	HPT_ENTRY(r24), r16
1674$hash_loop_l
1675	comb,=,n r0, r16, $tlbiflpa
1676	ldw	PV_VA(r16), r25
1677	ldw	PV_SPACE(r16), r17
1678	comb,<>,n r9, r25, $hash_loop_l
1679	ldw	PV_HASH(r16), r16
1680	comb,<>,n r8, r17, $hash_loop_l
1681	ldw	PV_HASH(r16), r16
1682
1683	/*
1684	 * If this mapping is not marked TLB_REF, and
1685	 * it isn't marked TLB_NO_RW_ALIAS, we have to
1686	 * flush any writable mapping for this page.
1687	 * Since TLB_REF and TLB_NO_RW_ALIAS are adjacent,
1688	 * we can test if they are both clear with one
1689	 * extru instruction.
1690	 */
1691	ldw	PV_TLBPAGE(r16), r17
1692	ldw	PV_TLBPROT(r16), r25
1693	extru,<> %r25, TLB_NO_RW_ALIAS_POS, 2, %r0
1694	b,n	$flush_writable_l
1695
1696	/* Mark this mapping as referenced. */
1697	depi	1, TLB_REF_POS, 1, r25
1698
1699/*
1700 * Load the HPT entry and TLB with a mapping.  On entry:
1701 *
1702 * %r1 = C trap number
1703 * %r8 = address space identifier
1704 * %r9 = address offset
1705 * %r16 = mapping
1706 * %r17 = TLB page
1707 * %r24 = HPT entry
1708 * %r25 = TLB protection
1709 */
1710$tlb_inshpt_l
1711	stw	r25, PV_TLBPROT(r16)
1712	VTAG(%r8, %r9, %r16)
1713
1714	stw	r16, HPT_TAG(r24)
1715	stw	r25, HPT_TLBPROT(r24)
1716	bb,<	r1, TFF_ITLB_POS, $tlb_itlb_l
1717	stw	r17, HPT_TLBPAGE(r24)
1718
1719	.word	0x04111440	; idtlbaf	r17
1720	.word	0x04191400	; idtlbpf	r25
1721	nop ! nop
1722	rfir
1723	nop
1724
1725$tlb_itlb_l
1726	.word	0x04110440	; iitlbaf	r17
1727	.word	0x04190400	; iitlbpf	r25
1728	nop ! nop
1729	rfir
1730	nop
1731
1732/*
1733 * Flush any writable mapping in the TLB and cache, in order
1734 * to insert a readable mapping.  On entry:
1735 *
1736 * %r1 = C trap number
1737 * %r8 = undefined
1738 * %r9 = undefined
1739 * %r16 = struct pv_entry * of readable mapping
1740 * %r17 = undefined
1741 * %r24 = undefined
1742 * %r25 = undefined
1743 */
1744$flush_writable_l
1745	/*
1746	 * Branch if this was an ITLB fault.
1747	 */
1748	bb,<,n	%r1, TFF_ITLB_POS, $flush_writable_itlb_l
1749
1750	/*
1751	 * Flush any writable mapping, then reload registers
1752	 * for an HPT and DTLB insertion.
1753	 */
1754	bl	$flush_writable, %r1
1755	copy	%r16, %r24
1756	copy	%r0, %r1			/* reload %r0, 0 => DTLB */
1757	DTLBPRE					/* reload %r8, %r9 */
1758	copy	%r24, %r16			/* reload %r16 */
1759	ldw	PV_TLBPAGE(%r16), %r17		/* reload %r17 */
1760	ldw	PV_TLBPROT(%r16), %r25		/* reload %r25 */
1761	mfctl	%cr28, %r24			/* reload %r24 */
1762	b	$tlb_inshpt_l
1763	depi	1, TLB_REF_POS, 1, %r25		/* set ref bit */
1764
1765$flush_writable_itlb_l
1766	/*
1767	 * Flush any writable mapping, then reload registers
1768	 * for an HPT and ITLB insertion.
1769	 */
1770	bl	$flush_writable, %r1
1771	copy	%r16, %r24
1772	ldil	L%TFF_ITLB, %r1			/* reload %r0 */
1773	ITLBPRE					/* reload %r8, %r9 */
1774	copy	%r24, %r16			/* reload %r16 */
1775	ldw	PV_TLBPAGE(%r16), %r17		/* reload %r17 */
1776	ldw	PV_TLBPROT(%r16), %r25		/* reload %r25 */
1777	mfctl	%cr28, %r24			/* reload %r24 */
1778	b	$tlb_inshpt_l
1779	depi	1, TLB_REF_POS, 1, %r25		/* set ref bit */
1780
1781#endif /* HP7100LC_CPU */
1782
1783	.export $tlbiflpa, entry
1784$tlbiflpa
1785	ldi	T_DTLBMISSNA, r16
1786	mfctl	iir, r17
1787	comb,<>,n r1, r16, TLABEL(all)
1788	extru	r17, 5, 6, r16
1789	ldi	0x4d, r25
1790	comib,<>,n 1, r16, TLABEL(all)
1791	extru	r17, 25, 8, r16
1792	comb,<>,n r25, r16, TLABEL(all)
1793
1794	/* ok, this is a miss in LPA */
1795	mfctl	ipsw, r16
1796	depi	1, PSW_N_POS, 1, r16
1797	depi	0, 26, 27, r17
1798	mtctl	r16, ipsw
1799
1800	ldi	$tlbiflpa_zr, r25
1801	bv	r17(r25)
1802$tlbiflpa_zr
1803	copy	r0, r0	!	rfir
1804	copy	r0, r1	!	rfir
1805	copy	r0, r2	!	rfir
1806	copy	r0, r3	!	rfir
1807	copy	r0, r4	!	rfir
1808	copy	r0, r5	!	rfir
1809	copy	r0, r6	!	rfir
1810	copy	r0, r7	!	rfir
1811	copy	r0, r8	!	rfir
1812	copy	r0, r9	!	rfir
1813	copy	r0, r10	!	rfir
1814	copy	r0, r11	!	rfir
1815	copy	r0, r12	!	rfir
1816	copy	r0, r13	!	rfir
1817	copy	r0, r14	!	rfir
1818	copy	r0, r15	!	rfir
1819	copy	r0, r16	!	rfir
1820	copy	r0, r17	!	rfir
1821	copy	r0, r18	!	rfir
1822	copy	r0, r19	!	rfir
1823	copy	r0, r20	!	rfir
1824	copy	r0, r21	!	rfir
1825	copy	r0, r22	!	rfir
1826	copy	r0, r23	!	rfir
1827	copy	r0, r24	!	rfir
1828	copy	r0, r25	!	rfir
1829	copy	r0, r26	!	rfir
1830	copy	r0, r27	!	rfir
1831	copy	r0, r28	!	rfir
1832	copy	r0, r29	!	rfir
1833	copy	r0, r30	!	rfir
1834	copy	r0, r31	!	rfir
1835
1836	.export	$tlb_missend, entry
1837$tlb_missend
1838
1839	.align	64
1840	.export	TLABEL(all), entry
1841ENTRY(TLABEL(all),0)
1842	/* r1 still has trap type */
1843
1844	/*
1845	 * at this point we have:
1846	 *	psw copied into ipsw
1847	 *	psw = E(default), M(1 if HPMC, else 0)
1848	 *	PL = 0
1849	 *	r1, r8, r9, r16, r17, r24, r25 shadowed (maybe)
1850	 *	trap number in r1 (old r1 is saved in tr7)
1851	 */
1852
1853	/* do not overwrite tr4(cr28) */
1854	mtctl	t3, tr2
1855
1856	ldil	L%$trap_tmp_save, t3
1857	stw	t1, TF_R22(t3)		/* use ,bc */
1858	stw	t2, TF_R21(t3)
1859
1860	mfctl	tr2, t1
1861	stw	sp, TF_R30(t3)	/* sp */
1862	stw	t1, TF_R20(t3)	/* t3 */
1863
1864	/*
1865	 * Now, save away other volatile state that prevents us from turning
1866	 * the PC queue back on, namely, the pc queue and ipsw, and the
1867	 * interrupt information.
1868	 */
1869
1870	mfctl	eiem, t1
1871	mfctl	ipsw, t2
1872	stw	t1, TF_CR15(t3)		/* use ,bc */
1873	stw	t2, TF_CR22(t3)
1874
1875	mfsp	sr3, t1
1876	mfctl	pidr1, t2
1877	stw	t1, TF_SR3(t3)
1878	stw	t2, TF_CR8(t3)
1879
1880	/*
1881	 * Setup kernel context
1882	 */
1883
1884	ldi	HPPA_PID_KERNEL,t1
1885	mtctl	t1, pidr1
1886	mtsp	r0, sr3
1887
1888	/* this will enable interrupts after `cold' */
1889	ldil	L%kpsw, t1
1890	ldw	R%kpsw(t1), t2
1891	mtctl	r0, eiem
1892	mtctl	t2, ipsw
1893
1894	mfctl	pcsq, t1
1895	mtctl	r0, pcsq
1896	mfctl	pcsq, t2
1897	stw	t1, TF_IISQH(t3)	/* use ,bc */
1898	stw	t2, TF_IISQT(t3)
1899	mtctl	r0, pcsq
1900
1901	/*
1902	 * Set up the kernel stack pointer.  If the trap happened
1903	 * while we were in unprivileged code, or in privileged
1904	 * code in the SYSCALLGATE page, move to the kernel stack
1905	 * in curproc's PCB; otherwise, start a new stack frame
1906	 * on whatever kernel stack we're already on.
1907	 *
1908	 * This used to check only for a trap while we were in
1909	 * unprivileged code, but this ignored the possibility
1910	 * that a trap could come in during the period between
1911	 * a gateway instruction to raise privilege and the
1912	 * disabling of interrupts.  During this period we're
1913	 * still on the user's stack, and we must move to the
1914	 * kernel stack.
1915	 */
1916	mfctl	pcoq, t1
1917	ldil	L%SYSCALLGATE, t2
1918	/* Start aligning the assumed kernel sp. */
1919	ldo	HPPA_FRAME_SIZE-1(sp), sp
1920	/* This dep leaves t2 with SYSCALLGATE | (pcoqh & PAGE_MASK). */
1921	dep	t1, 31, PGSHIFT, t2
1922	/* Nullify if pcoqh & HPPA_PC_PRIV_MASK != 0. */
1923	dep,<>	t1, 31, 2, r0
1924	/* Branch if (pcoqh & ~PAGE_MASK) != SYSCALLGATE */
1925	comb,<> t1, t2, $trap_from_kernel
1926	/* Finish aligning the assumed kernel sp. */
1927	dep	r0, 31, 6, sp
1928
1929	mfctl	cr30, t2
1930	depi	1, T_USER_POS, 1, r1
1931	depi	1, TFF_LAST_POS, 1, r1
1932	ldw	U_PCB+PCB_UVA(t2), sp
1933#ifdef DIAGNOSTIC
1934	b	$trap_have_stack
1935#endif
1936	ldo	NBPG(sp), sp
1937
1938$trap_from_kernel
1939#ifdef DIAGNOSTIC
1940	/*
1941	 * Use the emergency stack if we have taken some kind
1942	 * of TLB or protection fault on the kernel stack.
1943	 */
1944	mtctl	t1, tr2
1945	ldw	TF_R30(t3), t1
1946	mfctl	ior, t2
1947	dep	r0, 31, PGSHIFT, t1
1948	dep	r0, 31, PGSHIFT, t2
1949	comb,=,n t1, t2, 0
1950	ldo	NBPG(t1), t1
1951	comb,<>	t1, t2, $trap_have_stack
1952	mfctl	tr2, t1
1953	mfctl	isr, t2
1954	comib,<>,n HPPA_SID_KERNEL, t2, $trap_have_stack
1955#define _CHECK_TRAP_TYPE(tt) ldi tt, t2 ! comb,= r1, t2, $trap_kstack_fault
1956	_CHECK_TRAP_TYPE(T_ITLBMISS)
1957	_CHECK_TRAP_TYPE(T_DTLBMISS)
1958	_CHECK_TRAP_TYPE(T_ITLBMISSNA)
1959	_CHECK_TRAP_TYPE(T_DTLBMISSNA)
1960	_CHECK_TRAP_TYPE(T_DPROT)
1961	_CHECK_TRAP_TYPE(T_DATACC)
1962	_CHECK_TRAP_TYPE(T_DATAPID)
1963	ldi	T_DATALIGN, t2
1964	comb,<>,n r1, t2, $trap_have_stack
1965#undef _CHECK_TRAP_TYPE
1966$trap_kstack_fault
1967	ldil	L%emergency_stack_start, sp
1968	ldo	R%emergency_stack_start(sp), sp
1969$trap_have_stack
1970#endif
1971	ldil	L%$trapnowvirt, t2
1972	ldo	R%$trapnowvirt(t2), t2
1973	mtctl	t2, pcoq
1974	stw	t1, TF_IIOQH(t3)
1975	ldo	4(t2), t2
1976	mfctl	pcoq, t1
1977	stw	t1, TF_IIOQT(t3)
1978	mtctl	t2, pcoq
1979
1980	mfctl	isr, t1
1981	mfctl	ior, t2
1982	stw	t1, TF_CR20(t3)		/* use ,bc */
1983	stw	t2, TF_CR21(t3)
1984
1985	mfctl	iir, t2
1986	stw	t2, TF_CR19(t3)
1987	stw	r1, TF_FLAGS(t3)
1988	mfctl	tr7, r1
1989
1990	copy	sp, t3
1991	ldo	HPPA_FRAME_SIZE+TRAPFRAME_SIZEOF(sp), sp
1992	rfir
1993	nop
1994$trapnowvirt
1995	/*
1996	 * t3 contains the virtual address of the trapframe
1997	 * sp is loaded w/ the right VA (we did not need it being physical)
1998	 */
1999
2000	mfsp	sr0, t1
2001	mfsp	sr1, t2
2002	stw	t1, TF_SR0(sr3, t3)
2003	stw	t2, TF_SR1(sr3, t3)
2004
2005	mfsp	sr2, t1
2006	mfsp	sr4, t2
2007	stw	t1, TF_SR2(sr3, t3)
2008	stw	t2, TF_SR4(sr3, t3)
2009
2010	mfsp	sr5, t2
2011	mfsp	sr6, t1
2012	stw	t2, TF_SR5(sr3, t3)
2013	stw	t1, TF_SR6(sr3, t3)
2014
2015	mfsp	sr7, t1
2016	mfctl	pidr2, t2
2017	stw	t1, TF_SR7(sr3, t3)
2018	stw	t2, TF_CR9(sr3, t3)
2019
2020	mtsp	r0, sr0
2021	mtsp	r0, sr1
2022	mtsp	r0, sr2
2023	mtsp	r0, sr4
2024	mtsp	r0, sr5
2025	mtsp	r0, sr6
2026	mtsp	r0, sr7
2027
2028#if pbably_not_worth_it
2029	mfctl	pidr3, t1
2030	mfctl	pidr4, t2
2031	stw	t1, TF_CR12(t3)
2032	stw	t2, TF_CR13(t3)
2033#endif
2034
2035	/*
2036	 * Save all general registers that we haven't saved already
2037	 */
2038
2039#if defined(DDB) || defined(KGDB)
2040	stw	rp, HPPA_FRAME_CRP(sp)
2041	stw	r0, -HPPA_FRAME_SIZE(sp)
2042#endif
2043	stw	t3, -HPPA_FRAME_SIZE+4(sp)
2044
2045	mfctl	sar, t1			/* use ,bc each cache line */
2046	stw	t1, TF_CR11(t3)
2047	stw	r1, TF_R1(t3)
2048	stw	r2, TF_R2(t3)
2049	stw	r3, TF_R3(t3)
2050
2051	/*
2052	 * Copy partially saved state from the store into the frame
2053	 */
2054	ldil	L%$trap_tmp_save, t2
2055	/* use ,bc each line */
2056	ldw  0(t2), r1 ! ldw  4(t2), t1 ! stw r1,  0(t3) ! stw t1,  4(t3)
2057	ldw  8(t2), r1 ! ldw 12(t2), t1 ! stw r1,  8(t3) ! stw t1, 12(t3)
2058	ldw 16(t2), r1 ! ldw 20(t2), t1 ! stw r1, 16(t3) ! stw t1, 20(t3)
2059	ldw 24(t2), r1 ! ldw 28(t2), t1 ! stw r1, 24(t3) ! stw t1, 28(t3)
2060	ldw 32(t2), r1 ! ldw 36(t2), t1 ! stw r1, 32(t3) ! stw t1, 36(t3)
2061	ldw 40(t2), r1 ! ldw 44(t2), t1 ! stw r1, 40(t3) ! stw t1, 44(t3)
2062	ldw 48(t2), r1 ! ldw 52(t2), t1 ! stw r1, 48(t3) ! stw t1, 52(t3)
2063	ldw 56(t2), r1 ! ldw 60(t2), t1 ! stw r1, 56(t3) ! stw t1, 60(t3)
2064
2065	/*
2066	 * Normally, we'd only have to save and restore the
2067	 * caller-save registers, because the callee-save
2068	 * registers will be saved and restored automatically
2069	 * by our callee(s).
2070	 *
2071	 * However, in two cases we need to save and restore
2072	 * all of the general registers in the trapframe.  One,
2073	 * if we're running a debugger, we want the debugging
2074	 * person to be able to see and change any and all
2075	 * general register values at the trap site.  Two,
2076	 * if we have an FPU emulator, this trap may be to
2077	 * emulate an instruction that needs to read and write
2078	 * any and all general registers (for example, a load
2079	 * or store instruction with a modify completer).
2080	 *
2081	 * See similar #ifdefs in the syscall entry and exit code.
2082	 */
2083#if defined(DDB) || defined(KGDB) || defined(FPEMUL)
2084	stw	r4, TF_R4(t3)
2085	stw	r5, TF_R5(t3)
2086	stw	r6, TF_R6(t3)
2087	stw	r7, TF_R7(t3)
2088	stw	r8, TF_R8(t3)
2089	stw	r9, TF_R9(t3)
2090	stw	r10, TF_R10(t3)
2091	stw	r11, TF_R11(t3)
2092	stw	r12, TF_R12(t3)
2093	stw	r13, TF_R13(t3)
2094	stw	r14, TF_R14(t3)
2095	stw	r15, TF_R15(t3)
2096	stw	r16, TF_R16(t3)
2097	stw	r17, TF_R17(t3)
2098	stw	r18, TF_R18(t3)
2099#endif /* DDB || KGDB || FPEMUL */
2100	stw	t4, TF_R19(t3)
2101	stw	r23,TF_R23(t3)
2102	stw	r24,TF_R24(t3)
2103	stw	r25,TF_R25(t3)
2104	stw	r26,TF_R26(t3)
2105	stw	r27,TF_R27(t3)
2106	stw	r28,TF_R28(t3)
2107	stw	r29,TF_R29(t3)
2108	stw	r31,TF_R31(t3)
2109
2110	/*
2111	 * Save the necessary control registers that have not already saved.
2112	 */
2113
2114	mfctl	rctr, t1
2115	stw	t1, TF_CR0(t3)
2116	/* XXX save ccr here w/ rctr */
2117
2118#if defined(DDB) || defined(KGDB)
2119	/*
2120	 * Save hpt mask and v2p translation table pointer
2121	 */
2122	mfctl	eirr, t1
2123	mfctl	hptmask, t2
2124	stw	t1, TF_CR23(t3)
2125	stw	t2, TF_CR24(t3)
2126
2127	mfctl	vtop, t1
2128	mfctl	cr28, t2
2129	stw	t1, TF_CR25(t3)
2130	stw	t2, TF_CR28(t3)
2131#endif
2132	mfctl	cr30, t1
2133	stw	t1, TF_CR30(t3)
2134
2135	/*
2136	 * load the global pointer for the kernel
2137	 */
2138
2139	ldil	L%$global$, dp
2140	ldo	R%$global$(dp), dp
2141
2142	/*
2143	 * call the C routine trap().
2144	 * form trap type in the first argument to trap()
2145	 */
2146	ldw	TF_FLAGS(t3), arg0
2147	dep	r0, 24, 25, arg0
2148	copy	t3, arg1
2149
2150#if defined(DDB) || defined(KGDB)
2151	ldo	-HPPA_FRAME_SIZE(sp), r3
2152#endif
2153	.import	trap, code
2154	ldil	L%trap,t1
2155	ldo	R%trap(t1),t1
2156	.call
2157	blr	r0,rp
2158	bv,n	r0(t1)
2159	nop
2160
2161	ldw	-HPPA_FRAME_SIZE+4(sp), t3
2162	/* see if curproc have changed */
2163	ldw	TF_FLAGS(t3), arg0
2164	bb,>=,n	arg0, TFF_LAST_POS, $trap_return
2165	nop
2166
2167	/* see if curproc have really changed */
2168	ldil	L%curproc, t1
2169	ldw	R%curproc(t1), t2
2170	comb,=,n r0, t2, $trap_return
2171
2172	/* means curproc have actually changed */
2173	ldw	P_MD(t2), t3
2174
2175$trap_return
2176	ldil	L%$syscall_return, t1
2177	ldo	R%$syscall_return(t1), t1
2178	bv,n	r0(t1)
2179	nop
2180
2181	.export	$trap$all$end, entry
2182$trap$all$end
2183EXIT(TLABEL(all))
2184
2185	.align	32
2186	.export	TLABEL(ibrk), entry
2187ENTRY(TLABEL(ibrk),0)
2188	mtctl	t1, tr2
2189	mtctl	t2, tr3
2190
2191	/* If called by a user process then always pass it to trap() */
2192	mfctl	pcoq, t1
2193	extru,=	t1, 31, 2, r0
2194	b,n	$ibrk_bad
2195
2196	/* don't accept breaks from data segments */
2197	.import etext
2198	ldil	L%etext, t2
2199	ldo	R%etext(t2), t2
2200	comb,>>=,n t1, t2, $ibrk_bad
2201
2202	mfctl	iir, t1
2203	extru	t1, 31, 5, t2
2204	comib,<>,n HPPA_BREAK_KERNEL, t2, $ibrk_bad
2205
2206	/* now process all those `break' calls we make */
2207	extru	t1, 18, 13, t2
2208	comib,=,n HPPA_BREAK_GET_PSW, t2, $ibrk_getpsw
2209	comib,=,n HPPA_BREAK_SET_PSW, t2, $ibrk_setpsw
2210
2211$ibrk_bad
2212	/* illegal (unimplemented) break entry point */
2213	mfctl	tr3, t2
2214	b	TLABEL(all)
2215	mfctl	tr2, t1
2216
2217$ibrk_getpsw
2218	b	$ibrk_exit
2219	mfctl	ipsw, ret0
2220
2221$ibrk_setpsw
2222	mfctl	ipsw, ret0
2223	b	$ibrk_exit
2224	mtctl	arg0, ipsw
2225
2226	/* insert other fast breaks here */
2227	nop ! nop
2228
2229$ibrk_exit
2230	/* skip the break */
2231	mtctl	r0, pcoq
2232	mfctl	pcoq, t1
2233	mtctl	t1, pcoq
2234	ldo	4(t1), t1
2235	mtctl	t1, pcoq
2236	mfctl	tr3, t2
2237	mfctl	tr2, t1
2238	mfctl	tr7, r1
2239	rfi
2240	nop
2241EXIT(TLABEL(ibrk))
2242
2243/*
2244 * This macro changes the tlbpage register from a tlbpage
2245 * value into the struct pv_head * for that page.  It also
2246 * junks another register.
2247 *
2248 * The extru gets the physical page number out of the tlbpage,
2249 * and since sizeof(struct pv_head) == 8, we can use sh3add to
2250 * generate the final struct pv_head *.
2251 */
2252#define PV_HEAD(tlbpage, junk)			  \
2253	ldil	L%pv_head_tbl, junk		! \
2254	extru	tlbpage, 26, 20, tlbpage	! \
2255	ldw	R%pv_head_tbl(junk), junk	! \
2256	sh3add	tlbpage, junk, tlbpage
2257
2258/*
2259 * This macro copies the referenced and dirty information
2260 * from a TLB protection to a pv_head_writable_dirty_ref
2261 * value, but only if the TLB protection is managed.  The
2262 * magic 12 targets the instruction after the macro.
2263 */
2264#define PV_MODREF(tlbprot, pv_head_wdr)			  \
2265	bb,<,n	tlbprot, TLB_UNMANAGED_POS, 12		! \
2266	extru,=	tlbprot, TLB_REF_POS, 1, %r0		! \
2267	depi	1, PV_HEAD_REF_POS, 1, pv_head_wdr	! \
2268	extru,= tlbprot, TLB_DIRTY_POS, 1, %r0		! \
2269	depi	1, PV_HEAD_DIRTY_POS, 1, pv_head_wdr
2270
2271/*
2272 * This subroutine flushes all mappings of a page out of the TLB
2273 * and cache, in order to install a writable mapping.  Only shadowed
2274 * registers are available, and they are:
2275 *
2276 * %r1 = INPUT: return address, OUTPUT: preserved
2277 * %r8 = INPUT: undefined, OUTPUT: destroyed
2278 * %r9 = INPUT: undefined, OUTPUT: destroyed
2279 * %r16 = INPUT: undefined, OUTPUT: destroyed
2280 * %r17 = INPUT: undefined, OUTPUT: destroyed
2281 * %r24 = INPUT: struct pv_entry * of writable mapping, OUTPUT: preserved
2282 * %r25 = INPUT: undefined, OUTPUT: destroyed
2283 */
2284$flush_all_tlbd
2285
2286	/*
2287	 * Find the struct pv_head for this physical page.
2288	 * If this writable mapping is managed, we know
2289	 * for sure that this page is now referenced
2290	 * and dirty.  The ldi sets both PV_HEAD_REF_POS
2291	 * and PV_HEAD_DIRTY_POS.
2292	 */
2293	ldw	PV_TLBPAGE(%r24), %r17
2294	ldw	PV_TLBPROT(%r24), %r25
2295	PV_HEAD(%r17, %r16)
2296	ldi	3, %r16
2297	bb,>=,n	%r25, TLB_UNMANAGED_POS, $flush_all_tlbd_set_wdr
2298
2299	/*
2300	 * Otherwise, this writable mapping is unmanaged,
2301	 * which means we need to save referenced and dirty
2302	 * information from all managed mappings that we're
2303	 * about to flush.
2304	 */
2305	copy	%r0, %r16
2306	ldw	PV_HEAD_PVS(%r17), %r8
2307	ldw	PV_TLBPROT(%r8), %r25
2308$flush_all_tlbd_modref_loop
2309	ldw	PV_NEXT(%r8), %r8
2310	PV_MODREF(%r25, %r16)
2311	comb,<>,n %r0, %r8, $flush_all_tlbd_modref_loop
2312	ldw	PV_TLBPROT(%r8), %r25
2313
2314$flush_all_tlbd_set_wdr
2315	/*
2316	 * Now set the pv_head_writable_dirty_ref field,
2317	 * preserving any previously set referenced and
2318	 * dirty bits, and noting that this writable
2319	 * mapping is the current writable mapping.
2320	 */
2321	ldw	PV_HEAD_WRITABLE_DIRTY_REF(%r17), %r8
2322	or	%r24, %r16, %r16
2323	depi	0, PV_HEAD_WRITABLE_POS, 30, %r8
2324	or	%r16, %r8, %r8
2325	stw	%r8, PV_HEAD_WRITABLE_DIRTY_REF(%r17)
2326
2327	/*
2328	 * Now flush all other mappings out of the cache.
2329	 */
2330	ldw	PV_HEAD_PVS(%r17), %r17
2331	bl	0, %r16
2332$flush_all_tlbd_loop
2333	comb,<> %r17, %r24, $flush_mapping
2334	nop
2335	ldw	PV_NEXT(%r17), %r17
2336	comb,<>	%r17, %r0, $flush_all_tlbd_loop
2337	nop
2338
2339	/* Return to our caller. */
2340	bv	%r0(%r1)
2341	nop
2342
2343/*
2344 * This subroutine flushes any writable mapping of a page out of the
2345 * TLB and cache, in order to install a readable mapping.  Only shadowed
2346 * registers are available, and they are:
2347 *
2348 * %r1 = INPUT: return address, OUTPUT: preserved
2349 * %r8 = INPUT: undefined, OUTPUT: destroyed
2350 * %r9 = INPUT: undefined, OUTPUT: destroyed
2351 * %r16 = INPUT: undefined, OUTPUT: destroyed
2352 * %r17 = INPUT: undefined, OUTPUT: destroyed
2353 * %r24 = INPUT: struct pv_entry * of readable mapping, OUTPUT: preserved
2354 * %r25 = INPUT: undefined, OUTPUT: destroyed
2355 */
2356$flush_writable
2357
2358	/* Find the struct pv_head for this physical page. */
2359	ldw	PV_TLBPAGE(%r24), %r17
2360	PV_HEAD(%r17, %r16)
2361
2362	/*
2363	 * If this page doesn't have a writable mapping
2364	 * entered into the TLB and cache, return.  The
2365	 * single depi clears both PV_HEAD_REF_POS and
2366	 * PV_HEAD_DIRTY_POS.
2367         */
2368	ldw	PV_HEAD_WRITABLE_DIRTY_REF(%r17), %r16
2369	copy	%r16, %r8
2370	depi,<>	0, PV_HEAD_REF_POS, 2, %r16
2371	bv,n	%r0(%r1)
2372
2373	/*
2374	 * Clear the writable mapping, preserving the
2375	 * current referenced and dirty bits.
2376	 */
2377	depi	0, PV_HEAD_WRITABLE_POS, 30, %r8
2378	stw	%r8, PV_HEAD_WRITABLE_DIRTY_REF(%r17)
2379
2380	/*
2381	 * Flush the writable mapping.  We have $flush_mapping
2382	 * return directly to our caller.
2383	 */
2384	copy	%r16, %r17
2385	b	$flush_mapping
2386	copy	%r1, %r16
2387
2388/*
2389 * This flushes a mapping out of the TLB and cache.  Only shadowed
2390 * registers are available, and on entry they are:
2391 *
2392 * %r1 = INPUT: undefined, OUTPUT: preserved
2393 * %r8 = INPUT: undefined, OUTPUT: destroyed
2394 * %r9 = INPUT: undefined, OUTPUT: destroyed
2395 * %r16 = INPUT: return address, OUTPUT: preserved
2396 * %r17 = INPUT: mapping to flush, OUTPUT: preserved
2397 * %r24 = INPUT: undefined, OUTPUT: preserved
2398 * %r25 = INPUT: undefined, OUTPUT: destroyed
2399 *
2400 * NB: this function assumes that, once inserted, a TLB entry
2401 * remains inserted as long as the only virtual references made
2402 * use that TLB entry.  This function must be called in physical
2403 * mode.
2404 */
2405$flush_mapping
2406
2407	/*
2408	 * If this mapping has not been referenced, it cannot
2409	 * be in the TLB and cache, so just return.
2410	 */
2411	ldw	PV_TLBPROT(%r17), %r25
2412	extru,<> %r25, TLB_REF_POS, 1, %r0
2413	bv,n	%r0(%r16)
2414
2415	/*
2416	 * Clear the referenced and dirty bits, save %sr1
2417	 * into %r8, load the space into %sr1, load the
2418	 * virtual address into %r9.  If the mapping is
2419	 * not executable, skip the instruction cache flush.
2420	 * (Bit 6 is the "execute" bit in the TLB protection,
2421	 * assuming that we never see gateway page protections.)
2422	 */
2423	ldw	PV_SPACE(%r17), %r9
2424	depi	0, TLB_REF_POS, 1, %r25
2425	mfsp	%sr1, %r8
2426	depi	0, TLB_DIRTY_POS, 1, %r25
2427	mtsp	%r9, %sr1
2428	ldw	PV_VA(%r17), %r9
2429	bb,>=	%r25, 6, $flush_mapping_data
2430	stw	%r25, PV_TLBPROT(%r17)
2431
2432	/*
2433	 * Load this mapping into the ITLB and the DTLB, since
2434	 * fic may use the DTLB.
2435	 */
2436	ldw	PV_TLBPAGE(%r17), %r25
2437	iitlba	%r25, (%sr1, %r9)
2438	idtlba	%r25, (%sr1, %r9)
2439	ldw	PV_TLBPROT(%r17), %r25
2440	iitlbp	%r25, (%sr1, %r9)
2441	idtlbp	%r25, (%sr1, %r9)
2442	nop
2443	nop
2444
2445	/* Load the instruction cache stride. */
2446	ldil	L%icache_stride, %r25
2447	ldw	R%icache_stride(%r25), %r25
2448
2449	/*
2450	 * Enable data address translation (fic explicitly uses
2451	 * the D-bit to determine whether virtual or absolute
2452	 * addresses are used), and flush the instruction cache
2453	 * using a loop of 16 fic instructions. */
2454	ssm	PSW_D, %r0
2455$flush_mapping_fic_loop
2456	fic,m	%r25(%sr1, %r9)
2457	fic,m	%r25(%sr1, %r9)
2458	fic,m	%r25(%sr1, %r9)
2459	fic,m	%r25(%sr1, %r9)
2460	fic,m	%r25(%sr1, %r9)
2461	fic,m	%r25(%sr1, %r9)
2462	fic,m	%r25(%sr1, %r9)
2463	fic,m	%r25(%sr1, %r9)
2464	fic,m	%r25(%sr1, %r9)
2465	fic,m	%r25(%sr1, %r9)
2466	fic,m	%r25(%sr1, %r9)
2467	fic,m	%r25(%sr1, %r9)
2468	fic,m	%r25(%sr1, %r9)
2469	fic,m	%r25(%sr1, %r9)
2470	fic,m	%r25(%sr1, %r9)
2471	fic,m	%r25(%sr1, %r9)
2472	/* Stop looping if the page offset bits are all zero. */
2473	extru,= %r9, 31, PGSHIFT, %r0
2474	b,n	$flush_mapping_fic_loop
2475
2476	/* Sync. */
2477	sync
2478	nop
2479	nop
2480	syncdma
2481
2482	/* Disable data address translation. */
2483	rsm	PSW_D, %r0
2484
2485	/* Reload the virtual address and purge the ITLB. */
2486	ldw	PV_VA(%r17), %r9
2487	pitlb	%r0(%sr1, %r9)
2488
2489$flush_mapping_data
2490
2491	/* Load this mapping into the DTLB. */
2492	ldw	PV_TLBPAGE(%r17), %r25
2493	idtlba	%r25, (%sr1, %r9)
2494	ldw	PV_TLBPROT(%r17), %r25
2495	idtlbp	%r25, (%sr1, %r9)
2496	nop
2497	nop
2498
2499	/* Load the data cache stride. */
2500	ldil	L%dcache_stride, %r25
2501	ldw	R%dcache_stride(%r25), %r25
2502
2503	/*
2504	 * Enable data address translation and flush the data cache
2505	 * using a loop of 16 fdc instructions. */
2506	ssm	PSW_D, %r0
2507$flush_mapping_fdc_loop
2508	fdc,m	%r25(%sr1, %r9)
2509	fdc,m	%r25(%sr1, %r9)
2510	fdc,m	%r25(%sr1, %r9)
2511	fdc,m	%r25(%sr1, %r9)
2512	fdc,m	%r25(%sr1, %r9)
2513	fdc,m	%r25(%sr1, %r9)
2514	fdc,m	%r25(%sr1, %r9)
2515	fdc,m	%r25(%sr1, %r9)
2516	fdc,m	%r25(%sr1, %r9)
2517	fdc,m	%r25(%sr1, %r9)
2518	fdc,m	%r25(%sr1, %r9)
2519	fdc,m	%r25(%sr1, %r9)
2520	fdc,m	%r25(%sr1, %r9)
2521	fdc,m	%r25(%sr1, %r9)
2522	fdc,m	%r25(%sr1, %r9)
2523	fdc,m	%r25(%sr1, %r9)
2524	/* Stop looping if the page offset bits are all zero. */
2525	extru,= %r9, 31, PGSHIFT, %r0
2526	b,n	$flush_mapping_fdc_loop
2527
2528	/* Sync. */
2529	sync
2530	nop
2531	nop
2532	syncdma
2533
2534	/* Disable data address translation. */
2535	rsm	PSW_D, %r0
2536
2537	/* Reload the virtual address and purge the DTLB. */
2538	ldw	PV_VA(%r17), %r9
2539	pdtlb	%r0(%sr1, %r9)
2540
2541	/* Restore %sr1. */
2542	mtsp	%r8, %sr1
2543
2544	/*
2545	 * If this mapping is in the HPT, invalidate the
2546	 * HPT entry.
2547	 */
2548	ldw	PV_SPACE(%r17), %r8
2549	ldw	PV_HPT(%r17), %r25
2550	VTAG(%r8, %r9, %r9)
2551	ldw	HPT_TAG(%r25), %r8
2552	comb,<>,n %r8, %r9, $flush_mapping_done
2553	zdepi	-1, 31, 16, %r8	/* Make an invalid HPT tag. */
2554	stw	%r8, HPT_TAG(%r25)
2555
2556$flush_mapping_done
2557	/* Return. */
2558	bv	%r0(%r16)
2559	nop
2560
2561/*
2562 * void __pmap_pv_update(paddr_t pa, struct pv_entry *pv,
2563 * 			 u_int tlbprot_clear, u_int tlbprot_set);
2564 *
2565 * This is the helper function for _pmap_pv_update.  It flushes
2566 * one or more mappings of page pa and changes their protection.
2567 * tlbprot_clear and tlbprot_set describe the protection changes.
2568 * If pv is non-NULL, that mapping is flushed and takes all of
2569 * the protection changes.  If tlbprot_clear features any of
2570 * TLB_REF, TLB_DIRTY, and TLB_NO_RW_ALIAS, all other mappings of
2571 * the page are flushed and take only those protection changes.
2572 *
2573 * All of this work is done in physical mode.
2574 */
2575ENTRY(__pmap_pv_update,64)
2576
2577	/* Start stack calling convention. */
2578	stw	%rp, HPPA_FRAME_CRP(%sp)
2579	copy	%r3, %r1
2580	copy	%sp, %r3
2581	stw,ma	%r1, HPPA_FRAME_SIZE*2(%sp)
2582
2583	/*
2584	 * Save various callee-saved registers.  Note that as
2585	 * part of the stack calling convention, the caller's
2586	 * %r3 was saved at 0(%r3).
2587	 */
2588	stw	%r8, 4(%r3)
2589	stw	%r9, 8(%r3)
2590	stw	%r16, 12(%r3)
2591	stw	%r17, 16(%r3)
2592
2593	/*
2594	 * Disable interrupts and enter physical mode, but leave the
2595	 * interruption queues on.  This will leave the previous PSW
2596	 * in %ret0, where it will remain untouched until we're ready
2597	 * to return to virtual mode.
2598	 */
2599	copy	arg0, t1
2600	ldi	PSW_Q, arg0
2601	break	HPPA_BREAK_KERNEL, HPPA_BREAK_SET_PSW
2602	copy	t1, arg0
2603
2604	/*
2605	 * Find the struct pv_head for this physical page.
2606	 * If this is a page in I/O space, conjure up a fake
2607	 * struct pv_head on the stack.
2608	 */
2609	shd	%r0, arg0, (PGSHIFT - 5), t1	/* t1 = tlbbtop(arg0) */
2610	ldil	L%HPPA_IOSPACE, t2
2611	copy	%r0, %r1			/* fake pv_head_wrd value */
2612	comb,<<= t2, arg0, $pmap_pv_update_given
2613	ldo	20(%r3), arg0			/* fake pv_head pointer */
2614	copy	t1, arg0
2615	PV_HEAD(arg0, t1)
2616	ldw	PV_HEAD_WRITABLE_DIRTY_REF(arg0), %r1
2617
2618	/*
2619	 * This helper macro saves TLB_REF and TLB_DIRTY from
2620	 * a managed mapping, and if that mapping is the currently
2621	 * loaded writable mapping, clears that.  Then it
2622	 * flushes the mapping (saving %r25 around the call
2623	 * to $flush_mapping) and updates its protection.
2624	 * It destroys the t1 register.
2625	 */
2626#define PV_UPDATE(pv)				  \
2627	ldw	PV_TLBPROT(pv), t1		! \
2628	PV_MODREF(t1, %r1)			! \
2629	copy	%r1, t1				! \
2630	depi	0, PV_HEAD_REF_POS, 2, t1	! \
2631	comb,<>,n t1, pv, 0			! \
2632	depi	0, PV_HEAD_WRITABLE_POS, 30, %r1 ! \
2633	copy	%r25, t1			! \
2634	bl	$flush_mapping, %r16		! \
2635	copy	pv, %r17			! \
2636	copy	t1, %r25			! \
2637	ldw	PV_TLBPROT(pv), t1		! \
2638	andcm	t1, arg2, t1			! \
2639	or	t1, arg3, t1			! \
2640	stw	t1, PV_TLBPROT(pv)
2641
2642$pmap_pv_update_given
2643
2644	/* If pv is non-NULL, flush and update that mapping. */
2645	comb,=,n %r0, arg1, $pmap_pv_update_others
2646	PV_UPDATE(arg1)
2647
2648$pmap_pv_update_others
2649
2650	/*
2651	 * If none of TLB_REF, TLB_DIRTY, or TLB_NO_RW_ALIAS are
2652	 * set in tlbprot_clear, we're done.
2653	 */
2654	zdepi	1, TLB_REF_POS, 1, t1
2655	depi	1, TLB_DIRTY_POS, 1, t1
2656	depi	1, TLB_NO_RW_ALIAS_POS, 1, t1
2657	and,<>	arg2, t1, arg2
2658	b	$pmap_pv_update_done
2659	and	arg3, t1, arg3
2660
2661	/*
2662	 * Otherwise, update all of the mappings of this page,
2663	 * skipping any mapping we did above.
2664	 */
2665	ldw	PV_HEAD_PVS(arg0), %r17
2666$pmap_pv_update_loop
2667	comb,=,n %r17, %r0, $pmap_pv_update_done
2668	comb,=,n %r17, arg1, $pmap_pv_update_loop
2669	ldw	PV_NEXT(%r17), %r17
2670	PV_UPDATE(%r17)
2671	b	$pmap_pv_update_loop
2672	ldw	PV_NEXT(%r17), %r17
2673
2674$pmap_pv_update_done
2675
2676	/* Store the new pv_head_writable_ref_dirty value. */
2677	stw	%r1, PV_HEAD_WRITABLE_DIRTY_REF(arg0)
2678
2679	/*
2680	 * Return to virtual mode and reenable interrupts.
2681	 */
2682	copy	ret0, arg0
2683	break	HPPA_BREAK_KERNEL, HPPA_BREAK_SET_PSW
2684
2685	/*
2686	 * Restore various callee-saved registers.  Note that
2687	 * as part of the stack calling convention, the caller's
2688	 * %r3 was saved at 0(%r3) and is restored at the end.
2689	 */
2690	ldw	4(%r3), %r8
2691	ldw	8(%r3), %r9
2692	ldw	12(%r3), %r16
2693	ldw	16(%r3), %r17
2694
2695        /* End stack calling convention. */
2696	ldw	HPPA_FRAME_CRP(%r3), %rp
2697	ldo	HPPA_FRAME_SIZE(%r3), %sp
2698	ldw,mb	-HPPA_FRAME_SIZE(%sp), %r3
2699
2700	/* Return. */
2701	bv	%r0(%rp)
2702	nop
2703EXIT(__pmap_pv_update)
2704