1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2024 Mark Johnston <markj@FreeBSD.org>
5 */
6
7 #include <sys/systm.h>
8 #include <sys/sdt.h>
9
10 #include <machine/md_var.h>
11
12 /*
13 * Return true if we can overwrite a nop at "patchpoint" with a jump to the
14 * target address.
15 */
16 bool
sdt_tracepoint_valid(uintptr_t patchpoint,uintptr_t target)17 sdt_tracepoint_valid(uintptr_t patchpoint, uintptr_t target)
18 {
19 int64_t offset;
20
21 if (patchpoint == target ||
22 (patchpoint & 3) != 0 || (target & 3) != 0)
23 return (false);
24 offset = target - patchpoint;
25 if (offset < -(1 << 26) || offset > (1 << 26))
26 return (false);
27 return (true);
28 }
29
30 /*
31 * Overwrite the copy of _SDT_ASM_PATCH_INSTR at the tracepoint with a jump to
32 * the target address.
33 */
34 void
sdt_tracepoint_patch(uintptr_t patchpoint,uintptr_t target)35 sdt_tracepoint_patch(uintptr_t patchpoint, uintptr_t target)
36 {
37 uint32_t instr;
38
39 KASSERT(sdt_tracepoint_valid(patchpoint, target),
40 ("%s: invalid tracepoint %#lx -> %#lx",
41 __func__, patchpoint, target));
42
43 instr = ((target - patchpoint) & 0x7fffffful) | 0x48000000;
44 memcpy((void *)patchpoint, &instr, sizeof(instr));
45 __syncicache((void *)patchpoint, sizeof(instr));
46 }
47
48 /*
49 * Overwrite the patchpoint with a nop instruction.
50 */
51 void
sdt_tracepoint_restore(uintptr_t patchpoint)52 sdt_tracepoint_restore(uintptr_t patchpoint)
53 {
54 uint32_t instr;
55
56 instr = 0x60000000;
57 memcpy((void *)patchpoint, &instr, sizeof(instr));
58 __syncicache((void *)patchpoint, sizeof(instr));
59 }
60