xref: /freebsd/sys/riscv/riscv/sdt_machdep.c (revision ddf0ed09bd8f83677407db36828aca2c10f419c9)
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