Merge branch 'sched-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / 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         call    syscall_trace
1200          nop
1201
1202 1:
1203         /* We are returning to a signal handler. */
1204         RESTORE_ALL
1205
1206         /* Now that we have a real sys_clone, sys_fork() is
1207          * implemented in terms of it.  Our _real_ implementation
1208          * of SunOS vfork() will use sys_vfork().
1209          *
1210          * XXX These three should be consolidated into mostly shared
1211          * XXX code just like on sparc64... -DaveM
1212          */
1213         .align  4
1214         .globl  sys_fork, flush_patch_two
1215 sys_fork:
1216         mov     %o7, %l5
1217 flush_patch_two:
1218         FLUSH_ALL_KERNEL_WINDOWS;
1219         ld      [%curptr + TI_TASK], %o4
1220         rd      %psr, %g4
1221         WRITE_PAUSE
1222         mov     SIGCHLD, %o0                    ! arg0: clone flags
1223         rd      %wim, %g5
1224         WRITE_PAUSE
1225         mov     %fp, %o1                        ! arg1: usp
1226         std     %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
1227         add     %sp, STACKFRAME_SZ, %o2         ! arg2: pt_regs ptr
1228         mov     0, %o3
1229         call    sparc_do_fork
1230          mov    %l5, %o7
1231
1232         /* Whee, kernel threads! */
1233         .globl  sys_clone, flush_patch_three
1234 sys_clone:
1235         mov     %o7, %l5
1236 flush_patch_three:
1237         FLUSH_ALL_KERNEL_WINDOWS;
1238         ld      [%curptr + TI_TASK], %o4
1239         rd      %psr, %g4
1240         WRITE_PAUSE
1241
1242         /* arg0,1: flags,usp  -- loaded already */
1243         cmp     %o1, 0x0                        ! Is new_usp NULL?
1244         rd      %wim, %g5
1245         WRITE_PAUSE
1246         be,a    1f
1247          mov    %fp, %o1                        ! yes, use callers usp
1248         andn    %o1, 7, %o1                     ! no, align to 8 bytes
1249 1:
1250         std     %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
1251         add     %sp, STACKFRAME_SZ, %o2         ! arg2: pt_regs ptr
1252         mov     0, %o3
1253         call    sparc_do_fork
1254          mov    %l5, %o7
1255
1256         /* Whee, real vfork! */
1257         .globl  sys_vfork, flush_patch_four
1258 sys_vfork:
1259 flush_patch_four:
1260         FLUSH_ALL_KERNEL_WINDOWS;
1261         ld      [%curptr + TI_TASK], %o4
1262         rd      %psr, %g4
1263         WRITE_PAUSE
1264         rd      %wim, %g5
1265         WRITE_PAUSE
1266         std     %g4, [%o4 + AOFF_task_thread + AOFF_thread_fork_kpsr]
1267         sethi   %hi(0x4000 | 0x0100 | SIGCHLD), %o0
1268         mov     %fp, %o1
1269         or      %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0
1270         sethi   %hi(sparc_do_fork), %l1
1271         mov     0, %o3
1272         jmpl    %l1 + %lo(sparc_do_fork), %g0
1273          add    %sp, STACKFRAME_SZ, %o2
1274
1275         .align  4
1276 linux_sparc_ni_syscall:
1277         sethi   %hi(sys_ni_syscall), %l7
1278         b       syscall_is_too_hard
1279          or     %l7, %lo(sys_ni_syscall), %l7
1280
1281 linux_fast_syscall:
1282         andn    %l7, 3, %l7
1283         mov     %i0, %o0
1284         mov     %i1, %o1
1285         mov     %i2, %o2
1286         jmpl    %l7 + %g0, %g0
1287          mov    %i3, %o3
1288
1289 linux_syscall_trace:
1290         call    syscall_trace
1291          nop
1292         mov     %i0, %o0
1293         mov     %i1, %o1
1294         mov     %i2, %o2
1295         mov     %i3, %o3
1296         b       2f
1297          mov    %i4, %o4
1298
1299         .globl  ret_from_fork
1300 ret_from_fork:
1301         call    schedule_tail
1302          mov    %g3, %o0
1303         b       ret_sys_call
1304          ld     [%sp + STACKFRAME_SZ + PT_I0], %o0
1305
1306         /* Linux native system calls enter here... */
1307         .align  4
1308         .globl  linux_sparc_syscall
1309 linux_sparc_syscall:
1310         sethi   %hi(PSR_SYSCALL), %l4
1311         or      %l0, %l4, %l0
1312         /* Direct access to user regs, must faster. */
1313         cmp     %g1, NR_SYSCALLS
1314         bgeu    linux_sparc_ni_syscall
1315          sll    %g1, 2, %l4
1316         ld      [%l7 + %l4], %l7
1317         andcc   %l7, 1, %g0
1318         bne     linux_fast_syscall
1319          /* Just do first insn from SAVE_ALL in the delay slot */
1320
1321 syscall_is_too_hard:
1322         SAVE_ALL_HEAD
1323          rd     %wim, %l3
1324
1325         wr      %l0, PSR_ET, %psr
1326         mov     %i0, %o0
1327         mov     %i1, %o1
1328         mov     %i2, %o2
1329
1330         ld      [%curptr + TI_FLAGS], %l5
1331         mov     %i3, %o3
1332         andcc   %l5, _TIF_SYSCALL_TRACE, %g0
1333         mov     %i4, %o4
1334         bne     linux_syscall_trace
1335          mov    %i0, %l5
1336 2:
1337         call    %l7
1338          mov    %i5, %o5
1339
1340         st      %o0, [%sp + STACKFRAME_SZ + PT_I0]
1341
1342 ret_sys_call:
1343         ld      [%curptr + TI_FLAGS], %l6
1344         cmp     %o0, -ERESTART_RESTARTBLOCK
1345         ld      [%sp + STACKFRAME_SZ + PT_PSR], %g3
1346         set     PSR_C, %g2
1347         bgeu    1f
1348          andcc  %l6, _TIF_SYSCALL_TRACE, %g0
1349
1350         /* System call success, clear Carry condition code. */
1351         andn    %g3, %g2, %g3
1352         clr     %l6
1353         st      %g3, [%sp + STACKFRAME_SZ + PT_PSR]     
1354         bne     linux_syscall_trace2
1355          ld     [%sp + STACKFRAME_SZ + PT_NPC], %l1 /* pc = npc */
1356         add     %l1, 0x4, %l2                   /* npc = npc+4 */
1357         st      %l1, [%sp + STACKFRAME_SZ + PT_PC]
1358         b       ret_trap_entry
1359          st     %l2, [%sp + STACKFRAME_SZ + PT_NPC]
1360 1:
1361         /* System call failure, set Carry condition code.
1362          * Also, get abs(errno) to return to the process.
1363          */
1364         sub     %g0, %o0, %o0
1365         or      %g3, %g2, %g3
1366         st      %o0, [%sp + STACKFRAME_SZ + PT_I0]
1367         mov     1, %l6
1368         st      %g3, [%sp + STACKFRAME_SZ + PT_PSR]
1369         bne     linux_syscall_trace2
1370          ld     [%sp + STACKFRAME_SZ + PT_NPC], %l1 /* pc = npc */
1371         add     %l1, 0x4, %l2                   /* npc = npc+4 */
1372         st      %l1, [%sp + STACKFRAME_SZ + PT_PC]
1373         b       ret_trap_entry
1374          st     %l2, [%sp + STACKFRAME_SZ + PT_NPC]
1375
1376 linux_syscall_trace2:
1377         call    syscall_trace
1378          add    %l1, 0x4, %l2                   /* npc = npc+4 */
1379         st      %l1, [%sp + STACKFRAME_SZ + PT_PC]
1380         b       ret_trap_entry
1381          st     %l2, [%sp + STACKFRAME_SZ + PT_NPC]
1382
1383
1384 /* Saving and restoring the FPU state is best done from lowlevel code.
1385  *
1386  * void fpsave(unsigned long *fpregs, unsigned long *fsr,
1387  *             void *fpqueue, unsigned long *fpqdepth)
1388  */
1389
1390         .globl  fpsave
1391 fpsave:
1392         st      %fsr, [%o1]     ! this can trap on us if fpu is in bogon state
1393         ld      [%o1], %g1
1394         set     0x2000, %g4
1395         andcc   %g1, %g4, %g0
1396         be      2f
1397          mov    0, %g2
1398
1399         /* We have an fpqueue to save. */
1400 1:
1401         std     %fq, [%o2]
1402 fpsave_magic:
1403         st      %fsr, [%o1]
1404         ld      [%o1], %g3
1405         andcc   %g3, %g4, %g0
1406         add     %g2, 1, %g2
1407         bne     1b
1408          add    %o2, 8, %o2
1409
1410 2:
1411         st      %g2, [%o3]
1412
1413         std     %f0, [%o0 + 0x00]
1414         std     %f2, [%o0 + 0x08]
1415         std     %f4, [%o0 + 0x10]
1416         std     %f6, [%o0 + 0x18]
1417         std     %f8, [%o0 + 0x20]
1418         std     %f10, [%o0 + 0x28]
1419         std     %f12, [%o0 + 0x30]
1420         std     %f14, [%o0 + 0x38]
1421         std     %f16, [%o0 + 0x40]
1422         std     %f18, [%o0 + 0x48]
1423         std     %f20, [%o0 + 0x50]
1424         std     %f22, [%o0 + 0x58]
1425         std     %f24, [%o0 + 0x60]
1426         std     %f26, [%o0 + 0x68]
1427         std     %f28, [%o0 + 0x70]
1428         retl
1429          std    %f30, [%o0 + 0x78]
1430
1431         /* Thanks for Theo Deraadt and the authors of the Sprite/netbsd/openbsd
1432          * code for pointing out this possible deadlock, while we save state
1433          * above we could trap on the fsr store so our low level fpu trap
1434          * code has to know how to deal with this.
1435          */
1436 fpsave_catch:
1437         b       fpsave_magic + 4
1438          st     %fsr, [%o1]
1439
1440 fpsave_catch2:
1441         b       fpsave + 4
1442          st     %fsr, [%o1]
1443
1444         /* void fpload(unsigned long *fpregs, unsigned long *fsr); */
1445
1446         .globl  fpload
1447 fpload:
1448         ldd     [%o0 + 0x00], %f0
1449         ldd     [%o0 + 0x08], %f2
1450         ldd     [%o0 + 0x10], %f4
1451         ldd     [%o0 + 0x18], %f6
1452         ldd     [%o0 + 0x20], %f8
1453         ldd     [%o0 + 0x28], %f10
1454         ldd     [%o0 + 0x30], %f12
1455         ldd     [%o0 + 0x38], %f14
1456         ldd     [%o0 + 0x40], %f16
1457         ldd     [%o0 + 0x48], %f18
1458         ldd     [%o0 + 0x50], %f20
1459         ldd     [%o0 + 0x58], %f22
1460         ldd     [%o0 + 0x60], %f24
1461         ldd     [%o0 + 0x68], %f26
1462         ldd     [%o0 + 0x70], %f28
1463         ldd     [%o0 + 0x78], %f30
1464         ld      [%o1], %fsr
1465         retl
1466          nop
1467
1468         /* __ndelay and __udelay take two arguments:
1469          * 0 - nsecs or usecs to delay
1470          * 1 - per_cpu udelay_val (loops per jiffy)
1471          *
1472          * Note that ndelay gives HZ times higher resolution but has a 10ms
1473          * limit.  udelay can handle up to 1s.
1474          */
1475         .globl  __ndelay
1476 __ndelay:
1477         save    %sp, -STACKFRAME_SZ, %sp
1478         mov     %i0, %o0
1479         call    .umul                   ! round multiplier up so large ns ok
1480          mov    0x1ae, %o1              ! 2**32 / (1 000 000 000 / HZ)
1481         call    .umul
1482          mov    %i1, %o1                ! udelay_val
1483         ba      delay_continue
1484          mov    %o1, %o0                ! >>32 later for better resolution
1485
1486         .globl  __udelay
1487 __udelay:
1488         save    %sp, -STACKFRAME_SZ, %sp
1489         mov     %i0, %o0
1490         sethi   %hi(0x10c7), %o1        ! round multiplier up so large us ok
1491         call    .umul
1492          or     %o1, %lo(0x10c7), %o1   ! 2**32 / 1 000 000
1493         call    .umul
1494          mov    %i1, %o1                ! udelay_val
1495         sethi   %hi(0x028f4b62), %l0    ! Add in rounding constant * 2**32,
1496         or      %g0, %lo(0x028f4b62), %l0
1497         addcc   %o0, %l0, %o0           ! 2**32 * 0.009 999
1498         bcs,a   3f
1499          add    %o1, 0x01, %o1
1500 3:
1501         call    .umul
1502          mov    HZ, %o0                 ! >>32 earlier for wider range
1503
1504 delay_continue:
1505         cmp     %o0, 0x0
1506 1:
1507         bne     1b
1508          subcc  %o0, 1, %o0
1509         
1510         ret
1511         restore
1512
1513         /* Handle a software breakpoint */
1514         /* We have to inform parent that child has stopped */
1515         .align 4
1516         .globl breakpoint_trap
1517 breakpoint_trap:
1518         rd      %wim,%l3
1519         SAVE_ALL
1520         wr      %l0, PSR_ET, %psr
1521         WRITE_PAUSE
1522
1523         st      %i0, [%sp + STACKFRAME_SZ + PT_G0] ! for restarting syscalls
1524         call    sparc_breakpoint
1525          add    %sp, STACKFRAME_SZ, %o0
1526
1527         RESTORE_ALL
1528
1529 #ifdef CONFIG_KGDB
1530         .align  4
1531         .globl  kgdb_trap_low
1532         .type   kgdb_trap_low,#function
1533 kgdb_trap_low:
1534         rd      %wim,%l3
1535         SAVE_ALL
1536         wr      %l0, PSR_ET, %psr
1537         WRITE_PAUSE
1538
1539         call    kgdb_trap
1540          add    %sp, STACKFRAME_SZ, %o0
1541
1542         RESTORE_ALL
1543         .size   kgdb_trap_low,.-kgdb_trap_low
1544 #endif
1545
1546         .align  4
1547         .globl  flush_patch_exception
1548 flush_patch_exception:
1549         FLUSH_ALL_KERNEL_WINDOWS;
1550         ldd     [%o0], %o6
1551         jmpl    %o7 + 0xc, %g0                  ! see asm-sparc/processor.h
1552          mov    1, %g1                          ! signal EFAULT condition
1553
1554         .align  4
1555         .globl  kill_user_windows, kuw_patch1_7win
1556         .globl  kuw_patch1
1557 kuw_patch1_7win:        sll     %o3, 6, %o3
1558
1559         /* No matter how much overhead this routine has in the worst
1560          * case scenerio, it is several times better than taking the
1561          * traps with the old method of just doing flush_user_windows().
1562          */
1563 kill_user_windows:
1564         ld      [%g6 + TI_UWINMASK], %o0        ! get current umask
1565         orcc    %g0, %o0, %g0                   ! if no bits set, we are done
1566         be      3f                              ! nothing to do
1567          rd     %psr, %o5                       ! must clear interrupts
1568         or      %o5, PSR_PIL, %o4               ! or else that could change
1569         wr      %o4, 0x0, %psr                  ! the uwinmask state
1570         WRITE_PAUSE                             ! burn them cycles
1571 1:
1572         ld      [%g6 + TI_UWINMASK], %o0        ! get consistent state
1573         orcc    %g0, %o0, %g0                   ! did an interrupt come in?
1574         be      4f                              ! yep, we are done
1575          rd     %wim, %o3                       ! get current wim
1576         srl     %o3, 1, %o4                     ! simulate a save
1577 kuw_patch1:
1578         sll     %o3, 7, %o3                     ! compute next wim
1579         or      %o4, %o3, %o3                   ! result
1580         andncc  %o0, %o3, %o0                   ! clean this bit in umask
1581         bne     kuw_patch1                      ! not done yet
1582          srl    %o3, 1, %o4                     ! begin another save simulation
1583         wr      %o3, 0x0, %wim                  ! set the new wim
1584         st      %g0, [%g6 + TI_UWINMASK]        ! clear uwinmask
1585 4:
1586         wr      %o5, 0x0, %psr                  ! re-enable interrupts
1587         WRITE_PAUSE                             ! burn baby burn
1588 3:
1589         retl                                    ! return
1590          st     %g0, [%g6 + TI_W_SAVED]         ! no windows saved
1591
1592         .align  4
1593         .globl  restore_current
1594 restore_current:
1595         LOAD_CURRENT(g6, o0)
1596         retl
1597          nop
1598
1599 #ifdef CONFIG_PCI
1600 #include <asm/pcic.h>
1601
1602         .align  4
1603         .globl  linux_trap_ipi15_pcic
1604 linux_trap_ipi15_pcic:
1605         rd      %wim, %l3
1606         SAVE_ALL
1607
1608         /*
1609          * First deactivate NMI
1610          * or we cannot drop ET, cannot get window spill traps.
1611          * The busy loop is necessary because the PIO error
1612          * sometimes does not go away quickly and we trap again.
1613          */
1614         sethi   %hi(pcic_regs), %o1
1615         ld      [%o1 + %lo(pcic_regs)], %o2
1616
1617         ! Get pending status for printouts later.
1618         ld      [%o2 + PCI_SYS_INT_PENDING], %o0
1619
1620         mov     PCI_SYS_INT_PENDING_CLEAR_ALL, %o1
1621         stb     %o1, [%o2 + PCI_SYS_INT_PENDING_CLEAR]
1622 1:
1623         ld      [%o2 + PCI_SYS_INT_PENDING], %o1
1624         andcc   %o1, ((PCI_SYS_INT_PENDING_PIO|PCI_SYS_INT_PENDING_PCI)>>24), %g0
1625         bne     1b
1626          nop
1627
1628         or      %l0, PSR_PIL, %l4
1629         wr      %l4, 0x0, %psr
1630         WRITE_PAUSE
1631         wr      %l4, PSR_ET, %psr
1632         WRITE_PAUSE
1633
1634         call    pcic_nmi
1635          add    %sp, STACKFRAME_SZ, %o1 ! struct pt_regs *regs
1636         RESTORE_ALL
1637
1638         .globl  pcic_nmi_trap_patch
1639 pcic_nmi_trap_patch:
1640         sethi   %hi(linux_trap_ipi15_pcic), %l3
1641         jmpl    %l3 + %lo(linux_trap_ipi15_pcic), %g0
1642          rd     %psr, %l0
1643         .word   0
1644
1645 #endif /* CONFIG_PCI */
1646
1647         .globl  flushw_all
1648 flushw_all:
1649         save    %sp, -0x40, %sp
1650         save    %sp, -0x40, %sp
1651         save    %sp, -0x40, %sp
1652         save    %sp, -0x40, %sp
1653         save    %sp, -0x40, %sp
1654         save    %sp, -0x40, %sp
1655         save    %sp, -0x40, %sp
1656         restore
1657         restore
1658         restore
1659         restore
1660         restore
1661         restore
1662         ret
1663          restore
1664
1665 /* End of entry.S */