Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
ece9ae65 | 2 | * entry.S -- interrupt and exception processing for ColdFire |
1da177e4 | 3 | * |
2502b667 | 4 | * Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com) |
1da177e4 LT |
5 | * Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>, |
6 | * Kenneth Albanowski <kjahds@kjahds.com>, | |
623f523c PDM |
7 | * Copyright (C) 2000 Lineo Inc. (www.lineo.com) |
8 | * Copyright (C) 2004-2006 Macq Electronique SA. (www.macqel.com) | |
1da177e4 LT |
9 | * |
10 | * Based on: | |
11 | * | |
12 | * linux/arch/m68k/kernel/entry.S | |
13 | * | |
14 | * Copyright (C) 1991, 1992 Linus Torvalds | |
15 | * | |
16 | * This file is subject to the terms and conditions of the GNU General Public | |
17 | * License. See the file README.legal in the main directory of this archive | |
18 | * for more details. | |
19 | * | |
20 | * Linux/m68k support by Hamish Macdonald | |
21 | * | |
22 | * 68060 fixes by Jesper Skov | |
23 | * ColdFire support by Greg Ungerer (gerg@snapgear.com) | |
24 | * 5307 fixes by David W. Miller | |
25 | * linux 2.4 support David McCullough <davidm@snapgear.com> | |
26 | * Bug, speed and maintainability fixes by Philippe De Muyter <phdm@macqel.be> | |
27 | */ | |
28 | ||
1da177e4 LT |
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 | ||
1c83af5f GU |
38 | #ifdef CONFIG_COLDFIRE_SW_A7 |
39 | /* | |
40 | * Define software copies of the supervisor and user stack pointers. | |
41 | */ | |
1da177e4 | 42 | .bss |
1da177e4 LT |
43 | sw_ksp: |
44 | .long 0 | |
1da177e4 LT |
45 | sw_usp: |
46 | .long 0 | |
1c83af5f | 47 | #endif /* CONFIG_COLDFIRE_SW_A7 */ |
1da177e4 LT |
48 | |
49 | .text | |
50 | ||
51 | .globl system_call | |
52 | .globl resume | |
53 | .globl ret_from_exception | |
54 | .globl ret_from_signal | |
55 | .globl sys_call_table | |
1da177e4 | 56 | .globl inthandler |
1da177e4 | 57 | |
623f523c PDM |
58 | enosys: |
59 | mov.l #sys_ni_syscall,%d3 | |
60 | bra 1f | |
61 | ||
1da177e4 | 62 | ENTRY(system_call) |
61619b12 | 63 | SAVE_ALL_SYS |
1da177e4 | 64 | move #0x2000,%sr /* enable intrs again */ |
bbc6f1ba | 65 | GET_CURRENT(%d2) |
1da177e4 | 66 | |
623f523c PDM |
67 | cmpl #NR_syscalls,%d0 |
68 | jcc enosys | |
1da177e4 | 69 | lea sys_call_table,%a0 |
623f523c PDM |
70 | lsll #2,%d0 /* movel %a0@(%d0:l:4),%d3 */ |
71 | movel %a0@(%d0),%d3 | |
72 | jeq enosys | |
1da177e4 | 73 | |
623f523c | 74 | 1: |
1da177e4 LT |
75 | movel %sp,%d2 /* get thread_info pointer */ |
76 | andl #-THREAD_SIZE,%d2 /* at start of kernel stack */ | |
77 | movel %d2,%a0 | |
151941a8 MW |
78 | movel %a0@,%a1 /* save top of frame */ |
79 | movel %sp,%a1@(TASK_THREAD+THREAD_ESP0) | |
aa4d1f89 | 80 | btst #(TIF_SYSCALL_TRACE%8),%a0@(TINFO_FLAGS+(31-TIF_SYSCALL_TRACE)/8) |
1da177e4 LT |
81 | bnes 1f |
82 | ||
83 | movel %d3,%a0 | |
84 | jbsr %a0@ | |
c84b564e | 85 | movel %d0,%sp@(PT_OFF_D0) /* save the return value */ |
1da177e4 LT |
86 | jra ret_from_exception |
87 | 1: | |
c84b564e GU |
88 | movel #-ENOSYS,%d2 /* strace needs -ENOSYS in PT_OFF_D0 */ |
89 | movel %d2,PT_OFF_D0(%sp) /* on syscall entry */ | |
1da177e4 LT |
90 | subql #4,%sp |
91 | SAVE_SWITCH_STACK | |
55f411de | 92 | jbsr syscall_trace_enter |
1da177e4 LT |
93 | RESTORE_SWITCH_STACK |
94 | addql #4,%sp | |
95 | movel %d3,%a0 | |
96 | jbsr %a0@ | |
c84b564e | 97 | movel %d0,%sp@(PT_OFF_D0) /* save the return value */ |
1da177e4 LT |
98 | subql #4,%sp /* dummy return address */ |
99 | SAVE_SWITCH_STACK | |
55f411de | 100 | jbsr syscall_trace_leave |
1da177e4 LT |
101 | |
102 | ret_from_signal: | |
103 | RESTORE_SWITCH_STACK | |
104 | addql #4,%sp | |
105 | ||
106 | ret_from_exception: | |
6c5a7d50 | 107 | move #0x2700,%sr /* disable intrs */ |
c84b564e | 108 | btst #5,%sp@(PT_OFF_SR) /* check if returning to kernel */ |
1da177e4 LT |
109 | jeq Luser_return /* if so, skip resched, signals */ |
110 | ||
a19325a7 SS |
111 | #ifdef CONFIG_PREEMPT |
112 | movel %sp,%d1 /* get thread_info pointer */ | |
113 | andl #-THREAD_SIZE,%d1 /* at base of kernel stack */ | |
114 | movel %d1,%a0 | |
aa4d1f89 | 115 | movel %a0@(TINFO_FLAGS),%d1 /* get thread_info->flags */ |
cddafa35 | 116 | andl #(1<<TIF_NEED_RESCHED),%d1 |
a19325a7 SS |
117 | jeq Lkernel_return |
118 | ||
aa4d1f89 | 119 | movel %a0@(TINFO_PREEMPT),%d1 |
a19325a7 SS |
120 | cmpl #0,%d1 |
121 | jne Lkernel_return | |
122 | ||
123 | pea Lkernel_return | |
124 | jmp preempt_schedule_irq /* preempt the kernel */ | |
125 | #endif | |
126 | ||
1da177e4 LT |
127 | Lkernel_return: |
128 | moveml %sp@,%d1-%d5/%a0-%a2 | |
129 | lea %sp@(32),%sp /* space for 8 regs */ | |
130 | movel %sp@+,%d0 | |
131 | addql #4,%sp /* orig d0 */ | |
132 | addl %sp@+,%sp /* stk adj */ | |
133 | rte | |
134 | ||
135 | Luser_return: | |
136 | movel %sp,%d1 /* get thread_info pointer */ | |
137 | andl #-THREAD_SIZE,%d1 /* at base of kernel stack */ | |
138 | movel %d1,%a0 | |
8b3262c0 | 139 | moveb %a0@(TINFO_FLAGS+3),%d1 /* thread_info->flags (low 8 bits) */ |
1da177e4 LT |
140 | jne Lwork_to_do /* still work to do */ |
141 | ||
142 | Lreturn: | |
1c83af5f | 143 | RESTORE_USER |
1da177e4 LT |
144 | |
145 | Lwork_to_do: | |
aa4d1f89 | 146 | movel %a0@(TINFO_FLAGS),%d1 /* get thread_info->flags */ |
6c5a7d50 | 147 | move #0x2000,%sr /* enable intrs again */ |
1da177e4 LT |
148 | btst #TIF_NEED_RESCHED,%d1 |
149 | jne reschedule | |
150 | ||
1da177e4 LT |
151 | Lsignal_return: |
152 | subql #4,%sp /* dummy return address */ | |
153 | SAVE_SWITCH_STACK | |
154 | pea %sp@(SWITCH_STACK_SIZE) | |
a54f1655 | 155 | jsr do_notify_resume |
710e91e4 | 156 | addql #4,%sp |
1da177e4 LT |
157 | RESTORE_SWITCH_STACK |
158 | addql #4,%sp | |
d1574df7 | 159 | jmp Luser_return |
1da177e4 LT |
160 | |
161 | /* | |
162 | * This is the generic interrupt handler (for all hardware interrupt | |
25985edc | 163 | * sources). Calls up to high level code to do all the work. |
1da177e4 LT |
164 | */ |
165 | ENTRY(inthandler) | |
61619b12 | 166 | SAVE_ALL_INT |
bbc6f1ba | 167 | GET_CURRENT(%d2) |
1da177e4 | 168 | |
c84b564e | 169 | movew %sp@(PT_OFF_FORMATVEC),%d0 /* put exception # in d0 */ |
1da177e4 LT |
170 | andl #0x03fc,%d0 /* mask out vector only */ |
171 | ||
2502b667 | 172 | movel %sp,%sp@- /* push regs arg */ |
1da177e4 | 173 | lsrl #2,%d0 /* calculate real vector # */ |
2502b667 GU |
174 | movel %d0,%sp@- /* push vector number */ |
175 | jbsr do_IRQ /* call high level irq handler */ | |
176 | lea %sp@(8),%sp /* pop args off stack */ | |
1da177e4 | 177 | |
fb670fb8 | 178 | bra ret_from_exception |
1da177e4 LT |
179 | |
180 | /* | |
181 | * Beware - when entering resume, prev (the current task) is | |
f941f5ca | 182 | * in a0, next (the new task) is in a1, so don't change these |
1da177e4 LT |
183 | * registers until their contents are no longer needed. |
184 | */ | |
185 | ENTRY(resume) | |
f941f5ca GU |
186 | movew %sr,%d1 /* save current status */ |
187 | movew %d1,%a0@(TASK_THREAD+THREAD_SR) | |
188 | movel %a0,%d1 /* get prev thread in d1 */ | |
1da177e4 LT |
189 | SAVE_SWITCH_STACK |
190 | movel %sp,%a0@(TASK_THREAD+THREAD_KSP) /* save kernel stack pointer */ | |
f941f5ca GU |
191 | RDUSP /* movel %usp,%a3 */ |
192 | movel %a3,%a0@(TASK_THREAD+THREAD_USP) /* save thread user stack */ | |
bbc6f1ba GU |
193 | #ifdef CONFIG_MMU |
194 | movel %a1,%a2 /* set new current */ | |
195 | #endif | |
f941f5ca GU |
196 | movel %a1@(TASK_THREAD+THREAD_USP),%a3 /* restore thread user stack */ |
197 | WRUSP /* movel %a3,%usp */ | |
198 | movel %a1@(TASK_THREAD+THREAD_KSP),%sp /* restore new kernel stack */ | |
199 | movew %a1@(TASK_THREAD+THREAD_SR),%d7 /* restore new status */ | |
200 | movew %d7,%sr | |
1da177e4 | 201 | RESTORE_SWITCH_STACK |
1da177e4 | 202 | rts |
f941f5ca | 203 |