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