root/arch/sh/kernel/entry-common.S

/* [<][>][^][v][top][bottom][index][help] */
   1 /* SPDX-License-Identifier: GPL-2.0
   2  *
   3  *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
   4  *  Copyright (C) 2003 - 2008  Paul Mundt
   5  */
   6 
   7 ! NOTE:
   8 ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
   9 ! to be jumped is too far, but it causes illegal slot exception.
  10 
  11 /*      
  12  * entry.S contains the system-call and fault low-level handling routines.
  13  * This also contains the timer-interrupt handler, as well as all interrupts
  14  * and faults that can result in a task-switch.
  15  *
  16  * NOTE: This code handles signal-recognition, which happens every time
  17  * after a timer-interrupt and after each system call.
  18  *
  19  * NOTE: This code uses a convention that instructions in the delay slot
  20  * of a transfer-control instruction are indented by an extra space, thus:
  21  *
  22  *    jmp       @k0         ! control-transfer instruction
  23  *     ldc      k1, ssr     ! delay slot
  24  *
  25  * Stack layout in 'ret_from_syscall':
  26  *      ptrace needs to have all regs on the stack.
  27  *      if the order here is changed, it needs to be
  28  *      updated in ptrace.c and ptrace.h
  29  *
  30  *      r0
  31  *      ...
  32  *      r15 = stack pointer
  33  *      spc
  34  *      pr
  35  *      ssr
  36  *      gbr
  37  *      mach
  38  *      macl
  39  *      syscall #
  40  *
  41  */
  42 #include <asm/dwarf.h>
  43 
  44 #if defined(CONFIG_PREEMPT)
  45 #  define preempt_stop()        cli ; TRACE_IRQS_OFF
  46 #else
  47 #  define preempt_stop()
  48 #  define resume_kernel         __restore_all
  49 #endif
  50 
  51 
  52         .align  2
  53 ENTRY(exception_error)
  54         !
  55         TRACE_IRQS_ON
  56         sti
  57         mov.l   1f, r0
  58         jmp     @r0
  59          nop
  60 
  61         .align  2
  62 1:      .long   do_exception_error
  63 
  64         .align  2
  65 ret_from_exception:
  66         CFI_STARTPROC simple
  67         CFI_DEF_CFA r14, 0
  68         CFI_REL_OFFSET 17, 64
  69         CFI_REL_OFFSET 15, 60
  70         CFI_REL_OFFSET 14, 56
  71         CFI_REL_OFFSET 13, 52
  72         CFI_REL_OFFSET 12, 48
  73         CFI_REL_OFFSET 11, 44
  74         CFI_REL_OFFSET 10, 40
  75         CFI_REL_OFFSET 9, 36
  76         CFI_REL_OFFSET 8, 32
  77         preempt_stop()
  78 ENTRY(ret_from_irq)
  79         !
  80         mov     #OFF_SR, r0
  81         mov.l   @(r0,r15), r0   ! get status register
  82         shll    r0
  83         shll    r0              ! kernel space?
  84         get_current_thread_info r8, r0
  85         bt      resume_kernel   ! Yes, it's from kernel, go back soon
  86 
  87 #ifdef CONFIG_PREEMPT
  88         bra     resume_userspace
  89          nop
  90 ENTRY(resume_kernel)
  91         cli
  92         TRACE_IRQS_OFF
  93         mov.l   @(TI_PRE_COUNT,r8), r0  ! current_thread_info->preempt_count
  94         tst     r0, r0
  95         bf      noresched
  96 need_resched:
  97         mov.l   @(TI_FLAGS,r8), r0      ! current_thread_info->flags
  98         tst     #_TIF_NEED_RESCHED, r0  ! need_resched set?
  99         bt      noresched
 100 
 101         mov     #OFF_SR, r0
 102         mov.l   @(r0,r15), r0           ! get status register
 103         shlr    r0
 104         and     #(0xf0>>1), r0          ! interrupts off (exception path)?
 105         cmp/eq  #(0xf0>>1), r0
 106         bt      noresched
 107         mov.l   1f, r0
 108         jsr     @r0                     ! call preempt_schedule_irq
 109          nop
 110         bra     need_resched
 111          nop
 112 
 113 noresched:
 114         bra     __restore_all
 115          nop
 116 
 117         .align 2
 118 1:      .long   preempt_schedule_irq
 119 #endif
 120 
 121 ENTRY(resume_userspace)
 122         ! r8: current_thread_info
 123         cli
 124         TRACE_IRQS_OFF
 125         mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
 126         tst     #(_TIF_WORK_MASK & 0xff), r0
 127         bt/s    __restore_all
 128          tst    #_TIF_NEED_RESCHED, r0
 129 
 130         .align  2
 131 work_pending:
 132         ! r0: current_thread_info->flags
 133         ! r8: current_thread_info
 134         ! t:  result of "tst    #_TIF_NEED_RESCHED, r0"
 135         bf/s    work_resched
 136          tst    #(_TIF_SIGPENDING | _TIF_NOTIFY_RESUME), r0
 137 work_notifysig:
 138         bt/s    __restore_all
 139          mov    r15, r4
 140         mov     r12, r5         ! set arg1(save_r0)
 141         mov     r0, r6
 142         sti
 143         mov.l   2f, r1
 144         mov.l   3f, r0
 145         jmp     @r1
 146          lds    r0, pr
 147 work_resched:
 148         mov.l   1f, r1
 149         jsr     @r1                             ! schedule
 150          nop
 151         cli
 152         TRACE_IRQS_OFF
 153         !
 154         mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
 155         tst     #(_TIF_WORK_MASK & 0xff), r0
 156         bt      __restore_all
 157         bra     work_pending
 158          tst    #_TIF_NEED_RESCHED, r0
 159 
 160         .align  2
 161 1:      .long   schedule
 162 2:      .long   do_notify_resume
 163 3:      .long   resume_userspace
 164 
 165         .align  2
 166 syscall_exit_work:
 167         ! r0: current_thread_info->flags
 168         ! r8: current_thread_info
 169         tst     #(_TIF_WORK_SYSCALL_MASK & 0xff), r0
 170         bt/s    work_pending
 171          tst    #_TIF_NEED_RESCHED, r0
 172         TRACE_IRQS_ON
 173         sti
 174         mov     r15, r4
 175         mov.l   8f, r0                  ! do_syscall_trace_leave
 176         jsr     @r0
 177          nop
 178         bra     resume_userspace
 179          nop
 180 
 181         .align  2
 182 syscall_trace_entry:
 183         !                       Yes it is traced.
 184         mov     r15, r4
 185         mov.l   7f, r11         ! Call do_syscall_trace_enter which notifies
 186         jsr     @r11            ! superior (will chomp R[0-7])
 187          nop
 188         mov.l   r0, @(OFF_R0,r15)       ! Save return value
 189         !                       Reload R0-R4 from kernel stack, where the
 190         !                       parent may have modified them using
 191         !                       ptrace(POKEUSR).  (Note that R0-R2 are
 192         !                       reloaded from the kernel stack by syscall_call
 193         !                       below, so don't need to be reloaded here.)
 194         !                       This allows the parent to rewrite system calls
 195         !                       and args on the fly.
 196         mov.l   @(OFF_R4,r15), r4   ! arg0
 197         mov.l   @(OFF_R5,r15), r5
 198         mov.l   @(OFF_R6,r15), r6
 199         mov.l   @(OFF_R7,r15), r7   ! arg3
 200         mov.l   @(OFF_R3,r15), r3   ! syscall_nr
 201         !
 202         mov.l   2f, r10                 ! Number of syscalls
 203         cmp/hs  r10, r3
 204         bf      syscall_call
 205         mov     #-ENOSYS, r0
 206         bra     syscall_exit
 207          mov.l  r0, @(OFF_R0,r15)       ! Return value
 208 
 209 __restore_all:
 210         mov     #OFF_SR, r0
 211         mov.l   @(r0,r15), r0   ! get status register
 212 
 213         shlr2   r0
 214         and     #0x3c, r0
 215         cmp/eq  #0x3c, r0
 216         bt      1f
 217         TRACE_IRQS_ON
 218         bra     2f
 219          nop
 220 1:
 221         TRACE_IRQS_OFF
 222 2:
 223         mov.l   3f, r0
 224         jmp     @r0
 225          nop
 226 
 227         .align  2
 228 3:      .long   restore_all
 229 
 230         .align  2
 231 syscall_badsys:                 ! Bad syscall number
 232         get_current_thread_info r8, r0
 233         mov     #-ENOSYS, r0
 234         bra     resume_userspace
 235          mov.l  r0, @(OFF_R0,r15)       ! Return value
 236 
 237 /*
 238  * The main debug trap handler.
 239  *
 240  * r8=TRA (not the trap number!)
 241  *
 242  * Note: This assumes that the trapa value is left in its original
 243  * form (without the shlr2 shift) so the calculation for the jump
 244  * call table offset remains a simple in place mask.
 245  */
 246 debug_trap:
 247         mov     r8, r0
 248         and     #(0xf << 2), r0
 249         mov.l   1f, r8
 250         add     r0, r8
 251         mov.l   @r8, r8
 252         jsr     @r8
 253          nop
 254         bra     ret_from_exception
 255          nop
 256         CFI_ENDPROC
 257 
 258         .align  2
 259 1:      .long   debug_trap_table
 260 
 261 /*
 262  * Syscall interface:
 263  *
 264  *      Syscall #: R3
 265  *      Arguments #0 to #3: R4--R7
 266  *      Arguments #4 to #6: R0, R1, R2
 267  *      TRA: See following table.
 268  *
 269  * (TRA>>2)     Purpose
 270  * --------     -------
 271  * 0x00-0x0f    original SH-3/4 syscall ABI (not in general use).
 272  * 0x10-0x1f    general SH-3/4 syscall ABI.
 273  *      0x1f    unified SH-2/3/4 syscall ABI (preferred).
 274  * 0x20-0x2f    original SH-2 syscall ABI.
 275  * 0x30-0x3f    debug traps used by the kernel.
 276  * 0x40-0xff    Not supported by all parts, so left unhandled.
 277  *
 278  * For making system calls, any trap number in the range for the
 279  * given cpu model may be used, but the unified trap number 0x1f is
 280  * preferred for compatibility with all models.
 281  *
 282  * The low bits of the trap number were once documented as matching
 283  * the number of arguments, but they were never actually used as such
 284  * by the kernel. SH-2 originally used its own separate trap range
 285  * because several hardware exceptions fell in the range used for the
 286  * SH-3/4 syscall ABI.
 287  *
 288  * This code also handles delegating other traps to the BIOS/gdb stub.
 289  *
 290  * Note: When we're first called, the TRA value must be shifted
 291  * right 2 bits in order to get the value that was used as the "trapa"
 292  * argument.
 293  */
 294 
 295         .align  2
 296         .globl  ret_from_fork
 297 ret_from_fork:
 298         mov.l   1f, r8
 299         jsr     @r8
 300          mov    r0, r4
 301         bra     syscall_exit
 302          nop
 303 
 304         .align  2
 305         .globl  ret_from_kernel_thread
 306 ret_from_kernel_thread:
 307         mov.l   1f, r8
 308         jsr     @r8
 309          mov    r0, r4
 310         mov.l   @(OFF_R5,r15), r5   ! fn
 311         jsr     @r5
 312          mov.l  @(OFF_R4,r15), r4   ! arg
 313         bra     syscall_exit
 314          nop
 315 
 316         .align  2
 317 1:      .long   schedule_tail
 318 
 319 /*
 320  * The poorly named main trapa decode and dispatch routine, for
 321  * system calls and debug traps through their respective jump tables.
 322  */
 323 ENTRY(system_call)
 324         setup_frame_reg
 325 #if !defined(CONFIG_CPU_SH2)
 326         mov.l   1f, r9
 327         mov.l   @r9, r8         ! Read from TRA (Trap Address) Register
 328 #endif
 329 
 330         mov     #OFF_TRA, r10
 331         add     r15, r10
 332         mov.l   r8, @r10                ! set TRA value to tra
 333 
 334         /*
 335          * Check the trap type
 336          */
 337         mov     #((0x20 << 2) - 1), r9
 338         cmp/hi  r9, r8
 339         bt/s    debug_trap              ! it's a debug trap..
 340          nop
 341 
 342         TRACE_IRQS_ON
 343         sti
 344 
 345         !
 346         get_current_thread_info r8, r10
 347         mov.l   @(TI_FLAGS,r8), r8
 348         mov     #(_TIF_WORK_SYSCALL_MASK & 0xff), r10
 349         mov     #(_TIF_WORK_SYSCALL_MASK >> 8), r9
 350         tst     r10, r8
 351         shll8   r9
 352         bf      syscall_trace_entry
 353         tst     r9, r8
 354         bf      syscall_trace_entry
 355         !
 356         mov.l   2f, r8                  ! Number of syscalls
 357         cmp/hs  r8, r3
 358         bt      syscall_badsys
 359         !
 360 syscall_call:
 361         shll2   r3              ! x4
 362         mov.l   3f, r8          ! Load the address of sys_call_table
 363         add     r8, r3
 364         mov.l   @r3, r8
 365         mov.l   @(OFF_R2,r15), r2
 366         mov.l   @(OFF_R1,r15), r1
 367         mov.l   @(OFF_R0,r15), r0
 368         mov.l   r2, @-r15
 369         mov.l   r1, @-r15
 370         mov.l   r0, @-r15
 371         jsr     @r8             ! jump to specific syscall handler
 372          nop
 373         add     #12, r15
 374         mov.l   @(OFF_R0,r15), r12              ! save r0
 375         mov.l   r0, @(OFF_R0,r15)               ! save the return value
 376         !
 377 syscall_exit:
 378         cli
 379         TRACE_IRQS_OFF
 380         !
 381         get_current_thread_info r8, r0
 382         mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
 383         tst     #(_TIF_ALLWORK_MASK & 0xff), r0
 384         mov     #(_TIF_ALLWORK_MASK >> 8), r1
 385         bf      syscall_exit_work
 386         shlr8   r0
 387         tst     r0, r1
 388         bf      syscall_exit_work
 389         bra     __restore_all
 390          nop
 391         .align  2
 392 #if !defined(CONFIG_CPU_SH2)
 393 1:      .long   TRA
 394 #endif
 395 2:      .long   NR_syscalls
 396 3:      .long   sys_call_table
 397 7:      .long   do_syscall_trace_enter
 398 8:      .long   do_syscall_trace_leave

/* [<][>][^][v][top][bottom][index][help] */