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_PREEMPTION) 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 53ENTRY(exception_error) 54 ! 55 TRACE_IRQS_ON 56 sti 57 mov.l 1f, r0 58 jmp @r0 59 nop 60 61 .align 2 621: .long do_exception_error 63 64 .align 2 65ret_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() 78ENTRY(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_PREEMPTION 88 bra resume_userspace 89 nop 90ENTRY(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 96need_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 113noresched: 114 bra __restore_all 115 nop 116 117 .align 2 1181: .long preempt_schedule_irq 119#endif 120 121ENTRY(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 131work_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 137work_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 147work_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 1611: .long schedule 1622: .long do_notify_resume 1633: .long resume_userspace 164 165 .align 2 166syscall_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 182syscall_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 2201: 221 TRACE_IRQS_OFF 2222: 223 mov.l 3f, r0 224 jmp @r0 225 nop 226 227 .align 2 2283: .long restore_all 229 230 .align 2 231syscall_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 */ 246debug_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 2591: .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 297ret_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 306ret_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 3171: .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 */ 323ENTRY(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 ! 360syscall_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 ! 377syscall_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) 3931: .long TRA 394#endif 3952: .long NR_syscalls 3963: .long sys_call_table 3977: .long do_syscall_trace_enter 3988: .long do_syscall_trace_leave 399