arch/arm/kernel/ftrace.c

Source file repositories/reference/linux-study-clean/arch/arm/kernel/ftrace.c

File Facts

System
Linux kernel
Corpus path
arch/arm/kernel/ftrace.c
Extension
.c
Size
8005 bytes
Lines
324
Domain
Architecture Layer
Bucket
arch/arm
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

#include <linux/ftrace.h>
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/stop_machine.h>

#include <asm/cacheflush.h>
#include <asm/opcodes.h>
#include <asm/ftrace.h>
#include <asm/insn.h>
#include <asm/set_memory.h>
#include <asm/stacktrace.h>
#include <asm/text-patching.h>

/*
 * The compiler emitted profiling hook consists of
 *
 *   PUSH    {LR}
 *   BL	     __gnu_mcount_nc
 *
 * To turn this combined sequence into a NOP, we need to restore the value of
 * SP before the PUSH. Let's use an ADD rather than a POP into LR, as LR is not
 * modified anyway, and reloading LR from memory is highly likely to be less
 * efficient.
 */
#ifdef CONFIG_THUMB2_KERNEL
#define	NOP		0xf10d0d04	/* add.w sp, sp, #4 */
#else
#define	NOP		0xe28dd004	/* add   sp, sp, #4 */
#endif

#ifdef CONFIG_DYNAMIC_FTRACE

static int __ftrace_modify_code(void *data)
{
	int *command = data;

	ftrace_modify_all_code(*command);

	return 0;
}

void arch_ftrace_update_code(int command)
{
	stop_machine(__ftrace_modify_code, &command, NULL);
}

static unsigned long ftrace_nop_replace(struct dyn_ftrace *rec)
{
	return NOP;
}

void ftrace_caller_from_init(void);
void ftrace_regs_caller_from_init(void);

static unsigned long __ref adjust_address(struct dyn_ftrace *rec,
					  unsigned long addr)
{
	if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE) ||
	    system_state >= SYSTEM_FREEING_INITMEM ||
	    likely(!is_kernel_inittext(rec->ip)))
		return addr;
	if (!IS_ENABLED(CONFIG_DYNAMIC_FTRACE_WITH_REGS) ||
	    addr == (unsigned long)&ftrace_caller)
		return (unsigned long)&ftrace_caller_from_init;
	return (unsigned long)&ftrace_regs_caller_from_init;
}

void ftrace_arch_code_modify_prepare(void)
{
}

void ftrace_arch_code_modify_post_process(void)
{
	/* Make sure any TLB misses during machine stop are cleared. */
	flush_tlb_all();
}

static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr,
					 bool warn)
{
	return arm_gen_branch_link(pc, addr, warn);
}

static int ftrace_modify_code(unsigned long pc, unsigned long old,
			      unsigned long new, bool validate)
{
	unsigned long replaced;

	if (IS_ENABLED(CONFIG_THUMB2_KERNEL))
		old = __opcode_to_mem_thumb32(old);

Annotation

Implementation Notes