⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 entry.s

📁 linux 内核源代码
💻 S
📖 第 1 页 / 共 3 页
字号:
/* * File:         arch/blackfin/mach-common/entry.S * Based on: * Author:       Linus Torvalds * * Created:      ? * Description:  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. * * Modified: *               Copyright 2004-2006 Analog Devices Inc. * * Bugs:         Enter bugs at http://blackfin.uclinux.org/ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see the file COPYING, or write * to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA *//* NOTE: This code handles signal-recognition, which happens every time * after a timer-interrupt and after each system call. */#include <linux/init.h>#include <linux/linkage.h>#include <linux/unistd.h>#include <asm/blackfin.h>#include <asm/errno.h>#include <asm/thread_info.h>  /* TIF_NEED_RESCHED */#include <asm/asm-offsets.h>#include <asm/trace.h>#include <asm/mach-common/context.S>#if defined(CONFIG_BFIN_SCRATCH_REG_RETN)# define EX_SCRATCH_REG RETN#elif defined(CONFIG_BFIN_SCRATCH_REG_RETE)# define EX_SCRATCH_REG RETE#else# define EX_SCRATCH_REG CYCLES#endif#if ANOMALY_05000281ENTRY(_safe_speculative_execution)	NOP;	NOP;	NOP;	jump _safe_speculative_execution;ENDPROC(_safe_speculative_execution)#endif#ifdef CONFIG_EXCPT_IRQ_SYSC_L1.section .l1.text#else.text#endif/* Slightly simplified and streamlined entry point for CPLB misses. * This one does not lower the level to IRQ5, and thus can be used to * patch up CPLB misses on the kernel stack. */#if ANOMALY_05000261#define _ex_dviol _ex_workaround_261#define _ex_dmiss _ex_workaround_261#define _ex_dmult _ex_workaround_261ENTRY(_ex_workaround_261)	/*	 * Work around an anomaly: if we see a new DCPLB fault, return	 * without doing anything.  Then, if we get the same fault again,	 * handle it.	 */	P4 = R7;	/* Store EXCAUSE */	p5.l = _last_cplb_fault_retx;	p5.h = _last_cplb_fault_retx;	r7 = [p5];	r6 = retx;	[p5] = r6;	cc = r6 == r7;	if !cc jump _bfin_return_from_exception;	/* fall through */	R7 = P4;	R6 = 0x26;	/* Data CPLB Miss */	cc = R6 == R7;	if cc jump _ex_dcplb_miss (BP);	/* Handle 0x23 Data CPLB Protection Violation	 * and Data CPLB Multiple Hits - Linux Trap Zero	 */	jump _ex_trap_c;ENDPROC(_ex_workaround_261)#else#define _ex_dviol _ex_trap_c#define _ex_dmiss _ex_dcplb_miss#define _ex_dmult _ex_trap_c#endifENTRY(_ex_dcplb_miss)ENTRY(_ex_icplb_miss)	(R7:6,P5:4) = [sp++];	ASTAT = [sp++];	SAVE_ALL_SYS	call __cplb_hdr;	DEBUG_START_HWTRACE(p5, r7)	RESTORE_ALL_SYS	SP = EX_SCRATCH_REG;	rtx;ENDPROC(_ex_icplb_miss)ENTRY(_ex_syscall)	DEBUG_START_HWTRACE(p5, r7)	(R7:6,P5:4) = [sp++];	ASTAT = [sp++];	raise 15;		/* invoked by TRAP #0, for sys call */	sp = EX_SCRATCH_REG;	rtxENDPROC(_ex_syscall)ENTRY(_ex_soft_bp)	r7 = retx;	r7 += -2;	retx = r7;	jump.s _ex_trap_c;ENDPROC(_ex_soft_bp)ENTRY(_ex_single_step)	r7 = retx;	r6 = reti;	cc = r7 == r6;	if cc jump _bfin_return_from_exception	r7 = syscfg;	bitclr (r7, 0);	syscfg = R7;	p5.l = lo(IPEND);	p5.h = hi(IPEND);	r6 = [p5];	cc = bittst(r6, 5);	if !cc jump _ex_trap_c;	p4.l = lo(EVT5);	p4.h = hi(EVT5);	r6.h = _exception_to_level5;	r6.l = _exception_to_level5;	r7 = [p4];	cc = r6 == r7;	if !cc jump _ex_trap_c;ENDPROC(_ex_single_step)ENTRY(_bfin_return_from_exception)	DEBUG_START_HWTRACE(p5, r7)#if ANOMALY_05000257	R7=LC0;	LC0=R7;	R7=LC1;	LC1=R7;#endif	(R7:6,P5:4) = [sp++];	ASTAT = [sp++];	sp = EX_SCRATCH_REG;	rtx;ENDPROC(_bfin_return_from_exception)ENTRY(_handle_bad_cplb)	/* To get here, we just tried and failed to change a CPLB	 * so, handle things in trap_c (C code), by lowering to	 * IRQ5, just like we normally do. Since this is not a	 * "normal" return path, we have a do alot of stuff to	 * the stack to get ready so, we can fall through - we	 * need to make a CPLB exception look like a normal exception	 */	DEBUG_START_HWTRACE(p5, r7)	RESTORE_ALL_SYS	[--sp] = ASTAT;	[--sp] = (R7:6, P5:4);ENTRY(_ex_replaceable)	nop;ENTRY(_ex_trap_c)	/* Make sure we are not in a double fault */	p4.l = lo(IPEND);	p4.h = hi(IPEND);	r7 = [p4];	CC = BITTST (r7, 5);	if CC jump _double_fault;	/* Call C code (trap_c) to handle the exception, which most	 * likely involves sending a signal to the current process.	 * To avoid double faults, lower our priority to IRQ5 first.	 */	P5.h = _exception_to_level5;	P5.l = _exception_to_level5;	p4.l = lo(EVT5);	p4.h = hi(EVT5);	[p4] = p5;	csync;	/* Disable all interrupts, but make sure level 5 is enabled so	 * we can switch to that level.  Save the old mask.  */	cli r6;	p4.l = _excpt_saved_imask;	p4.h = _excpt_saved_imask;	[p4] = r6;	r6 = 0x3f;	sti r6;	/* Save the excause into a circular buffer, in case the instruction	 * which caused this excecptions causes others.	 */	P5.l = _in_ptr_excause;	P5.h = _in_ptr_excause;	R7 = [P5];	R7 += 4;	R6 = 0xF;	R7 = R7 & R6;	[P5] = R7;	R6.l = _excause_circ_buf;	R6.h = _excause_circ_buf;	R7 = R7 + R6;	p5 = R7;	R6 = SEQSTAT;	[P5] = R6;	DEBUG_START_HWTRACE(p5, r7)	(R7:6,P5:4) = [sp++];	ASTAT = [sp++];	SP = EX_SCRATCH_REG;	raise 5;	rtx;ENDPROC(_ex_trap_c)/* We just realized we got an exception, while we were processing a different * exception. This is a unrecoverable event, so crash */ENTRY(_double_fault)        /* Turn caches & protection off, to ensure we don't get any more         * double exceptions         */        P4.L = LO(IMEM_CONTROL);        P4.H = HI(IMEM_CONTROL);        R5 = [P4];              /* Control Register*/        BITCLR(R5,ENICPLB_P);        SSYNC;          /* SSYNC required before writing to IMEM_CONTROL. */        .align 8;        [P4] = R5;        SSYNC;        P4.L = LO(DMEM_CONTROL);        P4.H = HI(DMEM_CONTROL);        R5 = [P4];        BITCLR(R5,ENDCPLB_P);        SSYNC;          /* SSYNC required before writing to DMEM_CONTROL. */        .align 8;        [P4] = R5;        SSYNC;        /* Fix up the stack */        (R7:6,P5:4) = [sp++];        ASTAT = [sp++];        SP = EX_SCRATCH_REG;        /* We should be out of the exception stack, and back down into         * kernel or user space stack         */        SAVE_ALL_SYS        r0 = sp;        /* stack frame pt_regs pointer argument ==> r0 */        SP += -12;        call _double_fault_c;        SP += 12;.L_double_fault_panic:        JUMP .L_double_fault_panicENDPROC(_double_fault)ENTRY(_exception_to_level5)	SAVE_ALL_SYS	/* Restore interrupt mask.  We haven't pushed RETI, so this	 * doesn't enable interrupts until we return from this handler.  */	p4.l = _excpt_saved_imask;	p4.h = _excpt_saved_imask;	r6 = [p4];	sti r6;	/* Restore the hardware error vector.  */	P5.h = _evt_ivhw;	P5.l = _evt_ivhw;	p4.l = lo(EVT5);	p4.h = hi(EVT5);	[p4] = p5;	csync;	p2.l = lo(IPEND);	p2.h = hi(IPEND);	csync;	r0 = [p2];              /* Read current IPEND */	[sp + PT_IPEND] = r0;   /* Store IPEND */	/* Pop the excause from the circular buffer and push it on the stack	 * (in the right place - if you change the location of SEQSTAT, you	 * must change this offset.	 */.L_excep_to_5_again:	P5.l = _out_ptr_excause;	P5.h = _out_ptr_excause;	R7 = [P5];	R7 += 4;	R6 = 0xF;	R7 = R7 & R6;	[P5] = R7;	R6.l = _excause_circ_buf;	R6.h = _excause_circ_buf;	R7 = R7 + R6;	P5 = R7;	R1 = [P5];	[SP + 8] = r1;	r0 = sp; 	/* stack frame pt_regs pointer argument ==> r0 */	SP += -12;	call _trap_c;	SP += 12;	/* See if anything else is in the exception buffer	 * if there is, process it	 */	P5.l = _out_ptr_excause;	P5.h = _out_ptr_excause;	P4.l = _in_ptr_excause;	P4.h = _in_ptr_excause;	R6 = [P5];	R7 = [P4];	CC = R6 == R7;	if ! CC JUMP .L_excep_to_5_again	call _ret_from_exception;	RESTORE_ALL_SYS	rti;ENDPROC(_exception_to_level5)ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/	/* Since the kernel stack can be anywhere, it's not guaranteed to be	 * covered by a CPLB.  Switch to an exception stack; use RETN as a	 * scratch register (for want of a better option).	 */	EX_SCRATCH_REG = sp;	sp.l = _exception_stack_top;	sp.h = _exception_stack_top;	/* Try to deal with syscalls quickly.  */	[--sp] = ASTAT;	[--sp] = (R7:6, P5:4);	DEBUG_STOP_HWTRACE(p5, r7)	r7 = SEQSTAT;		/* reason code is in bit 5:0 */	r6.l = lo(SEQSTAT_EXCAUSE);	r6.h = hi(SEQSTAT_EXCAUSE);	r7 = r7 & r6;	p5.h = _ex_table;	p5.l = _ex_table;	p4 = r7;	p5 = p5 + (p4 << 2);	p4 = [p5];	jump (p4);.Lbadsys:	r7 = -ENOSYS; 		/* signextending enough */	[sp + PT_R0] = r7;	/* return value from system call */	jump .Lsyscall_really_exit;ENDPROC(_trap)ENTRY(_kernel_execve)	link SIZEOF_PTREGS;	p0 = sp;	r3 = SIZEOF_PTREGS / 4;	r4 = 0(x);0:	[p0++] = r4;	r3 += -1;	cc = r3 == 0;	if !cc jump 0b (bp);	p0 = sp;	sp += -16;	[sp + 12] = p0;	call _do_execve;	SP += 16;	cc = r0 == 0;	if ! cc jump 1f;	/* Success.  Copy our temporary pt_regs to the top of the kernel	 * stack and do a normal exception return.	 */	r1 = sp;	r0 = (-KERNEL_STACK_SIZE) (x);	r1 = r1 & r0;	p2 = r1;	p3 = [p2];	r0 = KERNEL_STACK_SIZE - 4 (z);	p1 = r0;	p1 = p1 + p2;	p0 = fp;	r4 = [p0--];	r3 = SIZEOF_PTREGS / 4;0:	r4 = [p0--];	[p1--] = r4;	r3 += -1;	cc = r3 == 0;	if ! cc jump 0b (bp);	r0 = (KERNEL_STACK_SIZE - SIZEOF_PTREGS) (z);	p1 = r0;	p1 = p1 + p2;	sp = p1;	r0 = syscfg;	[SP + PT_SYSCFG] = r0;	[p3 + (TASK_THREAD + THREAD_KSP)] = sp;	RESTORE_CONTEXT;	rti;1:	unlink;	rts;ENDPROC(_kernel_execve)ENTRY(_system_call)	/* Store IPEND */	p2.l = lo(IPEND);	p2.h = hi(IPEND);	csync;	r0 = [p2];	[sp + PT_IPEND] = r0;	/* Store RETS for now */	r0 = rets;	[sp + PT_RESERVED] = r0;	/* Set the stack for the current process */	r7 = sp;	r6.l = lo(ALIGN_PAGE_MASK);	r6.h = hi(ALIGN_PAGE_MASK);	r7 = r7 & r6;  		/* thread_info */	p2 = r7;	p2 = [p2];	[p2+(TASK_THREAD+THREAD_KSP)] = sp;	/* Check the System Call */	r7 = __NR_syscall;	/* System call number is passed in P0 */	r6 = p0;	cc = r6 < r7;	if ! cc jump .Lbadsys;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -