2 * SPDX-License-Identifier: CDDL 1.0
4 * Copyright 2022 Christos Margiolis <christos@FreeBSD.org>
5 * Copyright 2022 Mark Johnston <markj@FreeBSD.org>
9 #include <sys/bitset.h>
11 #include <sys/eventhandler.h>
12 #include <sys/kernel.h>
14 #include <sys/malloc.h>
16 #include <sys/queue.h>
20 #include <vm/vm_param.h>
22 #include <vm/vm_map.h>
23 #include <vm/vm_kern.h>
24 #include <vm/vm_object.h>
26 #include <cddl/dev/dtrace/dtrace_cddl.h>
29 #include "kinst_isa.h"
32 * We can have 4KB/32B = 128 trampolines per chunk.
34 #define KINST_TRAMPS_PER_CHUNK (KINST_TRAMPCHUNK_SIZE / KINST_TRAMP_SIZE)
37 TAILQ_ENTRY(trampchunk) next;
39 /* 0 -> allocated, 1 -> free */
40 BITSET_DEFINE(, KINST_TRAMPS_PER_CHUNK) free;
43 static TAILQ_HEAD(, trampchunk) kinst_trampchunks =
44 TAILQ_HEAD_INITIALIZER(kinst_trampchunks);
45 static struct sx kinst_tramp_sx;
46 SX_SYSINIT(kinst_tramp_sx, &kinst_tramp_sx, "kinst tramp");
47 static eventhandler_tag kinst_thread_ctor_handler;
48 static eventhandler_tag kinst_thread_dtor_handler;
50 static struct trampchunk *
51 kinst_trampchunk_alloc(void)
53 struct trampchunk *chunk;
54 vm_offset_t trampaddr;
57 sx_assert(&kinst_tramp_sx, SX_XLOCKED);
60 * Allocate virtual memory for the trampoline chunk. The returned
61 * address is saved in "trampaddr". To simplify population of
62 * trampolines, we follow the amd64 kernel's code model and allocate
63 * them above KERNBASE, i.e., in the top 2GB of the kernel's virtual
64 * address space. Trampolines must be executable so max_prot must
65 * include VM_PROT_EXECUTE.
68 error = vm_map_find(kernel_map, NULL, 0, &trampaddr,
69 KINST_TRAMPCHUNK_SIZE, 0, VMFS_ANY_SPACE, VM_PROT_ALL, VM_PROT_ALL,
71 if (error != KERN_SUCCESS) {
72 KINST_LOG("trampoline chunk allocation failed: %d", error);
76 error = kmem_back(kernel_object, trampaddr, KINST_TRAMPCHUNK_SIZE,
78 KASSERT(error == KERN_SUCCESS, ("kmem_back failed: %d", error));
80 KINST_TRAMP_INIT((void *)trampaddr, KINST_TRAMPCHUNK_SIZE);
82 /* Allocate a tracker for this chunk. */
83 chunk = malloc(sizeof(*chunk), M_KINST, M_WAITOK);
84 chunk->addr = (void *)trampaddr;
85 BIT_FILL(KINST_TRAMPS_PER_CHUNK, &chunk->free);
87 TAILQ_INSERT_HEAD(&kinst_trampchunks, chunk, next);
93 kinst_trampchunk_free(struct trampchunk *chunk)
95 sx_assert(&kinst_tramp_sx, SX_XLOCKED);
97 TAILQ_REMOVE(&kinst_trampchunks, chunk, next);
98 kmem_unback(kernel_object, (vm_offset_t)chunk->addr,
99 KINST_TRAMPCHUNK_SIZE);
100 (void)vm_map_remove(kernel_map, (vm_offset_t)chunk->addr,
101 (vm_offset_t)(chunk->addr + KINST_TRAMPCHUNK_SIZE));
102 free(chunk, M_KINST);
106 kinst_trampoline_alloc_locked(int how)
108 struct trampchunk *chunk;
112 sx_assert(&kinst_tramp_sx, SX_XLOCKED);
114 TAILQ_FOREACH(chunk, &kinst_trampchunks, next) {
115 /* All trampolines from this chunk are already allocated. */
116 if ((off = BIT_FFS(KINST_TRAMPS_PER_CHUNK, &chunk->free)) == 0)
118 /* BIT_FFS() returns indices starting at 1 instead of 0. */
123 if ((how & M_NOWAIT) != 0)
127 * We didn't find any free trampoline in the current list,
128 * allocate a new one. If that fails the provider will no
129 * longer be reliable, so try to warn the user.
131 if ((chunk = kinst_trampchunk_alloc()) == NULL) {
132 static bool once = true;
137 "kinst: failed to allocate trampoline, "
138 "probes may not fire");
144 BIT_CLR(KINST_TRAMPS_PER_CHUNK, off, &chunk->free);
145 tramp = chunk->addr + off * KINST_TRAMP_SIZE;
150 kinst_trampoline_alloc(int how)
154 sx_xlock(&kinst_tramp_sx);
155 tramp = kinst_trampoline_alloc_locked(how);
156 sx_xunlock(&kinst_tramp_sx);
161 kinst_trampoline_dealloc_locked(uint8_t *tramp, bool freechunks)
163 struct trampchunk *chunk;
169 TAILQ_FOREACH(chunk, &kinst_trampchunks, next) {
170 for (off = 0; off < KINST_TRAMPS_PER_CHUNK; off++) {
171 if (chunk->addr + off * KINST_TRAMP_SIZE == tramp) {
172 KINST_TRAMP_INIT(tramp, KINST_TRAMP_SIZE);
173 BIT_SET(KINST_TRAMPS_PER_CHUNK, off,
176 BIT_ISFULLSET(KINST_TRAMPS_PER_CHUNK,
178 kinst_trampchunk_free(chunk);
183 panic("%s: did not find trampoline chunk for %p", __func__, tramp);
187 kinst_trampoline_dealloc(uint8_t *tramp)
189 sx_xlock(&kinst_tramp_sx);
190 kinst_trampoline_dealloc_locked(tramp, true);
191 sx_xunlock(&kinst_tramp_sx);
195 kinst_thread_ctor(void *arg __unused, struct thread *td)
197 td->t_kinst = kinst_trampoline_alloc(M_WAITOK);
201 kinst_thread_dtor(void *arg __unused, struct thread *td)
209 * This assumes that the thread_dtor event permits sleeping, which
210 * appears to be true for the time being.
212 kinst_trampoline_dealloc(tramp);
216 kinst_trampoline_init(void)
223 kinst_thread_ctor_handler = EVENTHANDLER_REGISTER(thread_ctor,
224 kinst_thread_ctor, NULL, EVENTHANDLER_PRI_ANY);
225 kinst_thread_dtor_handler = EVENTHANDLER_REGISTER(thread_dtor,
226 kinst_thread_dtor, NULL, EVENTHANDLER_PRI_ANY);
231 sx_slock(&allproc_lock);
232 sx_xlock(&kinst_tramp_sx);
233 FOREACH_PROC_IN_SYSTEM(p) {
236 FOREACH_THREAD_IN_PROC(p, td) {
237 if (td->t_kinst != NULL)
241 * Try to allocate a trampoline without dropping
242 * the process lock. If all chunks are fully
243 * utilized, we must release the lock and try
246 tramp = kinst_trampoline_alloc_locked(M_NOWAIT);
249 tramp = kinst_trampoline_alloc_locked(
253 * Let the unload handler clean
268 sx_xunlock(&kinst_tramp_sx);
269 sx_sunlock(&allproc_lock);
274 kinst_trampoline_deinit(void)
276 struct trampchunk *chunk, *tmp;
280 EVENTHANDLER_DEREGISTER(thread_ctor, kinst_thread_ctor_handler);
281 EVENTHANDLER_DEREGISTER(thread_dtor, kinst_thread_dtor_handler);
283 sx_slock(&allproc_lock);
284 sx_xlock(&kinst_tramp_sx);
285 FOREACH_PROC_IN_SYSTEM(p) {
287 FOREACH_THREAD_IN_PROC(p, td) {
288 kinst_trampoline_dealloc_locked(td->t_kinst, false);
293 sx_sunlock(&allproc_lock);
294 TAILQ_FOREACH_SAFE(chunk, &kinst_trampchunks, next, tmp)
295 kinst_trampchunk_free(chunk);
296 sx_xunlock(&kinst_tramp_sx);