311 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			311 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
/*
 | 
						|
 * arch/sh/lib/mcount.S
 | 
						|
 *
 | 
						|
 *  Copyright (C) 2008, 2009  Paul Mundt
 | 
						|
 *  Copyright (C) 2008, 2009  Matt Fleming
 | 
						|
 *
 | 
						|
 * This file is subject to the terms and conditions of the GNU General Public
 | 
						|
 * License.  See the file "COPYING" in the main directory of this archive
 | 
						|
 * for more details.
 | 
						|
 */
 | 
						|
#include <asm/ftrace.h>
 | 
						|
#include <asm/thread_info.h>
 | 
						|
#include <asm/asm-offsets.h>
 | 
						|
 | 
						|
#define MCOUNT_ENTER()		\
 | 
						|
	mov.l	r4, @-r15;	\
 | 
						|
	mov.l	r5, @-r15;	\
 | 
						|
	mov.l	r6, @-r15;	\
 | 
						|
	mov.l	r7, @-r15;	\
 | 
						|
	sts.l	pr, @-r15;	\
 | 
						|
				\
 | 
						|
	mov.l	@(20,r15),r4;	\
 | 
						|
	sts	pr, r5
 | 
						|
 | 
						|
#define MCOUNT_LEAVE()		\
 | 
						|
	lds.l	@r15+, pr;	\
 | 
						|
	mov.l	@r15+, r7;	\
 | 
						|
	mov.l	@r15+, r6;	\
 | 
						|
	mov.l	@r15+, r5;	\
 | 
						|
	rts;			\
 | 
						|
	 mov.l	@r15+, r4
 | 
						|
 | 
						|
#ifdef CONFIG_STACK_DEBUG
 | 
						|
/*
 | 
						|
 * Perform diagnostic checks on the state of the kernel stack.
 | 
						|
 *
 | 
						|
 * Check for stack overflow. If there is less than 1KB free
 | 
						|
 * then it has overflowed.
 | 
						|
 *
 | 
						|
 * Make sure the stack pointer contains a valid address. Valid
 | 
						|
 * addresses for kernel stacks are anywhere after the bss
 | 
						|
 * (after _ebss) and anywhere in init_thread_union (init_stack).
 | 
						|
 */
 | 
						|
#define STACK_CHECK()					\
 | 
						|
	mov	#(THREAD_SIZE >> 10), r0;		\
 | 
						|
	shll8	r0;					\
 | 
						|
	shll2	r0;					\
 | 
						|
							\
 | 
						|
	/* r1 = sp & (THREAD_SIZE - 1) */		\
 | 
						|
	mov	#-1, r1;				\
 | 
						|
	add	r0, r1;					\
 | 
						|
	and	r15, r1;				\
 | 
						|
							\
 | 
						|
	mov	#TI_SIZE, r3;				\
 | 
						|
	mov	#(STACK_WARN >> 8), r2;			\
 | 
						|
	shll8	r2;					\
 | 
						|
	add	r3, r2;					\
 | 
						|
							\
 | 
						|
	/* Is the stack overflowing? */			\
 | 
						|
	cmp/hi	r2, r1;					\
 | 
						|
	bf	stack_panic;				\
 | 
						|
							\
 | 
						|
	/* If sp > _ebss then we're OK. */		\
 | 
						|
	mov.l	.L_ebss, r1;				\
 | 
						|
	cmp/hi	r1, r15;				\
 | 
						|
	bt	1f;					\
 | 
						|
							\
 | 
						|
	/* If sp < init_stack, we're not OK. */		\
 | 
						|
	mov.l	.L_init_thread_union, r1;		\
 | 
						|
	cmp/hs	r1, r15;				\
 | 
						|
	bf	stack_panic;				\
 | 
						|
							\
 | 
						|
	/* If sp > init_stack && sp < _ebss, not OK. */	\
 | 
						|
	add	r0, r1;					\
 | 
						|
	cmp/hs	r1, r15;				\
 | 
						|
	bt	stack_panic;				\
 | 
						|
1:
 | 
						|
#else
 | 
						|
#define STACK_CHECK()
 | 
						|
#endif /* CONFIG_STACK_DEBUG */
 | 
						|
 | 
						|
	.align 2
 | 
						|
	.globl	_mcount
 | 
						|
	.type	_mcount,@function
 | 
						|
	.globl	mcount
 | 
						|
	.type	mcount,@function
 | 
						|
_mcount:
 | 
						|
mcount:
 | 
						|
	STACK_CHECK()
 | 
						|
 | 
						|
