entry.s

来自「Linux Kernel 2.6.9 for OMAP1710」· S 代码 · 共 1,094 行 · 第 1/3 页

S
1,094
字号
	cmpu.w	NR_syscalls, $r9		bcc	ret_from_sys_call	lslq	2, $r9		;  multiply by 4, in the delay slot	;; as a bonus 7th parameter, we give the location on the stack	;; of the register structure itself. some syscalls need this.	push	$sp		;; the parameter carrying registers r10, r11, r12 and 13 are intact.	;; the fifth and sixth parameters (if any) was in mof and srp 	;; respectively, and we need to put them on the stack.	push	$srp	push	$mof		jsr	[$r9+sys_call_table]	; actually do the system call	addq	3*4, $sp		; pop the mof, srp and regs parameters	move.d	$r10, [$sp+PT_r10]	; save the return value	moveq	1, $r9		; "parameter" to ret_from_sys_call to show it was a sys call		;; fall through into ret_from_sys_call to return	ret_from_sys_call:	;; r9 is a parameter - if >=1 we came from a syscall, if 0, from an irq			;; get the current task-struct pointer (see top for defs)	movs.w	-8192, $r0	; THREAD_SIZE == 8192 	and.d	$sp, $r0	di			; make sure need_resched and sigpending don't change	move.d	[$r0+TI_flags],$r1	and.d	_TIF_ALLWORK_MASK, $r1	bne	_syscall_exit_work	nop_Rexit:	;; this epilogue MUST match the prologues in multiple_interrupt, irq.h and ptregs.h	pop	$r10		; frametype	bne	_RBFexit	; was not CRIS_FRAME_NORMAL, handle otherwise	addq	4, $sp		; skip orig_r10, in delayslot	movem	[$sp+], $r13	; registers r0-r13	pop	$mof		; multiply overflow register 	pop	$dccr		; condition codes	pop	$srp		; subroutine return pointer	;; now we have a 4-word SBFS frame which we do not want to restore	;; using RBF since it was not stacked with SBFS. instead we would like to	;; just get the PC value to restart it with, and skip the rest of	;; the frame.	;; Also notice that it's important to use instructions here that	;; keep the interrupts disabled (since we've already popped DCCR)	move	[$sp=$sp+16], $p8; pop the SBFS frame from the sp	jmpu	[$sp-16]	; return through the irp field in the sbfs frame_RBFexit:	movem	[$sp+], $r13	; registers r0-r13, in delay slot	pop	$mof		; multiply overflow register 	pop	$dccr		; condition codes	pop	$srp		; subroutine return pointer	rbf	[$sp+]		; return by popping the CPU status	;; We get here after doing a syscall if extra work might need to be done	;; perform syscall exit tracing if needed	_syscall_exit_work:	;; $r0 contains current at this point and irq's are disabled	move.d  [$r0+TI_flags], $r1	btstq	TIF_SYSCALL_TRACE, $r1	bpl	_work_pending	nop		ei	move.d	$r9, $r1	; preserve r9	jsr	do_syscall_trace	move.d	$r1, $r9		ba	_resume_userspace	nop	_work_pending:	move.d  [$r0+TI_flags], $r1	btstq   TIF_NEED_RESCHED, $r1	bpl	_work_notifysig	; was neither trace nor sched, must be signal/notify	nop	_work_resched:	move.d	$r9, $r1	; preserve r9	jsr	schedule	move.d	$r1, $r9	di	move.d	[$r0+TI_flags], $r1	and.d	_TIF_WORK_MASK, $r1; ignore the syscall trace counter	beq	_Rexit	nop	btstq	TIF_NEED_RESCHED, $r1	bmi	_work_resched	; current->work.need_resched	nop_work_notifysig:	;; deal with pending signals and notify-resume requests	move.d	$r9, $r10	; do_notify_resume syscall/irq param	moveq	0, $r11		; oldset param - 0 in this case	move.d	$sp, $r12	; the regs param	move.d  $r1, $r13	; the thread_info_flags parameter	jsr	do_notify_resume		ba _Rexit	nop	;; We get here as a sidetrack when we've entered a syscall with the	;; trace-bit set. We need to call do_syscall_trace and then continue	;; with the call.	_syscall_trace_entry:	;; PT_r10 in the frame contains -ENOSYS as required, at this point		jsr	do_syscall_trace	;; now re-enter the syscall code to do the syscall itself	;; we need to restore $r9 here to contain the wanted syscall, and	;; the other parameter-bearing registers	move.d	[$sp+PT_r9], $r9	move.d	[$sp+PT_orig_r10], $r10  ; PT_r10 is already filled with -ENOSYS.	move.d	[$sp+PT_r11],      $r11	move.d	[$sp+PT_r12],      $r12	move.d	[$sp+PT_r13],      $r13	move	[$sp+PT_mof],      $mof	move	[$sp+PT_srp],      $srp		ba	_syscall_traced	nop		;; resume performs the actual task-switching, by switching stack pointers	;; input arguments: r10 = prev, r11 = next, r12 = thread offset in task struct	;; returns old current in r10	;;	;; TODO:  see the i386 version. The switch_to which calls resume in our version	;;        could really be an inline asm of this.resume:		push	$srp		         ; we keep the old/new PC on the stack 	add.d	$r12, $r10		 ; r10 = current tasks tss	move	$dccr, [$r10+THREAD_dccr]; save irq enable state	di	move	$usp, [$r10+ THREAD_usp] ; save user-mode stackpointer		;; See copy_thread for the reason why register R9 is saved.	subq	10*4, $sp	movem	$r9, [$sp]		 ; save non-scratch registers and R9.		move.d	$sp, [$r10+THREAD_ksp]	 ; save the kernel stack pointer for the old task	move.d	$sp, $r10		 ; return last running task in r10	and.d   -8192, $r10	         ; get thread_info from stackpointer	move.d  [$r10+TI_task], $r10     ; get task  	add.d	$r12, $r11		 ; find the new tasks tss	move.d	[$r11+THREAD_ksp], $sp	 ; switch into the new stackframe by restoring kernel sp	movem	[$sp+], $r9		 ; restore non-scratch registers and R9.	move	[$r11+THREAD_usp], $usp ; restore user-mode stackpointer		move	[$r11+THREAD_dccr], $dccr ; restore irq enable status	jump	[$sp+]		         ; restore PC	;; This is the MMU bus fault handler.	;; It needs to stack the CPU status and overall is different	;; from the other interrupt handlers.mmu_bus_fault:		sbfs	[$sp=$sp-16]	; push the internal CPU status	;; the first longword in the sbfs frame was the interrupted PC	;; which fits nicely with the "IRP" slot in pt_regs normally used to	;; contain the return address. used by Oops to print kernel errors..	push	$srp		; make a stackframe similar to pt_regs	push	$dccr	push	$mof	di	subq	14*4, $sp	movem	$r13, [$sp]	push	$r10		; dummy orig_r10	moveq	1, $r10	push	$r10		; frametype == 1, BUSFAULT frame type	move.d	$sp, $r10	; pt_regs argument to handle_mmu_bus_fault			jsr	handle_mmu_bus_fault  ; in arch/cris/mm/fault.c	;; now we need to return through the normal path, we cannot just	;; do the RBFexit since we might have killed off the running	;; process due to a SEGV, scheduled due to a page blocking or	;; whatever.	moveq	0, $r9		; busfault is equivalent to an irq			ba	ret_from_intr	nop			;; special handlers for breakpoint and NMI#if 0			hwbreakpoint:	push	$dccr	di	push	$r10	push	$r11	push	$r12	push	$r13	clearf	b	move	$brp,$r11	move.d	[hw_bp_msg],$r10	jsr	printk	setf	b	pop	$r13	pop	$r12	pop	$r11	pop	$r10	pop	$dccr	retb	nop#elsehwbreakpoint:	push	$dccr	di#if 1	push	$r10	push	$r11	move.d	[hw_bp_trig_ptr],$r10	move.d	[$r10],$r11	cmp.d	42,$r11	beq	1f	nop	move	$brp,$r11	move.d	$r11,[$r10+]	move.d	$r10,[hw_bp_trig_ptr]1:	pop	$r11	pop	$r10#endif	pop	$dccr	retb	nop#endif	IRQ1_interrupt:#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM);; If we receive a watchdog interrupt while it is not expected, then set;; up a canonical frame and dump register contents before dying.	;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!!	move	$brp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame	push	$srp	push	$dccr	push	$mof	di	subq	14*4, $sp	movem	$r13, [$sp]	push	$r10		; push orig_r10	clear.d [$sp=$sp-4]	; frametype == 0, normal frame;; We don't check that we actually were bit by the watchdog as opposed to;; an external NMI, since there is currently no handler for external NMI.;; Check if we're waiting for reset to happen, as signalled by;; hard_reset_now setting cause_of_death to a magic value.  If so, just;; get stuck until reset happens.	.comm	cause_of_death, 4	;; Don't declare this anywhere.	move.d	[cause_of_death], $r10	cmp.d	0xbedead, $r10_killed_by_death:	beq	_killed_by_death	nop;; We'll see this in ksymoops dumps.Watchdog_bite:#ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY       ;; We just restart the watchdog here to be sure we dont get       ;; hit while printing the watchdogmsg below       ;; This restart is compatible with the rest of the C-code, so       ;; the C-code can keep restarting the watchdog after this point.       ;; The non-NICE_DOGGY code below though, disables the possibility       ;; to restart since it changes the watchdog key, to avoid any       ;; buggy loops etc. keeping the watchdog alive after this.       jsr     reset_watchdog#else;; We need to extend the 3.3ms after the NMI at watchdog bite, so we have;; time for an oops-dump over a 115k2 serial wire.  Another 100ms should do.;; Change the watchdog key to an arbitrary 3-bit value and restart the;; watchdog.#define WD_INIT 2	moveq	  IO_FIELD (R_WATCHDOG, key, WD_INIT), $r10	move.d	R_WATCHDOG, $r11	move.d	$r10, [$r11]	moveq	  IO_FIELD (R_WATCHDOG, key,				\			    IO_EXTRACT (R_WATCHDOG, key,		\					IO_MASK (R_WATCHDOG, key))	\			    ^ WD_INIT)					\		| IO_STATE (R_WATCHDOG, enable, start), $r10	move.d	$r10, [$r11]#endif	;; Note that we don't do "setf m" here (or after two necessary NOPs),;; since *not* doing that saves us from re-entrancy checks.  We don't want;; to get here again due to possible subsequent NMIs; we want the watchdog;; to reset us.	move.d	_watchdogmsg,$r10	jsr	printk	move.d	$sp, $r10	jsr	watchdog_bite_hook;; This nop is here so we see the "Watchdog_bite" label in ksymoops dumps;; rather than "spurious_interrupt".	nop;; At this point we drop down into spurious_interrupt, which will do a;; hard reset.	.section .rodata,"a"_watchdogmsg:	.ascii	"Oops: bitten by watchdog\n\0"	.previous#endif /* CONFIG_ETRAX_WATCHDOG and not CONFIG_SVINTO_SIM */spurious_interrupt:		di	jump hard_reset_now	;; this handles the case when multiple interrupts arrive at the same time	;; we jump to the first set interrupt bit in a priority fashion	;; the hardware will call the unserved interrupts after the handler finishes	multiple_interrupt:	;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!!	move	$irp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame	push	$srp	push	$dccr	push	$mof	di	subq	14*4, $sp	movem	$r13, [$sp]	push	$r10		; push orig_r10	clear.d [$sp=$sp-4]	; frametype == 0, normal frame		move.d	irq_shortcuts + 8, $r1	moveq	2, $r2		; first bit we care about is the timer0 irq	move.d	[R_VECT_MASK_RD], $r0; read the irq bits that triggered the multiple irq1:		btst	$r2, $r0	; check for the irq given by bit r2	bmi	_do_shortcut	; actually do the shortcut	nop	addq	1, $r2		; next vector bit	addq	4, $r1		; next vector

⌨️ 快捷键说明

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