xref: /freebsd-src/sys/cddl/dev/kinst/trampoline.c (revision 5b701ed19c2ed439457b0177681472aac21fde94)
1f0bc4ed1SChristos Margiolis /*
2f0bc4ed1SChristos Margiolis  * SPDX-License-Identifier: CDDL 1.0
3f0bc4ed1SChristos Margiolis  *
49310bf54SChristos Margiolis  * Copyright (c) 2022 Christos Margiolis <christos@FreeBSD.org>
59310bf54SChristos Margiolis  * Copyright (c) 2022 Mark Johnston <markj@FreeBSD.org>
69310bf54SChristos Margiolis  * Copyright (c) 2023 The FreeBSD Foundation
79310bf54SChristos Margiolis  *
89310bf54SChristos Margiolis  * Portions of this software were developed by Christos Margiolis
99310bf54SChristos Margiolis  * <christos@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
10f0bc4ed1SChristos Margiolis  */
11f0bc4ed1SChristos Margiolis 
12f0bc4ed1SChristos Margiolis #include <sys/param.h>
13f0bc4ed1SChristos Margiolis #include <sys/bitset.h>
14f0bc4ed1SChristos Margiolis #include <sys/cred.h>
15f0bc4ed1SChristos Margiolis #include <sys/eventhandler.h>
16f0bc4ed1SChristos Margiolis #include <sys/kernel.h>
17f0bc4ed1SChristos Margiolis #include <sys/lock.h>
18f0bc4ed1SChristos Margiolis #include <sys/malloc.h>
19f0bc4ed1SChristos Margiolis #include <sys/proc.h>
20f0bc4ed1SChristos Margiolis #include <sys/queue.h>
21f0bc4ed1SChristos Margiolis #include <sys/sx.h>
22f0bc4ed1SChristos Margiolis 
23f0bc4ed1SChristos Margiolis #include <vm/vm.h>
24f0bc4ed1SChristos Margiolis #include <vm/vm_param.h>
25f0bc4ed1SChristos Margiolis #include <vm/pmap.h>
26f0bc4ed1SChristos Margiolis #include <vm/vm_map.h>
27f0bc4ed1SChristos Margiolis #include <vm/vm_kern.h>
28f0bc4ed1SChristos Margiolis #include <vm/vm_object.h>
29f0bc4ed1SChristos Margiolis 
30f0bc4ed1SChristos Margiolis #include <cddl/dev/dtrace/dtrace_cddl.h>
31f0bc4ed1SChristos Margiolis 
32f0bc4ed1SChristos Margiolis #include "kinst.h"
33f0bc4ed1SChristos Margiolis #include "kinst_isa.h"
34f0bc4ed1SChristos Margiolis 
359b091f12SChristos Margiolis #define KINST_TRAMP_FILL_PATTERN	((kinst_patchval_t []){KINST_PATCHVAL})
369b091f12SChristos Margiolis #define KINST_TRAMP_FILL_SIZE		sizeof(kinst_patchval_t)
379b091f12SChristos Margiolis 
3833373127SChristos Margiolis #define KINST_TRAMPCHUNK_SIZE		PAGE_SIZE
39f0bc4ed1SChristos Margiolis #define KINST_TRAMPS_PER_CHUNK		(KINST_TRAMPCHUNK_SIZE / KINST_TRAMP_SIZE)
40f0bc4ed1SChristos Margiolis 
41f0bc4ed1SChristos Margiolis struct trampchunk {
42f0bc4ed1SChristos Margiolis 	TAILQ_ENTRY(trampchunk) next;
43f0bc4ed1SChristos Margiolis 	uint8_t *addr;
44f0bc4ed1SChristos Margiolis 	/* 0 -> allocated, 1 -> free */
45f0bc4ed1SChristos Margiolis 	BITSET_DEFINE(, KINST_TRAMPS_PER_CHUNK) free;
46f0bc4ed1SChristos Margiolis };
47f0bc4ed1SChristos Margiolis 
48f0bc4ed1SChristos Margiolis static TAILQ_HEAD(, trampchunk)	kinst_trampchunks =
49f0bc4ed1SChristos Margiolis     TAILQ_HEAD_INITIALIZER(kinst_trampchunks);
50f0bc4ed1SChristos Margiolis static struct sx		kinst_tramp_sx;
51f0bc4ed1SChristos Margiolis SX_SYSINIT(kinst_tramp_sx, &kinst_tramp_sx, "kinst tramp");
52*5b701ed1SChristos Margiolis #ifdef __amd64__
53f0bc4ed1SChristos Margiolis static eventhandler_tag		kinst_thread_ctor_handler;
54f0bc4ed1SChristos Margiolis static eventhandler_tag		kinst_thread_dtor_handler;
55*5b701ed1SChristos Margiolis #endif
56f0bc4ed1SChristos Margiolis 
57ecca3180SChristos Margiolis /*
58ecca3180SChristos Margiolis  * Fill the trampolines with KINST_TRAMP_FILL_PATTERN so that the kernel will
59ecca3180SChristos Margiolis  * crash cleanly if things somehow go wrong.
60ecca3180SChristos Margiolis  */
61ecca3180SChristos Margiolis static void
kinst_trampoline_fill(uint8_t * addr,int size)62ecca3180SChristos Margiolis kinst_trampoline_fill(uint8_t *addr, int size)
63ecca3180SChristos Margiolis {
64ecca3180SChristos Margiolis 	int i;
65ecca3180SChristos Margiolis 
66ecca3180SChristos Margiolis 	for (i = 0; i < size; i += KINST_TRAMP_FILL_SIZE) {
67ecca3180SChristos Margiolis 		memcpy(&addr[i], KINST_TRAMP_FILL_PATTERN,
68ecca3180SChristos Margiolis 		    KINST_TRAMP_FILL_SIZE);
69ecca3180SChristos Margiolis 	}
70ecca3180SChristos Margiolis }
71ecca3180SChristos Margiolis 
72f0bc4ed1SChristos Margiolis static struct trampchunk *
kinst_trampchunk_alloc(void)73f0bc4ed1SChristos Margiolis kinst_trampchunk_alloc(void)
74f0bc4ed1SChristos Margiolis {
75f0bc4ed1SChristos Margiolis 	struct trampchunk *chunk;
76f0bc4ed1SChristos Margiolis 	vm_offset_t trampaddr;
77f0bc4ed1SChristos Margiolis 	int error __diagused;
78f0bc4ed1SChristos Margiolis 
79f0bc4ed1SChristos Margiolis 	sx_assert(&kinst_tramp_sx, SX_XLOCKED);
80f0bc4ed1SChristos Margiolis 
81855ade9eSChristos Margiolis #ifdef __amd64__
82f0bc4ed1SChristos Margiolis 	/*
83855ade9eSChristos Margiolis 	 * To simplify population of trampolines, we follow the amd64 kernel's
84855ade9eSChristos Margiolis 	 * code model and allocate them above KERNBASE, i.e., in the top 2GB of
85855ade9eSChristos Margiolis 	 * the kernel's virtual address space (not the case for other
86855ade9eSChristos Margiolis 	 * platforms).
87f0bc4ed1SChristos Margiolis 	 */
88f0bc4ed1SChristos Margiolis 	trampaddr = KERNBASE;
89855ade9eSChristos Margiolis #else
90855ade9eSChristos Margiolis 	trampaddr = VM_MIN_KERNEL_ADDRESS;
91855ade9eSChristos Margiolis #endif
92855ade9eSChristos Margiolis 	/*
93855ade9eSChristos Margiolis 	 * Allocate virtual memory for the trampoline chunk. The returned
94855ade9eSChristos Margiolis 	 * address is saved in "trampaddr". Trampolines must be executable so
95855ade9eSChristos Margiolis 	 * max_prot must include VM_PROT_EXECUTE.
96855ade9eSChristos Margiolis 	 */
97f0bc4ed1SChristos Margiolis 	error = vm_map_find(kernel_map, NULL, 0, &trampaddr,
98f0bc4ed1SChristos Margiolis 	    KINST_TRAMPCHUNK_SIZE, 0, VMFS_ANY_SPACE, VM_PROT_ALL, VM_PROT_ALL,
99f0bc4ed1SChristos Margiolis 	    0);
100f0bc4ed1SChristos Margiolis 	if (error != KERN_SUCCESS) {
101f0bc4ed1SChristos Margiolis 		KINST_LOG("trampoline chunk allocation failed: %d", error);
102f0bc4ed1SChristos Margiolis 		return (NULL);
103f0bc4ed1SChristos Margiolis 	}
104f0bc4ed1SChristos Margiolis 
105f0bc4ed1SChristos Margiolis 	error = kmem_back(kernel_object, trampaddr, KINST_TRAMPCHUNK_SIZE,
106f0bc4ed1SChristos Margiolis 	    M_WAITOK | M_EXEC);
107f0bc4ed1SChristos Margiolis 	KASSERT(error == KERN_SUCCESS, ("kmem_back failed: %d", error));
108f0bc4ed1SChristos Margiolis 
109ecca3180SChristos Margiolis 	kinst_trampoline_fill((uint8_t *)trampaddr, KINST_TRAMPCHUNK_SIZE);
110f0bc4ed1SChristos Margiolis 
111f0bc4ed1SChristos Margiolis 	/* Allocate a tracker for this chunk. */
112f0bc4ed1SChristos Margiolis 	chunk = malloc(sizeof(*chunk), M_KINST, M_WAITOK);
113f0bc4ed1SChristos Margiolis 	chunk->addr = (void *)trampaddr;
114f0bc4ed1SChristos Margiolis 	BIT_FILL(KINST_TRAMPS_PER_CHUNK, &chunk->free);
115f0bc4ed1SChristos Margiolis 
116f0bc4ed1SChristos Margiolis 	TAILQ_INSERT_HEAD(&kinst_trampchunks, chunk, next);
117f0bc4ed1SChristos Margiolis 
118f0bc4ed1SChristos Margiolis 	return (chunk);
119f0bc4ed1SChristos Margiolis }
120f0bc4ed1SChristos Margiolis 
121f0bc4ed1SChristos Margiolis static void
kinst_trampchunk_free(struct trampchunk * chunk)122f0bc4ed1SChristos Margiolis kinst_trampchunk_free(struct trampchunk *chunk)
123f0bc4ed1SChristos Margiolis {
124f0bc4ed1SChristos Margiolis 	sx_assert(&kinst_tramp_sx, SX_XLOCKED);
125f0bc4ed1SChristos Margiolis 
126f0bc4ed1SChristos Margiolis 	TAILQ_REMOVE(&kinst_trampchunks, chunk, next);
127f0bc4ed1SChristos Margiolis 	kmem_unback(kernel_object, (vm_offset_t)chunk->addr,
128f0bc4ed1SChristos Margiolis 	    KINST_TRAMPCHUNK_SIZE);
129f0bc4ed1SChristos Margiolis 	(void)vm_map_remove(kernel_map, (vm_offset_t)chunk->addr,
130f0bc4ed1SChristos Margiolis 	    (vm_offset_t)(chunk->addr + KINST_TRAMPCHUNK_SIZE));
131f0bc4ed1SChristos Margiolis 	free(chunk, M_KINST);
132f0bc4ed1SChristos Margiolis }
133f0bc4ed1SChristos Margiolis 
134f0bc4ed1SChristos Margiolis static uint8_t *
kinst_trampoline_alloc_locked(int how)135f0bc4ed1SChristos Margiolis kinst_trampoline_alloc_locked(int how)
136f0bc4ed1SChristos Margiolis {
137f0bc4ed1SChristos Margiolis 	struct trampchunk *chunk;
138f0bc4ed1SChristos Margiolis 	uint8_t *tramp;
139f0bc4ed1SChristos Margiolis 	int off;
140f0bc4ed1SChristos Margiolis 
141f0bc4ed1SChristos Margiolis 	sx_assert(&kinst_tramp_sx, SX_XLOCKED);
142f0bc4ed1SChristos Margiolis 
143f0bc4ed1SChristos Margiolis 	TAILQ_FOREACH(chunk, &kinst_trampchunks, next) {
144f0bc4ed1SChristos Margiolis 		/* All trampolines from this chunk are already allocated. */
145f0bc4ed1SChristos Margiolis 		if ((off = BIT_FFS(KINST_TRAMPS_PER_CHUNK, &chunk->free)) == 0)
146f0bc4ed1SChristos Margiolis 			continue;
147f0bc4ed1SChristos Margiolis 		/* BIT_FFS() returns indices starting at 1 instead of 0. */
148f0bc4ed1SChristos Margiolis 		off--;
149f0bc4ed1SChristos Margiolis 		break;
150f0bc4ed1SChristos Margiolis 	}
151f0bc4ed1SChristos Margiolis 	if (chunk == NULL) {
152f0bc4ed1SChristos Margiolis 		if ((how & M_NOWAIT) != 0)
153f0bc4ed1SChristos Margiolis 			return (NULL);
154f0bc4ed1SChristos Margiolis 
155f0bc4ed1SChristos Margiolis 		if ((chunk = kinst_trampchunk_alloc()) == NULL) {
156*5b701ed1SChristos Margiolis #ifdef __amd64__
157*5b701ed1SChristos Margiolis 			/*
158*5b701ed1SChristos Margiolis 			 * We didn't find any free trampoline in the current
159*5b701ed1SChristos Margiolis 			 * list, allocate a new one.  If that fails the
160*5b701ed1SChristos Margiolis 			 * provider will no longer be reliable, so try to warn
161*5b701ed1SChristos Margiolis 			 * the user.
162*5b701ed1SChristos Margiolis 			 */
163f0bc4ed1SChristos Margiolis 			static bool once = true;
164f0bc4ed1SChristos Margiolis 
165f0bc4ed1SChristos Margiolis 			if (once) {
166f0bc4ed1SChristos Margiolis 				once = false;
167f0bc4ed1SChristos Margiolis 				KINST_LOG(
168f0bc4ed1SChristos Margiolis 				    "kinst: failed to allocate trampoline, "
169f0bc4ed1SChristos Margiolis 				    "probes may not fire");
170f0bc4ed1SChristos Margiolis 			}
171*5b701ed1SChristos Margiolis #endif
172f0bc4ed1SChristos Margiolis 			return (NULL);
173f0bc4ed1SChristos Margiolis 		}
174f0bc4ed1SChristos Margiolis 		off = 0;
175f0bc4ed1SChristos Margiolis 	}
176f0bc4ed1SChristos Margiolis 	BIT_CLR(KINST_TRAMPS_PER_CHUNK, off, &chunk->free);
177f0bc4ed1SChristos Margiolis 	tramp = chunk->addr + off * KINST_TRAMP_SIZE;
178f0bc4ed1SChristos Margiolis 	return (tramp);
179f0bc4ed1SChristos Margiolis }
180f0bc4ed1SChristos Margiolis 
181f0bc4ed1SChristos Margiolis uint8_t *
kinst_trampoline_alloc(int how)182f0bc4ed1SChristos Margiolis kinst_trampoline_alloc(int how)
183f0bc4ed1SChristos Margiolis {
184f0bc4ed1SChristos Margiolis 	uint8_t *tramp;
185f0bc4ed1SChristos Margiolis 
186f0bc4ed1SChristos Margiolis 	sx_xlock(&kinst_tramp_sx);
187f0bc4ed1SChristos Margiolis 	tramp = kinst_trampoline_alloc_locked(how);
188f0bc4ed1SChristos Margiolis 	sx_xunlock(&kinst_tramp_sx);
189f0bc4ed1SChristos Margiolis 	return (tramp);
190f0bc4ed1SChristos Margiolis }
191f0bc4ed1SChristos Margiolis 
192f0bc4ed1SChristos Margiolis static void
kinst_trampoline_dealloc_locked(uint8_t * tramp,bool freechunks)193f0bc4ed1SChristos Margiolis kinst_trampoline_dealloc_locked(uint8_t *tramp, bool freechunks)
194f0bc4ed1SChristos Margiolis {
195f0bc4ed1SChristos Margiolis 	struct trampchunk *chunk;
196f0bc4ed1SChristos Margiolis 	int off;
197f0bc4ed1SChristos Margiolis 
198e11d11c5SChristos Margiolis 	sx_assert(&kinst_tramp_sx, SX_XLOCKED);
199e11d11c5SChristos Margiolis 
200f0bc4ed1SChristos Margiolis 	if (tramp == NULL)
201f0bc4ed1SChristos Margiolis 		return;
202f0bc4ed1SChristos Margiolis 
203f0bc4ed1SChristos Margiolis 	TAILQ_FOREACH(chunk, &kinst_trampchunks, next) {
204f0bc4ed1SChristos Margiolis 		for (off = 0; off < KINST_TRAMPS_PER_CHUNK; off++) {
205f0bc4ed1SChristos Margiolis 			if (chunk->addr + off * KINST_TRAMP_SIZE == tramp) {
206ecca3180SChristos Margiolis 				kinst_trampoline_fill(tramp, KINST_TRAMP_SIZE);
207f0bc4ed1SChristos Margiolis 				BIT_SET(KINST_TRAMPS_PER_CHUNK, off,
208f0bc4ed1SChristos Margiolis 				    &chunk->free);
209f0bc4ed1SChristos Margiolis 				if (freechunks &&
210f0bc4ed1SChristos Margiolis 				    BIT_ISFULLSET(KINST_TRAMPS_PER_CHUNK,
211f0bc4ed1SChristos Margiolis 				    &chunk->free))
212f0bc4ed1SChristos Margiolis 					kinst_trampchunk_free(chunk);
213f0bc4ed1SChristos Margiolis 				return;
214f0bc4ed1SChristos Margiolis 			}
215f0bc4ed1SChristos Margiolis 		}
216f0bc4ed1SChristos Margiolis 	}
217f0bc4ed1SChristos Margiolis 	panic("%s: did not find trampoline chunk for %p", __func__, tramp);
218f0bc4ed1SChristos Margiolis }
219f0bc4ed1SChristos Margiolis 
220f0bc4ed1SChristos Margiolis void
kinst_trampoline_dealloc(uint8_t * tramp)221f0bc4ed1SChristos Margiolis kinst_trampoline_dealloc(uint8_t *tramp)
222f0bc4ed1SChristos Margiolis {
223f0bc4ed1SChristos Margiolis 	sx_xlock(&kinst_tramp_sx);
224f0bc4ed1SChristos Margiolis 	kinst_trampoline_dealloc_locked(tramp, true);
225f0bc4ed1SChristos Margiolis 	sx_xunlock(&kinst_tramp_sx);
226f0bc4ed1SChristos Margiolis }
227f0bc4ed1SChristos Margiolis 
228*5b701ed1SChristos Margiolis #ifdef __amd64__
229f0bc4ed1SChristos Margiolis static void
kinst_thread_ctor(void * arg __unused,struct thread * td)230f0bc4ed1SChristos Margiolis kinst_thread_ctor(void *arg __unused, struct thread *td)
231f0bc4ed1SChristos Margiolis {
2321aa48621SChristos Margiolis 	td->t_kinst_tramp = kinst_trampoline_alloc(M_WAITOK);
233f0bc4ed1SChristos Margiolis }
234f0bc4ed1SChristos Margiolis 
235f0bc4ed1SChristos Margiolis static void
kinst_thread_dtor(void * arg __unused,struct thread * td)236f0bc4ed1SChristos Margiolis kinst_thread_dtor(void *arg __unused, struct thread *td)
237f0bc4ed1SChristos Margiolis {
238f0bc4ed1SChristos Margiolis 	void *tramp;
239f0bc4ed1SChristos Margiolis 
2401aa48621SChristos Margiolis 	tramp = td->t_kinst_tramp;
2411aa48621SChristos Margiolis 	td->t_kinst_tramp = NULL;
242f0bc4ed1SChristos Margiolis 
243f0bc4ed1SChristos Margiolis 	/*
244f0bc4ed1SChristos Margiolis 	 * This assumes that the thread_dtor event permits sleeping, which
245f0bc4ed1SChristos Margiolis 	 * appears to be true for the time being.
246f0bc4ed1SChristos Margiolis 	 */
247f0bc4ed1SChristos Margiolis 	kinst_trampoline_dealloc(tramp);
248f0bc4ed1SChristos Margiolis }
249*5b701ed1SChristos Margiolis #endif
250f0bc4ed1SChristos Margiolis 
251f0bc4ed1SChristos Margiolis int
kinst_trampoline_init(void)252f0bc4ed1SChristos Margiolis kinst_trampoline_init(void)
253f0bc4ed1SChristos Margiolis {
254*5b701ed1SChristos Margiolis #ifdef __amd64__
255f0bc4ed1SChristos Margiolis 	struct proc *p;
256f0bc4ed1SChristos Margiolis 	struct thread *td;
257f0bc4ed1SChristos Margiolis 	void *tramp;
258f0bc4ed1SChristos Margiolis 	int error;
259f0bc4ed1SChristos Margiolis 
260f0bc4ed1SChristos Margiolis 	kinst_thread_ctor_handler = EVENTHANDLER_REGISTER(thread_ctor,
261f0bc4ed1SChristos Margiolis 	    kinst_thread_ctor, NULL, EVENTHANDLER_PRI_ANY);
262f0bc4ed1SChristos Margiolis 	kinst_thread_dtor_handler = EVENTHANDLER_REGISTER(thread_dtor,
263f0bc4ed1SChristos Margiolis 	    kinst_thread_dtor, NULL, EVENTHANDLER_PRI_ANY);
264f0bc4ed1SChristos Margiolis 
265f0bc4ed1SChristos Margiolis 	error = 0;
266f0bc4ed1SChristos Margiolis 	tramp = NULL;
267f0bc4ed1SChristos Margiolis 
268f0bc4ed1SChristos Margiolis 	sx_slock(&allproc_lock);
269f0bc4ed1SChristos Margiolis 	sx_xlock(&kinst_tramp_sx);
270f0bc4ed1SChristos Margiolis 	FOREACH_PROC_IN_SYSTEM(p) {
271f0bc4ed1SChristos Margiolis retry:
272f0bc4ed1SChristos Margiolis 		PROC_LOCK(p);
273f0bc4ed1SChristos Margiolis 		FOREACH_THREAD_IN_PROC(p, td) {
2741aa48621SChristos Margiolis 			if (td->t_kinst_tramp != NULL)
275f0bc4ed1SChristos Margiolis 				continue;
276f0bc4ed1SChristos Margiolis 			if (tramp == NULL) {
277f0bc4ed1SChristos Margiolis 				/*
278f0bc4ed1SChristos Margiolis 				 * Try to allocate a trampoline without dropping
279f0bc4ed1SChristos Margiolis 				 * the process lock.  If all chunks are fully
280f0bc4ed1SChristos Margiolis 				 * utilized, we must release the lock and try
281f0bc4ed1SChristos Margiolis 				 * again.
282f0bc4ed1SChristos Margiolis 				 */
283f0bc4ed1SChristos Margiolis 				tramp = kinst_trampoline_alloc_locked(M_NOWAIT);
284f0bc4ed1SChristos Margiolis 				if (tramp == NULL) {
285f0bc4ed1SChristos Margiolis 					PROC_UNLOCK(p);
286f0bc4ed1SChristos Margiolis 					tramp = kinst_trampoline_alloc_locked(
287f0bc4ed1SChristos Margiolis 					    M_WAITOK);
288f0bc4ed1SChristos Margiolis 					if (tramp == NULL) {
289f0bc4ed1SChristos Margiolis 						/*
290f0bc4ed1SChristos Margiolis 						 * Let the unload handler clean
291f0bc4ed1SChristos Margiolis 						 * up.
292f0bc4ed1SChristos Margiolis 						 */
293f0bc4ed1SChristos Margiolis 						error = ENOMEM;
294f0bc4ed1SChristos Margiolis 						goto out;
295f0bc4ed1SChristos Margiolis 					} else
296f0bc4ed1SChristos Margiolis 						goto retry;
297f0bc4ed1SChristos Margiolis 				}
298f0bc4ed1SChristos Margiolis 			}
2991aa48621SChristos Margiolis 			td->t_kinst_tramp = tramp;
300f0bc4ed1SChristos Margiolis 			tramp = NULL;
301f0bc4ed1SChristos Margiolis 		}
302f0bc4ed1SChristos Margiolis 		PROC_UNLOCK(p);
303f0bc4ed1SChristos Margiolis 	}
304f0bc4ed1SChristos Margiolis out:
305f0bc4ed1SChristos Margiolis 	sx_xunlock(&kinst_tramp_sx);
306f0bc4ed1SChristos Margiolis 	sx_sunlock(&allproc_lock);
307*5b701ed1SChristos Margiolis #else
308*5b701ed1SChristos Margiolis 	int error = 0;
309*5b701ed1SChristos Margiolis 
310*5b701ed1SChristos Margiolis 	sx_xlock(&kinst_tramp_sx);
311*5b701ed1SChristos Margiolis 	TAILQ_INIT(&kinst_trampchunks);
312*5b701ed1SChristos Margiolis 	sx_xunlock(&kinst_tramp_sx);
313*5b701ed1SChristos Margiolis #endif
314*5b701ed1SChristos Margiolis 
315f0bc4ed1SChristos Margiolis 	return (error);
316f0bc4ed1SChristos Margiolis }
317f0bc4ed1SChristos Margiolis 
318f0bc4ed1SChristos Margiolis int
kinst_trampoline_deinit(void)319f0bc4ed1SChristos Margiolis kinst_trampoline_deinit(void)
320f0bc4ed1SChristos Margiolis {
321*5b701ed1SChristos Margiolis #ifdef __amd64__
322f0bc4ed1SChristos Margiolis 	struct trampchunk *chunk, *tmp;
323f0bc4ed1SChristos Margiolis 	struct proc *p;
324f0bc4ed1SChristos Margiolis 	struct thread *td;
325f0bc4ed1SChristos Margiolis 
326f0bc4ed1SChristos Margiolis 	EVENTHANDLER_DEREGISTER(thread_ctor, kinst_thread_ctor_handler);
327f0bc4ed1SChristos Margiolis 	EVENTHANDLER_DEREGISTER(thread_dtor, kinst_thread_dtor_handler);
328f0bc4ed1SChristos Margiolis 
329f0bc4ed1SChristos Margiolis 	sx_slock(&allproc_lock);
330f0bc4ed1SChristos Margiolis 	sx_xlock(&kinst_tramp_sx);
331f0bc4ed1SChristos Margiolis 	FOREACH_PROC_IN_SYSTEM(p) {
332f0bc4ed1SChristos Margiolis 		PROC_LOCK(p);
333f0bc4ed1SChristos Margiolis 		FOREACH_THREAD_IN_PROC(p, td) {
3341aa48621SChristos Margiolis 			kinst_trampoline_dealloc_locked(td->t_kinst_tramp,
3351aa48621SChristos Margiolis 			    false);
3361aa48621SChristos Margiolis 			td->t_kinst_tramp = NULL;
337f0bc4ed1SChristos Margiolis 		}
338f0bc4ed1SChristos Margiolis 		PROC_UNLOCK(p);
339f0bc4ed1SChristos Margiolis 	}
340f0bc4ed1SChristos Margiolis 	sx_sunlock(&allproc_lock);
341f0bc4ed1SChristos Margiolis 	TAILQ_FOREACH_SAFE(chunk, &kinst_trampchunks, next, tmp)
342f0bc4ed1SChristos Margiolis 		kinst_trampchunk_free(chunk);
343f0bc4ed1SChristos Margiolis 	sx_xunlock(&kinst_tramp_sx);
344*5b701ed1SChristos Margiolis #else
345*5b701ed1SChristos Margiolis 	struct trampchunk *chunk, *tmp;
346*5b701ed1SChristos Margiolis 
347*5b701ed1SChristos Margiolis 	sx_xlock(&kinst_tramp_sx);
348*5b701ed1SChristos Margiolis 	TAILQ_FOREACH_SAFE(chunk, &kinst_trampchunks, next, tmp)
349*5b701ed1SChristos Margiolis 		kinst_trampchunk_free(chunk);
350*5b701ed1SChristos Margiolis 	sx_xunlock(&kinst_tramp_sx);
351*5b701ed1SChristos Margiolis #endif
352f0bc4ed1SChristos Margiolis 
353f0bc4ed1SChristos Margiolis 	return (0);
354f0bc4ed1SChristos Margiolis }
355