#ifndef CONFIG_FUNCTION_TRACER
 | 
						|
	rts
 | 
						|
	 nop
 | 
						|
#else
 | 
						|
#ifndef CONFIG_DYNAMIC_FTRACE
 | 
						|
	mov.l	.Lfunction_trace_stop, r0
 | 
						|
	mov.l	@r0, r0
 | 
						|
	tst	r0, r0
 | 
						|
	bf	ftrace_stub
 | 
						|
#endif
 | 
						|
 | 
						|
	MCOUNT_ENTER()
 | 
						|
 | 
						|
#ifdef CONFIG_DYNAMIC_FTRACE
 | 
						|
	.globl	mcount_call
 | 
						|
mcount_call:
 | 
						|
	mov.l	.Lftrace_stub, r6
 | 
						|
#else
 | 
						|
	mov.l	.Lftrace_trace_function, r6
 | 
						|
	mov.l	ftrace_stub, r7
 | 
						|
	cmp/eq	r6, r7
 | 
						|
	bt	skip_trace
 | 
						|
	mov.l	@r6, r6
 | 
						|
#endif
 | 
						|
 | 
						|
	jsr	@r6
 | 
						|
	 nop
 | 
						|
 | 
						|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
 | 
						|
	mov.l   .Lftrace_graph_return, r6
 | 
						|
	mov.l   .Lftrace_stub, r7
 | 
						|
	cmp/eq  r6, r7
 | 
						|
	bt      1f
 | 
						|
 | 
						|
	mov.l   .Lftrace_graph_caller, r0
 | 
						|
	jmp     @r0
 | 
						|
	 nop
 | 
						|
 | 
						|
1:
 | 
						|
	mov.l	.Lftrace_graph_entry, r6
 | 
						|
	mov.l	.Lftrace_graph_entry_stub, r7
 | 
						|
	cmp/eq	r6, r7
 | 
						|
	bt	skip_trace
 | 
						|
 | 
						|
	mov.l   .Lftrace_graph_caller, r0
 | 
						|
	jmp	@r0
 | 
						|
	 nop
 | 
						|
 | 
						|
	.align 2
 | 
						|
.Lftrace_graph_return:
 | 
						|
	.long   ftrace_graph_return
 | 
						|
.Lftrace_graph_entry:
 | 
						|
	.long   ftrace_graph_entry
 | 
						|
.Lftrace_graph_entry_stub:
 | 
						|
	.long   ftrace_graph_entry_stub
 | 
						|
.Lftrace_graph_caller:
 | 
						|
	.long   ftrace_graph_caller
 | 
						|
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
 | 
						|
 | 
						|
	.globl skip_trace
 | 
						|
skip_trace:
 | 
						|
	MCOUNT_LEAVE()
 | 
						|
 | 
						|
	.align 2
 | 
						|
.Lftrace_trace_function:
 | 
						|
	.long   ftrace_trace_function
 | 
						|
 | 
						|
#ifdef CONFIG_DYNAMIC_FTRACE
 | 
						|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
 | 
						|
/*
 | 
						|
 * NOTE: Do not move either ftrace_graph_call or ftrace_caller
 | 
						|
 * as this will affect the calculation of GRAPH_INSN_OFFSET.
 | 
						|
 */
 | 
						|
	.globl ftrace_graph_call
 | 
						|
ftrace_graph_call:
 | 
						|
	mov.l	.Lskip_trace, r0
 | 
						|
	jmp	@r0
 | 
						|
	 nop
 | 
						|
 | 
						|
	.align 2
 | 
						|
.Lskip_trace:
 | 
						|
	.long	skip_trace
 | 
						|
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
 | 
						|
 | 
						|
	.globl ftrace_caller
 | 
						|
ftrace_caller:
 | 
						|
	mov.l	.Lfunction_trace_stop, r0
 | 
						|
	mov.l	@r0, r0
 | 
						|
	tst	r0, r0
 | 
						|
	bf	ftrace_stub
 | 
						|
 | 
						|
	MCOUNT_ENTER()
 | 
						|
 | 
						|
	.globl ftrace_call
 | 
						|
ftrace_call:
 | 
						|
	mov.l	.Lftrace_stub, r6
 | 
						|
	jsr	@r6
 | 
						|
	 nop
 | 
						|
 | 
						|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
 | 
						|
	bra	ftrace_graph_call
 | 
						|
	 nop
 | 
						|
#else
 | 
						|
	MCOUNT_LEAVE()
 | 
						|
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
 | 
						|
#endif /* CONFIG_DYNAMIC_FTRACE */
 | 
						|
 | 
						|
	.align 2
 | 
						|
