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