162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#ifndef _ASM_POWERPC_FTRACE
362306a36Sopenharmony_ci#define _ASM_POWERPC_FTRACE
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include <asm/types.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#ifdef CONFIG_FUNCTION_TRACER
862306a36Sopenharmony_ci#define MCOUNT_ADDR		((unsigned long)(_mcount))
962306a36Sopenharmony_ci#define MCOUNT_INSN_SIZE	4 /* sizeof mcount call */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci/* Ignore unused weak functions which will have larger offsets */
1462306a36Sopenharmony_ci#if defined(CONFIG_MPROFILE_KERNEL) || defined(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY)
1562306a36Sopenharmony_ci#define FTRACE_MCOUNT_MAX_OFFSET	16
1662306a36Sopenharmony_ci#elif defined(CONFIG_PPC32)
1762306a36Sopenharmony_ci#define FTRACE_MCOUNT_MAX_OFFSET	8
1862306a36Sopenharmony_ci#endif
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#ifndef __ASSEMBLY__
2162306a36Sopenharmony_ciextern void _mcount(void);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic inline unsigned long ftrace_call_adjust(unsigned long addr)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY))
2662306a36Sopenharmony_ci		addr += MCOUNT_INSN_SIZE;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci       return addr;
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ciunsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip,
3262306a36Sopenharmony_ci				    unsigned long sp);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistruct module;
3562306a36Sopenharmony_cistruct dyn_ftrace;
3662306a36Sopenharmony_cistruct dyn_arch_ftrace {
3762306a36Sopenharmony_ci	struct module *mod;
3862306a36Sopenharmony_ci};
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#ifdef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
4162306a36Sopenharmony_ci#define ftrace_need_init_nop()	(true)
4262306a36Sopenharmony_ciint ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
4362306a36Sopenharmony_ci#define ftrace_init_nop ftrace_init_nop
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistruct ftrace_regs {
4662306a36Sopenharmony_ci	struct pt_regs regs;
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *fregs)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	/* We clear regs.msr in ftrace_call */
5262306a36Sopenharmony_ci	return fregs->regs.msr ? &fregs->regs : NULL;
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic __always_inline void
5662306a36Sopenharmony_ciftrace_regs_set_instruction_pointer(struct ftrace_regs *fregs,
5762306a36Sopenharmony_ci				    unsigned long ip)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	regs_set_return_ip(&fregs->regs, ip);
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic __always_inline unsigned long
6362306a36Sopenharmony_ciftrace_regs_get_instruction_pointer(struct ftrace_regs *fregs)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	return instruction_pointer(&fregs->regs);
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#define ftrace_regs_get_argument(fregs, n) \
6962306a36Sopenharmony_ci	regs_get_kernel_argument(&(fregs)->regs, n)
7062306a36Sopenharmony_ci#define ftrace_regs_get_stack_pointer(fregs) \
7162306a36Sopenharmony_ci	kernel_stack_pointer(&(fregs)->regs)
7262306a36Sopenharmony_ci#define ftrace_regs_return_value(fregs) \
7362306a36Sopenharmony_ci	regs_return_value(&(fregs)->regs)
7462306a36Sopenharmony_ci#define ftrace_regs_set_return_value(fregs, ret) \
7562306a36Sopenharmony_ci	regs_set_return_value(&(fregs)->regs, ret)
7662306a36Sopenharmony_ci#define ftrace_override_function_with_return(fregs) \
7762306a36Sopenharmony_ci	override_function_with_return(&(fregs)->regs)
7862306a36Sopenharmony_ci#define ftrace_regs_query_register_offset(name) \
7962306a36Sopenharmony_ci	regs_query_register_offset(name)
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistruct ftrace_ops;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci#define ftrace_graph_func ftrace_graph_func
8462306a36Sopenharmony_civoid ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
8562306a36Sopenharmony_ci		       struct ftrace_ops *op, struct ftrace_regs *fregs);
8662306a36Sopenharmony_ci#endif
8762306a36Sopenharmony_ci#endif /* __ASSEMBLY__ */
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
9062306a36Sopenharmony_ci#define ARCH_SUPPORTS_FTRACE_OPS 1
9162306a36Sopenharmony_ci#endif
9262306a36Sopenharmony_ci#endif /* CONFIG_FUNCTION_TRACER */
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci#ifndef __ASSEMBLY__
9562306a36Sopenharmony_ci#ifdef CONFIG_FTRACE_SYSCALLS
9662306a36Sopenharmony_ci/*
9762306a36Sopenharmony_ci * Some syscall entry functions on powerpc start with "ppc_" (fork and clone,
9862306a36Sopenharmony_ci * for instance) or ppc32_/ppc64_. We should also match the sys_ variant with
9962306a36Sopenharmony_ci * those.
10062306a36Sopenharmony_ci */
10162306a36Sopenharmony_ci#define ARCH_HAS_SYSCALL_MATCH_SYM_NAME
10262306a36Sopenharmony_cistatic inline bool arch_syscall_match_sym_name(const char *sym, const char *name)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	return !strcmp(sym, name) ||
10562306a36Sopenharmony_ci		(!strncmp(sym, "__se_sys", 8) && !strcmp(sym + 5, name)) ||
10662306a36Sopenharmony_ci		(!strncmp(sym, "ppc_", 4) && !strcmp(sym + 4, name + 4)) ||
10762306a36Sopenharmony_ci		(!strncmp(sym, "ppc32_", 6) && !strcmp(sym + 6, name + 4)) ||
10862306a36Sopenharmony_ci		(!strncmp(sym, "ppc64_", 6) && !strcmp(sym + 6, name + 4));
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci#endif /* CONFIG_FTRACE_SYSCALLS */
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci#if defined(CONFIG_PPC64) && defined(CONFIG_FUNCTION_TRACER)
11362306a36Sopenharmony_ci#include <asm/paca.h>
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic inline void this_cpu_disable_ftrace(void)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	get_paca()->ftrace_enabled = 0;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic inline void this_cpu_enable_ftrace(void)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	get_paca()->ftrace_enabled = 1;
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci/* Disable ftrace on this CPU if possible (may not be implemented) */
12662306a36Sopenharmony_cistatic inline void this_cpu_set_ftrace_enabled(u8 ftrace_enabled)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	get_paca()->ftrace_enabled = ftrace_enabled;
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic inline u8 this_cpu_get_ftrace_enabled(void)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	return get_paca()->ftrace_enabled;
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci#else /* CONFIG_PPC64 */
13662306a36Sopenharmony_cistatic inline void this_cpu_disable_ftrace(void) { }
13762306a36Sopenharmony_cistatic inline void this_cpu_enable_ftrace(void) { }
13862306a36Sopenharmony_cistatic inline void this_cpu_set_ftrace_enabled(u8 ftrace_enabled) { }
13962306a36Sopenharmony_cistatic inline u8 this_cpu_get_ftrace_enabled(void) { return 1; }
14062306a36Sopenharmony_ci#endif /* CONFIG_PPC64 */
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci#ifdef CONFIG_FUNCTION_TRACER
14362306a36Sopenharmony_ciextern unsigned int ftrace_tramp_text[], ftrace_tramp_init[];
14462306a36Sopenharmony_civoid ftrace_free_init_tramp(void);
14562306a36Sopenharmony_ci#else
14662306a36Sopenharmony_cistatic inline void ftrace_free_init_tramp(void) { }
14762306a36Sopenharmony_ci#endif
14862306a36Sopenharmony_ci#endif /* !__ASSEMBLY__ */
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci#endif /* _ASM_POWERPC_FTRACE */
151