]> git.saurik.com Git - apple/xnu.git/blame - bsd/dev/dtrace/fbt.c
xnu-6153.141.1.tar.gz
[apple/xnu.git] / bsd / dev / dtrace / fbt.c
CommitLineData
2d21ac55
A
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
b0d623f7
A
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
2d21ac55
A
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
6d2010ae 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2d21ac55
A
23 * Use is subject to license terms.
24 */
25
5ba3f43e 26#include <mach-o/loader.h>
b0d623f7 27#include <libkern/kernel_mach_header.h>
2d21ac55
A
28
29#include <sys/param.h>
30#include <sys/systm.h>
5ba3f43e 31#include <sys/sysctl.h>
2d21ac55
A
32#include <sys/errno.h>
33#include <sys/stat.h>
34#include <sys/ioctl.h>
35#include <sys/conf.h>
36#include <sys/fcntl.h>
37#include <miscfs/devfs/devfs.h>
38#include <pexpert/pexpert.h>
39
40#include <sys/dtrace.h>
41#include <sys/dtrace_impl.h>
42#include <sys/fbt.h>
43
44#include <sys/dtrace_glue.h>
a39ff7e2 45#include <san/kasan.h>
2d21ac55
A
46
47/* #include <machine/trap.h> */
48struct savearea_t; /* Used anonymously */
2d21ac55 49
5ba3f43e
A
50#if defined(__arm__) || defined(__arm64__)
51typedef kern_return_t (*perfCallback)(int, struct savearea_t *, __unused int, __unused int);
52extern perfCallback tempDTraceTrapHook;
53extern kern_return_t fbt_perfCallback(int, struct savearea_t *, __unused int, __unused int);
54#elif defined(__x86_64__)
39236c6e 55typedef kern_return_t (*perfCallback)(int, struct savearea_t *, uintptr_t *, __unused int);
2d21ac55 56extern perfCallback tempDTraceTrapHook;
39236c6e 57extern kern_return_t fbt_perfCallback(int, struct savearea_t *, uintptr_t *, __unused int);
fe8ab488
A
58#else
59#error Unknown architecture
60#endif
2d21ac55 61
d9a64523
A
62__private_extern__
63void
64qsort(void *a, size_t n, size_t es, int (*cmp)(const void *, const void *));
65
0a7de745
A
66#define FBT_ADDR2NDX(addr) ((((uintptr_t)(addr)) >> 4) & fbt_probetab_mask)
67#define FBT_PROBETAB_SIZE 0x8000 /* 32k entries -- 128K total */
2d21ac55 68
0a7de745
A
69static int fbt_probetab_size;
70dtrace_provider_id_t fbt_id;
71fbt_probe_t **fbt_probetab;
72int fbt_probetab_mask;
73static int fbt_verbose = 0;
2d21ac55 74
cb323159 75extern int ignore_fbt_blacklist;
5ba3f43e
A
76
77extern int dtrace_kernel_symbol_mode;
78
79
2d21ac55
A
80void fbt_init( void );
81
82/*ARGSUSED*/
83static void
84fbt_destroy(void *arg, dtrace_id_t id, void *parg)
85{
86#pragma unused(arg,id)
87 fbt_probe_t *fbt = parg, *next, *hash, *last;
88 int ndx;
89
90 do {
91 /*
92 * Now we need to remove this probe from the fbt_probetab.
93 */
94 ndx = FBT_ADDR2NDX(fbt->fbtp_patchpoint);
95 last = NULL;
96 hash = fbt_probetab[ndx];
97
98 while (hash != fbt) {
99 ASSERT(hash != NULL);
100 last = hash;
101 hash = hash->fbtp_hashnext;
102 }
103
104 if (last != NULL) {
105 last->fbtp_hashnext = fbt->fbtp_hashnext;
106 } else {
107 fbt_probetab[ndx] = fbt->fbtp_hashnext;
108 }
109
110 next = fbt->fbtp_next;
0a7de745 111 kmem_free(fbt, sizeof(fbt_probe_t));
2d21ac55
A
112
113 fbt = next;
114 } while (fbt != NULL);
115}
116
117/*ARGSUSED*/
6d2010ae 118int
2d21ac55
A
119fbt_enable(void *arg, dtrace_id_t id, void *parg)
120{
121#pragma unused(arg,id)
122 fbt_probe_t *fbt = parg;
6d2010ae
A
123 struct modctl *ctl = NULL;
124
0a7de745
A
125 for (; fbt != NULL; fbt = fbt->fbtp_next) {
126 ctl = fbt->fbtp_ctl;
2d21ac55 127
0a7de745
A
128 if (!ctl->mod_loaded) {
129 if (fbt_verbose) {
130 cmn_err(CE_NOTE, "fbt is failing for probe %s "
131 "(module %s unloaded)",
132 fbt->fbtp_name, ctl->mod_modname);
133 }
d9a64523 134
0a7de745 135 continue;
2d21ac55 136 }
6d2010ae 137
0a7de745
A
138 /*
139 * Now check that our modctl has the expected load count. If it
140 * doesn't, this module must have been unloaded and reloaded -- and
141 * we're not going to touch it.
142 */
143 if (ctl->mod_loadcnt != fbt->fbtp_loadcnt) {
144 if (fbt_verbose) {
145 cmn_err(CE_NOTE, "fbt is failing for probe %s "
146 "(module %s reloaded)",
147 fbt->fbtp_name, ctl->mod_modname);
148 }
6d2010ae 149
0a7de745 150 continue;
6d2010ae
A
151 }
152
0a7de745
A
153 dtrace_casptr(&tempDTraceTrapHook, NULL, fbt_perfCallback);
154 if (tempDTraceTrapHook != (perfCallback)fbt_perfCallback) {
155 if (fbt_verbose) {
156 cmn_err(CE_NOTE, "fbt_enable is failing for probe %s "
157 "in module %s: tempDTraceTrapHook already occupied.",
158 fbt->fbtp_name, ctl->mod_modname);
159 }
160 continue;
2d21ac55 161 }
2d21ac55 162
0a7de745 163 if (fbt->fbtp_currentval != fbt->fbtp_patchval) {
a39ff7e2 164#if KASAN
0a7de745
A
165 /* Since dtrace probes can call into KASan and vice versa, things can get
166 * very slow if we have a lot of probes. This call will disable the KASan
167 * fakestack after a threshold of probes is reached. */
168 kasan_fakestack_suspend();
a39ff7e2
A
169#endif
170
0a7de745
A
171 (void)ml_nofault_copy((vm_offset_t)&fbt->fbtp_patchval, (vm_offset_t)fbt->fbtp_patchpoint,
172 sizeof(fbt->fbtp_patchval));
173 /*
174 * Make the patched instruction visible via a data + instruction
175 * cache flush for the platforms that need it
176 */
177 flush_dcache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_patchval), 0);
178 invalidate_icache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_patchval), 0);
179 fbt->fbtp_currentval = fbt->fbtp_patchval;
39037602 180
0a7de745
A
181 ctl->mod_nenabled++;
182 }
6d2010ae
A
183 }
184
0a7de745 185 dtrace_membar_consumer();
d9a64523 186
0a7de745 187 return 0;
2d21ac55
A
188}
189
190/*ARGSUSED*/
191static void
192fbt_disable(void *arg, dtrace_id_t id, void *parg)
193{
194#pragma unused(arg,id)
195 fbt_probe_t *fbt = parg;
6d2010ae
A
196 struct modctl *ctl = NULL;
197
198 for (; fbt != NULL; fbt = fbt->fbtp_next) {
0a7de745 199 ctl = fbt->fbtp_ctl;
d9a64523 200
0a7de745
A
201 if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt)) {
202 continue;
203 }
2d21ac55 204
0a7de745
A
205 if (fbt->fbtp_currentval != fbt->fbtp_savedval) {
206 (void)ml_nofault_copy((vm_offset_t)&fbt->fbtp_savedval, (vm_offset_t)fbt->fbtp_patchpoint,
207 sizeof(fbt->fbtp_savedval));
208 /*
209 * Make the patched instruction visible via a data + instruction
210 * cache flush for the platforms that need it
211 */
212 flush_dcache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_patchval), 0);
213 invalidate_icache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_patchval), 0);
39037602 214
0a7de745
A
215 fbt->fbtp_currentval = fbt->fbtp_savedval;
216 ASSERT(ctl->mod_nenabled > 0);
217 ctl->mod_nenabled--;
a39ff7e2
A
218
219#if KASAN
0a7de745 220 kasan_fakestack_resume();
a39ff7e2 221#endif
0a7de745 222 }
6d2010ae 223 }
2d21ac55
A
224 dtrace_membar_consumer();
225}
226
227/*ARGSUSED*/
228static void
229fbt_suspend(void *arg, dtrace_id_t id, void *parg)
230{
231#pragma unused(arg,id)
232 fbt_probe_t *fbt = parg;
6d2010ae 233 struct modctl *ctl = NULL;
2d21ac55 234
6d2010ae 235 for (; fbt != NULL; fbt = fbt->fbtp_next) {
0a7de745 236 ctl = fbt->fbtp_ctl;
6d2010ae 237
0a7de745
A
238 ASSERT(ctl->mod_nenabled > 0);
239 if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt)) {
240 continue;
241 }
6d2010ae 242
0a7de745
A
243 (void)ml_nofault_copy((vm_offset_t)&fbt->fbtp_savedval, (vm_offset_t)fbt->fbtp_patchpoint,
244 sizeof(fbt->fbtp_savedval));
d9a64523 245
39037602
A
246 /*
247 * Make the patched instruction visible via a data + instruction
248 * cache flush for the platforms that need it
249 */
0a7de745
A
250 flush_dcache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_savedval), 0);
251 invalidate_icache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_savedval), 0);
d9a64523 252
39037602 253 fbt->fbtp_currentval = fbt->fbtp_savedval;
6d2010ae 254 }
d9a64523 255
2d21ac55
A
256 dtrace_membar_consumer();
257}
258
259/*ARGSUSED*/
260static void
261fbt_resume(void *arg, dtrace_id_t id, void *parg)
262{
263#pragma unused(arg,id)
264 fbt_probe_t *fbt = parg;
6d2010ae 265 struct modctl *ctl = NULL;
2d21ac55 266
6d2010ae 267 for (; fbt != NULL; fbt = fbt->fbtp_next) {
0a7de745
A
268 ctl = fbt->fbtp_ctl;
269
270 ASSERT(ctl->mod_nenabled > 0);
271 if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt)) {
272 continue;
2d21ac55 273 }
d9a64523 274
0a7de745
A
275 dtrace_casptr(&tempDTraceTrapHook, NULL, fbt_perfCallback);
276 if (tempDTraceTrapHook != (perfCallback)fbt_perfCallback) {
277 if (fbt_verbose) {
278 cmn_err(CE_NOTE, "fbt_resume is failing for probe %s "
279 "in module %s: tempDTraceTrapHook already occupied.",
280 fbt->fbtp_name, ctl->mod_modname);
281 }
282 return;
283 }
284
285 (void)ml_nofault_copy((vm_offset_t)&fbt->fbtp_patchval, (vm_offset_t)fbt->fbtp_patchpoint,
286 sizeof(fbt->fbtp_patchval));
39236c6e 287
5ba3f43e
A
288 /*
289 * Make the patched instruction visible via a data + instruction cache flush.
290 */
0a7de745
A
291 flush_dcache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_patchval), 0);
292 invalidate_icache((vm_offset_t)fbt->fbtp_patchpoint, (vm_size_t)sizeof(fbt->fbtp_patchval), 0);
2d21ac55 293
0a7de745 294 fbt->fbtp_currentval = fbt->fbtp_patchval;
2d21ac55 295 }
2d21ac55 296
d9a64523 297 dtrace_membar_consumer();
2d21ac55 298}
2d21ac55 299
5ba3f43e
A
300static void
301fbt_provide_module_user_syms(struct modctl *ctl)
302{
303 unsigned int i;
304 char *modname = ctl->mod_modname;
305
306 dtrace_module_symbols_t* module_symbols = ctl->mod_user_symbols;
307 if (module_symbols) {
0a7de745
A
308 for (i = 0; i < module_symbols->dtmodsyms_count; i++) {
309 /*
5ba3f43e
A
310 * symbol->dtsym_addr (the symbol address) passed in from
311 * user space, is already slid for both kexts and kernel.
312 */
313 dtrace_symbol_t* symbol = &module_symbols->dtmodsyms_symbols[i];
314
315 char* name = symbol->dtsym_name;
316
317 /* Lop off omnipresent leading underscore. */
0a7de745 318 if (*name == '_') {
5ba3f43e 319 name += 1;
0a7de745 320 }
5ba3f43e 321
cb323159 322 if (fbt_excluded(name)) {
d9a64523 323 continue;
0a7de745 324 }
5ba3f43e
A
325
326 /*
327 * Ignore symbols with a null address
328 */
0a7de745 329 if (!symbol->dtsym_addr) {
5ba3f43e 330 continue;
0a7de745 331 }
5ba3f43e 332
d9a64523
A
333 /*
334 * Ignore symbols not part of this module
335 */
0a7de745 336 if (!dtrace_addr_in_module((void*)symbol->dtsym_addr, ctl)) {
d9a64523 337 continue;
0a7de745 338 }
d9a64523
A
339
340 fbt_provide_probe(ctl, modname, name, (machine_inst_t*)(uintptr_t)symbol->dtsym_addr, (machine_inst_t*)(uintptr_t)(symbol->dtsym_addr + symbol->dtsym_size));
5ba3f43e
A
341 }
342 }
343}
d9a64523
A
344static void
345fbt_provide_kernel_section(struct modctl *ctl, kernel_section_t *sect, kernel_nlist_t *sym, uint32_t nsyms, const char *strings)
346{
347 uintptr_t sect_start = (uintptr_t)sect->addr;
348 uintptr_t sect_end = (uintptr_t)sect->size + sect->addr;
349 unsigned int i;
350
351 if ((sect->flags & S_ATTR_PURE_INSTRUCTIONS) != S_ATTR_PURE_INSTRUCTIONS) {
352 return;
353 }
354
355 for (i = 0; i < nsyms; i++) {
356 uint8_t n_type = sym[i].n_type & (N_TYPE | N_EXT);
357 const char *name = strings + sym[i].n_un.n_strx;
358 uint64_t limit;
359
0a7de745 360 if (sym[i].n_value < sect_start || sym[i].n_value > sect_end) {
d9a64523 361 continue;
0a7de745 362 }
d9a64523
A
363
364 /* Check that the symbol is a global and that it has a name. */
0a7de745 365 if (((N_SECT | N_EXT) != n_type && (N_ABS | N_EXT) != n_type)) {
d9a64523 366 continue;
0a7de745 367 }
d9a64523 368
0a7de745 369 if (0 == sym[i].n_un.n_strx) { /* iff a null, "", name. */
d9a64523 370 continue;
0a7de745 371 }
d9a64523
A
372
373 /* Lop off omnipresent leading underscore. */
0a7de745 374 if (*name == '_') {
d9a64523 375 name += 1;
0a7de745 376 }
d9a64523
A
377
378#if defined(__arm__)
379 // Skip non-thumb functions on arm32
380 if (sym[i].n_sect == 1 && !(sym[i].n_desc & N_ARM_THUMB_DEF)) {
381 continue;
382 }
383#endif /* defined(__arm__) */
384
cb323159 385 if (fbt_excluded(name)) {
d9a64523 386 continue;
0a7de745 387 }
d9a64523
A
388
389 /*
390 * Find the function boundary by looking at either the
391 * end of the section or the beginning of the next symbol
392 */
393 if (i == nsyms - 1) {
394 limit = sect_end;
0a7de745 395 } else {
d9a64523
A
396 limit = sym[i + 1].n_value;
397 }
398
399 fbt_provide_probe(ctl, ctl->mod_modname, name, (machine_inst_t*)sym[i].n_value, (machine_inst_t*)limit);
400 }
d9a64523
A
401}
402
403static int
404fbt_sym_cmp(const void *ap, const void *bp)
405{
406 return (int)(((const kernel_nlist_t*)ap)->n_value - ((const kernel_nlist_t*)bp)->n_value);
407}
408
409static void
410fbt_provide_module_kernel_syms(struct modctl *ctl)
411{
412 kernel_mach_header_t *mh = (kernel_mach_header_t *)(ctl->mod_address);
413 kernel_segment_command_t *seg;
414 struct load_command *cmd;
415 kernel_segment_command_t *linkedit = NULL;
416 struct symtab_command *symtab = NULL;
417 kernel_nlist_t *syms = NULL, *sorted_syms = NULL;
418 const char *strings;
419 unsigned int i;
420 size_t symlen;
421
0a7de745 422 if (mh->magic != MH_MAGIC_KERNEL) {
d9a64523 423 return;
0a7de745 424 }
d9a64523
A
425
426 cmd = (struct load_command *) &mh[1];
427 for (i = 0; i < mh->ncmds; i++) {
428 if (cmd->cmd == LC_SEGMENT_KERNEL) {
429 kernel_segment_command_t *orig_sg = (kernel_segment_command_t *) cmd;
0a7de745 430 if (LIT_STRNEQL(orig_sg->segname, SEG_LINKEDIT)) {
d9a64523 431 linkedit = orig_sg;
0a7de745 432 }
d9a64523
A
433 } else if (cmd->cmd == LC_SYMTAB) {
434 symtab = (struct symtab_command *) cmd;
435 }
436 if (symtab && linkedit) {
437 break;
438 }
439 cmd = (struct load_command *) ((caddr_t) cmd + cmd->cmdsize);
440 }
5ba3f43e 441
d9a64523
A
442 if ((symtab == NULL) || (linkedit == NULL)) {
443 return;
444 }
445
446 syms = (kernel_nlist_t *)(linkedit->vmaddr + symtab->symoff - linkedit->fileoff);
447 strings = (const char *)(linkedit->vmaddr + symtab->stroff - linkedit->fileoff);
448
449 /*
450 * Make a copy of the symbol table and sort it to not cross into the next function
451 * when disassembling the function
452 */
453 symlen = sizeof(kernel_nlist_t) * symtab->nsyms;
454 sorted_syms = kmem_alloc(symlen, KM_SLEEP);
455 bcopy(syms, sorted_syms, symlen);
456 qsort(sorted_syms, symtab->nsyms, sizeof(kernel_nlist_t), fbt_sym_cmp);
457
458 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
459 kernel_section_t *sect = firstsect(seg);
460
461 if (strcmp(seg->segname, "__KLD") == 0) {
462 continue;
463 }
464
465 for (sect = firstsect(seg); sect != NULL; sect = nextsect(seg, sect)) {
466 fbt_provide_kernel_section(ctl, sect, sorted_syms, symtab->nsyms, strings);
467 }
468 }
469
470 kmem_free(sorted_syms, symlen);
471}
5ba3f43e
A
472
473void
474fbt_provide_module(void *arg, struct modctl *ctl)
475{
476#pragma unused(arg)
477 ASSERT(ctl != NULL);
478 ASSERT(dtrace_kernel_symbol_mode != DTRACE_KERNEL_SYMBOLS_NEVER);
479 LCK_MTX_ASSERT(&mod_lock, LCK_MTX_ASSERT_OWNED);
480
481 // Update the "ignore blacklist" bit
0a7de745 482 if (ignore_fbt_blacklist) {
5ba3f43e 483 ctl->mod_flags |= MODCTL_FBT_PROVIDE_BLACKLISTED_PROBES;
0a7de745 484 }
5ba3f43e 485
0a7de745 486 if (MOD_FBT_DONE(ctl)) {
5ba3f43e 487 return;
0a7de745 488 }
5ba3f43e
A
489
490 if (fbt_module_excluded(ctl)) {
491 ctl->mod_flags |= MODCTL_FBT_INVALID;
492 return;
493 }
494
495 if (MOD_HAS_KERNEL_SYMBOLS(ctl)) {
496 fbt_provide_module_kernel_syms(ctl);
497 ctl->mod_flags |= MODCTL_FBT_PROBES_PROVIDED;
0a7de745 498 if (MOD_FBT_PROVIDE_BLACKLISTED_PROBES(ctl)) {
5ba3f43e 499 ctl->mod_flags |= MODCTL_FBT_BLACKLISTED_PROBES_PROVIDED;
0a7de745 500 }
5ba3f43e
A
501 return;
502 }
503
504 if (MOD_HAS_USERSPACE_SYMBOLS(ctl)) {
505 fbt_provide_module_user_syms(ctl);
506 ctl->mod_flags |= MODCTL_FBT_PROBES_PROVIDED;
0a7de745 507 if (MOD_FBT_PROVIDE_BLACKLISTED_PROBES(ctl)) {
5ba3f43e 508 ctl->mod_flags |= MODCTL_FBT_BLACKLISTED_PROBES_PROVIDED;
0a7de745 509 }
5ba3f43e
A
510 return;
511 }
512}
513
2d21ac55 514static dtrace_pattr_t fbt_attr = {
0a7de745
A
515 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
516 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
517 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
518 { DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
519 { DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_ISA },
2d21ac55
A
520};
521
522static dtrace_pops_t fbt_pops = {
0a7de745
A
523 .dtps_provide = NULL,
524 .dtps_provide_module = fbt_provide_module,
525 .dtps_enable = fbt_enable,
526 .dtps_disable = fbt_disable,
527 .dtps_suspend = fbt_suspend,
528 .dtps_resume = fbt_resume,
529 .dtps_getargdesc = NULL, /* APPLE NOTE: fbt_getargdesc implemented in userspace */
530 .dtps_getargval = NULL,
531 .dtps_usermode = NULL,
532 .dtps_destroy = fbt_destroy
2d21ac55
A
533};
534
535static void
536fbt_cleanup(dev_info_t *devi)
537{
538 dtrace_invop_remove(fbt_invop);
539 ddi_remove_minor_node(devi, NULL);
0a7de745 540 kmem_free(fbt_probetab, fbt_probetab_size * sizeof(fbt_probe_t *));
2d21ac55
A
541 fbt_probetab = NULL;
542 fbt_probetab_mask = 0;
543}
544
545static int
d9a64523 546fbt_attach(dev_info_t *devi)
2d21ac55 547{
0a7de745 548 if (fbt_probetab_size == 0) {
2d21ac55 549 fbt_probetab_size = FBT_PROBETAB_SIZE;
0a7de745 550 }
2d21ac55
A
551
552 fbt_probetab_mask = fbt_probetab_size - 1;
553 fbt_probetab =
0a7de745 554 kmem_zalloc(fbt_probetab_size * sizeof(fbt_probe_t *), KM_SLEEP);
2d21ac55
A
555
556 dtrace_invop_add(fbt_invop);
557
b0d623f7
A
558 if (ddi_create_minor_node(devi, "fbt", S_IFCHR, 0,
559 DDI_PSEUDO, 0) == DDI_FAILURE ||
560 dtrace_register("fbt", &fbt_attr, DTRACE_PRIV_KERNEL, NULL,
561 &fbt_pops, NULL, &fbt_id) != 0) {
562 fbt_cleanup(devi);
0a7de745 563 return DDI_FAILURE;
b0d623f7 564 }
2d21ac55 565
0a7de745 566 return DDI_SUCCESS;
2d21ac55
A
567}
568
569static d_open_t _fbt_open;
570
571static int
572_fbt_open(dev_t dev, int flags, int devtype, struct proc *p)
573{
574#pragma unused(dev,flags,devtype,p)
575 return 0;
576}
577
578#define FBT_MAJOR -24 /* let the kernel pick the device number */
579
5ba3f43e 580
2d21ac55
A
581/*
582 * A struct describing which functions will get invoked for certain
583 * actions.
584 */
585static struct cdevsw fbt_cdevsw =
586{
0a7de745
A
587 _fbt_open, /* open */
588 eno_opcl, /* close */
589 eno_rdwrt, /* read */
590 eno_rdwrt, /* write */
591 eno_ioctl, /* ioctl */
2d21ac55
A
592 (stop_fcn_t *)nulldev, /* stop */
593 (reset_fcn_t *)nulldev, /* reset */
0a7de745
A
594 NULL, /* tty's */
595 eno_select, /* select */
596 eno_mmap, /* mmap */
597 eno_strat, /* strategy */
598 eno_getc, /* getc */
599 eno_putc, /* putc */
600 0 /* type */
2d21ac55
A
601};
602
2d21ac55
A
603#undef kmem_alloc /* from its binding to dt_kmem_alloc glue */
604#undef kmem_free /* from its binding to dt_kmem_free glue */
605#include <vm/vm_kern.h>
606
cb323159 607
2d21ac55
A
608void
609fbt_init( void )
610{
d9a64523 611 int majdevno = cdevsw_add(FBT_MAJOR, &fbt_cdevsw);
2d21ac55 612
d9a64523
A
613 if (majdevno < 0) {
614 printf("fbt_init: failed to allocate a major number!\n");
615 return;
2d21ac55 616 }
d9a64523 617
cb323159 618 fbt_blacklist_init();
d9a64523 619 fbt_attach((dev_info_t*)(uintptr_t)majdevno);
2d21ac55
A
620}
621#undef FBT_MAJOR