Merge tag 'v3.3.7' into 3.3/master
[zen-stable.git] / arch / m68k / kernel / entry_mm.S
blob675a854966a62df047045c8dc8fc8016530e77c6
1 /* -*- mode: asm -*-
2  *
3  *  linux/arch/m68k/kernel/entry.S
4  *
5  *  Copyright (C) 1991, 1992  Linus Torvalds
6  *
7  * This file is subject to the terms and conditions of the GNU General Public
8  * License.  See the file README.legal in the main directory of this archive
9  * for more details.
10  *
11  * Linux/m68k support by Hamish Macdonald
12  *
13  * 68060 fixes by Jesper Skov
14  *
15  */
18  * entry.S  contains the system-call and fault low-level handling routines.
19  * This also contains the timer-interrupt handler, as well as all interrupts
20  * and faults that can result in a task-switch.
21  *
22  * NOTE: This code handles signal-recognition, which happens every time
23  * after a timer-interrupt and after each system call.
24  *
25  */
28  * 12/03/96 Jes: Currently we only support m68k single-cpu systems, so
29  *               all pointers that used to be 'current' are now entry
30  *               number 0 in the 'current_set' list.
31  *
32  *  6/05/00 RZ:  addedd writeback completion after return from sighandler
33  *               for 68040
34  */
36 #include <linux/linkage.h>
37 #include <asm/entry.h>
38 #include <asm/errno.h>
39 #include <asm/setup.h>
40 #include <asm/segment.h>
41 #include <asm/traps.h>
42 #include <asm/unistd.h>
44 #include <asm/asm-offsets.h>
46 .globl system_call, buserr, trap, resume
47 .globl sys_call_table
48 .globl sys_fork, sys_clone, sys_vfork
49 .globl ret_from_interrupt, bad_interrupt
50 .globl auto_irqhandler_fixup
51 .globl user_irqvec_fixup
53 .text
54 ENTRY(buserr)
55         SAVE_ALL_INT
56         GET_CURRENT(%d0)
57         movel   %sp,%sp@-               | stack frame pointer argument
58         bsrl    buserr_c
59         addql   #4,%sp
60         jra     .Lret_from_exception
62 ENTRY(trap)
63         SAVE_ALL_INT
64         GET_CURRENT(%d0)
65         movel   %sp,%sp@-               | stack frame pointer argument
66         bsrl    trap_c
67         addql   #4,%sp
68         jra     .Lret_from_exception
70         | After a fork we jump here directly from resume,
71         | so that %d1 contains the previous task
72         | schedule_tail now used regardless of CONFIG_SMP
73 ENTRY(ret_from_fork)
74         movel   %d1,%sp@-
75         jsr     schedule_tail
76         addql   #4,%sp
77         jra     .Lret_from_exception
79 do_trace_entry:
80         movel   #-ENOSYS,%sp@(PT_OFF_D0)| needed for strace
81         subql   #4,%sp
82         SAVE_SWITCH_STACK
83         jbsr    syscall_trace
84         RESTORE_SWITCH_STACK
85         addql   #4,%sp
86         movel   %sp@(PT_OFF_ORIG_D0),%d0
87         cmpl    #NR_syscalls,%d0
88         jcs     syscall
89 badsys:
90         movel   #-ENOSYS,%sp@(PT_OFF_D0)
91         jra     ret_from_syscall
93 do_trace_exit:
94         subql   #4,%sp
95         SAVE_SWITCH_STACK
96         jbsr    syscall_trace
97         RESTORE_SWITCH_STACK
98         addql   #4,%sp
99         jra     .Lret_from_exception
101 ENTRY(ret_from_signal)
102         movel   %curptr@(TASK_STACK),%a1
103         tstb    %a1@(TINFO_FLAGS+2)
104         jge     1f
105         jbsr    syscall_trace
106 1:      RESTORE_SWITCH_STACK
107         addql   #4,%sp
108 /* on 68040 complete pending writebacks if any */
109 #ifdef CONFIG_M68040
110         bfextu  %sp@(PT_OFF_FORMATVEC){#0,#4},%d0
111         subql   #7,%d0                          | bus error frame ?
112         jbne    1f
113         movel   %sp,%sp@-
114         jbsr    berr_040cleanup
115         addql   #4,%sp
117 #endif
118         jra     .Lret_from_exception
120 ENTRY(system_call)
121         SAVE_ALL_SYS
123         GET_CURRENT(%d1)
124         movel   %d1,%a1
126         | save top of frame
127         movel   %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
129         | syscall trace?
130         tstb    %a1@(TINFO_FLAGS+2)
131         jmi     do_trace_entry
132         cmpl    #NR_syscalls,%d0
133         jcc     badsys
134 syscall:
135         jbsr    @(sys_call_table,%d0:l:4)@(0)
136         movel   %d0,%sp@(PT_OFF_D0)     | save the return value
137 ret_from_syscall:
138         |oriw   #0x0700,%sr
139         movel   %curptr@(TASK_STACK),%a1
140         movew   %a1@(TINFO_FLAGS+2),%d0
141         jne     syscall_exit_work
142 1:      RESTORE_ALL
144 syscall_exit_work:
145         btst    #5,%sp@(PT_OFF_SR)      | check if returning to kernel
146         bnes    1b                      | if so, skip resched, signals
147         lslw    #1,%d0
148         jcs     do_trace_exit
149         jmi     do_delayed_trace
150         lslw    #8,%d0
151         jmi     do_signal_return
152         pea     resume_userspace
153         jra     schedule
156 ENTRY(ret_from_exception)
157 .Lret_from_exception:
158         btst    #5,%sp@(PT_OFF_SR)      | check if returning to kernel
159         bnes    1f                      | if so, skip resched, signals
160         | only allow interrupts when we are really the last one on the
161         | kernel stack, otherwise stack overflow can occur during
162         | heavy interrupt load
163         andw    #ALLOWINT,%sr
165 resume_userspace:
166         movel   %curptr@(TASK_STACK),%a1
167         moveb   %a1@(TINFO_FLAGS+3),%d0
168         jne     exit_work
169 1:      RESTORE_ALL
171 exit_work:
172         | save top of frame
173         movel   %sp,%curptr@(TASK_THREAD+THREAD_ESP0)
174         lslb    #1,%d0
175         jmi     do_signal_return
176         pea     resume_userspace
177         jra     schedule
180 do_signal_return:
181         |andw   #ALLOWINT,%sr
182         subql   #4,%sp                  | dummy return address
183         SAVE_SWITCH_STACK
184         pea     %sp@(SWITCH_STACK_SIZE)
185         bsrl    do_signal
186         addql   #4,%sp
187         RESTORE_SWITCH_STACK
188         addql   #4,%sp
189         jbra    resume_userspace
191 do_delayed_trace:
192         bclr    #7,%sp@(PT_OFF_SR)      | clear trace bit in SR
193         pea     1                       | send SIGTRAP
194         movel   %curptr,%sp@-
195         pea     LSIGTRAP
196         jbsr    send_sig
197         addql   #8,%sp
198         addql   #4,%sp
199         jbra    resume_userspace
202 /* This is the main interrupt handler for autovector interrupts */
204 ENTRY(auto_inthandler)
205         SAVE_ALL_INT
206         GET_CURRENT(%d0)
207         movel   %d0,%a1
208         addqb   #1,%a1@(TINFO_PREEMPT+1)
209                                         |  put exception # in d0
210         bfextu  %sp@(PT_OFF_FORMATVEC){#4,#10},%d0
211         subw    #VEC_SPUR,%d0
213         movel   %sp,%sp@-
214         movel   %d0,%sp@-               |  put vector # on stack
215 auto_irqhandler_fixup = . + 2
216         jsr     do_IRQ                  |  process the IRQ
217         addql   #8,%sp                  |  pop parameters off stack
219 ret_from_interrupt:
220         movel   %curptr@(TASK_STACK),%a1
221         subqb   #1,%a1@(TINFO_PREEMPT+1)
222         jeq     ret_from_last_interrupt
223 2:      RESTORE_ALL
225         ALIGN
226 ret_from_last_interrupt:
227         moveq   #(~ALLOWINT>>8)&0xff,%d0
228         andb    %sp@(PT_OFF_SR),%d0
229         jne     2b
231         /* check if we need to do software interrupts */
232         tstl    irq_stat+CPUSTAT_SOFTIRQ_PENDING
233         jeq     .Lret_from_exception
234         pea     ret_from_exception
235         jra     do_softirq
237 /* Handler for user defined interrupt vectors */
239 ENTRY(user_inthandler)
240         SAVE_ALL_INT
241         GET_CURRENT(%d0)
242         movel   %d0,%a1
243         addqb   #1,%a1@(TINFO_PREEMPT+1)
244                                         |  put exception # in d0
245         bfextu  %sp@(PT_OFF_FORMATVEC){#4,#10},%d0
246 user_irqvec_fixup = . + 2
247         subw    #VEC_USER,%d0
249         movel   %sp,%sp@-
250         movel   %d0,%sp@-               |  put vector # on stack
251         jsr     do_IRQ                  |  process the IRQ
252         addql   #8,%sp                  |  pop parameters off stack
254         movel   %curptr@(TASK_STACK),%a1
255         subqb   #1,%a1@(TINFO_PREEMPT+1)
256         jeq     ret_from_last_interrupt
257         RESTORE_ALL
259 /* Handler for uninitialized and spurious interrupts */
261 ENTRY(bad_inthandler)
262         SAVE_ALL_INT
263         GET_CURRENT(%d0)
264         movel   %d0,%a1
265         addqb   #1,%a1@(TINFO_PREEMPT+1)
267         movel   %sp,%sp@-
268         jsr     handle_badint
269         addql   #4,%sp
271         movel   %curptr@(TASK_STACK),%a1
272         subqb   #1,%a1@(TINFO_PREEMPT+1)
273         jeq     ret_from_last_interrupt
274         RESTORE_ALL
277 ENTRY(sys_fork)
278         SAVE_SWITCH_STACK
279         pea     %sp@(SWITCH_STACK_SIZE)
280         jbsr    m68k_fork
281         addql   #4,%sp
282         RESTORE_SWITCH_STACK
283         rts
285 ENTRY(sys_clone)
286         SAVE_SWITCH_STACK
287         pea     %sp@(SWITCH_STACK_SIZE)
288         jbsr    m68k_clone
289         addql   #4,%sp
290         RESTORE_SWITCH_STACK
291         rts
293 ENTRY(sys_vfork)
294         SAVE_SWITCH_STACK
295         pea     %sp@(SWITCH_STACK_SIZE)
296         jbsr    m68k_vfork
297         addql   #4,%sp
298         RESTORE_SWITCH_STACK
299         rts
301 ENTRY(sys_sigreturn)
302         SAVE_SWITCH_STACK
303         jbsr    do_sigreturn
304         RESTORE_SWITCH_STACK
305         rts
307 ENTRY(sys_rt_sigreturn)
308         SAVE_SWITCH_STACK
309         jbsr    do_rt_sigreturn
310         RESTORE_SWITCH_STACK
311         rts
313 resume:
314         /*
315          * Beware - when entering resume, prev (the current task) is
316          * in a0, next (the new task) is in a1,so don't change these
317          * registers until their contents are no longer needed.
318          */
320         /* save sr */
321         movew   %sr,%a0@(TASK_THREAD+THREAD_SR)
323         /* save fs (sfc,%dfc) (may be pointing to kernel memory) */
324         movec   %sfc,%d0
325         movew   %d0,%a0@(TASK_THREAD+THREAD_FS)
327         /* save usp */
328         /* it is better to use a movel here instead of a movew 8*) */
329         movec   %usp,%d0
330         movel   %d0,%a0@(TASK_THREAD+THREAD_USP)
332         /* save non-scratch registers on stack */
333         SAVE_SWITCH_STACK
335         /* save current kernel stack pointer */
336         movel   %sp,%a0@(TASK_THREAD+THREAD_KSP)
338         /* save floating point context */
339 #ifndef CONFIG_M68KFPU_EMU_ONLY
340 #ifdef CONFIG_M68KFPU_EMU
341         tstl    m68k_fputype
342         jeq     3f
343 #endif
344         fsave   %a0@(TASK_THREAD+THREAD_FPSTATE)
346 #if defined(CONFIG_M68060)
347 #if !defined(CPU_M68060_ONLY)
348         btst    #3,m68k_cputype+3
349         beqs    1f
350 #endif
351         /* The 060 FPU keeps status in bits 15-8 of the first longword */
352         tstb    %a0@(TASK_THREAD+THREAD_FPSTATE+2)
353         jeq     3f
354 #if !defined(CPU_M68060_ONLY)
355         jra     2f
356 #endif
357 #endif /* CONFIG_M68060 */
358 #if !defined(CPU_M68060_ONLY)
359 1:      tstb    %a0@(TASK_THREAD+THREAD_FPSTATE)
360         jeq     3f
361 #endif
362 2:      fmovemx %fp0-%fp7,%a0@(TASK_THREAD+THREAD_FPREG)
363         fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_THREAD+THREAD_FPCNTL)
365 #endif  /* CONFIG_M68KFPU_EMU_ONLY */
366         /* Return previous task in %d1 */
367         movel   %curptr,%d1
369         /* switch to new task (a1 contains new task) */
370         movel   %a1,%curptr
372         /* restore floating point context */
373 #ifndef CONFIG_M68KFPU_EMU_ONLY
374 #ifdef CONFIG_M68KFPU_EMU
375         tstl    m68k_fputype
376         jeq     4f
377 #endif
378 #if defined(CONFIG_M68060)
379 #if !defined(CPU_M68060_ONLY)
380         btst    #3,m68k_cputype+3
381         beqs    1f
382 #endif
383         /* The 060 FPU keeps status in bits 15-8 of the first longword */
384         tstb    %a1@(TASK_THREAD+THREAD_FPSTATE+2)
385         jeq     3f
386 #if !defined(CPU_M68060_ONLY)
387         jra     2f
388 #endif
389 #endif /* CONFIG_M68060 */
390 #if !defined(CPU_M68060_ONLY)
391 1:      tstb    %a1@(TASK_THREAD+THREAD_FPSTATE)
392         jeq     3f
393 #endif
394 2:      fmovemx %a1@(TASK_THREAD+THREAD_FPREG),%fp0-%fp7
395         fmoveml %a1@(TASK_THREAD+THREAD_FPCNTL),%fpcr/%fpsr/%fpiar
396 3:      frestore %a1@(TASK_THREAD+THREAD_FPSTATE)
398 #endif  /* CONFIG_M68KFPU_EMU_ONLY */
400         /* restore the kernel stack pointer */
401         movel   %a1@(TASK_THREAD+THREAD_KSP),%sp
403         /* restore non-scratch registers */
404         RESTORE_SWITCH_STACK
406         /* restore user stack pointer */
407         movel   %a1@(TASK_THREAD+THREAD_USP),%a0
408         movel   %a0,%usp
410         /* restore fs (sfc,%dfc) */
411         movew   %a1@(TASK_THREAD+THREAD_FS),%a0
412         movec   %a0,%sfc
413         movec   %a0,%dfc
415         /* restore status register */
416         movew   %a1@(TASK_THREAD+THREAD_SR),%sr
418         rts