score: Add support for Sunplus S+core architecture
[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/errno.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         enable_irq
399
400         sw      r4, [r0, PT_ORIG_R4]    #for restart syscall
401         sw      r7, [r0, PT_ORIG_R7]    #for restart syscall
402         sw      r27, [r0, PT_IS_SYSCALL] # it from syscall
403
404         lw      r9, [r0, PT_EPC]        # skip syscall on return
405         addi    r9, 4
406         sw      r9, [r0, PT_EPC]
407
408         cmpi.c  r27, __NR_syscalls      # check syscall number
409         bgtu    illegal_syscall
410
411         slli    r8, r27, 3              # get syscall routine
412         la      r11, sys_call_table
413         add     r11, r11, r8
414         lw      r10, [r11]              # get syscall entry
415         lw      r11, [r11, 4]           # get number of args
416
417         cmpz.c  r10
418         beq     illegal_syscall
419
420         cmpi.c  r11, 4                  # more than 4 arguments?
421         bgtu    stackargs
422
423 stack_done:
424         lw      r8, [r28, TI_FLAGS]
425         li      r9, _TIF_SYSCALL_TRACE
426         and.c   r8, r8, r9
427         bne     syscall_trace_entry
428
429         brl     r10                     # Do The Real system call
430
431         cmpi.c  r4, 0
432         blt     1f
433         ldi     r8, 0
434         sw      r8, [r0, PT_R7]
435         b 2f
436 1:
437         cmpi.c  r4, -EMAXERRNO-1        # -EMAXERRNO - 1=-1134
438         ble     2f
439         ldi     r8, 0x1;
440         sw      r8, [r0, PT_R7]
441         neg     r4, r4
442 2:
443         sw      r4, [r0, PT_R4]         # save result
444
445 syscall_return:
446         disable_irq
447         lw      r6, [r28, TI_FLAGS]     # current->work
448         li      r8, _TIF_WORK_MASK
449         and.c   r8, r6, r8
450         bne     syscall_return_work
451         j       restore_all
452
453 syscall_return_work:
454         j       syscall_exit_work
455
456 syscall_trace_entry:
457         mv      r16, r10
458         mv      r4, r0
459         li      r5, 0
460         bl      do_syscall_trace
461
462         mv      r8, r16
463         lw      r4, [r0, PT_R4]         # Restore argument registers
464         lw      r5, [r0, PT_R5]
465         lw      r6, [r0, PT_R6]
466         lw      r7, [r0, PT_R7]
467         brl     r8
468
469         li      r8, -EMAXERRNO - 1      # error?
470         sw      r8, [r0, PT_R7]         # set error flag
471
472         neg     r4, r4                  # error
473         sw      r4, [r0, PT_R0]         # set flag for syscall
474                                         # restarting
475 1:      sw      r4, [r0, PT_R2]         # result
476         j       syscall_exit
477
478 stackargs:
479         lw      r8, [r0, PT_R0]
480         andri.c r9, r8, 3               # test whether user sp is align a word
481         bne     bad_stack
482         subi    r11, 5
483         slli    r9, r11, 2
484         add.c   r9, r9, r8
485
486         bmi     bad_stack
487         la      r9, 3f                  # calculate branch address
488         slli    r11, r11, 3
489         sub     r9, r9, r11
490         br      r9
491
492 2:      lw      r9, [r8, 20]            # argument 6 from usp
493         sw      r9, [r0, 20]
494
495 3:      lw      r9, [r8, 16]            # argument 5 from usp
496         sw      r9, [r0, 16]
497         j       stack_done
498
499         .section __ex_table,"a"
500         .word   2b, bad_stack
501         .word   3b, bad_stack
502         .previous
503
504         /*
505          * The stackpointer for a call with more than 4 arguments is bad.
506          * We probably should handle this case a bit more drastic.
507          */
508 bad_stack:
509         neg     r27, r27                # error
510         sw      r27, [r0, PT_ORIG_R4]
511         sw      r27, [r0, PT_R4]
512         ldi     r8, 1                   # set error flag
513         sw      r8, [r0, PT_R7]
514         j       syscall_return
515
516 illegal_syscall:
517         ldi     r4, -ENOSYS             # error
518         sw      r4, [r0, PT_ORIG_R4]
519         sw      r4, [r0, PT_R4]
520         ldi     r9, 1                   # set error flag
521         sw      r9, [r0, PT_R7]
522         j       syscall_return
523
524 ENTRY(sys_execve)
525         mv      r4, r0
526         la      r8, score_execve
527         br      r8
528
529 ENTRY(sys_clone)
530         mv      r4, r0
531         la      r8, score_clone
532         br      r8
533
534 ENTRY(sys_rt_sigreturn)
535         mv      r4, r0
536         la      r8, score_rt_sigreturn
537         br      r8
538
539 ENTRY(sys_sigaltstack)
540         mv      r4, r0
541         la      r8, score_sigaltstack
542         br      r8