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