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