xref: /freebsd/sys/cddl/dev/kinst/kinst.h (revision 06c3fb27)
1 /*
2  * SPDX-License-Identifier: CDDL 1.0
3  *
4  * Copyright (c) 2022 Christos Margiolis <christos@FreeBSD.org>
5  * Copyright (c) 2023 The FreeBSD Foundation
6  *
7  * Portions of this software were developed by Christos Margiolis
8  * <christos@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
9  */
10 
11 #ifndef _KINST_H_
12 #define _KINST_H_
13 
14 #include <sys/dtrace.h>
15 
16 typedef struct {
17 	char	kpd_func[DTRACE_FUNCNAMELEN];
18 	char	kpd_mod[DTRACE_MODNAMELEN];
19 	int	kpd_off;
20 } dtrace_kinst_probedesc_t;
21 
22 #define KINSTIOC_MAKEPROBE	_IOW('k', 1, dtrace_kinst_probedesc_t)
23 
24 #ifdef _KERNEL
25 
26 #include <sys/queue.h>
27 
28 #include "kinst_isa.h"
29 
30 struct kinst_probe {
31 	LIST_ENTRY(kinst_probe)	kp_hashnext;
32 	const char		*kp_func;
33 	char			kp_name[16];
34 	dtrace_id_t		kp_id;
35 	kinst_patchval_t	kp_patchval;
36 	kinst_patchval_t	kp_savedval;
37 	kinst_patchval_t	*kp_patchpoint;
38 	uint8_t			*kp_tramp;
39 
40 	struct kinst_probe_md	kp_md;
41 };
42 
43 struct kinst_cpu_state {
44 	/*
45 	 * kinst uses a breakpoint to return from the trampoline and resume
46 	 * execution. To do this safely, kinst implements a per-CPU state
47 	 * machine; the state is set to KINST_PROBE_FIRED for the duration of
48 	 * the trampoline execution (i.e from the time we transfer execution to
49 	 * it, until we return). Upon return, the state is set to
50 	 * KINST_PROBE_ARMED to indicate that a probe is not currently firing.
51 	 * All CPUs have their state initialized to KINST_PROBE_ARMED when
52 	 * kinst is loaded.
53 	 */
54 	enum {
55 		KINST_PROBE_ARMED,
56 		KINST_PROBE_FIRED,
57 	} state;
58 	/*
59 	 * Points to the probe whose trampoline we're currently executing.
60 	 */
61 	const struct kinst_probe *kp;
62 	/*
63 	 * Because we execute trampolines with interrupts disabled, we have to
64 	 * cache the CPU's status in order to restore it when we return from
65 	 * the trampoline.
66 	 */
67 	uint64_t status;
68 };
69 
70 LIST_HEAD(kinst_probe_list, kinst_probe);
71 
72 extern struct kinst_probe_list	*kinst_probetab;
73 
74 #define KINST_PROBETAB_MAX	0x8000	/* 32k */
75 #define KINST_ADDR2NDX(addr)	(((uintptr_t)(addr)) & (KINST_PROBETAB_MAX - 1))
76 #define KINST_GETPROBE(i) 	(&kinst_probetab[KINST_ADDR2NDX(i)])
77 
78 struct linker_file;
79 struct linker_symval;
80 
81 /* kinst.c */
82 volatile void	*kinst_memcpy(volatile void *, volatile const void *, size_t);
83 bool	kinst_excluded(const char *);
84 void	kinst_probe_create(struct kinst_probe *, struct linker_file *);
85 
86 /* arch/kinst_isa.c */
87 int	kinst_invop(uintptr_t, struct trapframe *, uintptr_t);
88 void	kinst_patch_tracepoint(struct kinst_probe *, kinst_patchval_t);
89 int	kinst_make_probe(struct linker_file *, int, struct linker_symval *,
90 	    void *);
91 int	kinst_md_init(void);
92 void	kinst_md_deinit(void);
93 bool	kinst_md_excluded(const char *);
94 
95 /* trampoline.c */
96 int	kinst_trampoline_init(void);
97 int	kinst_trampoline_deinit(void);
98 uint8_t	*kinst_trampoline_alloc(int);
99 void	kinst_trampoline_dealloc(uint8_t *);
100 
101 #ifdef MALLOC_DECLARE
102 MALLOC_DECLARE(M_KINST);
103 #endif /* MALLOC_DECLARE */
104 
105 #define KINST_LOG_HELPER(fmt, ...)	\
106 	printf("%s:%d: " fmt "%s\n", __func__, __LINE__, __VA_ARGS__)
107 #define KINST_LOG(...)			\
108 	KINST_LOG_HELPER(__VA_ARGS__, "")
109 
110 #endif /* _KERNEL */
111 
112 #endif /* _KINST_H_ */
113