ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / m68knommu / platform / 5307 / entry.S
1 /*
2  *  linux/arch/m68knommu/platform/5307/entry.S
3  *
4  *  Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
5  *  Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
6  *                      Kenneth Albanowski <kjahds@kjahds.com>,
7  *  Copyright (C) 2000  Lineo Inc. (www.lineo.com) 
8  *
9  * Based on:
10  *
11  *  linux/arch/m68k/kernel/entry.S
12  *
13  *  Copyright (C) 1991, 1992  Linus Torvalds
14  *
15  * This file is subject to the terms and conditions of the GNU General Public
16  * License.  See the file README.legal in the main directory of this archive
17  * for more details.
18  *
19  * Linux/m68k support by Hamish Macdonald
20  *
21  * 68060 fixes by Jesper Skov
22  * ColdFire support by Greg Ungerer (gerg@snapgear.com)
23  * 5307 fixes by David W. Miller
24  * linux 2.4 support David McCullough <davidm@snapgear.com>
25  */
26
27 #include <linux/config.h>
28 #include <linux/sys.h>
29 #include <linux/linkage.h>
30 #include <asm/unistd.h>
31 #include <asm/thread_info.h>
32 #include <asm/errno.h>
33 #include <asm/setup.h>
34 #include <asm/segment.h>
35 #include <asm/asm-offsets.h>
36 #include <asm/entry.h>
37
38 .data
39
40 sw_ksp:
41 .long   0
42
43 sw_usp:
44 .long   0
45
46 .text
47
48 .globl system_call
49 .globl resume
50 .globl ret_from_exception
51 .globl ret_from_signal
52 .globl sys_call_table
53 .globl ret_from_interrupt
54 .globl inthandler
55 .globl fasthandler
56
57 ENTRY(system_call)
58         SAVE_ALL
59         move    #0x2000,%sr             /* enable intrs again */
60
61         movel   #-LENOSYS,%d2
62         movel   %d2,LD0(%sp)            /* default return value in d0 */
63                                         /* original D0 is in orig_d0 */
64         movel   %d0,%d2
65
66         /* save top of frame */
67         pea     %sp@
68         jbsr    set_esp0
69         addql   #4,%sp
70
71         cmpl    #NR_syscalls,%d2
72         jcc     ret_from_exception
73         lea     sys_call_table,%a0
74         lsll    #2,%d2                  /* movel %a0@(%d2:l:4),%d3 */
75         movel   %a0@(%d2),%d3
76         jeq     ret_from_exception
77         lsrl    #2,%d2
78
79         movel   %sp,%d2                 /* get thread_info pointer */
80         andl    #0xffffe000,%d2         /* at start of 8k kernel stack */
81         movel   %d2,%a0
82         btst    #TIF_SYSCALL_TRACE,%a0@(TI_FLAGS)
83         bnes    1f
84
85         movel   %d3,%a0
86         jbsr    %a0@
87         movel   %d0,%sp@(LD0)           /* save the return value */
88         jra     ret_from_exception
89 1:
90         subql   #4,%sp
91         SAVE_SWITCH_STACK
92         jbsr    syscall_trace
93         RESTORE_SWITCH_STACK
94         addql   #4,%sp
95         movel   %d3,%a0
96         jbsr    %a0@
97         movel   %d0,%sp@(LD0)           /* save the return value */
98         subql   #4,%sp                  /* dummy return address */
99         SAVE_SWITCH_STACK
100         jbsr    syscall_trace
101
102 ret_from_signal:
103         RESTORE_SWITCH_STACK
104         addql   #4,%sp
105
106 ret_from_exception:
107         btst    #5,%sp@(LSR)            /* check if returning to kernel */
108         jeq     Luser_return            /* if so, skip resched, signals */
109
110 Lkernel_return:
111         moveml  %sp@,%d1-%d5/%a0-%a2
112         addl    #32,%sp                 /* space for 8 regs */
113         movel   %sp@+,%d0
114         addql   #4,%sp                  /* orig d0 */
115         addl    %sp@+,%sp               /* stk adj */
116         rte
117
118 Luser_return:
119         movel   %sp,%d1                 /* get thread_info pointer */
120         andl    #0xffffe000,%d1         /* at base of 8k kernel stack */
121         movel   %d1,%a0
122         movel   %a0@(TI_FLAGS),%d1      /* get thread_info->flags */
123         andl    #_TIF_WORK_MASK,%d1
124         jne     Lwork_to_do             /* still work to do */
125
126 Lreturn:
127         move    #0x2700,%sr             /* disable intrs */
128         movel   sw_usp,%a0              /* get usp */
129         moveml  %sp@(LFORMATVEC),%d1-%d2 /* copy exception */
130         moveml  %d1-%d2,%a0@(-8)
131         bclr    #5,%a0@(-8)             /* clear format byte, bit 5 to make
132                                          * stack appear modulo 4 which it WILL
133                                          * be when we do the rte because it was
134                                          * generated in setup_frame
135                                          */
136         bclr    #4,%a0@(-8)             /* clear format byte, bit 4 to make 
137                                          * stack appear modulo 4 which it WILL
138                                          * be when we do the rte because it was
139                                          * generated in setup_frame
140                                          */
141         moveml  %sp@,%d1-%d5/%a0-%a2
142         addl    #32,%sp                 /* space for 8 regs */
143         movel   %sp@+,%d0                  
144         addql   #4,%sp                  /* orig d0 */
145         addl    %sp@+,%sp               /* stk adj */
146         addql   #8,%sp                  /* remove exception */
147         movel   %sp,sw_ksp              /* save ksp */
148         movel   sw_usp,%sp              /* restore usp */
149         subql   #8,%sp                  /* set exception */
150         rte
151
152 Lwork_to_do:
153         movel   %a0@(TI_FLAGS),%d1      /* get thread_info->flags */
154         btst    #TIF_NEED_RESCHED,%d1
155         jne     reschedule
156
157         /* GERG: do we need something here for TRACEing?? */
158
159 Lsignal_return:
160         subql   #4,%sp                  /* dummy return address */
161         SAVE_SWITCH_STACK
162         pea     %sp@(SWITCH_STACK_SIZE)
163         clr     %d1
164         movel   %d1,%sp@-
165         jsr     do_signal
166         addql   #8,%sp
167         RESTORE_SWITCH_STACK
168         addql   #4,%sp
169         jmp     Lreturn
170
171 /*
172  * This is the generic interrupt handler (for all hardware interrupt
173  * sources). It figures out the vector number and calls the appropriate
174  * interrupt service routine directly.
175  */
176 ENTRY(inthandler)
177         SAVE_ALL
178         moveq   #-1,%d0
179         movel   %d0,%sp@(LORIG_D0)
180         addql   #1,local_irq_count
181
182         movew   %sp@(LFORMATVEC),%d0    /* put exception # in d0 */
183         andl    #0x03fc,%d0             /* mask out vector only */
184
185         leal    per_cpu__kstat+STAT_IRQ,%a0
186         addql   #1,%a0@(%d0)
187
188         lsrl    #2,%d0                  /* calculate real vector # */
189         movel   %d0,%d1                 /* calculate array offset */
190         lsll    #4,%d1
191         lea     irq_list,%a0
192         addl    %d1,%a0                 /* pointer to array struct */
193
194         movel   %sp,%sp@-               /* push regs arg onto stack */
195         movel   %a0@(8),%sp@-           /* push devid arg */
196         movel   %d0,%sp@-               /* push vector # on stack */
197
198         movel   %a0@,%a0                /* get function to call */
199         jbsr    %a0@                    /* call vector handler */
200         addl    #12,%sp                 /* pop parameters off stack */
201
202         bra     ret_from_interrupt      /* this was fallthrough */
203
204 /*
205  * This is the fast interrupt handler (for certain hardware interrupt
206  * sources). Unlike the normal interrupt handler it just uses the
207  * current stack (doesn't care if it is user or kernel). It also
208  * doesn't bother doing the bottom half handlers.
209  */
210 ENTRY(fasthandler)
211         SAVE_LOCAL
212
213         movew   %sp@(LFORMATVEC),%d0
214         andl    #0x03fc,%d0             /* mask out vector only */
215
216         leal    per_cpu__kstat+STAT_IRQ,%a0
217         addql   #1,%a0@(%d0)
218
219         movel   %sp,%sp@-               /* push regs arg onto stack */
220         clrl    %d1
221         movel   %d1,%sp@-               /* push devid arg */
222         lsrl    #2,%d0                  /* calculate real vector # */
223         movel   %d0,%sp@-               /* push vector # on stack */
224
225         lsll    #4,%d0                  /* adjust for array offset */
226         lea     irq_list,%a0
227         movel   %a0@(%d0),%a0           /* get function to call */
228         jbsr    %a0@                    /* call vector handler */
229         addl    #12,%sp                 /* pop parameters off stack */
230
231         RESTORE_LOCAL
232
233 ENTRY(ret_from_interrupt)
234         subql   #1,local_irq_count
235         jeq     2f
236 1:
237         RESTORE_ALL
238 2:
239         moveb   %sp@(LSR),%d0
240         andl    #0x7,%d0
241         jhi     1b
242
243         /* check if we need to do software interrupts */
244         movel   irq_stat+CPUSTAT_SOFTIRQ_PENDING,%d0
245         jeq     ret_from_exception
246
247         pea     ret_from_exception
248         jmp     do_softirq
249
250 /*
251  * Beware - when entering resume, prev (the current task) is
252  * in a0, next (the new task) is in a1,so don't change these
253  * registers until their contents are no longer needed.
254  */
255 ENTRY(resume)
256         movel   %a0, %d1                        /* get prev thread in d1 */
257
258         movew   %sr,%d0                         /* save thread status reg */
259         movew   %d0,%a0@(TASK_THREAD+THREAD_SR)
260
261         oril    #0x700,%d0                      /* disable interrupts */
262         move    %d0,%sr
263
264         movel   sw_usp,%d0                      /* save usp */
265         movel   %d0,%a0@(TASK_THREAD+THREAD_USP)
266
267         SAVE_SWITCH_STACK
268         movel   %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack pointer */
269         movel   %a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new thread stack */
270         RESTORE_SWITCH_STACK
271
272         movel   %a1@(TASK_THREAD+THREAD_USP),%a0 /* restore thread user stack */
273         movel   %a0, sw_usp
274
275         movew   %a1@(TASK_THREAD+THREAD_SR),%d0 /* restore thread status reg */
276         movew   %d0, %sr
277         rts
278