/* -*- mode: asm -*-1*2* linux/arch/m68k/kernel/entry.S3*4* Copyright (C) 1991, 1992 Linus Torvalds5*6* This file is subject to the terms and conditions of the GNU General Public7* License. See the file README.legal in the main directory of this archive8* for more details.9*10* Linux/m68k support by Hamish Macdonald11*12* 68060 fixes by Jesper Skov13*14*/1516/*17* entry.S contains the system-call and fault low-level handling routines.18* This also contains the timer-interrupt handler, as well as all interrupts19* and faults that can result in a task-switch.20*21* NOTE: This code handles signal-recognition, which happens every time22* after a timer-interrupt and after each system call.23*24*/2526/*27* 12/03/96 Jes: Currently we only support m68k single-cpu systems, so28* all pointers that used to be 'current' are now entry29* number 0 in the 'current_set' list.30*31* 6/05/00 RZ: addedd writeback completion after return from sighandler32* for 6804033*/3435#include <linux/linkage.h>36#include <asm/entry.h>37#include <asm/errno.h>38#include <asm/setup.h>39#include <asm/segment.h>40#include <asm/traps.h>41#include <asm/unistd.h>4243#include <asm/asm-offsets.h>4445.globl system_call, buserr, trap, resume46.globl sys_call_table47.globl sys_fork, sys_clone, sys_vfork48.globl ret_from_interrupt, bad_interrupt49.globl auto_irqhandler_fixup50.globl user_irqvec_fixup, user_irqhandler_fixup5152.text53ENTRY(buserr)54SAVE_ALL_INT55GET_CURRENT(%d0)56movel %sp,%sp@- | stack frame pointer argument57bsrl buserr_c58addql #4,%sp59jra .Lret_from_exception6061ENTRY(trap)62SAVE_ALL_INT63GET_CURRENT(%d0)64movel %sp,%sp@- | stack frame pointer argument65bsrl trap_c66addql #4,%sp67jra .Lret_from_exception6869| After a fork we jump here directly from resume,70| so that %d1 contains the previous task71| schedule_tail now used regardless of CONFIG_SMP72ENTRY(ret_from_fork)73movel %d1,%sp@-74jsr schedule_tail75addql #4,%sp76jra .Lret_from_exception7778do_trace_entry:79movel #-ENOSYS,%sp@(PT_OFF_D0)| needed for strace80subql #4,%sp81SAVE_SWITCH_STACK82jbsr syscall_trace83RESTORE_SWITCH_STACK84addql #4,%sp85movel %sp@(PT_OFF_ORIG_D0),%d086cmpl #NR_syscalls,%d087jcs syscall88badsys:89movel #-ENOSYS,%sp@(PT_OFF_D0)90jra ret_from_syscall9192do_trace_exit:93subql #4,%sp94SAVE_SWITCH_STACK95jbsr syscall_trace96RESTORE_SWITCH_STACK97addql #4,%sp98jra .Lret_from_exception99100ENTRY(ret_from_signal)101tstb %curptr@(TASK_INFO+TINFO_FLAGS+2)102jge 1f103jbsr syscall_trace1041: RESTORE_SWITCH_STACK105addql #4,%sp106/* on 68040 complete pending writebacks if any */107#ifdef CONFIG_M68040108bfextu %sp@(PT_OFF_FORMATVEC){#0,#4},%d0109subql #7,%d0 | bus error frame ?110jbne 1f111movel %sp,%sp@-112jbsr berr_040cleanup113addql #4,%sp1141:115#endif116jra .Lret_from_exception117118ENTRY(system_call)119SAVE_ALL_SYS120121GET_CURRENT(%d1)122| save top of frame123movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0)124125| syscall trace?126tstb %curptr@(TASK_INFO+TINFO_FLAGS+2)127jmi do_trace_entry128cmpl #NR_syscalls,%d0129jcc badsys130syscall:131jbsr @(sys_call_table,%d0:l:4)@(0)132movel %d0,%sp@(PT_OFF_D0) | save the return value133ret_from_syscall:134|oriw #0x0700,%sr135movew %curptr@(TASK_INFO+TINFO_FLAGS+2),%d0136jne syscall_exit_work1371: RESTORE_ALL138139syscall_exit_work:140btst #5,%sp@(PT_OFF_SR) | check if returning to kernel141bnes 1b | if so, skip resched, signals142lslw #1,%d0143jcs do_trace_exit144jmi do_delayed_trace145lslw #8,%d0146jmi do_signal_return147pea resume_userspace148jra schedule149150151ENTRY(ret_from_exception)152.Lret_from_exception:153btst #5,%sp@(PT_OFF_SR) | check if returning to kernel154bnes 1f | if so, skip resched, signals155| only allow interrupts when we are really the last one on the156| kernel stack, otherwise stack overflow can occur during157| heavy interrupt load158andw #ALLOWINT,%sr159160resume_userspace:161moveb %curptr@(TASK_INFO+TINFO_FLAGS+3),%d0162jne exit_work1631: RESTORE_ALL164165exit_work:166| save top of frame167movel %sp,%curptr@(TASK_THREAD+THREAD_ESP0)168lslb #1,%d0169jmi do_signal_return170pea resume_userspace171jra schedule172173174do_signal_return:175|andw #ALLOWINT,%sr176subql #4,%sp | dummy return address177SAVE_SWITCH_STACK178pea %sp@(SWITCH_STACK_SIZE)179bsrl do_signal180addql #4,%sp181RESTORE_SWITCH_STACK182addql #4,%sp183jbra resume_userspace184185do_delayed_trace:186bclr #7,%sp@(PT_OFF_SR) | clear trace bit in SR187pea 1 | send SIGTRAP188movel %curptr,%sp@-189pea LSIGTRAP190jbsr send_sig191addql #8,%sp192addql #4,%sp193jbra resume_userspace194195196/* This is the main interrupt handler for autovector interrupts */197198ENTRY(auto_inthandler)199SAVE_ALL_INT200GET_CURRENT(%d0)201addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)202| put exception # in d0203bfextu %sp@(PT_OFF_FORMATVEC){#4,#10},%d0204subw #VEC_SPUR,%d0205206movel %sp,%sp@-207movel %d0,%sp@- | put vector # on stack208auto_irqhandler_fixup = . + 2209jsr __m68k_handle_int | process the IRQ210addql #8,%sp | pop parameters off stack211212ret_from_interrupt:213subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)214jeq ret_from_last_interrupt2152: RESTORE_ALL216217ALIGN218ret_from_last_interrupt:219moveq #(~ALLOWINT>>8)&0xff,%d0220andb %sp@(PT_OFF_SR),%d0221jne 2b222223/* check if we need to do software interrupts */224tstl irq_stat+CPUSTAT_SOFTIRQ_PENDING225jeq .Lret_from_exception226pea ret_from_exception227jra do_softirq228229/* Handler for user defined interrupt vectors */230231ENTRY(user_inthandler)232SAVE_ALL_INT233GET_CURRENT(%d0)234addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)235| put exception # in d0236bfextu %sp@(PT_OFF_FORMATVEC){#4,#10},%d0237user_irqvec_fixup = . + 2238subw #VEC_USER,%d0239240movel %sp,%sp@-241movel %d0,%sp@- | put vector # on stack242user_irqhandler_fixup = . + 2243jsr __m68k_handle_int | process the IRQ244addql #8,%sp | pop parameters off stack245246subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)247jeq ret_from_last_interrupt248RESTORE_ALL249250/* Handler for uninitialized and spurious interrupts */251252ENTRY(bad_inthandler)253SAVE_ALL_INT254GET_CURRENT(%d0)255addqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)256257movel %sp,%sp@-258jsr handle_badint259addql #4,%sp260261subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)262jeq ret_from_last_interrupt263RESTORE_ALL264265266ENTRY(sys_fork)267SAVE_SWITCH_STACK268pea %sp@(SWITCH_STACK_SIZE)269jbsr m68k_fork270addql #4,%sp271RESTORE_SWITCH_STACK272rts273274ENTRY(sys_clone)275SAVE_SWITCH_STACK276pea %sp@(SWITCH_STACK_SIZE)277jbsr m68k_clone278addql #4,%sp279RESTORE_SWITCH_STACK280rts281282ENTRY(sys_vfork)283SAVE_SWITCH_STACK284pea %sp@(SWITCH_STACK_SIZE)285jbsr m68k_vfork286addql #4,%sp287RESTORE_SWITCH_STACK288rts289290ENTRY(sys_sigreturn)291SAVE_SWITCH_STACK292jbsr do_sigreturn293RESTORE_SWITCH_STACK294rts295296ENTRY(sys_rt_sigreturn)297SAVE_SWITCH_STACK298jbsr do_rt_sigreturn299RESTORE_SWITCH_STACK300rts301302resume:303/*304* Beware - when entering resume, prev (the current task) is305* in a0, next (the new task) is in a1,so don't change these306* registers until their contents are no longer needed.307*/308309/* save sr */310movew %sr,%a0@(TASK_THREAD+THREAD_SR)311312/* save fs (sfc,%dfc) (may be pointing to kernel memory) */313movec %sfc,%d0314movew %d0,%a0@(TASK_THREAD+THREAD_FS)315316/* save usp */317/* it is better to use a movel here instead of a movew 8*) */318movec %usp,%d0319movel %d0,%a0@(TASK_THREAD+THREAD_USP)320321/* save non-scratch registers on stack */322SAVE_SWITCH_STACK323324/* save current kernel stack pointer */325movel %sp,%a0@(TASK_THREAD+THREAD_KSP)326327/* save floating point context */328#ifndef CONFIG_M68KFPU_EMU_ONLY329#ifdef CONFIG_M68KFPU_EMU330tstl m68k_fputype331jeq 3f332#endif333fsave %a0@(TASK_THREAD+THREAD_FPSTATE)334335#if defined(CONFIG_M68060)336#if !defined(CPU_M68060_ONLY)337btst #3,m68k_cputype+3338beqs 1f339#endif340/* The 060 FPU keeps status in bits 15-8 of the first longword */341tstb %a0@(TASK_THREAD+THREAD_FPSTATE+2)342jeq 3f343#if !defined(CPU_M68060_ONLY)344jra 2f345#endif346#endif /* CONFIG_M68060 */347#if !defined(CPU_M68060_ONLY)3481: tstb %a0@(TASK_THREAD+THREAD_FPSTATE)349jeq 3f350#endif3512: fmovemx %fp0-%fp7,%a0@(TASK_THREAD+THREAD_FPREG)352fmoveml %fpcr/%fpsr/%fpiar,%a0@(TASK_THREAD+THREAD_FPCNTL)3533:354#endif /* CONFIG_M68KFPU_EMU_ONLY */355/* Return previous task in %d1 */356movel %curptr,%d1357358/* switch to new task (a1 contains new task) */359movel %a1,%curptr360361/* restore floating point context */362#ifndef CONFIG_M68KFPU_EMU_ONLY363#ifdef CONFIG_M68KFPU_EMU364tstl m68k_fputype365jeq 4f366#endif367#if defined(CONFIG_M68060)368#if !defined(CPU_M68060_ONLY)369btst #3,m68k_cputype+3370beqs 1f371#endif372/* The 060 FPU keeps status in bits 15-8 of the first longword */373tstb %a1@(TASK_THREAD+THREAD_FPSTATE+2)374jeq 3f375#if !defined(CPU_M68060_ONLY)376jra 2f377#endif378#endif /* CONFIG_M68060 */379#if !defined(CPU_M68060_ONLY)3801: tstb %a1@(TASK_THREAD+THREAD_FPSTATE)381jeq 3f382#endif3832: fmovemx %a1@(TASK_THREAD+THREAD_FPREG),%fp0-%fp7384fmoveml %a1@(TASK_THREAD+THREAD_FPCNTL),%fpcr/%fpsr/%fpiar3853: frestore %a1@(TASK_THREAD+THREAD_FPSTATE)3864:387#endif /* CONFIG_M68KFPU_EMU_ONLY */388389/* restore the kernel stack pointer */390movel %a1@(TASK_THREAD+THREAD_KSP),%sp391392/* restore non-scratch registers */393RESTORE_SWITCH_STACK394395/* restore user stack pointer */396movel %a1@(TASK_THREAD+THREAD_USP),%a0397movel %a0,%usp398399/* restore fs (sfc,%dfc) */400movew %a1@(TASK_THREAD+THREAD_FS),%a0401movec %a0,%sfc402movec %a0,%dfc403404/* restore status register */405movew %a1@(TASK_THREAD+THREAD_SR),%sr406407rts408409410411