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