📄 entry.s
字号:
/* -*- mode: asm -*- * * linux/arch/m68knommu/platform/5307/entry.S * * Copyright (C) 1999 Greg Ungerer (gerg@snapgear.com) * Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>, * Kenneth Albanowski <kjahds@kjahds.com>, * Copyright (C) 2000 Lineo Inc. (www.lineo.com) * * Based on: * * linux/arch/m68k/kernel/entry.S * * Copyright (C) 1991, 1992 Linus Torvalds * * This file is subject to the terms and conditions of the GNU General Public * License. See the file README.legal in the main directory of this archive * for more details. * * Linux/m68k support by Hamish Macdonald * * 68060 fixes by Jesper Skov * ColdFire support by Greg Ungerer (gerg@snapgear.com) * 5307 fixes by David W. Miller * linux 2.4 support David McCullough <davidm@lineo.com> *//* * entry.S contains the system-call and fault low-level handling routines. * This also contains the timer-interrupt handler, as well as all interrupts * and faults that can result in a task-switch. * * NOTE: This code handles signal-recognition, which happens every time * after a timer-interrupt and after each system call. * * Stack layout in 'ret_from_exception': * * This allows access to the syscall arguments in registers d1-d5 * * 0(sp) - d1 * 4(sp) - d2 * 8(sp) - d3 * C(sp) - d4 * 10(sp) - d5 * 14(sp) - a0 * 18(sp) - a1 * 1C(sp) - a2 * 20(sp) - d0 * 24(sp) - orig_d0 * 28(sp) - stack adjustment * 2C(sp) - format & vector } * 2E(sp) - sr } different to m68k * 30(sp) - pc } */#include <linux/sys.h>#include <linux/config.h>#include <linux/linkage.h>#include <asm/setup.h>#include <asm/segment.h>#include "m68k_defs.h"LENOSYS = 38/* the following macro is used when enabling interrupts */#define ALLOWINT 0xf8ff#define MAX_NOINT_IPL 0LD0 = 0x20LORIG_D0 = 0x24LFORMATVEC = 0x2cLSR = 0x2eLPC = 0x30/* * This defines the normal kernel pt-regs layout. * * regs are a2-a6 and d6-d7 preserved by C code * the kernel doesn't mess with usp unless it needs to * * This is made a little more tricky on the ColdFire. There is no * separate kernel and user stack pointers. Need to artificially * construct a usp in software... When doing this we need to disable * interrupts, otherwise bad things could happen. */#define SAVE_ALL \ move #0x2700,%sr; /* disable intrs */ \ btst #5,%sp@(2); /* from user? */ \ bnes 6f; /* no, skip */ \ movel %sp,sw_usp; /* save user sp */ \ addql #8,sw_usp; /* remove exception */ \ movel sw_ksp,%sp; /* kernel sp */ \ subql #8,%sp; /* room for exception */\ clrl %sp@-; /* stk_adj */ \ movel %d0,%sp@-; /* orig d0 */ \ movel %d0,%sp@-; /* d0 */ \ subl #32,%sp; /* space for 8 regs */ \ moveml %d1-%d5/%a0-%a2,%sp@; \ movel sw_usp,%a0; /* get usp */ \ moveml %a0@(-8),%d1-%d2; /* get exception */ \ moveml %d1-%d2,%sp@(LFORMATVEC); /* copy exception */ \ bra 7f; \ 6: \ clrl %sp@-; /* stk_adj */ \ movel %d0,%sp@-; /* orig d0 */ \ movel %d0,%sp@-; /* d0 */ \ subl #32,%sp; /* space for 7 regs */ \ moveml %d1-%d5/%a0-%a2,%sp@; \ 7:#define RESTORE_ALL \ btst #5,%sp@(LSR); /* going user? */ \ bnes 8f; /* no, skip */ \ move #0x2700,%sr; /* disable intrs */ \ movel sw_usp,%a0; /* get usp */ \ moveml %sp@(LFORMATVEC),%d1-%d2; /* copy exception */ \ moveml %d1-%d2,%a0@(-8); \ moveml %sp@,%d1-%d5/%a0-%a2; \ addl #32,%sp; /* space for 8 regs */ \ movel %sp@+,%d0; \ addql #4,%sp; /* orig d0 */ \ addl %sp@+,%sp; /* stk adj */ \ addql #8,%sp; /* remove exception */ \ movel %sp,sw_ksp; /* save ksp */ \ subql #8,sw_usp; /* set exception */ \ movel sw_usp,%sp; /* restore usp */ \ rte; \ 8: \ moveml %sp@,%d1-%d5/%a0-%a2; \ addl #32,%sp; /* space for 8 regs */ \ movel %sp@+,%d0; \ addql #4,%sp; /* orig d0 */ \ addl %sp@+,%sp; /* stk adj */ \ rte/* * Quick exception save, use current stack only. */#define SAVE_LOCAL \ move #0x2700,%sr; /* disable intrs */ \ clrl %sp@-; /* stk_adj */ \ movel %d0,%sp@-; /* orig d0 */ \ movel %d0,%sp@-; /* d0 */ \ subl #32,%sp; /* space for 8 regs */ \ moveml %d1-%d5/%a0-%a2,%sp@;#define RESTORE_LOCAL \ moveml %sp@,%d1-%d5/%a0-%a2; \ addl #32,%sp; /* space for 8 regs */ \ movel %sp@+,%d0; \ addql #4,%sp; /* orig d0 */ \ addl %sp@+,%sp; /* stk adj */ \ rte#define SWITCH_STACK_SIZE (6*4+4) /* includes return address */#define SAVE_SWITCH_STACK \ subl #24,%sp; /* 6 regs */ \ moveml %a3-%a6/%d6-%d7,%sp@#define RESTORE_SWITCH_STACK \ moveml %sp@,%a3-%a6/%d6-%d7; \ addl #24,%sp /* 6 regs *//* * Software copy of the user and kernel stack pointers... Ugh... * Need these to get around ColdFire not having separate kernel * and user stack pointers. */.globl SYMBOL_NAME(sw_usp).globl SYMBOL_NAME(sw_ksp).datasw_ksp:.long 0sw_usp:.long 0.text.globl SYMBOL_NAME(buserr).globl SYMBOL_NAME(trap).globl SYMBOL_NAME(system_call).globl SYMBOL_NAME(resume), SYMBOL_NAME(ret_from_exception).globl SYMBOL_NAME(ret_from_signal).globl SYMBOL_NAME(sys_call_table).globl SYMBOL_NAME(sys_fork), SYMBOL_NAME(sys_clone), SYMBOL_NAME(sys_vfork).globl SYMBOL_NAME(ret_from_interrupt).globl SYMBOL_NAME(inthandler).globl SYMBOL_NAME(fasthandler)#ifdef TRAP_DBG_INTERRUPT.globl SYMBOL_NAME(dbginterrupt)#endif.textENTRY(buserr) SAVE_ALL moveq #-1,%d0 movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field | signifies that the stack frame | is NOT for syscall movel %sp,%sp@- | stack frame pointer argument jsr SYMBOL_NAME(buserr_c) addql #4,%sp jra SYMBOL_NAME(ret_from_exception)#ifdef TRAP_DBG_INTERRUPTENTRY(dbginterrupt) SAVE_ALL moveq #-1,%d0 movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field | signifies that the stack frame | is NOT for syscall movel %sp,%sp@- | stack frame pointer argument jsr SYMBOL_NAME(dbginterrupt_c) addql #4,%sp jra SYMBOL_NAME(ret_from_exception)#endifENTRY(reschedule) | save top of frame pea %sp@ jbsr SYMBOL_NAME(set_esp0) addql #4,%sp pea SYMBOL_NAME(ret_from_exception) jmp SYMBOL_NAME(schedule) | After a fork we jump here directly from resume, | so that %d1 contains the previous task | Theoretically only needed on SMP, but lets watch | what happens in schedule_tail() in future...ENTRY(ret_from_fork) movel %d1,%sp@- jsr SYMBOL_NAME(schedule_tail) addql #4,%sp jra SYMBOL_NAME(ret_from_exception)ENTRY(system_call) SAVE_ALL move #0x2000,%sr; | enable intrs again movel #-LENOSYS,%d2 movel %d2,LD0(%sp) | default return value in d0 | original D0 is in orig_d0 movel %d0,%d2 | save top of frame pea %sp@ jbsr SYMBOL_NAME(set_esp0) addql #4,%sp cmpl #NR_syscalls,%d2 jcc SYMBOL_NAME(ret_from_exception) lea SYMBOL_NAME(sys_call_table),%a0 lsll #2,%d2 | movel %a0@(%d2:l:4),%d3 movel %a0@(%d2),%d3 jeq SYMBOL_NAME(ret_from_exception) lsrl #2,%d2 movel SYMBOL_NAME(_current_task),%a0 btst #1,%a0@(TASK_PTRACE+3) | PT_TRACESYS bnes 1f movel %d3,%a0 jbsr %a0@ movel %d0,%sp@(LD0) | save the return value jra SYMBOL_NAME(ret_from_exception)1: subql #4,%sp SAVE_SWITCH_STACK jbsr SYMBOL_NAME(syscall_trace) RESTORE_SWITCH_STACK addql #4,%sp movel %d3,%a0 jbsr %a0@ movel %d0,%sp@(LD0) | save the return value subql #4,%sp | dummy return address SAVE_SWITCH_STACK jbsr SYMBOL_NAME(syscall_trace)SYMBOL_NAME_LABEL(ret_from_signal) RESTORE_SWITCH_STACK addql #4,%spSYMBOL_NAME_LABEL(ret_from_exception) btst #5,%sp@(LSR) | check if returning to kernel bnes 2f | if so, skip resched, signals | tstl SYMBOL_NAME(need_resched) | jne SYMBOL_NAME(reschedule) movel SYMBOL_NAME(_current_task),%a0 tstl %a0@(TASK_NEEDRESCHED) jne SYMBOL_NAME(reschedule)#if 0 /* as per m68k */ cmpl #SYMBOL_NAME(task),%a0 | task[0] cannot have signals jeq 2f#endif bclr #2,%a0@(TASK_PTRACE+3) | check for delayed trace jeq 1f bclr #7,%sp@(LSR) | clear trace bit in SR pea 1 | send SIGTRAP movel %a0,%sp@- pea 5 jbsr SYMBOL_NAME(send_sig) addql #8,%sp addql #4,%sp movel SYMBOL_NAME(_current_task),%a01: tstl %a0@(TASK_STATE) | state jne SYMBOL_NAME(reschedule) tstl %a0@(TASK_COUNTER) | counter jeq SYMBOL_NAME(reschedule) movel %a0@(TASK_BLOCKED),%d0 notl %d0 btst #0,%a0@(TASK_PTRACE+3) | PT_PTRACED jeq 1f moveq #-1,%d0 | let the debugger see all signals1: andl %a0@(TASK_SIGPENDING),%d0 jne Lsignal_return2: RESTORE_ALL | Does RTELsignal_return: subql #4,%sp | dummy return address SAVE_SWITCH_STACK pea %sp@(SWITCH_STACK_SIZE) clrl %sp@- jsr SYMBOL_NAME(do_signal) addql #8,%sp RESTORE_SWITCH_STACK addql #4,%sp btst #5,%sp@(LSR); /* going user? */ bnes not_user; /* no, skip */ move #0x2700,%sr; /* disable intrs */ movel sw_usp,%a0; /* get usp */ moveml %sp@(LFORMATVEC),%d1-%d2; /* copy exception */ moveml %d1-%d2,%a0@(-8); bclr #5,%a0@(-8); /* clear format byte, bit 5 to make stack appear modulo 4 which it WILL be when we do the rte because it was generated in setup_frame */ bclr #4,%a0@(-8); /* clear format byte, bit 4 to make stack appear modulo 4 which it WILL be when we do the rte because it was generated in setup_frame */ /* * if an app is getting tricky and using "a5", the signal handler * may trigger while "a5" is invalid, so we have to set it here */ jsr SYMBOL_NAME(get_pic_a5) movel %d0, %a5 moveml %sp@,%d1-%d5/%a0-%a2; addl #32,%sp; /* space for 8 regs */ movel %sp@+,%d0; addql #4,%sp; /* orig d0 */ addl %sp@+,%sp; /* stk adj */ addql #8,%sp; /* remove exception */ movel %sp,sw_ksp; /* save ksp */ movel sw_usp,%sp; /* restore usp */ subql #8,%sp; /* set exception */ rte; not_user: moveml %sp@,%d1-%d5/%a0-%a2; addl #32,%sp; /* space for 8 regs */ movel %sp@+,%d0; addql #4,%sp; /* orig d0 */ addl %sp@+,%sp; /* stk adj */ rte/*--------------------------------------------------------------------------*//* * Common ColdFire trap handler. Most traps come through here first. */ENTRY(trap) SAVE_ALL moveq #-1,%d0 movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field | signifies that the stack frame | is NOT for syscall movel %sp,%sp@- | stack frame pointer argument jsr SYMBOL_NAME(trap_c) addql #4,%sp jra SYMBOL_NAME(ret_from_exception)/* * This is the generic interrupt handler (for all hardware interrupt * sources). It figures out the vector number and calls the appropriate * interrupt service routine directly. */SYMBOL_NAME_LABEL(inthandler) SAVE_ALL moveq #-1,%d0 movel %d0,%sp@(LORIG_D0) | a -1 in the ORIG_D0 field | signifies that the stack frame | is NOT for syscall addql #1,SYMBOL_NAME(local_irq_count) | put exception # in d0 movew %sp@(LFORMATVEC),%d0 andl #0x03fc,%d0 | mask out vector only movel SYMBOL_NAME(mach_kstat_irqs),%a0 | get addr of kstat struct addql #1,%a0@(%d0) | incr irq intr count lsrl #2,%d0 | calculate real vector # movel %d0,%d1 | calculate array offset lsll #4,%d1 lea SYMBOL_NAME(irq_list),%a0 addl %d1,%a0 | pointer to array struct movel %sp,%sp@- | push regs arg onto stack movel %a0@(8),%sp@- | push devid arg movel %d0,%sp@- | push vector # on stack
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -