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/encoding.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 & (INSN_C_SIZE - 1)) != 0 ||
23 (target & (INSN_C_SIZE - 1)) != 0)
24 return (false);
25 offset = target - patchpoint;
26 if (offset < -(1 << 19) || offset > (1 << 19))
27 return (false);
28 return (true);
29 }
30
31 /*
32 * Overwrite the copy of _SDT_ASM_PATCH_INSTR at the tracepoint with a jump to
33 * the target address.
34 */
35 void
sdt_tracepoint_patch(uintptr_t patchpoint,uintptr_t target)36 sdt_tracepoint_patch(uintptr_t patchpoint, uintptr_t target)
37 {
38 int32_t imm;
39 uint32_t instr;
40
41 KASSERT(sdt_tracepoint_valid(patchpoint, target),
42 ("%s: invalid tracepoint %#lx -> %#lx",
43 __func__, patchpoint, target));
44
45 imm = target - patchpoint;
46 imm = (imm & 0x100000) |
47 ((imm & 0x7fe) << 8) |
48 ((imm & 0x800) >> 2) |
49 ((imm & 0xff000) >> 12);
50 instr = (imm << 12) | MATCH_JAL;
51
52 memcpy((void *)patchpoint, &instr, sizeof(instr));
53 fence_i();
54 }
55
56 /*
57 * Overwrite the patchpoint with a nop instruction.
58 */
59 void
sdt_tracepoint_restore(uintptr_t patchpoint)60 sdt_tracepoint_restore(uintptr_t patchpoint)
61 {
62 uint32_t instr;
63
64 instr = 0x13; /* uncompressed nop */
65
66 memcpy((void *)patchpoint, &instr, sizeof(instr));
67 fence_i();
68 }
69