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 16typedef 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 30struct 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 43struct 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 70LIST_HEAD(kinst_probe_list, kinst_probe); 71 72extern 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 78struct linker_file; 79struct linker_symval; 80 81/* kinst.c */ 82volatile void *kinst_memcpy(volatile void *, volatile const void *, size_t); 83bool kinst_excluded(const char *); 84void kinst_probe_create(struct kinst_probe *, struct linker_file *); 85 86/* arch/kinst_isa.c */ 87int kinst_invop(uintptr_t, struct trapframe *, uintptr_t); 88void kinst_patch_tracepoint(struct kinst_probe *, kinst_patchval_t); 89int kinst_make_probe(struct linker_file *, int, struct linker_symval *, 90 void *); 91int kinst_md_init(void); 92void kinst_md_deinit(void); 93bool kinst_md_excluded(const char *); 94 95/* trampoline.c */ 96int kinst_trampoline_init(void); 97int kinst_trampoline_deinit(void); 98uint8_t *kinst_trampoline_alloc(int); 99void kinst_trampoline_dealloc(uint8_t *); 100 101#ifdef MALLOC_DECLARE 102MALLOC_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