xref: /freebsd/sys/cddl/dev/kinst/kinst.h (revision 02402ec88896eda56be4ae41779ddc719f6b0e9d)
1f0bc4ed1SChristos Margiolis /*
2f0bc4ed1SChristos Margiolis  * SPDX-License-Identifier: CDDL 1.0
3f0bc4ed1SChristos Margiolis  *
49310bf54SChristos Margiolis  * Copyright (c) 2022 Christos Margiolis <christos@FreeBSD.org>
59310bf54SChristos Margiolis  * Copyright (c) 2023 The FreeBSD Foundation
69310bf54SChristos Margiolis  *
79310bf54SChristos Margiolis  * Portions of this software were developed by Christos Margiolis
89310bf54SChristos Margiolis  * <christos@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
9f0bc4ed1SChristos Margiolis  */
10f0bc4ed1SChristos Margiolis 
11f0bc4ed1SChristos Margiolis #ifndef _KINST_H_
12f0bc4ed1SChristos Margiolis #define _KINST_H_
13f0bc4ed1SChristos Margiolis 
14f0bc4ed1SChristos Margiolis #include <sys/dtrace.h>
15f0bc4ed1SChristos Margiolis 
16f0bc4ed1SChristos Margiolis typedef struct {
17f0bc4ed1SChristos Margiolis 	char	kpd_func[DTRACE_FUNCNAMELEN];
18f0bc4ed1SChristos Margiolis 	char	kpd_mod[DTRACE_MODNAMELEN];
19f0bc4ed1SChristos Margiolis 	int	kpd_off;
20f0bc4ed1SChristos Margiolis } dtrace_kinst_probedesc_t;
21f0bc4ed1SChristos Margiolis 
22f0bc4ed1SChristos Margiolis #define KINSTIOC_MAKEPROBE	_IOW('k', 1, dtrace_kinst_probedesc_t)
23f0bc4ed1SChristos Margiolis 
24f0bc4ed1SChristos Margiolis #ifdef _KERNEL
25f0bc4ed1SChristos Margiolis 
26f0bc4ed1SChristos Margiolis #include <sys/queue.h>
27f0bc4ed1SChristos Margiolis 
28f0bc4ed1SChristos Margiolis #include "kinst_isa.h"
29f0bc4ed1SChristos Margiolis 
30f0bc4ed1SChristos Margiolis struct kinst_probe {
31f0bc4ed1SChristos Margiolis 	LIST_ENTRY(kinst_probe)	kp_hashnext;
32f0bc4ed1SChristos Margiolis 	const char		*kp_func;
33f0bc4ed1SChristos Margiolis 	char			kp_name[16];
34f0bc4ed1SChristos Margiolis 	dtrace_id_t		kp_id;
35f0bc4ed1SChristos Margiolis 	kinst_patchval_t	kp_patchval;
36f0bc4ed1SChristos Margiolis 	kinst_patchval_t	kp_savedval;
37f0bc4ed1SChristos Margiolis 	kinst_patchval_t	*kp_patchpoint;
385b701ed1SChristos Margiolis 	uint8_t			*kp_tramp;
39f0bc4ed1SChristos Margiolis 
40f0bc4ed1SChristos Margiolis 	struct kinst_probe_md	kp_md;
41f0bc4ed1SChristos Margiolis };
42f0bc4ed1SChristos Margiolis 
435b701ed1SChristos Margiolis struct kinst_cpu_state {
445b701ed1SChristos Margiolis 	/*
455b701ed1SChristos Margiolis 	 * kinst uses a breakpoint to return from the trampoline and resume
465b701ed1SChristos Margiolis 	 * execution. To do this safely, kinst implements a per-CPU state
475b701ed1SChristos Margiolis 	 * machine; the state is set to KINST_PROBE_FIRED for the duration of
485b701ed1SChristos Margiolis 	 * the trampoline execution (i.e from the time we transfer execution to
495b701ed1SChristos Margiolis 	 * it, until we return). Upon return, the state is set to
505b701ed1SChristos Margiolis 	 * KINST_PROBE_ARMED to indicate that a probe is not currently firing.
515b701ed1SChristos Margiolis 	 * All CPUs have their state initialized to KINST_PROBE_ARMED when
525b701ed1SChristos Margiolis 	 * kinst is loaded.
535b701ed1SChristos Margiolis 	 */
545b701ed1SChristos Margiolis 	enum {
555b701ed1SChristos Margiolis 		KINST_PROBE_ARMED,
565b701ed1SChristos Margiolis 		KINST_PROBE_FIRED,
575b701ed1SChristos Margiolis 	} state;
585b701ed1SChristos Margiolis 	/*
595b701ed1SChristos Margiolis 	 * Points to the probe whose trampoline we're currently executing.
605b701ed1SChristos Margiolis 	 */
61*02402ec8SChristos Margiolis 	const struct kinst_probe *kp;
625b701ed1SChristos Margiolis 	/*
635b701ed1SChristos Margiolis 	 * Because we execute trampolines with interrupts disabled, we have to
645b701ed1SChristos Margiolis 	 * cache the CPU's status in order to restore it when we return from
655b701ed1SChristos Margiolis 	 * the trampoline.
665b701ed1SChristos Margiolis 	 */
675b701ed1SChristos Margiolis 	uint64_t status;
685b701ed1SChristos Margiolis };
695b701ed1SChristos Margiolis 
70f0bc4ed1SChristos Margiolis LIST_HEAD(kinst_probe_list, kinst_probe);
71f0bc4ed1SChristos Margiolis 
72f0bc4ed1SChristos Margiolis extern struct kinst_probe_list	*kinst_probetab;
73f0bc4ed1SChristos Margiolis 
74f0bc4ed1SChristos Margiolis #define KINST_PROBETAB_MAX	0x8000	/* 32k */
75f0bc4ed1SChristos Margiolis #define KINST_ADDR2NDX(addr)	(((uintptr_t)(addr)) & (KINST_PROBETAB_MAX - 1))
76f0bc4ed1SChristos Margiolis #define KINST_GETPROBE(i) 	(&kinst_probetab[KINST_ADDR2NDX(i)])
77f0bc4ed1SChristos Margiolis 
78f0bc4ed1SChristos Margiolis struct linker_file;
79f0bc4ed1SChristos Margiolis struct linker_symval;
80f0bc4ed1SChristos Margiolis 
818ada3f78SChristos Margiolis /* kinst.c */
825c134fbaSChristos Margiolis volatile void	*kinst_memcpy(volatile void *, volatile const void *, size_t);
83d434607bSChristos Margiolis bool	kinst_excluded(const char *);
84f0bc4ed1SChristos Margiolis void	kinst_probe_create(struct kinst_probe *, struct linker_file *);
85f0bc4ed1SChristos Margiolis 
868ada3f78SChristos Margiolis /* arch/kinst_isa.c */
878ada3f78SChristos Margiolis int	kinst_invop(uintptr_t, struct trapframe *, uintptr_t);
888ada3f78SChristos Margiolis void	kinst_patch_tracepoint(struct kinst_probe *, kinst_patchval_t);
898ada3f78SChristos Margiolis int	kinst_make_probe(struct linker_file *, int, struct linker_symval *,
908ada3f78SChristos Margiolis 	    void *);
918ada3f78SChristos Margiolis int	kinst_md_init(void);
928ada3f78SChristos Margiolis void	kinst_md_deinit(void);
938ada3f78SChristos Margiolis bool	kinst_md_excluded(const char *);
948ada3f78SChristos Margiolis 
958ada3f78SChristos Margiolis /* trampoline.c */
96f0bc4ed1SChristos Margiolis int	kinst_trampoline_init(void);
97f0bc4ed1SChristos Margiolis int	kinst_trampoline_deinit(void);
98f0bc4ed1SChristos Margiolis uint8_t	*kinst_trampoline_alloc(int);
99f0bc4ed1SChristos Margiolis void	kinst_trampoline_dealloc(uint8_t *);
100f0bc4ed1SChristos Margiolis 
101f0bc4ed1SChristos Margiolis #ifdef MALLOC_DECLARE
102f0bc4ed1SChristos Margiolis MALLOC_DECLARE(M_KINST);
103f0bc4ed1SChristos Margiolis #endif /* MALLOC_DECLARE */
104f0bc4ed1SChristos Margiolis 
105f0bc4ed1SChristos Margiolis #define KINST_LOG_HELPER(fmt, ...)	\
106f0bc4ed1SChristos Margiolis 	printf("%s:%d: " fmt "%s\n", __func__, __LINE__, __VA_ARGS__)
107f0bc4ed1SChristos Margiolis #define KINST_LOG(...)			\
108f0bc4ed1SChristos Margiolis 	KINST_LOG_HELPER(__VA_ARGS__, "")
109f0bc4ed1SChristos Margiolis 
110f0bc4ed1SChristos Margiolis #endif /* _KERNEL */
111f0bc4ed1SChristos Margiolis 
112f0bc4ed1SChristos Margiolis #endif /* _KINST_H_ */
113