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__restore_all: 182 mov #OFF_SR, r0 183 mov.l @(r0,r15), r0 ! get status register 184 185 shlr2 r0 186 and #0x3c, r0 187 cmp/eq #0x3c, r0 188 bt 1f 189 TRACE_IRQS_ON 190 bra 2f 191 nop 1921: 193 TRACE_IRQS_OFF 1942: 195 mov.l 3f, r0 196 jmp @r0 197 nop 198 199 .align 2 2003: .long restore_all 201 202 .align 2 203syscall_badsys: ! Bad syscall number 204 get_current_thread_info r8, r0 205 mov #-ENOSYS, r0 206 bra resume_userspace 207 mov.l r0, @(OFF_R0,r15) ! Return value 208 209/* 210 * The main debug trap handler. 211 * 212 * r8=TRA (not the trap number!) 213 * 214 * Note: This assumes that the trapa value is left in its original 215 * form (without the shlr2 shift) so the calculation for the jump 216 * call table offset remains a simple in place mask. 217 */ 218debug_trap: 219 mov r8, r0 220 and #(0xf << 2), r0 221 mov.l 1f, r8 222 add r0, r8 223 mov.l @r8, r8 224 jsr @r8 225 nop 226 bra ret_from_exception 227 nop 228 CFI_ENDPROC 229 230 .align 2 2311: .long debug_trap_table 232 233/* 234 * Syscall interface: 235 * 236 * Syscall #: R3 237 * Arguments #0 to #3: R4--R7 238 * Arguments #4 to #6: R0, R1, R2 239 * TRA: See following table. 240 * 241 * (TRA>>2) Purpose 242 * -------- ------- 243 * 0x00-0x0f original SH-3/4 syscall ABI (not in general use). 244 * 0x10-0x1f general SH-3/4 syscall ABI. 245 * 0x1f unified SH-2/3/4 syscall ABI (preferred). 246 * 0x20-0x2f original SH-2 syscall ABI. 247 * 0x30-0x3f debug traps used by the kernel. 248 * 0x40-0xff Not supported by all parts, so left unhandled. 249 * 250 * For making system calls, any trap number in the range for the 251 * given cpu model may be used, but the unified trap number 0x1f is 252 * preferred for compatibility with all models. 253 * 254 * The low bits of the trap number were once documented as matching 255 * the number of arguments, but they were never actually used as such 256 * by the kernel. SH-2 originally used its own separate trap range 257 * because several hardware exceptions fell in the range used for the 258 * SH-3/4 syscall ABI. 259 * 260 * This code also handles delegating other traps to the BIOS/gdb stub. 261 * 262 * Note: When we're first called, the TRA value must be shifted 263 * right 2 bits in order to get the value that was used as the "trapa" 264 * argument. 265 */ 266 267 .align 2 268 .globl ret_from_fork 269ret_from_fork: 270 mov.l 1f, r8 271 jsr @r8 272 mov r0, r4 273 bra syscall_exit 274 nop 275 276 .align 2 277 .globl ret_from_kernel_thread 278ret_from_kernel_thread: 279 mov.l 1f, r8 280 jsr @r8 281 mov r0, r4 282 mov.l @(OFF_R5,r15), r5 ! fn 283 jsr @r5 284 mov.l @(OFF_R4,r15), r4 ! arg 285 bra syscall_exit 286 nop 287 288 .align 2 2891: .long schedule_tail 290 291/* 292 * The poorly named main trapa decode and dispatch routine, for 293 * system calls and debug traps through their respective jump tables. 294 */ 295ENTRY(system_call) 296 setup_frame_reg 297#if !defined(CONFIG_CPU_SH2) 298 mov.l 1f, r9 299 mov.l @r9, r8 ! Read from TRA (Trap Address) Register 300#endif 301 302 mov #OFF_TRA, r10 303 add r15, r10 304 mov.l r8, @r10 ! set TRA value to tra 305 306 /* 307 * Check the trap type 308 */ 309 mov #((0x20 << 2) - 1), r9 310 cmp/hi r9, r8 311 bt/s debug_trap ! it's a debug trap.. 312 nop 313 314 TRACE_IRQS_ON 315 sti 316 317 ! 318 get_current_thread_info r8, r10 319 mov.l @(TI_FLAGS,r8), r8 320 mov #(_TIF_WORK_SYSCALL_MASK & 0xff), r10 321 mov #(_TIF_WORK_SYSCALL_MASK >> 8), r9 322 tst r10, r8 323 shll8 r9 324 bf syscall_trace_entry 325 tst r9, r8 326 bf syscall_trace_entry 327 ! 328 mov.l 6f, r8 ! Number of syscalls 329 cmp/hs r8, r3 330 bt syscall_badsys 331 ! 332syscall_call: 333 shll2 r3 ! x4 334 mov.l 3f, r8 ! Load the address of sys_call_table 335 add r8, r3 336 mov.l @r3, r8 337 mov.l @(OFF_R2,r15), r2 338 mov.l @(OFF_R1,r15), r1 339 mov.l @(OFF_R0,r15), r0 340 mov.l r2, @-r15 341 mov.l r1, @-r15 342 mov.l r0, @-r15 343 jsr @r8 ! jump to specific syscall handler 344 nop 345 add #12, r15 346 mov.l @(OFF_R0,r15), r12 ! save r0 347 mov.l r0, @(OFF_R0,r15) ! save the return value 348 ! 349syscall_exit: 350 cli 351 TRACE_IRQS_OFF 352 ! 353 get_current_thread_info r8, r0 354 mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags 355 tst #(_TIF_ALLWORK_MASK & 0xff), r0 356 mov #(_TIF_ALLWORK_MASK >> 8), r1 357 bf syscall_exit_work 358 shlr8 r0 359 tst r0, r1 360 bf syscall_exit_work 361 bra __restore_all 362 nop 363 364 .align 2 365syscall_trace_entry: 366 ! Yes it is traced. 367 mov r15, r4 368 mov.l 7f, r11 ! Call do_syscall_trace_enter which notifies 369 jsr @r11 ! superior (will chomp R[0-7]) 370 nop 371 cmp/eq #-1, r0 372 bt syscall_exit 373 ! Reload R0-R4 from kernel stack, where the 374 ! parent may have modified them using 375 ! ptrace(POKEUSR). (Note that R0-R2 are 376 ! reloaded from the kernel stack by syscall_call 377 ! below, so don't need to be reloaded here.) 378 ! This allows the parent to rewrite system calls 379 ! and args on the fly. 380 mov.l @(OFF_R4,r15), r4 ! arg0 381 mov.l @(OFF_R5,r15), r5 382 mov.l @(OFF_R6,r15), r6 383 mov.l @(OFF_R7,r15), r7 ! arg3 384 mov.l @(OFF_R3,r15), r3 ! syscall_nr 385 ! 386 mov.l 6f, r10 ! Number of syscalls 387 cmp/hs r10, r3 388 bf syscall_call 389 mov #-ENOSYS, r0 390 bra syscall_exit 391 mov.l r0, @(OFF_R0,r15) ! Return value 392 393 .align 2 394#if !defined(CONFIG_CPU_SH2) 3951: .long TRA 396#endif 3976: .long NR_syscalls 3983: .long sys_call_table 3997: .long do_syscall_trace_enter 4008: .long do_syscall_trace_leave 401