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