10e859ddefd11ba7930a70bcc58f307c2814d436
[linux-2.6.git] / arch / score / kernel / entry.S
1 /*
2  * arch/score/kernel/entry.S
3  *
4  * Score Processor version.
5  *
6  * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
7  *  Chen Liqin <liqin.chen@sunplusct.com>
8  *  Lennox Wu <lennox.wu@sunplusct.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, see the file COPYING, or write
22  * to the Free Software Foundation, Inc.,
23  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24  */
25
26 #include <linux/err.h>
27 #include <linux/init.h>
28 #include <linux/linkage.h>
29
30 #include <asm/asmmacro.h>
31 #include <asm/thread_info.h>
32 #include <asm/unistd.h>
33
34 /*
35  * disable interrupts.
36  */
37 .macro  disable_irq
38         mfcr    r8, cr0
39         srli    r8, r8, 1
40         slli    r8, r8, 1
41         mtcr    r8, cr0
42         nop
43         nop
44         nop
45         nop
46         nop
47 .endm
48
49 /*
50  * enable interrupts.
51  */
52 .macro  enable_irq
53         mfcr    r8, cr0
54         ori     r8, 1
55         mtcr    r8, cr0
56         nop
57         nop
58         nop
59         nop
60         nop
61 .endm
62
63 __INIT
64 ENTRY(debug_exception_vector)
65         nop!
66         nop!
67         nop!
68         nop!
69         nop!
70         nop!
71         nop!
72         nop!
73
74 ENTRY(general_exception_vector)                 # should move to addr 0x200
75         j       general_exception
76         nop!
77         nop!
78         nop!
79         nop!
80         nop!
81         nop!
82
83 ENTRY(interrupt_exception_vector)               # should move to addr 0x210
84         j       interrupt_exception
85         nop!
86         nop!
87         nop!
88         nop!
89         nop!
90         nop!
91
92         .section ".text", "ax"
93         .align  2;
94 general_exception:
95         mfcr    r31, cr2
96         nop
97         la      r30, exception_handlers
98         andi    r31, 0x1f                       # get ecr.exc_code
99         slli    r31, r31, 2
100         add     r30, r30, r31
101         lw      r30, [r30]
102         br      r30
103
104 interrupt_exception:
105         SAVE_ALL
106         mfcr    r4, cr2
107         nop
108         lw      r16, [r28, TI_REGS]
109         sw      r0, [r28, TI_REGS]
110         la      r3, ret_from_irq
111         srli    r4, r4, 18                      # get ecr.ip[7:2], interrupt No.
112         mv      r5, r0
113         j       do_IRQ
114
115 ENTRY(handle_nmi)                               # NMI #1
116         SAVE_ALL
117         mv      r4, r0
118         la      r8, nmi_exception_handler
119         brl     r8
120         j       restore_all
121
122 ENTRY(handle_adelinsn)                          # AdEL-instruction #2
123         SAVE_ALL
124         mfcr    r8, cr6
125         nop
126         nop
127         sw      r8, [r0, PT_EMA]
128         mv      r4, r0
129         la      r8, do_adelinsn
130         brl     r8
131         mv      r4, r0
132         j       ret_from_exception
133         nop
134
135 ENTRY(handle_ibe)                               # BusEL-instruction #5
136         SAVE_ALL
137         mv      r4, r0
138         la      r8, do_be
139         brl     r8
140         mv      r4, r0
141         j       ret_from_exception
142         nop
143
144 ENTRY(handle_pel)                               # P-EL #6
145         SAVE_ALL
146         mv      r4, r0
147         la      r8, do_pel
148         brl     r8
149         mv      r4, r0
150         j       ret_from_exception
151         nop
152
153 ENTRY(handle_ccu)                               # CCU #8
154         SAVE_ALL
155         mv      r4, r0
156         la      r8, do_ccu
157         brl     r8
158         mv      r4, r0
159         j       ret_from_exception
160         nop
161
162 ENTRY(handle_ri)                                # RI #9
163         SAVE_ALL
164         mv      r4, r0
165         la      r8, do_ri
166         brl     r8
167         mv      r4, r0
168         j       ret_from_exception
169         nop
170
171 ENTRY(handle_tr)                                # Trap #10
172         SAVE_ALL
173         mv      r4, r0
174         la      r8, do_tr
175         brl     r8
176         mv      r4, r0
177         j       ret_from_exception
178         nop
179
180 ENTRY(handle_adedata)                           # AdES-instruction #12
181         SAVE_ALL
182         mfcr    r8, cr6
183         nop
184         nop
185         sw      r8, [r0, PT_EMA]
186         mv      r4, r0
187         la      r8, do_adedata
188         brl     r8
189         mv      r4, r0
190         j       ret_from_exception
191         nop
192
193 ENTRY(handle_cee)                               # CeE #16
194         SAVE_ALL
195         mv      r4, r0
196         la      r8, do_cee
197         brl     r8
198         mv      r4, r0
199         j       ret_from_exception
200         nop
201
202 ENTRY(handle_cpe)                               # CpE #17
203         SAVE_ALL
204         mv      r4, r0
205         la      r8, do_cpe
206         brl     r8
207         mv      r4, r0
208         j       ret_from_exception
209         nop
210
211 ENTRY(handle_dbe)                               # BusEL-data #18
212         SAVE_ALL
213         mv      r4, r0
214         la      r8, do_be
215         brl     r8
216         mv      r4, r0
217         j       ret_from_exception
218         nop
219
220 ENTRY(handle_reserved)                          # others
221         SAVE_ALL
222         mv      r4, r0
223         la      r8, do_reserved
224         brl     r8
225         mv      r4, r0
226         j       ret_from_exception
227         nop
228
229 #ifndef CONFIG_PREEMPT
230 #define resume_kernel   restore_all
231 #else
232 #define __ret_from_irq  ret_from_exception
233 #endif
234
235         .align  2
236 #ifndef CONFIG_PREEMPT
237 ENTRY(ret_from_exception)
238         disable_irq                     # preempt stop
239         nop
240         j       __ret_from_irq
241         nop
242 #endif
243
244 ENTRY(ret_from_irq)
245         sw      r16, [r28, TI_REGS]
246
247 ENTRY(__ret_from_irq)
248         lw      r8, [r0, PT_PSR]        # returning to kernel mode?
249         andri.c r8, r8, KU_USER
250         beq     resume_kernel
251
252 resume_userspace:
253         disable_irq
254         lw      r6, [r28, TI_FLAGS]     # current->work
255         li      r8, _TIF_WORK_MASK
256         and.c   r8, r8, r6              # ignoring syscall_trace
257         bne     work_pending
258         nop
259         j       restore_all
260         nop
261
262 #ifdef CONFIG_PREEMPT
263 resume_kernel:
264         disable_irq
265         lw      r8, [r28, TI_PRE_COUNT]
266         cmpz.c  r8
267         bne     r8, restore_all
268 need_resched:
269         lw      r8, [r28, TI_FLAGS]
270         andri.c r9, r8, _TIF_NEED_RESCHED
271         beq     restore_all
272         lw      r8, [r28, PT_PSR]               # Interrupts off?
273         andri.c r8, r8, 1
274         beq     restore_all
275         bl      preempt_schedule_irq
276         nop
277         j       need_resched
278         nop
279 #endif
280
281 ENTRY(ret_from_fork)
282         bl      schedule_tail                   # r4=struct task_struct *prev
283
284 ENTRY(syscall_exit)
285         nop
286         disable_irq
287         lw      r6, [r28, TI_FLAGS]             # current->work
288         li      r8, _TIF_WORK_MASK
289         and.c   r8, r6, r8
290         bne     syscall_exit_work
291
292 ENTRY(restore_all)                                      # restore full frame
293         RESTORE_ALL_AND_RET
294
295 work_pending:
296         andri.c r8, r6, _TIF_NEED_RESCHED # r6 is preloaded with TI_FLAGS
297         beq     work_notifysig
298 work_resched:
299         bl      schedule
300         nop
301         disable_irq
302         lw      r6, [r28, TI_FLAGS]
303         li      r8, _TIF_WORK_MASK
304         and.c   r8, r6, r8      # is there any work to be done
305                                 # other than syscall tracing?
306         beq     restore_all
307         andri.c r8, r6, _TIF_NEED_RESCHED
308         bne     work_resched
309
310 work_notifysig:
311         mv      r4, r0
312         li      r5, 0
313         bl      do_notify_resume        # r6 already loaded
314         nop
315         j       resume_userspace
316         nop
317
318 ENTRY(syscall_exit_work)
319         li      r8, _TIF_SYSCALL_TRACE
320         and.c   r8, r8, r6              # r6 is preloaded with TI_FLAGS
321         beq     work_pending            # trace bit set?
322         nop
323         enable_irq
324         mv      r4, r0
325         li      r5, 1
326         bl      do_syscall_trace
327         nop
328         b       resume_userspace
329         nop
330
331 .macro  save_context    reg
332         sw      r12, [\reg, THREAD_REG12];
333         sw      r13, [\reg, THREAD_REG13];
334         sw      r14, [\reg, THREAD_REG14];
335         sw      r15, [\reg, THREAD_REG15];
336         sw      r16, [\reg, THREAD_REG16];
337         sw      r17, [\reg, THREAD_REG17];
338         sw      r18, [\reg, THREAD_REG18];
339         sw      r19, [\reg, THREAD_REG19];
340         sw      r20, [\reg, THREAD_REG20];
341         sw      r21, [\reg, THREAD_REG21];
342         sw      r29, [\reg, THREAD_REG29];
343         sw      r2, [\reg, THREAD_REG2];
344         sw      r0, [\reg, THREAD_REG0]
345 .endm
346
347 .macro  restore_context reg
348         lw      r12, [\reg, THREAD_REG12];
349         lw      r13, [\reg, THREAD_REG13];
350         lw      r14, [\reg, THREAD_REG14];
351         lw      r15, [\reg, THREAD_REG15];
352         lw      r16, [\reg, THREAD_REG16];
353         lw      r17, [\reg, THREAD_REG17];
354         lw      r18, [\reg, THREAD_REG18];
355         lw      r19, [\reg, THREAD_REG19];
356         lw      r20, [\reg, THREAD_REG20];
357         lw      r21, [\reg, THREAD_REG21];
358         lw      r29, [\reg, THREAD_REG29];
359         lw      r0, [\reg, THREAD_REG0];
360         lw      r2, [\reg, THREAD_REG2];
361         lw      r3, [\reg, THREAD_REG3]
362 .endm
363
364 /*
365  * task_struct *resume(task_struct *prev, task_struct *next,
366  *                      struct thread_info *next_ti)
367  */
368 ENTRY(resume)
369         mfcr    r9, cr0
370         nop
371         nop
372         sw      r9, [r4, THREAD_PSR]
373         save_context    r4
374         sw      r3, [r4, THREAD_REG3]
375
376         mv      r28, r6
377         restore_context r5
378         mv      r8, r6
379         addi    r8, KERNEL_STACK_SIZE
380         subi    r8, 32
381         la      r9, kernelsp;
382         sw      r8, [r9];
383
384         mfcr    r9, cr0
385         ldis    r7, 0x00ff
386         nop
387         and     r9, r9, r7
388         lw      r6, [r5, THREAD_PSR]
389         not     r7, r7
390         and     r6, r6, r7
391         or      r6, r6, r9
392         mtcr    r6, cr0
393         nop; nop; nop; nop; nop
394         br      r3
395
396 ENTRY(handle_sys)
397         SAVE_ALL
398         sw      r8, [r0, 16]            # argument 5 from user r8
399         sw      r9, [r0, 20]            # argument 6 from user r9
400         enable_irq
401
402         sw      r4, [r0, PT_ORIG_R4]    #for restart syscall
403         sw      r7, [r0, PT_ORIG_R7]    #for restart syscall
404         sw      r27, [r0, PT_IS_SYSCALL] # it from syscall
405
406         lw      r9, [r0, PT_EPC]        # skip syscall on return
407         addi    r9, 4
408         sw      r9, [r0, PT_EPC]
409
410         cmpi.c  r27, __NR_syscalls      # check syscall number
411         bgtu    illegal_syscall
412
413         slli    r8, r27, 2              # get syscall routine
414         la      r11, sys_call_table
415         add     r11, r11, r8
416         lw      r10, [r11]              # get syscall entry
417
418         cmpz.c  r10
419         beq     illegal_syscall
420
421         lw      r8, [r28, TI_FLAGS]
422         li      r9, _TIF_SYSCALL_TRACE
423         and.c   r8, r8, r9
424         bne     syscall_trace_entry
425
426         brl     r10                     # Do The Real system call
427
428         cmpi.c  r4, 0
429         blt     1f
430         ldi     r8, 0
431         sw      r8, [r0, PT_R7]
432         b 2f
433 1:
434         cmpi.c  r4, -MAX_ERRNO - 1
435         ble     2f
436         ldi     r8, 0x1;
437         sw      r8, [r0, PT_R7]
438         neg     r4, r4
439 2:
440         sw      r4, [r0, PT_R4]         # save result
441
442 syscall_return:
443         disable_irq
444         lw      r6, [r28, TI_FLAGS]     # current->work
445         li      r8, _TIF_WORK_MASK
446         and.c   r8, r6, r8
447         bne     syscall_return_work
448         j       restore_all
449
450 syscall_return_work:
451         j       syscall_exit_work
452
453 syscall_trace_entry:
454         mv      r16, r10
455         mv      r4, r0
456         li      r5, 0
457         bl      do_syscall_trace
458
459         mv      r8, r16
460         lw      r4, [r0, PT_R4]         # Restore argument registers
461         lw      r5, [r0, PT_R5]
462         lw      r6, [r0, PT_R6]
463         lw      r7, [r0, PT_R7]
464         brl     r8
465
466         li      r8, -MAX_ERRNO - 1
467         sw      r8, [r0, PT_R7]         # set error flag
468
469         neg     r4, r4                  # error
470         sw      r4, [r0, PT_R0]         # set flag for syscall
471                                         # restarting
472 1:      sw      r4, [r0, PT_R2]         # result
473         j       syscall_exit
474
475 illegal_syscall:
476         ldi     r4, -ENOSYS             # error
477         sw      r4, [r0, PT_ORIG_R4]
478         sw      r4, [r0, PT_R4]
479         ldi     r9, 1                   # set error flag
480         sw      r9, [r0, PT_R7]
481         j       syscall_return
482
483 ENTRY(sys_execve)
484         mv      r4, r0
485         la      r8, score_execve
486         br      r8
487
488 ENTRY(sys_clone)
489         mv      r4, r0
490         la      r8, score_clone
491         br      r8
492
493 ENTRY(sys_rt_sigreturn)
494         mv      r4, r0
495         la      r8, score_rt_sigreturn
496         br      r8
497
498 ENTRY(sys_sigaltstack)
499         mv      r4, r0
500         la      r8, score_sigaltstack
501         br      r8