1179237Sjb/*
2179237Sjb * CDDL HEADER START
3179237Sjb *
4179237Sjb * The contents of this file are subject to the terms of the
5179237Sjb * Common Development and Distribution License (the "License").
6179237Sjb * You may not use this file except in compliance with the License.
7179237Sjb *
8179237Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9179237Sjb * or http://www.opensolaris.org/os/licensing.
10179237Sjb * See the License for the specific language governing permissions
11179237Sjb * and limitations under the License.
12179237Sjb *
13179237Sjb * When distributing Covered Code, include this CDDL HEADER in each
14179237Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15179237Sjb * If applicable, add the following below this CDDL HEADER, with the
16179237Sjb * fields enclosed by brackets "[]" replaced with your own identifying
17179237Sjb * information: Portions Copyright [yyyy] [name of copyright owner]
18179237Sjb *
19179237Sjb * CDDL HEADER END
20179237Sjb *
21179237Sjb * $FreeBSD$
22179237Sjb *
23179237Sjb */
24179237Sjb
25179237Sjbstatic void
26179237Sjbdtrace_ap_start(void *dummy)
27179237Sjb{
28179237Sjb	int i;
29179237Sjb
30179237Sjb	mutex_enter(&cpu_lock);
31179237Sjb
32179237Sjb	/* Setup the rest of the CPUs. */
33209059Sjhb	CPU_FOREACH(i) {
34209059Sjhb		if (i == 0)
35179237Sjb			continue;
36179237Sjb
37179237Sjb		(void) dtrace_cpu_setup(CPU_CONFIG, i);
38179237Sjb	}
39179237Sjb
40179237Sjb	mutex_exit(&cpu_lock);
41179237Sjb}
42179237Sjb
43179237SjbSYSINIT(dtrace_ap_start, SI_SUB_SMP, SI_ORDER_ANY, dtrace_ap_start, NULL);
44179237Sjb
45179237Sjbstatic void
46179237Sjbdtrace_load(void *dummy)
47179237Sjb{
48179237Sjb	dtrace_provider_id_t id;
49179237Sjb
50179237Sjb	/* Hook into the trap handler. */
51179237Sjb	dtrace_trap_func = dtrace_trap;
52179237Sjb
53179237Sjb	/* Hang our hook for thread switches. */
54179237Sjb	dtrace_vtime_switch_func = dtrace_vtime_switch;
55179237Sjb
56179237Sjb	/* Hang our hook for exceptions. */
57179237Sjb	dtrace_invop_init();
58179237Sjb
59262053Savg	dtrace_taskq = taskq_create("dtrace_taskq", 1, maxclsyspri, 0, 0, 0);
60262053Savg
61262055Savg	dtrace_arena = new_unrhdr(1, INT_MAX, &dtrace_unr_mtx);
62262055Savg
63255763Smarkj	/* Register callbacks for linker file load and unload events. */
64255763Smarkj	dtrace_kld_load_tag = EVENTHANDLER_REGISTER(kld_load,
65255763Smarkj	    dtrace_kld_load, NULL, EVENTHANDLER_PRI_ANY);
66262038Savg	dtrace_kld_unload_try_tag = EVENTHANDLER_REGISTER(kld_unload_try,
67262038Savg	    dtrace_kld_unload_try, NULL, EVENTHANDLER_PRI_ANY);
68255763Smarkj
69179237Sjb	/*
70179237Sjb	 * Initialise the mutexes without 'witness' because the dtrace
71179237Sjb	 * code is mostly written to wait for memory. To have the
72179237Sjb	 * witness code change a malloc() from M_WAITOK to M_NOWAIT
73179237Sjb	 * because a lock is held would surely create a panic in a
74179237Sjb	 * low memory situation. And that low memory situation might be
75179237Sjb	 * the very problem we are trying to trace.
76179237Sjb	 */
77179237Sjb	mutex_init(&dtrace_lock,"dtrace probe state", MUTEX_DEFAULT, NULL);
78179237Sjb	mutex_init(&dtrace_provider_lock,"dtrace provider state", MUTEX_DEFAULT, NULL);
79179237Sjb	mutex_init(&dtrace_meta_lock,"dtrace meta-provider state", MUTEX_DEFAULT, NULL);
80254704Savg#ifdef DEBUG
81179237Sjb	mutex_init(&dtrace_errlock,"dtrace error lock", MUTEX_DEFAULT, NULL);
82254704Savg#endif
83179237Sjb
84179237Sjb	mutex_enter(&dtrace_provider_lock);
85179237Sjb	mutex_enter(&dtrace_lock);
86179237Sjb	mutex_enter(&cpu_lock);
87179237Sjb
88179237Sjb	ASSERT(MUTEX_HELD(&cpu_lock));
89179237Sjb
90179237Sjb	dtrace_state_cache = kmem_cache_create("dtrace_state_cache",
91179237Sjb	    sizeof (dtrace_dstate_percpu_t) * NCPU, DTRACE_STATE_ALIGN,
92179237Sjb	    NULL, NULL, NULL, NULL, NULL, 0);
93179237Sjb
94179237Sjb	ASSERT(MUTEX_HELD(&cpu_lock));
95179237Sjb	dtrace_bymod = dtrace_hash_create(offsetof(dtrace_probe_t, dtpr_mod),
96179237Sjb	    offsetof(dtrace_probe_t, dtpr_nextmod),
97179237Sjb	    offsetof(dtrace_probe_t, dtpr_prevmod));
98179237Sjb
99179237Sjb	dtrace_byfunc = dtrace_hash_create(offsetof(dtrace_probe_t, dtpr_func),
100179237Sjb	    offsetof(dtrace_probe_t, dtpr_nextfunc),
101179237Sjb	    offsetof(dtrace_probe_t, dtpr_prevfunc));
102179237Sjb
103179237Sjb	dtrace_byname = dtrace_hash_create(offsetof(dtrace_probe_t, dtpr_name),
104179237Sjb	    offsetof(dtrace_probe_t, dtpr_nextname),
105179237Sjb	    offsetof(dtrace_probe_t, dtpr_prevname));
106179237Sjb
107179237Sjb	if (dtrace_retain_max < 1) {
108179237Sjb		cmn_err(CE_WARN, "illegal value (%lu) for dtrace_retain_max; "
109179237Sjb		    "setting to 1", dtrace_retain_max);
110179237Sjb		dtrace_retain_max = 1;
111179237Sjb	}
112179237Sjb
113179237Sjb	/*
114179237Sjb	 * Now discover our toxic ranges.
115179237Sjb	 */
116179237Sjb	dtrace_toxic_ranges(dtrace_toxrange_add);
117179237Sjb
118179237Sjb	/*
119179237Sjb	 * Before we register ourselves as a provider to our own framework,
120179237Sjb	 * we would like to assert that dtrace_provider is NULL -- but that's
121179237Sjb	 * not true if we were loaded as a dependency of a DTrace provider.
122179237Sjb	 * Once we've registered, we can assert that dtrace_provider is our
123179237Sjb	 * pseudo provider.
124179237Sjb	 */
125179237Sjb	(void) dtrace_register("dtrace", &dtrace_provider_attr,
126179237Sjb	    DTRACE_PRIV_NONE, 0, &dtrace_provider_ops, NULL, &id);
127179237Sjb
128179237Sjb	ASSERT(dtrace_provider != NULL);
129179237Sjb	ASSERT((dtrace_provider_id_t)dtrace_provider == id);
130179237Sjb
131179237Sjb	dtrace_probeid_begin = dtrace_probe_create((dtrace_provider_id_t)
132179237Sjb	    dtrace_provider, NULL, NULL, "BEGIN", 0, NULL);
133179237Sjb	dtrace_probeid_end = dtrace_probe_create((dtrace_provider_id_t)
134179237Sjb	    dtrace_provider, NULL, NULL, "END", 0, NULL);
135179237Sjb	dtrace_probeid_error = dtrace_probe_create((dtrace_provider_id_t)
136179237Sjb	    dtrace_provider, NULL, NULL, "ERROR", 1, NULL);
137179237Sjb
138179237Sjb	mutex_exit(&cpu_lock);
139179237Sjb
140179237Sjb	/*
141179237Sjb	 * If DTrace helper tracing is enabled, we need to allocate the
142179237Sjb	 * trace buffer and initialize the values.
143179237Sjb	 */
144179237Sjb	if (dtrace_helptrace_enabled) {
145179237Sjb		ASSERT(dtrace_helptrace_buffer == NULL);
146179237Sjb		dtrace_helptrace_buffer =
147179237Sjb		    kmem_zalloc(dtrace_helptrace_bufsize, KM_SLEEP);
148179237Sjb		dtrace_helptrace_next = 0;
149179237Sjb	}
150179237Sjb
151179237Sjb	mutex_exit(&dtrace_lock);
152179237Sjb	mutex_exit(&dtrace_provider_lock);
153179237Sjb
154179237Sjb	mutex_enter(&cpu_lock);
155179237Sjb
156179237Sjb	/* Setup the boot CPU */
157179237Sjb	(void) dtrace_cpu_setup(CPU_CONFIG, 0);
158179237Sjb
159179237Sjb	mutex_exit(&cpu_lock);
160179237Sjb
161184698Srodrigc#if __FreeBSD_version < 800039
162179237Sjb	/* Enable device cloning. */
163179237Sjb	clone_setup(&dtrace_clones);
164179237Sjb
165179237Sjb	/* Setup device cloning events. */
166179237Sjb	eh_tag = EVENTHANDLER_REGISTER(dev_clone, dtrace_clone, 0, 1000);
167184698Srodrigc#else
168211608Srpaulo	dtrace_dev = make_dev(&dtrace_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
169211608Srpaulo	    "dtrace/dtrace");
170212093Srpaulo	helper_dev = make_dev(&helper_cdevsw, 0, UID_ROOT, GID_WHEEL, 0660,
171211608Srpaulo	    "dtrace/helper");
172184698Srodrigc#endif
173179237Sjb
174179237Sjb	return;
175179237Sjb}
176