1/* $Id: entry.S,v 1.170 2001/11/13 00:57:05 davem Exp $
2 * arch/sparc/kernel/entry.S:  Sparc trap low-level entry points.
3 *
4 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
5 * Copyright (C) 1996 Eddie C. Dost   (ecd@skynet.be)
6 * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
7 * Copyright (C) 1996-1999 Jakub Jelinek   (jj@sunsite.mff.cuni.cz)
8 * Copyright (C) 1997 Anton Blanchard (anton@progsoc.uts.edu.au)
9 */
10
11#include <linux/config.h>
12#include <linux/errno.h>
13
14#include <asm/head.h>
15#include <asm/asi.h>
16#include <asm/smp.h>
17#include <asm/kgdb.h>
18#include <asm/contregs.h>
19#include <asm/ptrace.h>
20#include <asm/psr.h>
21#include <asm/cprefix.h>
22#include <asm/vaddrs.h>
23#include <asm/memreg.h>
24#include <asm/page.h>
25#ifdef CONFIG_SUN4
26#include <asm/pgtsun4.h>
27#else
28#include <asm/pgtsun4c.h>
29#endif
30#include <asm/winmacro.h>
31#include <asm/signal.h>
32#include <asm/obio.h>
33#include <asm/mxcc.h>
34
35#include <asm/asmmacro.h>
36
37#define curptr      g6
38
39#define NR_SYSCALLS 256      /* Each OS is different... */
40
41/* These are just handy. */
42#define _SV	save	%sp, -STACKFRAME_SZ, %sp
43#define _RS     restore
44
45#define FLUSH_ALL_KERNEL_WINDOWS \
46	_SV; _SV; _SV; _SV; _SV; _SV; _SV; \
47	_RS; _RS; _RS; _RS; _RS; _RS; _RS;
48
49/* First, KGDB low level things.  This is a rewrite
50 * of the routines found in the sparc-stub.c asm() statement
51 * from the gdb distribution.  This is also dual-purpose
52 * as a software trap for userlevel programs.
53 */
54	.data
55	.align	4
56
57in_trap_handler:
58	.word	0
59
60	.text
61	.align	4
62
63! This function is called when any SPARC trap (except window overflow or
64! underflow) occurs.  It makes sure that the invalid register window is still
65! available before jumping into C code.  It will also restore the world if you
66! return from handle_exception.
67
68	.globl	C_LABEL(trap_low)
69C_LABEL(trap_low):
70	rd	%wim, %l3
71	SAVE_ALL
72
73	sethi	%hi(in_trap_handler), %l4
74	ld	[%lo(in_trap_handler) + %l4], %l5
75	inc	%l5
76	st	%l5, [%lo(in_trap_handler) + %l4]
77
78	/* Make sure kgdb sees the same state we just saved. */
79	LOAD_PT_GLOBALS(sp)
80	LOAD_PT_INS(sp)
81	ld	[%sp + STACKFRAME_SZ + PT_Y], %l4
82	ld	[%sp + STACKFRAME_SZ + PT_WIM], %l3
83	ld	[%sp + STACKFRAME_SZ + PT_PSR], %l0
84	ld	[%sp + STACKFRAME_SZ + PT_PC], %l1
85	ld	[%sp + STACKFRAME_SZ + PT_NPC], %l2
86	rd	%tbr, %l5	/* Never changes... */
87
88	/* Make kgdb exception frame. */
89	sub	%sp,(16+1+6+1+72)*4,%sp	! Make room for input & locals
90 					! + hidden arg + arg spill
91					! + doubleword alignment
92					! + registers[72] local var
93	SAVE_KGDB_GLOBALS(sp)
94	SAVE_KGDB_INS(sp)
95	SAVE_KGDB_SREGS(sp, l4, l0, l3, l5, l1, l2)
96
97	/* We are increasing PIL, so two writes. */
98	or	%l0, PSR_PIL, %l0
99	wr	%l0, 0, %psr
100	WRITE_PAUSE
101	wr	%l0, PSR_ET, %psr
102	WRITE_PAUSE
103
104	call	C_LABEL(handle_exception)
105	 add	%sp, STACKFRAME_SZ, %o0	! Pass address of registers
106
107	/* Load new kgdb register set. */
108	LOAD_KGDB_GLOBALS(sp)
109	LOAD_KGDB_INS(sp)
110	LOAD_KGDB_SREGS(sp, l4, l0, l3, l5, l1, l2)
111	wr      %l4, 0x0, %y
112
113	sethi	%hi(in_trap_handler), %l4
114	ld	[%lo(in_trap_handler) + %l4], %l5
115	dec	%l5
116	st	%l5, [%lo(in_trap_handler) + %l4]
117
118	add	%sp,(16+1+6+1+72)*4,%sp	! Undo the kgdb trap frame.
119
120	/* Now take what kgdb did and place it into the pt_regs
121	 * frame which SparcLinux RESTORE_ALL understands.,
122	 */
123	STORE_PT_INS(sp)
124	STORE_PT_GLOBALS(sp)
125	STORE_PT_YREG(sp, g2)
126	STORE_PT_PRIV(sp, l0, l1, l2)
127
128	RESTORE_ALL
129
130
131#ifdef CONFIG_BLK_DEV_FD
132	.text
133	.align	4
134	.globl	C_LABEL(floppy_hardint)
135C_LABEL(floppy_hardint):
136	/*
137	 * This code cannot touch registers %l0 %l1 and %l2
138	 * because SAVE_ALL depends on their values. It depends
139	 * on %l3 also, but we regenerate it before a call.
140	 * Other registers are:
141	 * %l3 -- base address of fdc registers
142	 * %l4 -- pdma_vaddr
143	 * %l5 -- scratch for ld/st address
144	 * %l6 -- pdma_size
145	 * %l7 -- scratch [floppy byte, ld/st address, aux. data]
146	 */
147
148	/* Do we have work to do? */
149	sethi	%hi(C_LABEL(doing_pdma)), %l7
150	ld	[%l7 + %lo(C_LABEL(doing_pdma))], %l7
151	cmp	%l7, 0
152	be	floppy_dosoftint
153	 nop
154
155	/* Load fdc register base */
156	sethi	%hi(C_LABEL(fdc_status)), %l3
157	ld	[%l3 + %lo(C_LABEL(fdc_status))], %l3
158
159	/* Setup register addresses */
160	sethi	%hi(C_LABEL(pdma_vaddr)), %l5	! transfer buffer
161	ld	[%l5 + %lo(C_LABEL(pdma_vaddr))], %l4
162	sethi	%hi(C_LABEL(pdma_size)), %l5	! bytes to go
163	ld	[%l5 + %lo(C_LABEL(pdma_size))], %l6
164next_byte:
165  	ldub	[%l3], %l7
166
167	andcc	%l7, 0x80, %g0		! Does fifo still have data
168	bz	floppy_fifo_emptied	! fifo has been emptied...
169	 andcc	%l7, 0x20, %g0		! in non-dma mode still?
170	bz	floppy_overrun		! nope, overrun
171	 andcc	%l7, 0x40, %g0		! 0=write 1=read
172	bz	floppy_write
173	 sub	%l6, 0x1, %l6
174
175	/* Ok, actually read this byte */
176	ldub	[%l3 + 1], %l7
177	orcc	%g0, %l6, %g0
178	stb	%l7, [%l4]
179	bne	next_byte
180	 add	%l4, 0x1, %l4
181
182	b	floppy_tdone
183	 nop
184
185floppy_write:
186	/* Ok, actually write this byte */
187	ldub	[%l4], %l7
188	orcc	%g0, %l6, %g0
189	stb	%l7, [%l3 + 1]
190	bne	next_byte
191	 add	%l4, 0x1, %l4
192
193	/* fall through... */
194floppy_tdone:
195	sethi	%hi(C_LABEL(pdma_vaddr)), %l5
196	st	%l4, [%l5 + %lo(C_LABEL(pdma_vaddr))]
197	sethi	%hi(C_LABEL(pdma_size)), %l5
198	st	%l6, [%l5 + %lo(C_LABEL(pdma_size))]
199	/* Flip terminal count pin */
200	set	C_LABEL(auxio_register), %l7
201	ld	[%l7], %l7
202
203	set	C_LABEL(sparc_cpu_model), %l5
204	ld	[%l5], %l5
205	subcc   %l5, 1, %g0		/* enum { sun4c = 1 }; */
206	be	1f
207	 ldub	[%l7], %l5
208
209	or	%l5, 0xc2, %l5
210	stb	%l5, [%l7]
211	andn    %l5, 0x02, %l5
212	b	2f
213	 nop
214
2151:
216	or      %l5, 0xf4, %l5
217	stb     %l5, [%l7]
218	andn    %l5, 0x04, %l5
219
2202:
221	/* Kill some time so the bits set */
222	WRITE_PAUSE
223	WRITE_PAUSE
224
225	stb     %l5, [%l7]
226
227	/* Prevent recursion */
228	sethi	%hi(C_LABEL(doing_pdma)), %l7
229	b	floppy_dosoftint
230	 st	%g0, [%l7 + %lo(C_LABEL(doing_pdma))]
231
232	/* We emptied the FIFO, but we haven't read everything
233	 * as of yet.  Store the current transfer address and
234	 * bytes left to read so we can continue when the next
235	 * fast IRQ comes in.
236	 */
237floppy_fifo_emptied:
238	sethi	%hi(C_LABEL(pdma_vaddr)), %l5
239	st	%l4, [%l5 + %lo(C_LABEL(pdma_vaddr))]
240	sethi	%hi(C_LABEL(pdma_size)), %l7
241	st	%l6, [%l7 + %lo(C_LABEL(pdma_size))]
242
243	/* Restore condition codes */
244	wr	%l0, 0x0, %psr
245	WRITE_PAUSE
246
247	jmp	%l1
248	rett	%l2
249
250floppy_overrun:
251	sethi	%hi(C_LABEL(pdma_vaddr)), %l5
252	st	%l4, [%l5 + %lo(C_LABEL(pdma_vaddr))]
253	sethi	%hi(C_LABEL(pdma_size)), %l5
254	st	%l6, [%l5 + %lo(C_LABEL(pdma_size))]
255	/* Prevent recursion */
256	sethi	%hi(C_LABEL(doing_pdma)), %l7
257	st	%g0, [%l7 + %lo(C_LABEL(doing_pdma))]
258
259	/* fall through... */
260floppy_dosoftint:
261	rd	%wim, %l3
262	SAVE_ALL
263
264	/* Set all IRQs off. */
265	or	%l0, PSR_PIL, %l4
266	wr	%l4, 0x0, %psr
267	WRITE_PAUSE
268	wr	%l4, PSR_ET, %psr
269	WRITE_PAUSE
270
271	mov	11, %o0			! floppy irq level (unused anyway)
272	mov	%g0, %o1		! devid is not used in fast interrupts
273	call	C_LABEL(sparc_floppy_irq)
274	 add	%sp, STACKFRAME_SZ, %o2	! struct pt_regs *regs
275
276	RESTORE_ALL
277
278#endif /* (CONFIG_BLK_DEV_FD) */
279
280	/* Bad trap handler */
281	.globl	bad_trap_handler
282bad_trap_handler:
283	SAVE_ALL
284
285	wr	%l0, PSR_ET, %psr
286	WRITE_PAUSE
287
288	mov	%l7, %o0		! trap number
289	mov	%l0, %o1		! psr
290	call	C_LABEL(do_hw_interrupt)
291	 mov	%l1, %o2		! pc
292
293	RESTORE_ALL
294
295/* For now all IRQ's not registered get sent here. handler_irq() will
296 * see if a routine is registered to handle this interrupt and if not
297 * it will say so on the console.
298 */
299
300	.align	4
301	.globl	real_irq_entry, patch_handler_irq
302real_irq_entry:
303	SAVE_ALL
304
305#ifdef CONFIG_SMP
306	.globl	patchme_maybe_smp_msg
307
308	cmp	%l7, 12
309patchme_maybe_smp_msg:
310	bgu	maybe_smp4m_msg
311	 nop
312#endif
313
314real_irq_continue:
315	or	%l0, PSR_PIL, %g2
316	wr	%g2, 0x0, %psr
317	WRITE_PAUSE
318	wr	%g2, PSR_ET, %psr
319	WRITE_PAUSE
320	mov	%l7, %o0		! irq level
321patch_handler_irq:
322	call	C_LABEL(handler_irq)
323	 add	%sp, STACKFRAME_SZ, %o1	! pt_regs ptr
324	or	%l0, PSR_PIL, %g2	! restore PIL after handler_irq
325	wr	%g2, PSR_ET, %psr	! keep ET up
326	WRITE_PAUSE
327
328	RESTORE_ALL
329
330#ifdef CONFIG_SMP
331	/* SMP per-cpu ticker interrupts are handled specially. */
332smp4m_ticker:
333	bne	real_irq_continue+4
334	 or	%l0, PSR_PIL, %g2
335	wr	%g2, 0x0, %psr
336	WRITE_PAUSE
337	wr	%g2, PSR_ET, %psr
338	WRITE_PAUSE
339	call	C_LABEL(smp4m_percpu_timer_interrupt)
340	 add	%sp, STACKFRAME_SZ, %o0
341	wr	%l0, PSR_ET, %psr
342	WRITE_PAUSE
343	RESTORE_ALL
344
345	/* Here is where we check for possible SMP IPI passed to us
346	 * on some level other than 15 which is the NMI and only used
347	 * for cross calls.  That has a separate entry point below.
348	 */
349maybe_smp4m_msg:
350	GET_PROCESSOR_MID(o3, o2)
351	set	C_LABEL(sun4m_interrupts), %l5
352	ld	[%l5], %o5
353	sethi	%hi(0x60000000), %o4
354	sll	%o3, 12, %o3
355	ld	[%o5 + %o3], %o1
356	andcc	%o1, %o4, %g0
357	be,a	smp4m_ticker
358	 cmp	%l7, 14
359	cmp	%l7, 13
360	add	%o5, %o3, %o5
361	bne,a	1f
362	 sethi	%hi(0x40000000), %o2
363	sethi	%hi(0x20000000), %o2
3641:
365	st	%o2, [%o5 + 0x4]
366	WRITE_PAUSE
367	ld	[%o5], %g0
368	WRITE_PAUSE
369	or	%l0, PSR_PIL, %l4
370	wr	%l4, 0x0, %psr
371	WRITE_PAUSE
372	wr	%l4, PSR_ET, %psr
373	WRITE_PAUSE
374	cmp	%l7, 13
375	bne	2f
376	 nop
377	call	C_LABEL(smp_reschedule_irq)
378	 add	%o7, 8, %o7
3792:
380	call	C_LABEL(smp_stop_cpu_irq)
381	 nop
382	RESTORE_ALL
383
384	.align	4
385	.globl	linux_trap_ipi15_sun4m
386linux_trap_ipi15_sun4m:
387	SAVE_ALL
388	sethi	%hi(0x80000000), %o2
389	GET_PROCESSOR_MID(o0, o1)
390	set	C_LABEL(sun4m_interrupts), %l5
391	ld	[%l5], %o5
392	sll	%o0, 12, %o0
393	add	%o5, %o0, %o5
394	ld	[%o5], %o3
395	andcc	%o3, %o2, %g0
396	be	1f			! Must be an NMI async memory error
397	 st	%o2, [%o5 + 4]
398	WRITE_PAUSE
399	ld	[%o5], %g0
400	WRITE_PAUSE
401	or	%l0, PSR_PIL, %l4
402	wr	%l4, 0x0, %psr
403	WRITE_PAUSE
404	wr	%l4, PSR_ET, %psr
405	WRITE_PAUSE
406	call	C_LABEL(smp4m_cross_call_irq)
407	 nop
408	b	ret_trap_lockless_ipi
409	 clr	%l6
4101:
411	/* NMI async memory error handling. */
412	sethi	%hi(0x80000000), %l4
413	sethi	%hi(0x4000), %o3
414	sub	%o5, %o0, %o5
415	add	%o5, %o3, %l5
416	st	%l4, [%l5 + 0xc]
417	WRITE_PAUSE
418	ld	[%l5], %g0
419	WRITE_PAUSE
420	or	%l0, PSR_PIL, %l4
421	wr	%l4, 0x0, %psr
422	WRITE_PAUSE
423	wr	%l4, PSR_ET, %psr
424	WRITE_PAUSE
425	call	C_LABEL(sun4m_nmi)
426	 nop
427	st	%l4, [%l5 + 0x8]
428	WRITE_PAUSE
429	ld	[%l5], %g0
430	WRITE_PAUSE
431	RESTORE_ALL
432
433	.globl	smp4d_ticker
434	/* SMP per-cpu ticker interrupts are handled specially. */
435smp4d_ticker:
436	SAVE_ALL
437	or	%l0, PSR_PIL, %g2
438	sethi	%hi(CC_ICLR), %o0
439	sethi	%hi(1 << 14), %o1
440	or	%o0, %lo(CC_ICLR), %o0
441	stha	%o1, [%o0] ASI_M_MXCC	/* Clear PIL 14 in MXCC's ICLR */
442	wr	%g2, 0x0, %psr
443	WRITE_PAUSE
444	wr	%g2, PSR_ET, %psr
445	WRITE_PAUSE
446	call	C_LABEL(smp4d_percpu_timer_interrupt)
447	 add	%sp, STACKFRAME_SZ, %o0
448	wr	%l0, PSR_ET, %psr
449	WRITE_PAUSE
450	RESTORE_ALL
451
452	.align	4
453	.globl	linux_trap_ipi15_sun4d
454linux_trap_ipi15_sun4d:
455	SAVE_ALL
456	sethi	%hi(CC_BASE), %o4
457	sethi	%hi(MXCC_ERR_ME|MXCC_ERR_PEW|MXCC_ERR_ASE|MXCC_ERR_PEE), %o2
458	or	%o4, (CC_EREG - CC_BASE), %o0
459	ldda	[%o0] ASI_M_MXCC, %o0
460	andcc	%o0, %o2, %g0
461	bne	1f
462	 sethi	%hi(BB_STAT2), %o2
463	lduba	[%o2] ASI_M_CTL, %o2
464	andcc	%o2, BB_STAT2_MASK, %g0
465	bne	2f
466	 or	%o4, (CC_ICLR - CC_BASE), %o0
467	sethi	%hi(1 << 15), %o1
468	stha	%o1, [%o0] ASI_M_MXCC	/* Clear PIL 15 in MXCC's ICLR */
469	or	%l0, PSR_PIL, %l4
470	wr	%l4, 0x0, %psr
471	WRITE_PAUSE
472	wr	%l4, PSR_ET, %psr
473	WRITE_PAUSE
474	call	C_LABEL(smp4d_cross_call_irq)
475	 nop
476	b	ret_trap_lockless_ipi
477	 clr	%l6
478
4791:	/* MXCC error */
4802:	/* BB error */
481	/* Disable PIL 15 */
482	set	CC_IMSK, %l4
483	lduha	[%l4] ASI_M_MXCC, %l5
484	sethi	%hi(1 << 15), %l7
485	or	%l5, %l7, %l5
486	stha	%l5, [%l4] ASI_M_MXCC
487	/* FIXME */
4881:	b,a	1b
489
490#endif /* CONFIG_SMP */
491
492	/* This routine handles illegal instructions and privileged
493	 * instruction attempts from user code.
494	 */
495	.align	4
496	.globl	bad_instruction
497bad_instruction:
498	sethi	%hi(0xc1f80000), %l4
499	ld	[%l1], %l5
500	sethi	%hi(0x81d80000), %l7
501	and	%l5, %l4, %l5
502	cmp	%l5, %l7
503	be	1f
504	SAVE_ALL
505
506	wr	%l0, PSR_ET, %psr		! re-enable traps
507	WRITE_PAUSE
508
509	add	%sp, STACKFRAME_SZ, %o0
510	mov	%l1, %o1
511	mov	%l2, %o2
512	call	C_LABEL(do_illegal_instruction)
513	 mov	%l0, %o3
514
515	RESTORE_ALL
516
5171:	/* unimplemented flush - just skip */
518	jmpl	%l2, %g0
519	 rett	%l2 + 4
520
521	.align	4
522	.globl	priv_instruction
523priv_instruction:
524	SAVE_ALL
525
526	wr	%l0, PSR_ET, %psr
527	WRITE_PAUSE
528
529	add	%sp, STACKFRAME_SZ, %o0
530	mov	%l1, %o1
531	mov	%l2, %o2
532	call	C_LABEL(do_priv_instruction)
533	 mov	%l0, %o3
534
535	RESTORE_ALL
536
537	/* This routine handles unaligned data accesses. */
538	.align	4
539	.globl	mna_handler
540mna_handler:
541	andcc	%l0, PSR_PS, %g0
542	be	mna_fromuser
543	 nop
544
545	SAVE_ALL
546
547	wr	%l0, PSR_ET, %psr
548	WRITE_PAUSE
549
550	ld	[%l1], %o1
551	call	C_LABEL(kernel_unaligned_trap)
552	 add	%sp, STACKFRAME_SZ, %o0
553
554	RESTORE_ALL
555
556mna_fromuser:
557	SAVE_ALL
558
559	wr	%l0, PSR_ET, %psr		! re-enable traps
560	WRITE_PAUSE
561
562	ld	[%l1], %o1
563	call	C_LABEL(user_unaligned_trap)
564	 add	%sp, STACKFRAME_SZ, %o0
565
566	RESTORE_ALL
567
568	/* This routine handles floating point disabled traps. */
569	.align	4
570	.globl	fpd_trap_handler
571fpd_trap_handler:
572	SAVE_ALL
573
574	wr	%l0, PSR_ET, %psr		! re-enable traps
575	WRITE_PAUSE
576
577	add	%sp, STACKFRAME_SZ, %o0
578	mov	%l1, %o1
579	mov	%l2, %o2
580	call	C_LABEL(do_fpd_trap)
581	 mov	%l0, %o3
582
583	RESTORE_ALL
584
585	/* This routine handles Floating Point Exceptions. */
586	.align	4
587	.globl	fpe_trap_handler
588fpe_trap_handler:
589	set	fpsave_magic, %l5
590	cmp	%l1, %l5
591	be	1f
592	 sethi	%hi(C_LABEL(fpsave)), %l5
593	or	%l5, %lo(C_LABEL(fpsave)), %l5
594	cmp	%l1, %l5
595	bne	2f
596	 sethi	%hi(fpsave_catch2), %l5
597	or	%l5, %lo(fpsave_catch2), %l5
598	wr	%l0, 0x0, %psr
599	WRITE_PAUSE
600	jmp	%l5
601	 rett	%l5 + 4
6021:
603	sethi	%hi(fpsave_catch), %l5
604	or	%l5, %lo(fpsave_catch), %l5
605	wr	%l0, 0x0, %psr
606	WRITE_PAUSE
607	jmp	%l5
608	 rett	%l5 + 4
609
6102:
611	SAVE_ALL
612
613	wr	%l0, PSR_ET, %psr		! re-enable traps
614	WRITE_PAUSE
615
616	add	%sp, STACKFRAME_SZ, %o0
617	mov	%l1, %o1
618	mov	%l2, %o2
619	call	C_LABEL(do_fpe_trap)
620	 mov	%l0, %o3
621
622	RESTORE_ALL
623
624	/* This routine handles Tag Overflow Exceptions. */
625	.align	4
626	.globl	do_tag_overflow
627do_tag_overflow:
628	SAVE_ALL
629
630	wr	%l0, PSR_ET, %psr		! re-enable traps
631	WRITE_PAUSE
632
633	add	%sp, STACKFRAME_SZ, %o0
634	mov	%l1, %o1
635	mov	%l2, %o2
636	call	C_LABEL(handle_tag_overflow)
637	 mov	%l0, %o3
638
639	RESTORE_ALL
640
641	/* This routine handles Watchpoint Exceptions. */
642	.align	4
643	.globl	do_watchpoint
644do_watchpoint:
645	SAVE_ALL
646
647	wr	%l0, PSR_ET, %psr		! re-enable traps
648	WRITE_PAUSE
649
650	add	%sp, STACKFRAME_SZ, %o0
651	mov	%l1, %o1
652	mov	%l2, %o2
653	call	C_LABEL(handle_watchpoint)
654	 mov	%l0, %o3
655
656	RESTORE_ALL
657
658	/* This routine handles Register Access Exceptions. */
659	.align	4
660	.globl	do_reg_access
661do_reg_access:
662	SAVE_ALL
663
664	wr	%l0, PSR_ET, %psr		! re-enable traps
665	WRITE_PAUSE
666
667	add	%sp, STACKFRAME_SZ, %o0
668	mov	%l1, %o1
669	mov	%l2, %o2
670	call	C_LABEL(handle_reg_access)
671	 mov	%l0, %o3
672
673	RESTORE_ALL
674
675	/* This routine handles Co-Processor Disabled Exceptions. */
676	.align	4
677	.globl	do_cp_disabled
678do_cp_disabled:
679	SAVE_ALL
680
681	wr	%l0, PSR_ET, %psr		! re-enable traps
682	WRITE_PAUSE
683
684	add	%sp, STACKFRAME_SZ, %o0
685	mov	%l1, %o1
686	mov	%l2, %o2
687	call	C_LABEL(handle_cp_disabled)
688	 mov	%l0, %o3
689
690	RESTORE_ALL
691
692	/* This routine handles Co-Processor Exceptions. */
693	.align	4
694	.globl	do_cp_exception
695do_cp_exception:
696	SAVE_ALL
697
698	wr	%l0, PSR_ET, %psr		! re-enable traps
699	WRITE_PAUSE
700
701	add	%sp, STACKFRAME_SZ, %o0
702	mov	%l1, %o1
703	mov	%l2, %o2
704	call	C_LABEL(handle_cp_exception)
705	 mov	%l0, %o3
706
707	RESTORE_ALL
708
709	/* This routine handles Hardware Divide By Zero Exceptions. */
710	.align	4
711	.globl	do_hw_divzero
712do_hw_divzero:
713	SAVE_ALL
714
715	wr	%l0, PSR_ET, %psr		! re-enable traps
716	WRITE_PAUSE
717
718	add	%sp, STACKFRAME_SZ, %o0
719	mov	%l1, %o1
720	mov	%l2, %o2
721	call	C_LABEL(handle_hw_divzero)
722	 mov	%l0, %o3
723
724	RESTORE_ALL
725
726	.align	4
727	.globl	do_flush_windows
728do_flush_windows:
729	SAVE_ALL
730
731	wr	%l0, PSR_ET, %psr
732	WRITE_PAUSE
733
734	andcc	%l0, PSR_PS, %g0
735	bne	dfw_kernel
736	 nop
737
738	call	C_LABEL(flush_user_windows)
739	 nop
740
741	/* Advance over the trap instruction. */
742	ld	[%sp + STACKFRAME_SZ + PT_NPC], %l1
743	add	%l1, 0x4, %l2
744	st	%l1, [%sp + STACKFRAME_SZ + PT_PC]
745	st	%l2, [%sp + STACKFRAME_SZ + PT_NPC]
746
747	RESTORE_ALL
748
749	.globl	flush_patch_one
750
751	/* We get these for debugging routines using __builtin_return_address() */
752dfw_kernel:
753flush_patch_one:
754	FLUSH_ALL_KERNEL_WINDOWS
755
756	/* Advance over the trap instruction. */
757	ld	[%sp + STACKFRAME_SZ + PT_NPC], %l1
758	add	%l1, 0x4, %l2
759	st	%l1, [%sp + STACKFRAME_SZ + PT_PC]
760	st	%l2, [%sp + STACKFRAME_SZ + PT_NPC]
761
762	RESTORE_ALL
763
764	/* The getcc software trap.  The user wants the condition codes from
765	 * the %psr in register %g1.
766	 */
767
768	.align	4
769	.globl	getcc_trap_handler
770getcc_trap_handler:
771	srl	%l0, 20, %g1	! give user
772	and	%g1, 0xf, %g1	! only ICC bits in %psr
773	jmp	%l2		! advance over trap instruction
774	rett	%l2 + 0x4	! like this...
775
776	/* The setcc software trap.  The user has condition codes in %g1
777	 * that it would like placed in the %psr.  Be careful not to flip
778	 * any unintentional bits!
779	 */
780
781	.align	4
782	.globl	setcc_trap_handler
783setcc_trap_handler:
784	sll	%g1, 0x14, %l4
785	set	PSR_ICC, %l5
786	andn	%l0, %l5, %l0	! clear ICC bits in %psr
787	and	%l4, %l5, %l4	! clear non-ICC bits in user value
788	or	%l4, %l0, %l4	! or them in... mix mix mix
789
790	wr	%l4, 0x0, %psr	! set new %psr
791	WRITE_PAUSE		! TI scumbags...
792
793	jmp	%l2		! advance over trap instruction
794	rett	%l2 + 0x4	! like this...
795
796	.align	4
797	.globl	linux_trap_nmi_sun4c
798linux_trap_nmi_sun4c:
799	SAVE_ALL
800
801	/* Ugh, we need to clear the IRQ line.  This is now
802	 * a very sun4c specific trap handler...
803	 */
804	sethi	%hi(C_LABEL(interrupt_enable)), %l5
805	ld	[%l5 + %lo(C_LABEL(interrupt_enable))], %l5
806	ldub	[%l5], %l6
807	andn	%l6, INTS_ENAB, %l6
808	stb	%l6, [%l5]
809
810	/* Now it is safe to re-enable traps without recursion. */
811	or	%l0, PSR_PIL, %l0
812	wr	%l0, PSR_ET, %psr
813	WRITE_PAUSE
814
815	/* Now call the c-code with the pt_regs frame ptr and the
816	 * memory error registers as arguments.  The ordering chosen
817	 * here is due to unlatching semantics.
818	 */
819	sethi	%hi(AC_SYNC_ERR), %o0
820	add	%o0, 0x4, %o0
821	lda	[%o0] ASI_CONTROL, %o2	! sync vaddr
822	sub	%o0, 0x4, %o0
823	lda	[%o0] ASI_CONTROL, %o1	! sync error
824	add	%o0, 0xc, %o0
825	lda	[%o0] ASI_CONTROL, %o4	! async vaddr
826	sub	%o0, 0x4, %o0
827	lda	[%o0] ASI_CONTROL, %o3	! async error
828	call	C_LABEL(sparc_lvl15_nmi)
829	 add	%sp, STACKFRAME_SZ, %o0
830
831	RESTORE_ALL
832
833	.align	4
834	.globl	C_LABEL(invalid_segment_patch1_ff)
835	.globl	C_LABEL(invalid_segment_patch2_ff)
836C_LABEL(invalid_segment_patch1_ff):	cmp	%l4, 0xff
837C_LABEL(invalid_segment_patch2_ff):	mov	0xff, %l3
838
839	.align	4
840	.globl	C_LABEL(invalid_segment_patch1_1ff)
841	.globl	C_LABEL(invalid_segment_patch2_1ff)
842C_LABEL(invalid_segment_patch1_1ff):	cmp	%l4, 0x1ff
843C_LABEL(invalid_segment_patch2_1ff):	mov	0x1ff, %l3
844
845	.align	4
846	.globl	C_LABEL(num_context_patch1_16), C_LABEL(num_context_patch2_16)
847C_LABEL(num_context_patch1_16):		mov	0x10, %l7
848C_LABEL(num_context_patch2_16):		mov	0x10, %l7
849
850	.align	4
851	.globl	C_LABEL(vac_linesize_patch_32)
852C_LABEL(vac_linesize_patch_32):		subcc	%l7, 32, %l7
853
854	.align	4
855	.globl	C_LABEL(vac_hwflush_patch1_on), C_LABEL(vac_hwflush_patch2_on)
856
857/*
858 * Ugly, but we cant use hardware flushing on the sun4 and we'd require
859 * two instructions (Anton)
860 */
861#ifdef CONFIG_SUN4
862C_LABEL(vac_hwflush_patch1_on):		nop
863#else
864C_LABEL(vac_hwflush_patch1_on):		addcc	%l7, -PAGE_SIZE, %l7
865#endif
866
867C_LABEL(vac_hwflush_patch2_on):		sta	%g0, [%l3 + %l7] ASI_HWFLUSHSEG
868
869	.globl	C_LABEL(invalid_segment_patch1), C_LABEL(invalid_segment_patch2)
870	.globl	C_LABEL(num_context_patch1), C_LABEL(num_context_patch2)
871	.globl	C_LABEL(vac_linesize_patch), C_LABEL(vac_hwflush_patch1)
872	.globl	C_LABEL(vac_hwflush_patch2)
873
874	.align	4
875	.globl	sun4c_fault
876
877! %l0 = %psr
878! %l1 = %pc
879! %l2 = %npc
880! %l3 = %wim
881! %l7 = 1 for textfault
882! We want error in %l5, vaddr in %l6
883sun4c_fault:
884#ifdef CONFIG_SUN4
885	sethi	%hi(C_LABEL(sun4c_memerr_reg)), %l4
886	ld	[%l4+%lo(C_LABEL(sun4c_memerr_reg))], %l4  ! memerr ctrl reg addr
887	ld	[%l4], %l6		! memerr ctrl reg
888	ld	[%l4 + 4], %l5		! memerr vaddr reg
889	andcc	%l6, 0x80, %g0		! check for error type
890	st	%g0, [%l4 + 4]		! clear the error
891	be	0f			! normal error
892	 sethi	%hi(AC_BUS_ERROR), %l4	! bus err reg addr
893
894	call	C_LABEL(prom_halt)	! something weird happened
895					! what exactly did happen?
896					! what should we do here?
897
8980:	or	%l4, %lo(AC_BUS_ERROR), %l4	! bus err reg addr
899	lduba	[%l4] ASI_CONTROL, %l6	! bus err reg
900
901	cmp    %l7, 1			! text fault?
902	be	1f			! yes
903	 nop
904
905	ld     [%l1], %l4		! load instruction that caused fault
906	srl	%l4, 21, %l4
907	andcc	%l4, 1, %g0		! store instruction?
908
909	be	1f			! no
910	 sethi	%hi(SUN4C_SYNC_BADWRITE), %l4 ! yep
911					! %lo(SUN4C_SYNC_BADWRITE) = 0
912	or	%l4, %l6, %l6		! set write bit to emulate sun4c
9131:
914#else
915	sethi	%hi(AC_SYNC_ERR), %l4
916	add	%l4, 0x4, %l6			! AC_SYNC_VA in %l6
917	lda	[%l6] ASI_CONTROL, %l5		! Address
918	lda	[%l4] ASI_CONTROL, %l6		! Error, retained for a bit
919#endif
920
921	andn	%l5, 0xfff, %l5			! Encode all info into l7
922	srl	%l6, 14, %l4
923
924	and	%l4, 2, %l4
925	or	%l5, %l4, %l4
926
927	or	%l4, %l7, %l7			! l7 = [addr,write,txtfault]
928
929	andcc	%l0, PSR_PS, %g0
930	be	sun4c_fault_fromuser
931	 andcc	%l7, 1, %g0			! Text fault?
932
933	be	1f
934	 sethi	%hi(KERNBASE), %l4
935
936	mov	%l1, %l5			! PC
937
9381:
939	cmp	%l5, %l4
940	blu	sun4c_fault_fromuser
941	 sethi	%hi(~((1 << SUN4C_REAL_PGDIR_SHIFT) - 1)), %l4
942
943	/* If the kernel references a bum kernel pointer, or a pte which
944	 * points to a non existant page in ram, we will run this code
945	 * _forever_ and lock up the machine!!!!! So we must check for
946	 * this condition, the AC_SYNC_ERR bits are what we must examine.
947	 * Also a parity error would make this happen as well.  So we just
948	 * check that we are in fact servicing a tlb miss and not some
949	 * other type of fault for the kernel.
950	 */
951	andcc	%l6, 0x80, %g0
952	be	sun4c_fault_fromuser
953	 and	%l5, %l4, %l5
954
955	/* Test for NULL pte_t * in vmalloc area. */
956	sethi   %hi(VMALLOC_START), %l4
957	cmp     %l5, %l4
958	blu,a   C_LABEL(invalid_segment_patch1)
959	 lduXa	[%l5] ASI_SEGMAP, %l4
960
961	sethi   %hi(C_LABEL(swapper_pg_dir)), %l4
962	srl     %l5, SUN4C_PGDIR_SHIFT, %l6
963	or      %l4, %lo(C_LABEL(swapper_pg_dir)), %l4
964	sll     %l6, 2, %l6
965	ld      [%l4 + %l6], %l4
966#ifdef CONFIG_SUN4
967	sethi	%hi(PAGE_MASK), %l6
968	andcc	%l4, %l6, %g0
969#else
970	andcc   %l4, PAGE_MASK, %g0
971#endif
972	be      sun4c_fault_fromuser
973	 lduXa  [%l5] ASI_SEGMAP, %l4
974
975C_LABEL(invalid_segment_patch1):
976	cmp	%l4, 0x7f
977	bne	1f
978	 sethi	%hi(C_LABEL(sun4c_kfree_ring)), %l4
979	or	%l4, %lo(C_LABEL(sun4c_kfree_ring)), %l4
980	ld	[%l4 + 0x18], %l3
981	deccc	%l3			! do we have a free entry?
982	bcs,a	2f			! no, unmap one.
983	 sethi	%hi(C_LABEL(sun4c_kernel_ring)), %l4
984
985	st	%l3, [%l4 + 0x18]	! sun4c_kfree_ring.num_entries--
986
987	ld	[%l4 + 0x00], %l6	! entry = sun4c_kfree_ring.ringhd.next
988	st	%l5, [%l6 + 0x08]	! entry->vaddr = address
989
990	ld	[%l6 + 0x00], %l3	! next = entry->next
991	ld	[%l6 + 0x04], %l7	! entry->prev
992
993	st	%l7, [%l3 + 0x04]	! next->prev = entry->prev
994	st	%l3, [%l7 + 0x00]	! entry->prev->next = next
995
996	sethi	%hi(C_LABEL(sun4c_kernel_ring)), %l4
997	or	%l4, %lo(C_LABEL(sun4c_kernel_ring)), %l4
998					! head = &sun4c_kernel_ring.ringhd
999
1000	ld	[%l4 + 0x00], %l7	! head->next
1001
1002	st	%l4, [%l6 + 0x04]	! entry->prev = head
1003	st	%l7, [%l6 + 0x00]	! entry->next = head->next
1004	st	%l6, [%l7 + 0x04]	! head->next->prev = entry
1005
1006	st	%l6, [%l4 + 0x00]	! head->next = entry
1007
1008	ld	[%l4 + 0x18], %l3
1009	inc	%l3			! sun4c_kernel_ring.num_entries++
1010	st	%l3, [%l4 + 0x18]
1011	b	4f
1012	 ld	[%l6 + 0x08], %l5
1013
10142:
1015	or	%l4, %lo(C_LABEL(sun4c_kernel_ring)), %l4
1016					! head = &sun4c_kernel_ring.ringhd
1017
1018	ld	[%l4 + 0x04], %l6	! entry = head->prev
1019
1020	ld	[%l6 + 0x08], %l3	! tmp = entry->vaddr
1021
1022	! Flush segment from the cache.
1023#ifdef CONFIG_SUN4
1024	sethi	%hi((128 * 1024)), %l7
1025#else
1026	sethi	%hi((64 * 1024)), %l7
1027#endif
10289:
1029C_LABEL(vac_hwflush_patch1):
1030C_LABEL(vac_linesize_patch):
1031	subcc	%l7, 16, %l7
1032	bne	9b
1033C_LABEL(vac_hwflush_patch2):
1034	 sta	%g0, [%l3 + %l7] ASI_FLUSHSEG
1035
1036	st	%l5, [%l6 + 0x08]	! entry->vaddr = address
1037
1038	ld	[%l6 + 0x00], %l5	! next = entry->next
1039	ld	[%l6 + 0x04], %l7	! entry->prev
1040
1041	st	%l7, [%l5 + 0x04]	! next->prev = entry->prev
1042	st	%l5, [%l7 + 0x00]	! entry->prev->next = next
1043	st	%l4, [%l6 + 0x04]	! entry->prev = head
1044
1045	ld	[%l4 + 0x00], %l7	! head->next
1046
1047	st	%l7, [%l6 + 0x00]	! entry->next = head->next
1048	st	%l6, [%l7 + 0x04]	! head->next->prev = entry
1049	st	%l6, [%l4 + 0x00]	! head->next = entry
1050
1051	mov	%l3, %l5		! address = tmp
1052
10534:
1054C_LABEL(num_context_patch1):
1055	mov	0x08, %l7
1056
1057	ld	[%l6 + 0x08], %l4
1058	ldub	[%l6 + 0x0c], %l3
1059	or	%l4, %l3, %l4		! encode new vaddr/pseg into l4
1060
1061	sethi	%hi(AC_CONTEXT), %l3
1062	lduba	[%l3] ASI_CONTROL, %l6
1063
1064	/* Invalidate old mapping, instantiate new mapping,
1065	 * for each context.  Registers l6/l7 are live across
1066	 * this loop.
1067	 */
10683:	deccc	%l7
1069	sethi	%hi(AC_CONTEXT), %l3
1070	stba	%l7, [%l3] ASI_CONTROL
1071C_LABEL(invalid_segment_patch2):
1072	mov	0x7f, %l3
1073	stXa	%l3, [%l5] ASI_SEGMAP
1074	andn	%l4, 0x1ff, %l3
1075	bne	3b
1076	 stXa	%l4, [%l3] ASI_SEGMAP
1077
1078	sethi	%hi(AC_CONTEXT), %l3
1079	stba	%l6, [%l3] ASI_CONTROL
1080
1081	andn	%l4, 0x1ff, %l5
1082
10831:
1084	sethi	%hi(VMALLOC_START), %l4
1085	cmp	%l5, %l4
1086
1087	bgeu	1f
1088	 mov	1 << (SUN4C_REAL_PGDIR_SHIFT - PAGE_SHIFT), %l7
1089
1090	sethi	%hi(KERNBASE), %l6
1091
1092	sub	%l5, %l6, %l4
1093	srl	%l4, PAGE_SHIFT, %l4
1094	sethi	%hi((SUN4C_PAGE_KERNEL & 0xf4000000)), %l3
1095	or	%l3, %l4, %l3
1096
1097	sethi	%hi(PAGE_SIZE), %l4
1098
10992:
1100	sta	%l3, [%l5] ASI_PTE
1101	deccc	%l7
1102	inc	%l3
1103	bne	2b
1104	 add	%l5, %l4, %l5
1105
1106	b	7f
1107	 sethi	%hi(C_LABEL(sun4c_kernel_faults)), %l4
1108
11091:
1110	srl	%l5, SUN4C_PGDIR_SHIFT, %l3
1111	sethi	%hi(C_LABEL(swapper_pg_dir)), %l4
1112	or	%l4, %lo(C_LABEL(swapper_pg_dir)), %l4
1113	sll	%l3, 2, %l3
1114	ld	[%l4 + %l3], %l4
1115#ifndef CONFIG_SUN4
1116	and	%l4, PAGE_MASK, %l4
1117#else
1118	sethi	%hi(PAGE_MASK), %l6
1119	and	%l4, %l6, %l4
1120#endif
1121
1122	srl	%l5, (PAGE_SHIFT - 2), %l6
1123	and	%l6, ((SUN4C_PTRS_PER_PTE - 1) << 2), %l6
1124	add	%l6, %l4, %l6
1125
1126	sethi	%hi(PAGE_SIZE), %l4
1127
11282:
1129	ld	[%l6], %l3
1130	deccc	%l7
1131	sta	%l3, [%l5] ASI_PTE
1132	add	%l6, 0x4, %l6
1133	bne	2b
1134	 add	%l5, %l4, %l5
1135
1136	sethi	%hi(C_LABEL(sun4c_kernel_faults)), %l4
11377:
1138	ld	[%l4 + %lo(C_LABEL(sun4c_kernel_faults))], %l3
1139	inc	%l3
1140	st	%l3, [%l4 + %lo(C_LABEL(sun4c_kernel_faults))]
1141
1142	/* Restore condition codes */
1143	wr	%l0, 0x0, %psr
1144	WRITE_PAUSE
1145	jmp	%l1
1146	 rett	%l2
1147
1148sun4c_fault_fromuser:
1149	SAVE_ALL
1150	 nop
1151
1152	mov	%l7, %o1		! Decode the info from %l7
1153	mov	%l7, %o2
1154	and	%o1, 1, %o1		! arg2 = text_faultp
1155	mov	%l7, %o3
1156	and	%o2, 2, %o2		! arg3 = writep
1157	andn	%o3, 0xfff, %o3		! arg4 = faulting address
1158
1159	wr	%l0, PSR_ET, %psr
1160	WRITE_PAUSE
1161
1162	call	C_LABEL(do_sun4c_fault)
1163	 add	%sp, STACKFRAME_SZ, %o0	! arg1 = pt_regs ptr
1164
1165	RESTORE_ALL
1166
1167	.align	4
1168	.globl	C_LABEL(srmmu_fault)
1169C_LABEL(srmmu_fault):
1170	mov	0x400, %l5
1171	mov	0x300, %l4
1172
1173	lda	[%l5] ASI_M_MMUREGS, %l6	! read sfar first
1174	lda	[%l4] ASI_M_MMUREGS, %l5	! read sfsr last
1175
1176	andn	%l6, 0xfff, %l6
1177	srl	%l5, 6, %l5			! and encode all info into l7
1178
1179	and	%l5, 2, %l5
1180	or	%l5, %l6, %l6
1181
1182	or	%l6, %l7, %l7			! l7 = [addr,write,txtfault]
1183
1184	SAVE_ALL
1185
1186	mov	%l7, %o1
1187	mov	%l7, %o2
1188	and	%o1, 1, %o1		! arg2 = text_faultp
1189	mov	%l7, %o3
1190	and	%o2, 2, %o2		! arg3 = writep
1191	andn	%o3, 0xfff, %o3		! arg4 = faulting address
1192
1193	wr	%l0, PSR_ET, %psr
1194	WRITE_PAUSE
1195
1196	call	C_LABEL(do_sparc_fault)
1197	 add	%sp, STACKFRAME_SZ, %o0	! arg1 = pt_regs ptr
1198
1199	RESTORE_ALL
1200
1201#ifdef CONFIG_SUNOS_EMUL
1202	/* SunOS uses syscall zero as the 'indirect syscall' it looks
1203	 * like indir_syscall(scall_num, arg0, arg1, arg2...);  etc.
1204	 * This is complete brain damage.
1205	 */
1206	.globl	C_LABEL(sunos_indir)
1207C_LABEL(sunos_indir):
1208	mov	%o7, %l4
1209	cmp	%o0, NR_SYSCALLS
1210	blu,a	1f
1211	 sll	%o0, 0x2, %o0
1212
1213	sethi	%hi(C_LABEL(sunos_nosys)), %l6
1214	b	2f
1215	 or	%l6, %lo(C_LABEL(sunos_nosys)), %l6
1216
12171:
1218	set	C_LABEL(sunos_sys_table), %l7
1219	ld	[%l7 + %o0], %l6
1220
12212:
1222	mov	%o1, %o0
1223	mov	%o2, %o1
1224	mov	%o3, %o2
1225	mov	%o4, %o3
1226	mov	%o5, %o4
1227	call	%l6
1228	 mov	%l4, %o7
1229#endif
1230
1231	.align	4
1232	.globl	C_LABEL(sys_nis_syscall)
1233C_LABEL(sys_nis_syscall):
1234	mov	%o7, %l5
1235	add	%sp, STACKFRAME_SZ, %o0		! pt_regs *regs arg
1236	call	C_LABEL(c_sys_nis_syscall)
1237	 mov	%l5, %o7
1238
1239	.align 4
1240	.globl	C_LABEL(sys_ptrace)
1241C_LABEL(sys_ptrace):
1242	call	C_LABEL(do_ptrace)
1243	 add	%sp, STACKFRAME_SZ, %o0
1244
1245	ld	[%curptr + AOFF_task_ptrace], %l5
1246	andcc	%l5, 0x02, %g0
1247	be	1f
1248	 nop
1249
1250	call	C_LABEL(syscall_trace)
1251	 nop
1252
12531:
1254	RESTORE_ALL
1255
1256	.align	4
1257	.globl	C_LABEL(sys_execve)
1258C_LABEL(sys_execve):
1259	mov	%o7, %l5
1260	add	%sp, STACKFRAME_SZ, %o0		! pt_regs *regs arg
1261	call	C_LABEL(sparc_execve)
1262	 mov	%l5, %o7
1263
1264	.align	4
1265	.globl	C_LABEL(sys_pipe)
1266C_LABEL(sys_pipe):
1267	mov	%o7, %l5
1268	add	%sp, STACKFRAME_SZ, %o0		! pt_regs *regs arg
1269	call	C_LABEL(sparc_pipe)
1270	 mov	%l5, %o7
1271
1272	.align	4
1273	.globl	C_LABEL(sys_sigaltstack)
1274C_LABEL(sys_sigaltstack):
1275	mov	%o7, %l5
1276	mov	%fp, %o2
1277	call	C_LABEL(do_sigaltstack)
1278	 mov	%l5, %o7
1279
1280	.align	4
1281	.globl	C_LABEL(sys_sigstack)
1282C_LABEL(sys_sigstack):
1283	mov	%o7, %l5
1284	mov	%fp, %o2
1285	call	C_LABEL(do_sys_sigstack)
1286	 mov	%l5, %o7
1287
1288	.align	4
1289	.globl	C_LABEL(sys_sigpause)
1290C_LABEL(sys_sigpause):
1291	/* Note: %o0 already has correct value... */
1292	call	C_LABEL(do_sigpause)
1293	 add	%sp, STACKFRAME_SZ, %o1
1294
1295	ld	[%curptr + AOFF_task_ptrace], %l5
1296	andcc	%l5, 0x02, %g0
1297	be	1f
1298	 nop
1299
1300	call	C_LABEL(syscall_trace)
1301	 nop
1302
13031:
1304	/* We are returning to a signal handler. */
1305	RESTORE_ALL
1306
1307	.align	4
1308	.globl	C_LABEL(sys_sigsuspend)
1309C_LABEL(sys_sigsuspend):
1310	call	C_LABEL(do_sigsuspend)
1311	 add	%sp, STACKFRAME_SZ, %o0
1312
1313	ld	[%curptr + AOFF_task_ptrace], %l5
1314	andcc	%l5, 0x02, %g0
1315	be	1f
1316	 nop
1317
1318	call	C_LABEL(syscall_trace)
1319	 nop
1320
13211:
1322	/* We are returning to a signal handler. */
1323	RESTORE_ALL
1324
1325	.align	4
1326	.globl	C_LABEL(sys_rt_sigsuspend)
1327C_LABEL(sys_rt_sigsuspend):
1328	/* Note: %o0, %o1 already have correct value... */
1329	call	C_LABEL(do_rt_sigsuspend)
1330	 add	%sp, STACKFRAME_SZ, %o2
1331
1332	ld	[%curptr + AOFF_task_ptrace], %l5
1333	andcc	%l5, 0x02, %g0
1334	be	1f
1335	 nop
1336
1337	call	C_LABEL(syscall_trace)
1338	 nop
1339
13401:
1341	/* We are returning to a signal handler. */
1342	RESTORE_ALL
1343
1344	.align	4
1345	.globl	C_LABEL(sys_sigreturn)
1346C_LABEL(sys_sigreturn):
1347	call	C_LABEL(do_sigreturn)
1348	 add	%sp, STACKFRAME_SZ, %o0
1349
1350	ld	[%curptr + AOFF_task_ptrace], %l5
1351	andcc	%l5, 0x02, %g0
1352	be	1f
1353	 nop
1354
1355	call	C_LABEL(syscall_trace)
1356	 nop
1357
13581:
1359	/* We don't want to muck with user registers like a
1360	 * normal syscall, just return.
1361	 */
1362	RESTORE_ALL
1363
1364	.align	4
1365	.globl	C_LABEL(sys_rt_sigreturn)
1366C_LABEL(sys_rt_sigreturn):
1367	call	C_LABEL(do_rt_sigreturn)
1368	 add	%sp, STACKFRAME_SZ, %o0
1369
1370	ld	[%curptr + AOFF_task_ptrace], %l5
1371	andcc	%l5, 0x02, %g0
1372	be	1f
1373	 nop
1374
1375	call	C_LABEL(syscall_trace)
1376	 nop
1377
13781:
1379	/* We are returning to a signal handler. */
1380	RESTORE_ALL
1381
1382	/* Now that we have a real sys_clone, sys_fork() is
1383	 * implemented in terms of it.  Our _real_ implementation
1384	 * of SunOS vfork() will use sys_vfork().
1385	 *
1386	 * XXX These three should be consolidated into mostly shared
1387	 * XXX code just like on sparc64... -DaveM
1388	 */
1389	.align	4
1390	.globl	C_LABEL(sys_fork), flush_patch_two
1391C_LABEL(sys_fork):
1392	mov	%o7, %l5
1393flush_patch_two:
1394	FLUSH_ALL_KERNEL_WINDOWS;
1395	rd	%psr, %g4
1396	WRITE_PAUSE
1397	mov	SIGCHLD, %o0			! arg0:	clone flags
1398	rd	%wim, %g5
1399	WRITE_PAUSE
1400	mov	%fp, %o1			! arg1:	usp
1401	std	%g4, [%curptr + AOFF_task_thread + AOFF_thread_fork_kpsr]
1402	add	%sp, STACKFRAME_SZ, %o2		! arg2:	pt_regs ptr
1403	mov	0, %o3
1404	call	C_LABEL(do_fork)
1405	 mov	%l5, %o7
1406
1407	/* Whee, kernel threads! */
1408	.globl	C_LABEL(sys_clone), flush_patch_three
1409C_LABEL(sys_clone):
1410	mov	%o7, %l5
1411flush_patch_three:
1412	FLUSH_ALL_KERNEL_WINDOWS;
1413	rd	%psr, %g4
1414	WRITE_PAUSE
1415
1416	/* arg0,1: flags,usp  -- loaded already */
1417	cmp	%o1, 0x0			! Is new_usp NULL?
1418	rd	%wim, %g5
1419	WRITE_PAUSE
1420	be,a	1f
1421	 mov	%fp, %o1			! yes, use callers usp
1422	andn	%o1, 7, %o1			! no, align to 8 bytes
14231:
1424	std	%g4, [%curptr + AOFF_task_thread + AOFF_thread_fork_kpsr]
1425	add	%sp, STACKFRAME_SZ, %o2		! arg2:	pt_regs ptr
1426	mov	0, %o3
1427	call	C_LABEL(do_fork)
1428	 mov	%l5, %o7
1429
1430	/* Whee, real vfork! */
1431	.globl	C_LABEL(sys_vfork), flush_patch_four
1432C_LABEL(sys_vfork):
1433flush_patch_four:
1434	FLUSH_ALL_KERNEL_WINDOWS;
1435	rd	%psr, %g4
1436	WRITE_PAUSE
1437	rd	%wim, %g5
1438	WRITE_PAUSE
1439	std	%g4, [%curptr + AOFF_task_thread + AOFF_thread_fork_kpsr]
1440	sethi	%hi(0x4000 | 0x0100 | SIGCHLD), %o0
1441	mov	%fp, %o1
1442	or	%o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0
1443	sethi	%hi(C_LABEL(do_fork)), %l1
1444	mov	0, %o3
1445	jmpl	%l1 + %lo(C_LABEL(do_fork)), %g0
1446	 add	%sp, STACKFRAME_SZ, %o2
1447
1448        .align  4
1449linux_sparc_ni_syscall:
1450	sethi   %hi(C_LABEL(sys_ni_syscall)), %l7
1451	b       syscall_is_too_hard
1452	 or     %l7, %lo(C_LABEL(sys_ni_syscall)), %l7
1453
1454linux_fast_syscall:
1455	andn	%l7, 3, %l7
1456	mov	%i0, %o0
1457	mov	%i1, %o1
1458	mov 	%i2, %o2
1459	jmpl	%l7 + %g0, %g0
1460	 mov	%i3, %o3
1461
1462linux_syscall_trace:
1463	call	C_LABEL(syscall_trace)
1464	 nop
1465	mov	%i0, %o0
1466	mov	%i1, %o1
1467	mov	%i2, %o2
1468	mov	%i3, %o3
1469	b	2f
1470	 mov	%i4, %o4
1471
1472	.globl	C_LABEL(ret_from_fork)
1473C_LABEL(ret_from_fork):
1474	call	schedule_tail
1475	 mov	%g3, %o0
1476	b	C_LABEL(ret_sys_call)
1477	 ld	[%sp + STACKFRAME_SZ + PT_I0], %o0
1478
1479	/* Linux native and SunOS system calls enter here... */
1480	.align	4
1481	.globl	linux_sparc_syscall
1482linux_sparc_syscall:
1483	/* Direct access to user regs, must faster. */
1484	cmp	%g1, NR_SYSCALLS
1485	bgeu	linux_sparc_ni_syscall
1486	 sll	%g1, 2, %l4
1487	ld	[%l7 + %l4], %l7
1488	andcc	%l7, 1, %g0
1489	bne	linux_fast_syscall
1490	 /* Just do first insn from SAVE_ALL in the delay slot */
1491
1492	.globl	syscall_is_too_hard
1493syscall_is_too_hard:
1494	SAVE_ALL_HEAD
1495	 rd	%wim, %l3
1496
1497	wr	%l0, PSR_ET, %psr
1498	mov	%i0, %o0
1499	mov	%i1, %o1
1500	mov	%i2, %o2
1501
1502	ld	[%curptr + AOFF_task_ptrace], %l5
1503	mov	%i3, %o3
1504	andcc	%l5, 0x02, %g0
1505	mov	%i4, %o4
1506	bne	linux_syscall_trace
1507	 mov	%i0, %l5
15082:
1509	call	%l7
1510	 mov	%i5, %o5
1511
1512	st	%o0, [%sp + STACKFRAME_SZ + PT_I0]
1513
1514	.globl	C_LABEL(ret_sys_call)
1515C_LABEL(ret_sys_call):
1516	ld	[%curptr + AOFF_task_ptrace], %l6
1517	cmp	%o0, -ENOIOCTLCMD
1518	ld	[%sp + STACKFRAME_SZ + PT_PSR], %g3
1519	set	PSR_C, %g2
1520	bgeu	1f
1521	 andcc	%l6, 0x02, %l6
1522
1523	/* System call success, clear Carry condition code. */
1524	andn	%g3, %g2, %g3
1525	clr	%l6
1526	st	%g3, [%sp + STACKFRAME_SZ + PT_PSR]
1527	bne	linux_syscall_trace2
1528	 ld	[%sp + STACKFRAME_SZ + PT_NPC], %l1 /* pc = npc */
1529	add	%l1, 0x4, %l2			/* npc = npc+4 */
1530	st	%l1, [%sp + STACKFRAME_SZ + PT_PC]
1531	b	ret_trap_entry
1532	 st	%l2, [%sp + STACKFRAME_SZ + PT_NPC]
15331:
1534	/* System call failure, set Carry condition code.
1535	 * Also, get abs(errno) to return to the process.
1536	 */
1537	sub	%g0, %o0, %o0
1538	or	%g3, %g2, %g3
1539	st	%o0, [%sp + STACKFRAME_SZ + PT_I0]
1540	mov	1, %l6
1541	st	%g3, [%sp + STACKFRAME_SZ + PT_PSR]
1542	bne	linux_syscall_trace2
1543	 ld	[%sp + STACKFRAME_SZ + PT_NPC], %l1 /* pc = npc */
1544	add	%l1, 0x4, %l2			/* npc = npc+4 */
1545	st	%l1, [%sp + STACKFRAME_SZ + PT_PC]
1546	b	ret_trap_entry
1547	 st	%l2, [%sp + STACKFRAME_SZ + PT_NPC]
1548
1549linux_syscall_trace2:
1550	call	C_LABEL(syscall_trace)
1551	 add	%l1, 0x4, %l2			/* npc = npc+4 */
1552	st	%l1, [%sp + STACKFRAME_SZ + PT_PC]
1553	b	ret_trap_entry
1554	 st	%l2, [%sp + STACKFRAME_SZ + PT_NPC]
1555
1556
1557	/*
1558	 * Solaris system calls and indirect system calls enter here.
1559         *
1560	 * I have named the solaris indirect syscalls like that because
1561	 * it seems like Solaris has some fast path syscalls that can
1562	 * be handled as indirect system calls. - mig
1563	 */
1564
1565linux_syscall_for_solaris:
1566	sethi	%hi(sys_call_table), %l7
1567	b	linux_sparc_syscall
1568	 or	%l7, %lo(sys_call_table), %l7
1569
1570	.align	4
1571	.globl	solaris_syscall
1572solaris_syscall:
1573	cmp	%g1,59
1574	be	linux_syscall_for_solaris
1575	 cmp	%g1,2
1576	be	linux_syscall_for_solaris
1577	 cmp    %g1,42
1578	be      linux_syscall_for_solaris
1579	 cmp	%g1,119
1580	be,a	linux_syscall_for_solaris
1581	 mov	2, %g1
15821:
1583	SAVE_ALL_HEAD
1584	 rd	%wim, %l3
1585
1586	wr	%l0, PSR_ET, %psr
1587	nop
1588	nop
1589	mov	%i0, %l5
1590
1591	call	C_LABEL(do_solaris_syscall)
1592	 add	%sp, STACKFRAME_SZ, %o0
1593
1594	st	%o0, [%sp + STACKFRAME_SZ + PT_I0]
1595	set	PSR_C, %g2
1596	cmp	%o0, -ENOIOCTLCMD
1597	bgeu	1f
1598	 ld	[%sp + STACKFRAME_SZ + PT_PSR], %g3
1599
1600	/* System call success, clear Carry condition code. */
1601	andn	%g3, %g2, %g3
1602	clr	%l6
1603	b	2f
1604	 st	%g3, [%sp + STACKFRAME_SZ + PT_PSR]
1605
16061:
1607	/* System call failure, set Carry condition code.
1608	 * Also, get abs(errno) to return to the process.
1609	 */
1610	sub	%g0, %o0, %o0
1611	mov	1, %l6
1612	st	%o0, [%sp + STACKFRAME_SZ + PT_I0]
1613	or	%g3, %g2, %g3
1614	st	%g3, [%sp + STACKFRAME_SZ + PT_PSR]
1615
1616	/* Advance the pc and npc over the trap instruction.
1617	 * If the npc is unaligned (has a 1 in the lower byte), it means
1618	 * the kernel does not want us to play magic (ie, skipping over
1619	 * traps).  Mainly when the Solaris code wants to set some PC and
1620	 * nPC (setcontext).
1621	 */
16222:
1623	ld	[%sp + STACKFRAME_SZ + PT_NPC], %l1	/* pc  = npc   */
1624	andcc	%l1, 1, %g0
1625	bne	1f
1626	 add	%l1, 0x4, %l2			/* npc = npc+4 */
1627	st	%l1, [%sp + STACKFRAME_SZ + PT_PC]
1628	b	ret_trap_entry
1629	 st	%l2, [%sp + STACKFRAME_SZ + PT_NPC]
1630
1631	/* kernel knows what it is doing, fixup npc and continue */
16321:
1633	sub	%l1, 1, %l1
1634 	b	ret_trap_entry
1635	 st	%l1, [%sp + STACKFRAME_SZ + PT_NPC]
1636
1637#ifndef CONFIG_SUNOS_EMUL
1638	.align	4
1639	.globl	sunos_syscall
1640sunos_syscall:
1641	SAVE_ALL_HEAD
1642	 rd	%wim, %l3
1643	wr	%l0, PSR_ET, %psr
1644	nop
1645	nop
1646	mov	%i0, %l5
1647	call	C_LABEL(do_sunos_syscall)
1648	 add	%sp, STACKFRAME_SZ, %o0
1649#endif
1650
1651	/* {net, open}bsd system calls enter here... */
1652	.align	4
1653	.globl	bsd_syscall
1654bsd_syscall:
1655	/* Direct access to user regs, must faster. */
1656	cmp	%g1, NR_SYSCALLS
1657	blu,a	1f
1658	 sll	%g1, 2, %l4
1659
1660	set	C_LABEL(sys_ni_syscall), %l7
1661	b	bsd_is_too_hard
1662	 nop
1663
16641:
1665	ld	[%l7 + %l4], %l7
1666
1667	.globl	bsd_is_too_hard
1668bsd_is_too_hard:
1669	rd	%wim, %l3
1670	SAVE_ALL
1671
1672	wr	%l0, PSR_ET, %psr
1673	WRITE_PAUSE
1674
16752:
1676	mov	%i0, %o0
1677	mov	%i1, %o1
1678	mov	%i2, %o2
1679	mov	%i0, %l5
1680	mov	%i3, %o3
1681	mov	%i4, %o4
1682	call	%l7
1683	 mov	%i5, %o5
1684
1685	st	%o0, [%sp + STACKFRAME_SZ + PT_I0]
1686	set	PSR_C, %g2
1687	cmp	%o0, -ENOIOCTLCMD
1688	bgeu	1f
1689	 ld	[%sp + STACKFRAME_SZ + PT_PSR], %g3
1690
1691	/* System call success, clear Carry condition code. */
1692	andn	%g3, %g2, %g3
1693	clr	%l6
1694	b	2f
1695	 st	%g3, [%sp + STACKFRAME_SZ + PT_PSR]
1696
16971:
1698	/* System call failure, set Carry condition code.
1699	 * Also, get abs(errno) to return to the process.
1700	 */
1701	sub	%g0, %o0, %o0
1702#if 0 /* XXX todo XXX */
1703	sethi	%hi(C_LABEL(bsd_xlatb_rorl), %o3
1704	or	%o3, %lo(C_LABEL(bsd_xlatb_rorl)), %o3
1705	sll	%o0, 2, %o0
1706	ld	[%o3 + %o0], %o0
1707#endif
1708	mov	1, %l6
1709	st	%o0, [%sp + STACKFRAME_SZ + PT_I0]
1710	or	%g3, %g2, %g3
1711	st	%g3, [%sp + STACKFRAME_SZ + PT_PSR]
1712
1713	/* Advance the pc and npc over the trap instruction. */
17142:
1715	ld	[%sp + STACKFRAME_SZ + PT_NPC], %l1	/* pc  = npc   */
1716	add	%l1, 0x4, %l2			/* npc = npc+4 */
1717	st	%l1, [%sp + STACKFRAME_SZ + PT_PC]
1718	b	ret_trap_entry
1719	 st	%l2, [%sp + STACKFRAME_SZ + PT_NPC]
1720
1721/* Saving and restoring the FPU state is best done from lowlevel code.
1722 *
1723 * void fpsave(unsigned long *fpregs, unsigned long *fsr,
1724 *             void *fpqueue, unsigned long *fpqdepth)
1725 */
1726
1727	.globl	C_LABEL(fpsave)
1728C_LABEL(fpsave):
1729	st	%fsr, [%o1]	! this can trap on us if fpu is in bogon state
1730	ld	[%o1], %g1
1731	set	0x2000, %g4
1732	andcc	%g1, %g4, %g0
1733	be	2f
1734	 mov	0, %g2
1735
1736	/* We have an fpqueue to save. */
17371:
1738	std	%fq, [%o2]
1739fpsave_magic:
1740	st	%fsr, [%o1]
1741	ld	[%o1], %g3
1742	andcc	%g3, %g4, %g0
1743	add	%g2, 1, %g2
1744	bne	1b
1745	 add	%o2, 8, %o2
1746
17472:
1748	st	%g2, [%o3]
1749
1750	std	%f0, [%o0 + 0x00]
1751	std	%f2, [%o0 + 0x08]
1752	std	%f4, [%o0 + 0x10]
1753	std	%f6, [%o0 + 0x18]
1754	std	%f8, [%o0 + 0x20]
1755	std	%f10, [%o0 + 0x28]
1756	std	%f12, [%o0 + 0x30]
1757	std	%f14, [%o0 + 0x38]
1758	std	%f16, [%o0 + 0x40]
1759	std	%f18, [%o0 + 0x48]
1760	std	%f20, [%o0 + 0x50]
1761	std	%f22, [%o0 + 0x58]
1762	std	%f24, [%o0 + 0x60]
1763	std	%f26, [%o0 + 0x68]
1764	std	%f28, [%o0 + 0x70]
1765	retl
1766	 std	%f30, [%o0 + 0x78]
1767
1768	/* Thanks for Theo Deraadt and the authors of the Sprite/netbsd/openbsd
1769	 * code for pointing out this possible deadlock, while we save state
1770	 * above we could trap on the fsr store so our low level fpu trap
1771	 * code has to know how to deal with this.
1772	 */
1773fpsave_catch:
1774	b	fpsave_magic + 4
1775	 st	%fsr, [%o1]
1776
1777fpsave_catch2:
1778	b	C_LABEL(fpsave) + 4
1779	 st	%fsr, [%o1]
1780
1781	/* void fpload(unsigned long *fpregs, unsigned long *fsr); */
1782
1783	.globl	C_LABEL(fpload)
1784C_LABEL(fpload):
1785	ldd	[%o0 + 0x00], %f0
1786	ldd	[%o0 + 0x08], %f2
1787	ldd	[%o0 + 0x10], %f4
1788	ldd	[%o0 + 0x18], %f6
1789	ldd	[%o0 + 0x20], %f8
1790	ldd	[%o0 + 0x28], %f10
1791	ldd	[%o0 + 0x30], %f12
1792	ldd	[%o0 + 0x38], %f14
1793	ldd	[%o0 + 0x40], %f16
1794	ldd	[%o0 + 0x48], %f18
1795	ldd	[%o0 + 0x50], %f20
1796	ldd	[%o0 + 0x58], %f22
1797	ldd	[%o0 + 0x60], %f24
1798	ldd	[%o0 + 0x68], %f26
1799	ldd	[%o0 + 0x70], %f28
1800	ldd	[%o0 + 0x78], %f30
1801	ld	[%o1], %fsr
1802	retl
1803	 nop
1804
1805	.globl	C_LABEL(ndelay)
1806C_LABEL(ndelay):
1807	save	%sp, -STACKFRAME_SZ, %sp
1808	mov	%i0, %o0
1809	call	.umul
1810	 mov	5, %o1
1811	ba	delay_continue
1812	 nop
1813
1814	.globl	C_LABEL(udelay)
1815C_LABEL(udelay):
1816	save	%sp, -STACKFRAME_SZ, %sp
1817	mov	%i0, %o0
1818	sethi	%hi(0x10c6), %o1
1819	call	.umul
1820	 or	%o1, %lo(0x10c6), %o1
1821delay_continue:
1822#ifndef CONFIG_SMP
1823	sethi	%hi(C_LABEL(loops_per_jiffy)), %o3
1824	call	.umul
1825	 ld	[%o3 + %lo(C_LABEL(loops_per_jiffy))], %o1
1826#else
1827	GET_PROCESSOR_OFFSET(o4, o2)
1828	set	C_LABEL(cpu_data), %o3
1829	call	.umul
1830	 ld	[%o3 + %o4], %o1
1831#endif
1832	call	.umul
1833	 mov	100, %o0
1834
1835	cmp	%o0, 0x0
18361:
1837	bne	1b
1838	 subcc	%o0, 1, %o0
1839
1840	ret
1841	restore
1842
1843	/* Handle a software breakpoint */
1844	/* We have to inform parent that child has stopped */
1845	.align 4
1846	.globl breakpoint_trap
1847breakpoint_trap:
1848	rd	%wim,%l3
1849	SAVE_ALL
1850	wr 	%l0, PSR_ET, %psr
1851	WRITE_PAUSE
1852
1853	st	%i0, [%sp + STACKFRAME_SZ + PT_G0] ! for restarting syscalls
1854	call	C_LABEL(sparc_breakpoint)
1855	 add	%sp, STACKFRAME_SZ, %o0
1856
1857	RESTORE_ALL
1858
1859	.align	4
1860	.globl	C_LABEL(__handle_exception), flush_patch_exception
1861C_LABEL(__handle_exception):
1862flush_patch_exception:
1863	FLUSH_ALL_KERNEL_WINDOWS;
1864	ldd	[%o0], %o6
1865	jmpl	%o7 + 0xc, %g0			! see asm-sparc/processor.h
1866	 mov	1, %g1				! signal EFAULT condition
1867
1868	.align	4
1869	.globl	C_LABEL(kill_user_windows), kuw_patch1_7win
1870	.globl	kuw_patch1
1871kuw_patch1_7win:	sll	%o3, 6, %o3
1872
1873	/* No matter how much overhead this routine has in the worst
1874	 * case scenerio, it is several times better than taking the
1875	 * traps with the old method of just doing flush_user_windows().
1876	 */
1877C_LABEL(kill_user_windows):
1878	ld	[%g6 + AOFF_task_thread + AOFF_thread_uwinmask], %o0	! get current umask
1879	orcc	%g0, %o0, %g0			! if no bits set, we are done
1880	be	3f				! nothing to do
1881	 rd	%psr, %o5			! must clear interrupts
1882	or	%o5, PSR_PIL, %o4		! or else that could change
1883	wr	%o4, 0x0, %psr			! the uwinmask state
1884	WRITE_PAUSE				! burn them cycles
18851:
1886	ld	[%g6 + AOFF_task_thread + AOFF_thread_uwinmask], %o0	! get consistant state
1887	orcc	%g0, %o0, %g0			! did an interrupt come in?
1888	be	4f				! yep, we are done
1889	 rd	%wim, %o3			! get current wim
1890	srl	%o3, 1, %o4			! simulate a save
1891kuw_patch1:
1892	sll	%o3, 7, %o3			! compute next wim
1893	or	%o4, %o3, %o3			! result
1894	andncc	%o0, %o3, %o0			! clean this bit in umask
1895	bne	kuw_patch1			! not done yet
1896	 srl	%o3, 1, %o4			! begin another save simulation
1897	wr	%o3, 0x0, %wim			! set the new wim
1898	st	%g0, [%g6 + AOFF_task_thread + AOFF_thread_uwinmask]	! clear uwinmask
18994:
1900	wr	%o5, 0x0, %psr			! re-enable interrupts
1901	WRITE_PAUSE				! burn baby burn
19023:
1903	retl					! return
1904	 st	%g0, [%g6 + AOFF_task_thread + AOFF_thread_w_saved]	! no windows saved
1905
1906	.align	4
1907	.globl	C_LABEL(restore_current)
1908C_LABEL(restore_current):
1909	LOAD_CURRENT(g6, o0)
1910	retl
1911	 nop
1912
1913#ifdef CONFIG_PCI
1914#include <asm/pcic.h>
1915
1916	.align	4
1917	.globl	linux_trap_ipi15_pcic
1918linux_trap_ipi15_pcic:
1919	rd	%wim, %l3
1920	SAVE_ALL
1921
1922	/*
1923	 * First deactivate NMI
1924	 * or we cannot drop ET, cannot get window spill traps.
1925	 * The busy loop is necessary because the PIO error
1926	 * sometimes does not go away quickly and we trap again.
1927	 */
1928	sethi	%hi(C_LABEL(pcic_regs)), %o1
1929	ld	[%o1 + %lo(C_LABEL(pcic_regs))], %o2
1930
1931	! Get pending status for printouts later.
1932	ld	[%o2 + PCI_SYS_INT_PENDING], %o0
1933
1934	mov	PCI_SYS_INT_PENDING_CLEAR_ALL, %o1
1935	stb	%o1, [%o2 + PCI_SYS_INT_PENDING_CLEAR]
19361:
1937	ld	[%o2 + PCI_SYS_INT_PENDING], %o1
1938	andcc	%o1, ((PCI_SYS_INT_PENDING_PIO|PCI_SYS_INT_PENDING_PCI)>>24), %g0
1939	bne	1b
1940	 nop
1941
1942	or	%l0, PSR_PIL, %l4
1943	wr	%l4, 0x0, %psr
1944	WRITE_PAUSE
1945	wr	%l4, PSR_ET, %psr
1946	WRITE_PAUSE
1947
1948	call	C_LABEL(pcic_nmi)
1949	 add	%sp, STACKFRAME_SZ, %o1	! struct pt_regs *regs
1950	RESTORE_ALL
1951
1952	.globl	C_LABEL(pcic_nmi_trap_patch)
1953C_LABEL(pcic_nmi_trap_patch):
1954	sethi	%hi(linux_trap_ipi15_pcic), %l3
1955	jmpl	%l3 + %lo(linux_trap_ipi15_pcic), %g0
1956	 rd	%psr, %l0
1957	.word	0
1958
1959#endif /* CONFIG_PCI */
1960
1961/* End of entry.S */
1962