Back to home page

LXR

 
 

    


0001 /* 
0002  *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
0003  *  Copyright (C) 2003 - 2008  Paul Mundt
0004  *
0005  * This file is subject to the terms and conditions of the GNU General Public
0006  * License.  See the file "COPYING" in the main directory of this archive
0007  * for more details.
0008  *
0009  */
0010 
0011 ! NOTE:
0012 ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
0013 ! to be jumped is too far, but it causes illegal slot exception.
0014 
0015 /*  
0016  * entry.S contains the system-call and fault low-level handling routines.
0017  * This also contains the timer-interrupt handler, as well as all interrupts
0018  * and faults that can result in a task-switch.
0019  *
0020  * NOTE: This code handles signal-recognition, which happens every time
0021  * after a timer-interrupt and after each system call.
0022  *
0023  * NOTE: This code uses a convention that instructions in the delay slot
0024  * of a transfer-control instruction are indented by an extra space, thus:
0025  *
0026  *    jmp   @k0     ! control-transfer instruction
0027  *     ldc  k1, ssr     ! delay slot
0028  *
0029  * Stack layout in 'ret_from_syscall':
0030  *  ptrace needs to have all regs on the stack.
0031  *  if the order here is changed, it needs to be
0032  *  updated in ptrace.c and ptrace.h
0033  *
0034  *  r0
0035  *      ...
0036  *  r15 = stack pointer
0037  *  spc
0038  *  pr
0039  *  ssr
0040  *  gbr
0041  *  mach
0042  *  macl
0043  *  syscall #
0044  *
0045  */
0046 #include <asm/dwarf.h>
0047 
0048 #if defined(CONFIG_PREEMPT)
0049 #  define preempt_stop()    cli ; TRACE_IRQS_OFF
0050 #else
0051 #  define preempt_stop()
0052 #  define resume_kernel     __restore_all
0053 #endif
0054 
0055 
0056     .align  2
0057 ENTRY(exception_error)
0058     !
0059     TRACE_IRQS_ON
0060     sti
0061     mov.l   1f, r0
0062     jmp @r0
0063      nop
0064 
0065     .align  2
0066 1:  .long   do_exception_error
0067 
0068     .align  2
0069 ret_from_exception:
0070     CFI_STARTPROC simple
0071     CFI_DEF_CFA r14, 0
0072     CFI_REL_OFFSET 17, 64
0073     CFI_REL_OFFSET 15, 60
0074     CFI_REL_OFFSET 14, 56
0075     CFI_REL_OFFSET 13, 52
0076     CFI_REL_OFFSET 12, 48
0077     CFI_REL_OFFSET 11, 44
0078     CFI_REL_OFFSET 10, 40
0079     CFI_REL_OFFSET 9, 36
0080     CFI_REL_OFFSET 8, 32
0081     preempt_stop()
0082 ENTRY(ret_from_irq)
0083     !
0084     mov #OFF_SR, r0
0085     mov.l   @(r0,r15), r0   ! get status register
0086     shll    r0
0087     shll    r0      ! kernel space?
0088     get_current_thread_info r8, r0
0089     bt  resume_kernel   ! Yes, it's from kernel, go back soon
0090 
0091 #ifdef CONFIG_PREEMPT
0092     bra resume_userspace
0093      nop
0094 ENTRY(resume_kernel)
0095     cli
0096     TRACE_IRQS_OFF
0097     mov.l   @(TI_PRE_COUNT,r8), r0  ! current_thread_info->preempt_count
0098     tst r0, r0
0099     bf  noresched
0100 need_resched:
0101     mov.l   @(TI_FLAGS,r8), r0  ! current_thread_info->flags
0102     tst #_TIF_NEED_RESCHED, r0  ! need_resched set?
0103     bt  noresched
0104 
0105     mov #OFF_SR, r0
0106     mov.l   @(r0,r15), r0       ! get status register
0107     shlr    r0
0108     and #(0xf0>>1), r0      ! interrupts off (exception path)?
0109     cmp/eq  #(0xf0>>1), r0
0110     bt  noresched
0111     mov.l   1f, r0
0112     jsr @r0         ! call preempt_schedule_irq
0113      nop
0114     bra need_resched
0115      nop
0116 
0117 noresched:
0118     bra __restore_all
0119      nop
0120 
0121     .align 2
0122 1:  .long   preempt_schedule_irq
0123 #endif
0124 
0125 ENTRY(resume_userspace)
0126     ! r8: current_thread_info
0127     cli
0128     TRACE_IRQS_OFF
0129     mov.l   @(TI_FLAGS,r8), r0      ! current_thread_info->flags
0130     tst #(_TIF_WORK_MASK & 0xff), r0
0131     bt/s    __restore_all
0132      tst    #_TIF_NEED_RESCHED, r0
0133 
0134     .align  2
0135 work_pending:
0136     ! r0: current_thread_info->flags
0137     ! r8: current_thread_info
0138     ! t:  result of "tst    #_TIF_NEED_RESCHED, r0"
0139     bf/s    work_resched
0140      tst    #(_TIF_SIGPENDING | _TIF_NOTIFY_RESUME), r0
0141 work_notifysig:
0142     bt/s    __restore_all
0143      mov    r15, r4
0144     mov r12, r5     ! set arg1(save_r0)
0145     mov r0, r6
0146     sti
0147     mov.l   2f, r1
0148     mov.l   3f, r0
0149     jmp @r1
0150      lds    r0, pr
0151 work_resched:
0152     mov.l   1f, r1
0153     jsr @r1             ! schedule
0154      nop
0155     cli
0156     TRACE_IRQS_OFF
0157     !
0158     mov.l   @(TI_FLAGS,r8), r0      ! current_thread_info->flags
0159     tst #(_TIF_WORK_MASK & 0xff), r0
0160     bt  __restore_all
0161     bra work_pending
0162      tst    #_TIF_NEED_RESCHED, r0
0163 
0164     .align  2
0165 1:  .long   schedule
0166 2:  .long   do_notify_resume
0167 3:  .long   resume_userspace
0168 
0169     .align  2
0170 syscall_exit_work:
0171     ! r0: current_thread_info->flags
0172     ! r8: current_thread_info
0173     tst #(_TIF_WORK_SYSCALL_MASK & 0xff), r0
0174     bt/s    work_pending
0175      tst    #_TIF_NEED_RESCHED, r0
0176     TRACE_IRQS_ON
0177     sti
0178     mov r15, r4
0179     mov.l   8f, r0          ! do_syscall_trace_leave
0180     jsr @r0
0181      nop
0182     bra resume_userspace
0183      nop
0184 
0185     .align  2
0186 syscall_trace_entry:
0187     !                       Yes it is traced.
0188     mov     r15, r4
0189     mov.l   7f, r11     ! Call do_syscall_trace_enter which notifies
0190     jsr @r11            ! superior (will chomp R[0-7])
0191      nop
0192     mov.l   r0, @(OFF_R0,r15)   ! Save return value
0193     !           Reload R0-R4 from kernel stack, where the
0194     !                       parent may have modified them using
0195     !                       ptrace(POKEUSR).  (Note that R0-R2 are
0196     !                       reloaded from the kernel stack by syscall_call
0197     !                       below, so don't need to be reloaded here.)
0198     !                       This allows the parent to rewrite system calls
0199     !                       and args on the fly.
0200     mov.l   @(OFF_R4,r15), r4   ! arg0
0201     mov.l   @(OFF_R5,r15), r5
0202     mov.l   @(OFF_R6,r15), r6
0203     mov.l   @(OFF_R7,r15), r7   ! arg3
0204     mov.l   @(OFF_R3,r15), r3   ! syscall_nr
0205     !
0206     mov.l   2f, r10         ! Number of syscalls
0207     cmp/hs  r10, r3
0208     bf  syscall_call
0209     mov #-ENOSYS, r0
0210     bra syscall_exit
0211      mov.l  r0, @(OFF_R0,r15)   ! Return value
0212 
0213 __restore_all:
0214     mov #OFF_SR, r0
0215     mov.l   @(r0,r15), r0   ! get status register
0216 
0217     shlr2   r0
0218     and #0x3c, r0
0219     cmp/eq  #0x3c, r0
0220     bt  1f
0221     TRACE_IRQS_ON
0222     bra 2f
0223      nop
0224 1:
0225     TRACE_IRQS_OFF
0226 2:
0227     mov.l   3f, r0
0228     jmp @r0
0229      nop
0230 
0231     .align  2
0232 3:  .long   restore_all
0233 
0234     .align  2
0235 syscall_badsys:         ! Bad syscall number
0236     get_current_thread_info r8, r0
0237     mov #-ENOSYS, r0
0238     bra resume_userspace
0239      mov.l  r0, @(OFF_R0,r15)   ! Return value
0240 
0241 /*
0242  * The main debug trap handler.
0243  *
0244  * r8=TRA (not the trap number!)
0245  *
0246  * Note: This assumes that the trapa value is left in its original
0247  * form (without the shlr2 shift) so the calculation for the jump
0248  * call table offset remains a simple in place mask.
0249  */
0250 debug_trap:
0251     mov r8, r0
0252     and #(0xf << 2), r0
0253     mov.l   1f, r8
0254     add r0, r8
0255     mov.l   @r8, r8
0256     jsr @r8
0257      nop
0258     bra __restore_all
0259      nop
0260     CFI_ENDPROC
0261 
0262     .align  2
0263 1:  .long   debug_trap_table
0264 
0265 /*
0266  * Syscall interface:
0267  *
0268  *  Syscall #: R3
0269  *  Arguments #0 to #3: R4--R7
0270  *  Arguments #4 to #6: R0, R1, R2
0271  *  TRA: See following table.
0272  *
0273  * (TRA>>2) Purpose
0274  * -------- -------
0275  * 0x00-0x0f    original SH-3/4 syscall ABI (not in general use).
0276  * 0x10-0x1f    general SH-3/4 syscall ABI.
0277  *      0x1f    unified SH-2/3/4 syscall ABI (preferred).
0278  * 0x20-0x2f    original SH-2 syscall ABI.
0279  * 0x30-0x3f    debug traps used by the kernel.
0280  * 0x40-0xff    Not supported by all parts, so left unhandled.
0281  *
0282  * For making system calls, any trap number in the range for the
0283  * given cpu model may be used, but the unified trap number 0x1f is
0284  * preferred for compatibility with all models.
0285  *
0286  * The low bits of the trap number were once documented as matching
0287  * the number of arguments, but they were never actually used as such
0288  * by the kernel. SH-2 originally used its own separate trap range
0289  * because several hardware exceptions fell in the range used for the
0290  * SH-3/4 syscall ABI.
0291  *
0292  * This code also handles delegating other traps to the BIOS/gdb stub.
0293  *
0294  * Note: When we're first called, the TRA value must be shifted
0295  * right 2 bits in order to get the value that was used as the "trapa"
0296  * argument.
0297  */
0298 
0299     .align  2
0300     .globl  ret_from_fork
0301 ret_from_fork:
0302     mov.l   1f, r8
0303     jsr @r8
0304      mov    r0, r4
0305     bra syscall_exit
0306      nop
0307 
0308     .align  2
0309     .globl  ret_from_kernel_thread
0310 ret_from_kernel_thread:
0311     mov.l   1f, r8
0312     jsr @r8
0313      mov    r0, r4
0314     mov.l   @(OFF_R5,r15), r5   ! fn
0315     jsr @r5
0316      mov.l  @(OFF_R4,r15), r4   ! arg
0317     bra syscall_exit
0318      nop
0319 
0320     .align  2
0321 1:  .long   schedule_tail
0322 
0323 /*
0324  * The poorly named main trapa decode and dispatch routine, for
0325  * system calls and debug traps through their respective jump tables.
0326  */
0327 ENTRY(system_call)
0328     setup_frame_reg
0329 #if !defined(CONFIG_CPU_SH2)
0330     mov.l   1f, r9
0331     mov.l   @r9, r8     ! Read from TRA (Trap Address) Register
0332 #endif
0333 
0334     mov #OFF_TRA, r10
0335     add r15, r10
0336     mov.l   r8, @r10        ! set TRA value to tra
0337 
0338     /*
0339      * Check the trap type
0340      */
0341     mov #((0x20 << 2) - 1), r9
0342     cmp/hi  r9, r8
0343     bt/s    debug_trap      ! it's a debug trap..
0344      nop
0345 
0346     TRACE_IRQS_ON
0347     sti
0348 
0349     !
0350     get_current_thread_info r8, r10
0351     mov.l   @(TI_FLAGS,r8), r8
0352     mov #(_TIF_WORK_SYSCALL_MASK & 0xff), r10
0353     mov #(_TIF_WORK_SYSCALL_MASK >> 8), r9
0354     tst r10, r8
0355     shll8   r9
0356     bf  syscall_trace_entry
0357     tst r9, r8
0358     bf  syscall_trace_entry
0359     !
0360     mov.l   2f, r8          ! Number of syscalls
0361     cmp/hs  r8, r3
0362     bt  syscall_badsys
0363     !
0364 syscall_call:
0365     shll2   r3      ! x4
0366     mov.l   3f, r8      ! Load the address of sys_call_table
0367     add r8, r3
0368     mov.l   @r3, r8
0369     mov.l   @(OFF_R2,r15), r2
0370     mov.l   @(OFF_R1,r15), r1
0371     mov.l   @(OFF_R0,r15), r0
0372     mov.l   r2, @-r15
0373     mov.l   r1, @-r15
0374     mov.l   r0, @-r15
0375     jsr @r8         ! jump to specific syscall handler
0376      nop
0377     add #12, r15
0378     mov.l   @(OFF_R0,r15), r12      ! save r0
0379     mov.l   r0, @(OFF_R0,r15)       ! save the return value
0380     !
0381 syscall_exit:
0382     cli
0383     TRACE_IRQS_OFF
0384     !
0385     get_current_thread_info r8, r0
0386     mov.l   @(TI_FLAGS,r8), r0      ! current_thread_info->flags
0387     tst #(_TIF_ALLWORK_MASK & 0xff), r0
0388     mov #(_TIF_ALLWORK_MASK >> 8), r1
0389     bf  syscall_exit_work
0390     shlr8   r0
0391     tst r0, r1
0392     bf  syscall_exit_work
0393     bra __restore_all
0394      nop
0395     .align  2
0396 #if !defined(CONFIG_CPU_SH2)
0397 1:  .long   TRA
0398 #endif
0399 2:  .long   NR_syscalls
0400 3:  .long   sys_call_table
0401 7:  .long   do_syscall_trace_enter
0402 8:  .long   do_syscall_trace_leave