xref: /freebsd/sys/powerpc/powerpc/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/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