.Lfunction_trace_stop:
 | 
						|
	.long	function_trace_stop
 | 
						|
 | 
						|
/*
 | 
						|
 * NOTE: From here on the locations of the .Lftrace_stub label and
 | 
						|
 * ftrace_stub itself are fixed. Adding additional data here will skew
 | 
						|
 * the displacement for the memory table and break the block replacement.
 | 
						|
 * Place new labels either after the ftrace_stub body, or before
 | 
						|
 * ftrace_caller. You have been warned.
 | 
						|
 */
 | 
						|
.Lftrace_stub:
 | 
						|
	.long	ftrace_stub
 | 
						|
 | 
						|
	.globl	ftrace_stub
 | 
						|
ftrace_stub:
 | 
						|
	rts
 | 
						|
	 nop
 | 
						|
 | 
						|
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
 | 
						|
	.globl	ftrace_graph_caller
 | 
						|
ftrace_graph_caller:
 | 
						|
	mov.l	2f, r0
 | 
						|
	mov.l	@r0, r0
 | 
						|
	tst	r0, r0
 | 
						|
	bt	1f
 | 
						|
 | 
						|
	mov.l	3f, r1
 | 
						|
	jmp	@r1
 | 
						|
	 nop
 | 
						|
1:
 | 
						|
	/*
 | 
						|
	 * MCOUNT_ENTER() pushed 5 registers onto the stack, so
 | 
						|
	 * the stack address containing our return address is
 | 
						|
	 * r15 + 20.
 | 
						|
	 */
 | 
						|
	mov	#20, r0
 | 
						|
	add	r15, r0
 | 
						|
	mov	r0, r4
 | 
						|
 | 
						|
	mov.l	.Lprepare_ftrace_return, r0
 | 
						|
	jsr	@r0
 | 
						|
	 nop
 | 
						|
 | 
						|
	MCOUNT_LEAVE()
 | 
						|
 | 
						|
	.align 2
 | 
						|
2:	.long	function_trace_stop
 | 
						|
3:	.long	skip_trace
 | 
						|
.Lprepare_ftrace_return:
 | 
						|
	.long	prepare_ftrace_return
 | 
						|
 | 
						|
	.globl	return_to_handler
 | 
						|
return_to_handler:
 | 
						|
	/*
 | 
						|
	 * Save the return values.
 | 
						|
	 */
 | 
						|
	mov.l	r0, @-r15
 | 
						|
	mov.l	r1, @-r15
 | 
						|
 | 
						|
	mov	#0, r4
 | 
						|
 | 
						|
	mov.l	.Lftrace_return_to_handler, r0
 | 
						|
	jsr	@r0
 | 
						|
	 nop
 | 
						|
 | 
						|
	/*
 | 
						|
	 * The return value from ftrace_return_handler has the real
 | 
						|
	 * address that we should return to.
 | 
						|
	 */
 | 
						|
	lds	r0, pr
 | 
						|
	mov.l	@r15+, r1
 | 
						|
	rts
 | 
						|
	 mov.l	@r15+, r0
 | 
						|
 | 
						|
 | 
						|
	.align 2
 | 
						|
.Lftrace_return_to_handler:
 | 
						|
	.long	ftrace_return_to_handler
 | 
						|
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
 | 
						|
#endif /* CONFIG_FUNCTION_TRACER */
 | 
						|
 | 
						|
#ifdef CONFIG_STACK_DEBUG
 | 
						|
	.globl	stack_panic
 | 
						|
stack_panic:
 | 
						|
	mov.l	.Ldump_stack, r0
 | 
						|
	jsr	@r0
 | 
						|
	 nop
 | 
						|
 | 
						|
	mov.l	.Lpanic, r0
 | 
						|
	jsr	@r0
 | 
						|
	 mov.l	.Lpanic_s, r4
 | 
						|
 | 
						|
	rts
 | 
						|
	 nop
 | 
						|
 | 
						|
	.align 2
 | 
						|
.L_ebss:
 | 
						|
	.long	_ebss
 | 
						|
.L_init_thread_union:
 | 
						|
	.long	init_thread_union
 | 
						|
.Lpanic:
 | 
						|
	.long	panic
 | 
						|
.Lpanic_s:
 | 
						|
	.long	.Lpanic_str
 | 
						|
.Ldump_stack:
 | 
						|
	.long	dump_stack
 | 
						|
 | 
						|
	.section	.rodata
 | 
						|
	.align 2
 | 
						|
.Lpanic_str:
 | 
						|
	.string "Stack error"
 | 
						|
#endif /* CONFIG_STACK_DEBUG */
 |