162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * PowerPC BookIII S hardware breakpoint definitions
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2010, IBM Corporation.
662306a36Sopenharmony_ci * Author: K.Prasad <prasad@linux.vnet.ibm.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#ifndef _PPC_BOOK3S_64_HW_BREAKPOINT_H
1062306a36Sopenharmony_ci#define _PPC_BOOK3S_64_HW_BREAKPOINT_H
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <asm/cpu_has_feature.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#ifdef	__KERNEL__
1562306a36Sopenharmony_cistruct arch_hw_breakpoint {
1662306a36Sopenharmony_ci	unsigned long	address;
1762306a36Sopenharmony_ci	u16		type;
1862306a36Sopenharmony_ci	u16		len; /* length of the target data symbol */
1962306a36Sopenharmony_ci	u16		hw_len; /* length programmed in hw */
2062306a36Sopenharmony_ci	u8		flags;
2162306a36Sopenharmony_ci	bool		perf_single_step; /* temporarily uninstalled for a perf single step */
2262306a36Sopenharmony_ci};
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/* Note: Don't change the first 6 bits below as they are in the same order
2562306a36Sopenharmony_ci * as the dabr and dabrx.
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_ci#define HW_BRK_TYPE_READ		0x01
2862306a36Sopenharmony_ci#define HW_BRK_TYPE_WRITE		0x02
2962306a36Sopenharmony_ci#define HW_BRK_TYPE_TRANSLATE		0x04
3062306a36Sopenharmony_ci#define HW_BRK_TYPE_USER		0x08
3162306a36Sopenharmony_ci#define HW_BRK_TYPE_KERNEL		0x10
3262306a36Sopenharmony_ci#define HW_BRK_TYPE_HYP			0x20
3362306a36Sopenharmony_ci#define HW_BRK_TYPE_EXTRANEOUS_IRQ	0x80
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/* bits that overlap with the bottom 3 bits of the dabr */
3662306a36Sopenharmony_ci#define HW_BRK_TYPE_RDWR	(HW_BRK_TYPE_READ | HW_BRK_TYPE_WRITE)
3762306a36Sopenharmony_ci#define HW_BRK_TYPE_DABR	(HW_BRK_TYPE_RDWR | HW_BRK_TYPE_TRANSLATE)
3862306a36Sopenharmony_ci#define HW_BRK_TYPE_PRIV_ALL	(HW_BRK_TYPE_USER | HW_BRK_TYPE_KERNEL | \
3962306a36Sopenharmony_ci				 HW_BRK_TYPE_HYP)
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define HW_BRK_FLAG_DISABLED	0x1
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* Minimum granularity */
4462306a36Sopenharmony_ci#ifdef CONFIG_PPC_8xx
4562306a36Sopenharmony_ci#define HW_BREAKPOINT_SIZE  0x4
4662306a36Sopenharmony_ci#else
4762306a36Sopenharmony_ci#define HW_BREAKPOINT_SIZE  0x8
4862306a36Sopenharmony_ci#endif
4962306a36Sopenharmony_ci#define HW_BREAKPOINT_SIZE_QUADWORD	0x10
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define DABR_MAX_LEN	8
5262306a36Sopenharmony_ci#define DAWR_MAX_LEN	512
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic inline int nr_wp_slots(void)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	return cpu_has_feature(CPU_FTR_DAWR1) ? 2 : 1;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cibool wp_check_constraints(struct pt_regs *regs, ppc_inst_t instr,
6062306a36Sopenharmony_ci			  unsigned long ea, int type, int size,
6162306a36Sopenharmony_ci			  struct arch_hw_breakpoint *info);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_civoid wp_get_instr_detail(struct pt_regs *regs, ppc_inst_t *instr,
6462306a36Sopenharmony_ci			 int *type, int *size, unsigned long *ea);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#ifdef CONFIG_HAVE_HW_BREAKPOINT
6762306a36Sopenharmony_ci#include <linux/kdebug.h>
6862306a36Sopenharmony_ci#include <asm/reg.h>
6962306a36Sopenharmony_ci#include <asm/debug.h>
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistruct perf_event_attr;
7262306a36Sopenharmony_cistruct perf_event;
7362306a36Sopenharmony_cistruct pmu;
7462306a36Sopenharmony_cistruct perf_sample_data;
7562306a36Sopenharmony_cistruct task_struct;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ciextern int hw_breakpoint_slots(int type);
7862306a36Sopenharmony_ciextern int arch_bp_generic_fields(int type, int *gen_bp_type);
7962306a36Sopenharmony_ciextern int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw);
8062306a36Sopenharmony_ciextern int hw_breakpoint_arch_parse(struct perf_event *bp,
8162306a36Sopenharmony_ci				    const struct perf_event_attr *attr,
8262306a36Sopenharmony_ci				    struct arch_hw_breakpoint *hw);
8362306a36Sopenharmony_ciextern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
8462306a36Sopenharmony_ci						unsigned long val, void *data);
8562306a36Sopenharmony_ciint arch_install_hw_breakpoint(struct perf_event *bp);
8662306a36Sopenharmony_civoid arch_uninstall_hw_breakpoint(struct perf_event *bp);
8762306a36Sopenharmony_civoid hw_breakpoint_pmu_read(struct perf_event *bp);
8862306a36Sopenharmony_ciextern void flush_ptrace_hw_breakpoint(struct task_struct *tsk);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ciextern struct pmu perf_ops_bp;
9162306a36Sopenharmony_ciextern void ptrace_triggered(struct perf_event *bp,
9262306a36Sopenharmony_ci			struct perf_sample_data *data, struct pt_regs *regs);
9362306a36Sopenharmony_cistatic inline void hw_breakpoint_disable(void)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	int i;
9662306a36Sopenharmony_ci	struct arch_hw_breakpoint null_brk = {0};
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	if (!ppc_breakpoint_available())
9962306a36Sopenharmony_ci		return;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	for (i = 0; i < nr_wp_slots(); i++)
10262306a36Sopenharmony_ci		__set_breakpoint(i, &null_brk);
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ciextern void thread_change_pc(struct task_struct *tsk, struct pt_regs *regs);
10562306a36Sopenharmony_ciint hw_breakpoint_handler(struct die_args *args);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci#else	/* CONFIG_HAVE_HW_BREAKPOINT */
10862306a36Sopenharmony_cistatic inline void hw_breakpoint_disable(void) { }
10962306a36Sopenharmony_cistatic inline void thread_change_pc(struct task_struct *tsk,
11062306a36Sopenharmony_ci					struct pt_regs *regs) { }
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci#endif	/* CONFIG_HAVE_HW_BREAKPOINT */
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci#ifdef CONFIG_PPC_DAWR
11662306a36Sopenharmony_ciextern bool dawr_force_enable;
11762306a36Sopenharmony_cistatic inline bool dawr_enabled(void)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	return dawr_force_enable;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ciint set_dawr(int nr, struct arch_hw_breakpoint *brk);
12262306a36Sopenharmony_ci#else
12362306a36Sopenharmony_cistatic inline bool dawr_enabled(void) { return false; }
12462306a36Sopenharmony_cistatic inline int set_dawr(int nr, struct arch_hw_breakpoint *brk) { return -1; }
12562306a36Sopenharmony_ci#endif
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci#endif	/* __KERNEL__ */
12862306a36Sopenharmony_ci#endif	/* _PPC_BOOK3S_64_HW_BREAKPOINT_H */
129