xref: /freebsd/sys/arm/arm/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/cpu.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 	int32_t offset;
20 
21 	if (patchpoint == target ||
22 	    (patchpoint & (INSN_SIZE - 1)) != 0 ||
23 	    (target & (INSN_SIZE - 1)) != 0 ||
24 	    patchpoint + 2 * INSN_SIZE < patchpoint)
25 		return (false);
26 	offset = target - (patchpoint + 2 * INSN_SIZE);
27 	if (offset < -(1 << 24) || offset > (1 >> 24))
28 		return (false);
29 	return (true);
30 }
31 
32 /*
33  * Overwrite the copy of _SDT_ASM_PATCH_INSTR at the tracepoint with a jump to
34  * the target address.
35  */
36 void
sdt_tracepoint_patch(uintptr_t patchpoint,uintptr_t target)37 sdt_tracepoint_patch(uintptr_t patchpoint, uintptr_t target)
38 {
39 	uint32_t instr;
40 
41 	KASSERT(sdt_tracepoint_valid(patchpoint, target),
42 	    ("%s: invalid tracepoint %#x -> %#x",
43 	    __func__, patchpoint, target));
44 
45 	instr =
46 	    (((target - (patchpoint + 2 * INSN_SIZE)) >> 2) & ((1 << 24) - 1)) |
47 	    0xea000000;
48 	memcpy((void *)patchpoint, &instr, sizeof(instr));
49 	icache_sync(patchpoint, sizeof(instr));
50 }
51 
52 /*
53  * Overwrite the patchpoint with a nop instruction.
54  */
55 void
sdt_tracepoint_restore(uintptr_t patchpoint)56 sdt_tracepoint_restore(uintptr_t patchpoint)
57 {
58 	uint32_t instr;
59 
60 	instr = 0xe320f000u;
61 	memcpy((void *)patchpoint, &instr, sizeof(instr));
62 	icache_sync(patchpoint, sizeof(instr));
63 }
64