>> 1 /* SPDX-License-Identifier: GPL-2.0-or-later >> 2 * -*- mode: asm -*- >> 3 * >> 4 * linux/arch/m68k/kernel/entry.S >> 5 * >> 6 * Copyright (C) 1991, 1992 Linus Torvalds >> 7 * >> 8 * Linux/m68k support by Hamish Macdonald >> 9 * >> 10 * 68060 fixes by Jesper Skov >> 11 * >> 12 */ >> 13 1 /* 14 /* 2 * This file is subject to the terms and condi !! 15 * entry.S contains the system-call and fault low-level handling routines. 3 * License. See the file "COPYING" in the mai !! 16 * This also contains the timer-interrupt handler, as well as all interrupts 4 * for more details. !! 17 * and faults that can result in a task-switch. 5 * !! 18 * 6 * Copyright (C) 1994 - 2000, 2001, 2003 Ralf !! 19 * NOTE: This code handles signal-recognition, which happens every time 7 * Copyright (C) 1999, 2000 Silicon Graphics, !! 20 * after a timer-interrupt and after each system call. 8 * Copyright (C) 2001 MIPS Technologies, Inc. !! 21 * 9 */ 22 */ 10 23 11 #include <asm/asm.h> !! 24 /* 12 #include <asm/asmmacro.h> !! 25 * 12/03/96 Jes: Currently we only support m68k single-cpu systems, so 13 #include <asm/compiler.h> !! 26 * all pointers that used to be 'current' are now entry 14 #include <asm/irqflags.h> !! 27 * number 0 in the 'current_set' list. 15 #include <asm/regdef.h> !! 28 * 16 #include <asm/mipsregs.h> !! 29 * 6/05/00 RZ: addedd writeback completion after return from sighandler 17 #include <asm/stackframe.h> !! 30 * for 68040 18 #include <asm/isadep.h> !! 31 */ 19 #include <asm/thread_info.h> << 20 32 21 #ifndef CONFIG_PREEMPTION !! 33 #include <linux/linkage.h> 22 #define resume_kernel restore_all !! 34 #include <asm/errno.h> 23 #else !! 35 #include <asm/setup.h> 24 #define __ret_from_irq ret_from_exception !! 36 #include <asm/traps.h> >> 37 #include <asm/unistd.h> >> 38 #include <asm/asm-offsets.h> >> 39 #include <asm/entry.h> >> 40 >> 41 .globl system_call, buserr, trap, resume >> 42 .globl sys_call_table >> 43 .globl __sys_fork, __sys_clone, __sys_vfork >> 44 .globl bad_interrupt >> 45 .globl auto_irqhandler_fixup >> 46 .globl user_irqvec_fixup >> 47 >> 48 .text >> 49 ENTRY(__sys_fork) >> 50 SAVE_SWITCH_STACK >> 51 jbsr sys_fork >> 52 lea %sp@(24),%sp >> 53 rts >> 54 >> 55 ENTRY(__sys_clone) >> 56 SAVE_SWITCH_STACK >> 57 pea %sp@(SWITCH_STACK_SIZE) >> 58 jbsr m68k_clone >> 59 lea %sp@(28),%sp >> 60 rts >> 61 >> 62 ENTRY(__sys_vfork) >> 63 SAVE_SWITCH_STACK >> 64 jbsr sys_vfork >> 65 lea %sp@(24),%sp >> 66 rts >> 67 >> 68 ENTRY(__sys_clone3) >> 69 SAVE_SWITCH_STACK >> 70 pea %sp@(SWITCH_STACK_SIZE) >> 71 jbsr m68k_clone3 >> 72 lea %sp@(28),%sp >> 73 rts >> 74 >> 75 ENTRY(sys_sigreturn) >> 76 SAVE_SWITCH_STACK >> 77 movel %sp,%a1 | switch_stack pointer >> 78 lea %sp@(SWITCH_STACK_SIZE),%a0 | pt_regs pointer >> 79 lea %sp@(-84),%sp | leave a gap >> 80 movel %a1,%sp@- >> 81 movel %a0,%sp@- >> 82 jbsr do_sigreturn >> 83 jra 1f | shared with rt_sigreturn() >> 84 >> 85 ENTRY(sys_rt_sigreturn) >> 86 SAVE_SWITCH_STACK >> 87 movel %sp,%a1 | switch_stack pointer >> 88 lea %sp@(SWITCH_STACK_SIZE),%a0 | pt_regs pointer >> 89 lea %sp@(-84),%sp | leave a gap >> 90 movel %a1,%sp@- >> 91 movel %a0,%sp@- >> 92 | stack contents: >> 93 | [original pt_regs address] [original switch_stack address] >> 94 | [gap] [switch_stack] [pt_regs] [exception frame] >> 95 jbsr do_rt_sigreturn >> 96 >> 97 1: >> 98 | stack contents now: >> 99 | [original pt_regs address] [original switch_stack address] >> 100 | [unused part of the gap] [moved switch_stack] [moved pt_regs] >> 101 | [replacement exception frame] >> 102 | return value of do_{rt_,}sigreturn() points to moved switch_stack. >> 103 >> 104 movel %d0,%sp | discard the leftover junk >> 105 RESTORE_SWITCH_STACK >> 106 | stack contents now is just [syscall return address] [pt_regs] [frame] >> 107 | return pt_regs.d0 >> 108 movel %sp@(PT_OFF_D0+4),%d0 >> 109 rts >> 110 >> 111 ENTRY(buserr) >> 112 SAVE_ALL_INT >> 113 GET_CURRENT(%d0) >> 114 movel %sp,%sp@- | stack frame pointer argument >> 115 jbsr buserr_c >> 116 addql #4,%sp >> 117 jra ret_from_exception >> 118 >> 119 ENTRY(trap) >> 120 SAVE_ALL_INT >> 121 GET_CURRENT(%d0) >> 122 movel %sp,%sp@- | stack frame pointer argument >> 123 jbsr trap_c >> 124 addql #4,%sp >> 125 jra ret_from_exception >> 126 >> 127 | After a fork we jump here directly from resume, >> 128 | so that %d1 contains the previous task >> 129 | schedule_tail now used regardless of CONFIG_SMP >> 130 ENTRY(ret_from_fork) >> 131 movel %d1,%sp@- >> 132 jsr schedule_tail >> 133 addql #4,%sp >> 134 jra ret_from_exception >> 135 >> 136 ENTRY(ret_from_kernel_thread) >> 137 | a3 contains the kernel thread payload, d7 - its argument >> 138 movel %d1,%sp@- >> 139 jsr schedule_tail >> 140 movel %d7,(%sp) >> 141 jsr %a3@ >> 142 addql #4,%sp >> 143 jra ret_from_exception >> 144 >> 145 #if defined(CONFIG_COLDFIRE) || !defined(CONFIG_MMU) >> 146 >> 147 #ifdef TRAP_DBG_INTERRUPT >> 148 >> 149 .globl dbginterrupt >> 150 ENTRY(dbginterrupt) >> 151 SAVE_ALL_INT >> 152 GET_CURRENT(%d0) >> 153 movel %sp,%sp@- /* stack frame pointer argument */ >> 154 jsr dbginterrupt_c >> 155 addql #4,%sp >> 156 jra ret_from_exception 25 #endif 157 #endif 26 158 27 .text !! 159 ENTRY(reschedule) 28 .align 5 !! 160 /* save top of frame */ 29 #ifndef CONFIG_PREEMPTION !! 161 pea %sp@ 30 FEXPORT(ret_from_exception) !! 162 jbsr set_esp0 31 local_irq_disable !! 163 addql #4,%sp 32 b __ret_from_irq !! 164 pea ret_from_exception 33 #endif !! 165 jmp schedule 34 FEXPORT(ret_from_irq) !! 166 35 LONG_S s0, TI_REGS($28) !! 167 ENTRY(ret_from_user_signal) 36 FEXPORT(__ret_from_irq) !! 168 moveq #__NR_sigreturn,%d0 37 /* !! 169 trap #0 38 * We can be coming here from a syscall done i !! 170 39 * e.g. a failed kernel_execve(). !! 171 ENTRY(ret_from_user_rt_signal) 40 */ !! 172 movel #__NR_rt_sigreturn,%d0 41 resume_userspace_check: !! 173 trap #0 42 LONG_L t0, PT_STATUS(sp) << 43 andi t0, t0, KU_USER << 44 beqz t0, resume_kernel << 45 174 46 resume_userspace: << 47 local_irq_disable # make << 48 # inte << 49 # betw << 50 LONG_L a2, TI_FLAGS($28) # curr << 51 andi t0, a2, _TIF_WORK_MASK # (ign << 52 bnez t0, work_pending << 53 j restore_all << 54 << 55 #ifdef CONFIG_PREEMPTION << 56 resume_kernel: << 57 local_irq_disable << 58 lw t0, TI_PRE_COUNT($28) << 59 bnez t0, restore_all << 60 LONG_L t0, TI_FLAGS($28) << 61 andi t1, t0, _TIF_NEED_RESCHED << 62 beqz t1, restore_all << 63 LONG_L t0, PT_STATUS(sp) << 64 andi t0, 1 << 65 beqz t0, restore_all << 66 PTR_LA ra, restore_all << 67 j preempt_schedule_irq << 68 #endif << 69 << 70 FEXPORT(ret_from_kernel_thread) << 71 jal schedule_tail # a0 = << 72 move a0, s1 << 73 jal s0 << 74 j syscall_exit << 75 << 76 FEXPORT(ret_from_fork) << 77 jal schedule_tail # a0 = << 78 << 79 FEXPORT(syscall_exit) << 80 #ifdef CONFIG_DEBUG_RSEQ << 81 move a0, sp << 82 jal rseq_syscall << 83 #endif << 84 local_irq_disable # make << 85 # sign << 86 # samp << 87 LONG_L a2, TI_FLAGS($28) # curr << 88 li t0, _TIF_ALLWORK_MASK << 89 and t0, a2, t0 << 90 bnez t0, syscall_exit_work << 91 << 92 restore_all: # rest << 93 .set noat << 94 RESTORE_TEMP << 95 RESTORE_AT << 96 RESTORE_STATIC << 97 restore_partial: # restore part << 98 #ifdef CONFIG_TRACE_IRQFLAGS << 99 SAVE_STATIC << 100 SAVE_AT << 101 SAVE_TEMP << 102 LONG_L v0, PT_STATUS(sp) << 103 #if defined(CONFIG_CPU_R3000) << 104 and v0, ST0_IEP << 105 #else 175 #else 106 and v0, ST0_IE !! 176 107 #endif !! 177 do_trace_entry: 108 beqz v0, 1f !! 178 movel #-ENOSYS,%sp@(PT_OFF_D0)| needed for strace 109 jal trace_hardirqs_on !! 179 subql #4,%sp 110 b 2f !! 180 SAVE_SWITCH_STACK 111 1: jal trace_hardirqs_off !! 181 jbsr syscall_trace_enter 112 2: !! 182 RESTORE_SWITCH_STACK 113 RESTORE_TEMP !! 183 addql #4,%sp 114 RESTORE_AT !! 184 addql #1,%d0 | optimization for cmpil #-1,%d0 115 RESTORE_STATIC !! 185 jeq ret_from_syscall 116 #endif !! 186 movel %sp@(PT_OFF_ORIG_D0),%d0 117 RESTORE_SOME !! 187 cmpl #NR_syscalls,%d0 118 RESTORE_SP_AND_RET !! 188 jcs syscall 119 .set at !! 189 jra ret_from_syscall 120 !! 190 badsys: 121 work_pending: !! 191 movel #-ENOSYS,%sp@(PT_OFF_D0) 122 andi t0, a2, _TIF_NEED_RESCHED # a2 !! 192 jra ret_from_syscall 123 beqz t0, work_notifysig !! 193 124 work_resched: !! 194 do_trace_exit: 125 TRACE_IRQS_OFF !! 195 subql #4,%sp 126 jal schedule !! 196 SAVE_SWITCH_STACK 127 !! 197 jbsr syscall_trace_leave 128 local_irq_disable # make !! 198 RESTORE_SWITCH_STACK 129 # sign !! 199 addql #4,%sp 130 # samp !! 200 jra .Lret_from_exception 131 LONG_L a2, TI_FLAGS($28) !! 201 132 andi t0, a2, _TIF_WORK_MASK # is t !! 202 ENTRY(system_call) 133 # othe !! 203 SAVE_ALL_SYS 134 beqz t0, restore_all !! 204 135 andi t0, a2, _TIF_NEED_RESCHED !! 205 GET_CURRENT(%d1) 136 bnez t0, work_resched !! 206 movel %d1,%a1 137 !! 207 138 work_notifysig: # deal !! 208 | save top of frame 139 # noti !! 209 movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0) 140 move a0, sp !! 210 141 li a1, 0 !! 211 | syscall trace? 142 jal do_notify_resume # a2 a !! 212 tstb %a1@(TINFO_FLAGS+2) 143 j resume_userspace_check !! 213 jmi do_trace_entry 144 !! 214 | seccomp filter active? 145 FEXPORT(syscall_exit_partial) !! 215 btst #5,%a1@(TINFO_FLAGS+2) 146 #ifdef CONFIG_DEBUG_RSEQ !! 216 bnes do_trace_entry 147 move a0, sp !! 217 cmpl #NR_syscalls,%d0 148 jal rseq_syscall !! 218 jcc badsys 149 #endif !! 219 syscall: 150 local_irq_disable # make !! 220 jbsr @(sys_call_table,%d0:l:4)@(0) 151 # chan !! 221 movel %d0,%sp@(PT_OFF_D0) | save the return value 152 LONG_L a2, TI_FLAGS($28) # curr !! 222 ret_from_syscall: 153 li t0, _TIF_ALLWORK_MASK !! 223 |oriw #0x0700,%sr 154 and t0, a2 !! 224 movel %curptr@(TASK_STACK),%a1 155 beqz t0, restore_partial !! 225 movew %a1@(TINFO_FLAGS+2),%d0 156 SAVE_STATIC !! 226 jne syscall_exit_work >> 227 1: RESTORE_ALL >> 228 157 syscall_exit_work: 229 syscall_exit_work: 158 LONG_L t0, PT_STATUS(sp) !! 230 btst #5,%sp@(PT_OFF_SR) | check if returning to kernel 159 andi t0, t0, KU_USER !! 231 bnes 1b | if so, skip resched, signals 160 beqz t0, resume_kernel !! 232 lslw #1,%d0 161 li t0, _TIF_WORK_SYSCALL_EXIT !! 233 jcs do_trace_exit 162 and t0, a2 # a2 i !! 234 jmi do_delayed_trace 163 beqz t0, work_pending # trac !! 235 lslw #8,%d0 164 local_irq_enable # coul !! 236 jne do_signal_return 165 # call !! 237 pea resume_userspace 166 TRACE_IRQS_ON !! 238 jra schedule 167 move a0, sp !! 239 168 jal syscall_trace_leave !! 240 169 b resume_userspace !! 241 ENTRY(ret_from_exception) >> 242 .Lret_from_exception: >> 243 btst #5,%sp@(PT_OFF_SR) | check if returning to kernel >> 244 bnes 1f | if so, skip resched, signals >> 245 | only allow interrupts when we are really the last one on the >> 246 | kernel stack, otherwise stack overflow can occur during >> 247 | heavy interrupt load >> 248 andw #ALLOWINT,%sr 170 249 171 #if defined(CONFIG_CPU_MIPSR2) || defined(CONF !! 250 resume_userspace: 172 defined(CONFIG_CPU_MIPSR6) || defined(CONF !! 251 movel %curptr@(TASK_STACK),%a1 >> 252 moveb %a1@(TINFO_FLAGS+3),%d0 >> 253 jne exit_work >> 254 1: RESTORE_ALL >> 255 >> 256 exit_work: >> 257 | save top of frame >> 258 movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0) >> 259 lslb #1,%d0 >> 260 jne do_signal_return >> 261 pea resume_userspace >> 262 jra schedule >> 263 >> 264 >> 265 do_signal_return: >> 266 |andw #ALLOWINT,%sr >> 267 subql #4,%sp | dummy return address >> 268 SAVE_SWITCH_STACK >> 269 pea %sp@(SWITCH_STACK_SIZE) >> 270 bsrl do_notify_resume >> 271 addql #4,%sp >> 272 RESTORE_SWITCH_STACK >> 273 addql #4,%sp >> 274 jbra resume_userspace >> 275 >> 276 do_delayed_trace: >> 277 bclr #7,%sp@(PT_OFF_SR) | clear trace bit in SR >> 278 pea 1 | send SIGTRAP >> 279 movel %curptr,%sp@- >> 280 pea LSIGTRAP >> 281 jbsr send_sig >> 282 addql #8,%sp >> 283 addql #4,%sp >> 284 jbra resume_userspace >> 285 >> 286 >> 287 /* This is the main interrupt handler for autovector interrupts */ >> 288 >> 289 ENTRY(auto_inthandler) >> 290 SAVE_ALL_INT >> 291 GET_CURRENT(%d0) >> 292 | put exception # in d0 >> 293 bfextu %sp@(PT_OFF_FORMATVEC){#4,#10},%d0 >> 294 subw #VEC_SPUR,%d0 >> 295 >> 296 movel %sp,%sp@- >> 297 movel %d0,%sp@- | put vector # on stack >> 298 auto_irqhandler_fixup = . + 2 >> 299 jsr do_IRQ | process the IRQ >> 300 addql #8,%sp | pop parameters off stack >> 301 jra ret_from_exception >> 302 >> 303 /* Handler for user defined interrupt vectors */ >> 304 >> 305 ENTRY(user_inthandler) >> 306 SAVE_ALL_INT >> 307 GET_CURRENT(%d0) >> 308 | put exception # in d0 >> 309 bfextu %sp@(PT_OFF_FORMATVEC){#4,#10},%d0 >> 310 user_irqvec_fixup = . + 2 >> 311 subw #VEC_USER,%d0 >> 312 >> 313 movel %sp,%sp@- >> 314 movel %d0,%sp@- | put vector # on stack >> 315 jsr do_IRQ | process the IRQ >> 316 addql #8,%sp | pop parameters off stack >> 317 jra ret_from_exception >> 318 >> 319 /* Handler for uninitialized and spurious interrupts */ >> 320 >> 321 ENTRY(bad_inthandler) >> 322 SAVE_ALL_INT >> 323 GET_CURRENT(%d0) >> 324 >> 325 movel %sp,%sp@- >> 326 jsr handle_badint >> 327 addql #4,%sp >> 328 jra ret_from_exception >> 329 >> 330 resume: >> 331 /* >> 332 * Beware - when entering resume, prev (the current task) is >> 333 * in a0, next (the new task) is in a1,so don't change these >> 334 * registers until their contents are no longer needed. >> 335 */ >> 336 >> 337 /* save sr */ >> 338 movew %sr,%a0@(TASK_THREAD+THREAD_SR) >> 339 >> 340 /* save fs (sfc,%dfc) (may be pointing to kernel memory) */ >> 341 movec %sfc,%d0 >> 342 movew %d0,%a0@(TASK_THREAD+THREAD_FC) >> 343 >> 344 /* save usp */ >> 345 /* it is better to use a movel here instead of a movew 8*) */ >> 346 movec %usp,%d0 >> 347 movel %d0,%a0@(TASK_THREAD+THREAD_USP) >> 348 >> 349 /* save non-scratch registers on stack */ >> 350 SAVE_SWITCH_STACK >> 351 >> 352 /* save current kernel stack pointer */ >> 353 movel %sp,%a0@(TASK_THREAD+THREAD_KSP) >> 354 >> 355 /* save floating point context */ >> 356 #ifndef CONFIG_M68KFPU_EMU_ONLY >> 357 #ifdef CONFIG_M68KFPU_EMU >> 358 tstl m68k_fputype >> 359 jeq 3f >> 360 #endif >> 361 fsave %a0@(TASK_THREAD+THREAD_FPSTATE) 173 362 174 /* !! 363 #if defined(CONFIG_M68060) 175 * MIPS32R2 Instruction Hazard Barrier - must !! 364 #if !defined(CPU_M68060_ONLY) 176 * !! 365 btst #3,m68k_cputype+3 177 * For C code use the inline version named ins !! 366 beqs 1f 178 */ !! 367 #endif 179 LEAF(mips_ihb) !! 368 /* The 060 FPU keeps status in bits 15-8 of the first longword */ 180 .set MIPS_ISA_LEVEL_RAW !! 369 tstb %a0@(TASK_THREAD+THREAD_FPSTATE+2) 181 jr.hb ra !! 370 jeq 3f 182 nop !! 371 #if !defined(CPU_M68060_ONLY) 183 END(mips_ihb) !! 372 jra 2f >> 373 #endif >> 374 #endif /* CONFIG_M68060 */ >> 375 #if !defined(CPU_M68060_ONLY) >> 376 1: tstb %a0@(TASK_THREAD+THREAD_FPSTATE) >> 377 jeq 3f >> 378 #endif >> 379 2: fmovemx %fp0-%fp7,%a0@(TASK_THREAD+THREAD_FPREG) >> 380 fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_THREAD+THREAD_FPCNTL) >> 381 3: >> 382 #endif /* CONFIG_M68KFPU_EMU_ONLY */ >> 383 /* Return previous task in %d1 */ >> 384 movel %curptr,%d1 >> 385 >> 386 /* switch to new task (a1 contains new task) */ >> 387 movel %a1,%curptr >> 388 >> 389 /* restore floating point context */ >> 390 #ifndef CONFIG_M68KFPU_EMU_ONLY >> 391 #ifdef CONFIG_M68KFPU_EMU >> 392 tstl m68k_fputype >> 393 jeq 4f >> 394 #endif >> 395 #if defined(CONFIG_M68060) >> 396 #if !defined(CPU_M68060_ONLY) >> 397 btst #3,m68k_cputype+3 >> 398 beqs 1f >> 399 #endif >> 400 /* The 060 FPU keeps status in bits 15-8 of the first longword */ >> 401 tstb %a1@(TASK_THREAD+THREAD_FPSTATE+2) >> 402 jeq 3f >> 403 #if !defined(CPU_M68060_ONLY) >> 404 jra 2f >> 405 #endif >> 406 #endif /* CONFIG_M68060 */ >> 407 #if !defined(CPU_M68060_ONLY) >> 408 1: tstb %a1@(TASK_THREAD+THREAD_FPSTATE) >> 409 jeq 3f >> 410 #endif >> 411 2: fmovemx %a1@(TASK_THREAD+THREAD_FPREG),%fp0-%fp7 >> 412 fmoveml %a1@(TASK_THREAD+THREAD_FPCNTL),%fpcr/%fpsr/%fpiar >> 413 3: frestore %a1@(TASK_THREAD+THREAD_FPSTATE) >> 414 4: >> 415 #endif /* CONFIG_M68KFPU_EMU_ONLY */ >> 416 >> 417 /* restore the kernel stack pointer */ >> 418 movel %a1@(TASK_THREAD+THREAD_KSP),%sp >> 419 >> 420 /* restore non-scratch registers */ >> 421 RESTORE_SWITCH_STACK >> 422 >> 423 /* restore user stack pointer */ >> 424 movel %a1@(TASK_THREAD+THREAD_USP),%a0 >> 425 movel %a0,%usp >> 426 >> 427 /* restore fs (sfc,%dfc) */ >> 428 movew %a1@(TASK_THREAD+THREAD_FC),%a0 >> 429 movec %a0,%sfc >> 430 movec %a0,%dfc >> 431 >> 432 /* restore status register */ >> 433 movew %a1@(TASK_THREAD+THREAD_SR),%d0 >> 434 oriw #0x0700,%d0 >> 435 movew %d0,%sr >> 436 >> 437 rts 184 438 185 #endif /* CONFIG_CPU_MIPSR2 - CONFIG_CPU_MIPSR !! 439 #endif /* CONFIG_MMU && !CONFIG_COLDFIRE */
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.