4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
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.
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]
22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* #pragma ident "@(#)profile.c 1.7 07/01/10 SMI" */
28 #if !defined(__APPLE__)
29 #include <sys/errno.h>
31 #include <sys/modctl.h>
33 #include <sys/systm.h>
35 #include <sys/sunddi.h>
36 #include <sys/cpuvar.h>
38 #include <sys/strsubr.h>
39 #include <sys/dtrace.h>
40 #include <sys/cyclic.h>
41 #include <sys/atomic.h>
45 #define _KERNEL /* Solaris vs. Darwin */
49 #define MACH__POSIX_C_SOURCE_PRIVATE 1 /* pulls in suitable savearea from mach/ppc/thread_status.h */
50 #include <kern/cpu_data.h>
51 #include <kern/thread.h>
52 #include <mach/thread_status.h>
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/errno.h>
58 #include <sys/ioctl.h>
60 #include <sys/fcntl.h>
61 #include <miscfs/devfs/devfs.h>
63 #include <sys/dtrace.h>
64 #include <sys/dtrace_impl.h>
66 #include <sys/dtrace_glue.h>
68 #if defined(__ppc__) || defined(__ppc64__)
69 extern struct savearea
*find_kern_regs(thread_t
);
70 #elif defined(__i386__) || defined(__x86_64__)
71 extern x86_saved_state_t
*find_kern_regs(thread_t
);
73 #error Unknown architecture
77 #define ASSERT(x) do {} while(0)
79 extern void profile_init(void);
80 #endif /* __APPLE__ */
82 static dev_info_t
*profile_devi
;
83 static dtrace_provider_id_t profile_id
;
86 * Regardless of platform, the stack frames look like this in the case of the
95 * On x86, there are five frames from the generic interrupt code; further, the
96 * interrupted instruction appears as its own stack frame, giving us a total of
99 * On SPARC, the picture is further complicated because the compiler
100 * optimizes away tail-calls -- so the following frames are optimized away:
105 * This gives three frames. However, on DEBUG kernels, the cyclic_expire
106 * frame cannot be tail-call eliminated, yielding four frames in this case.
108 * All of the above constraints lead to the mess below. Yes, the profile
109 * provider should ideally figure this out on-the-fly by hitting one of its own
110 * probes and then walking its own stack trace. This is complicated, however,
111 * and the static definition doesn't seem to be overly brittle. Still, we
112 * allow for a manual override in case we get it completely wrong.
114 #if !defined(__APPLE__)
117 #define PROF_ARTIFICIAL_FRAMES 10
121 #define PROF_ARTIFICIAL_FRAMES 4
123 #define PROF_ARTIFICIAL_FRAMES 3
128 #else /* is Mac OS X */
130 #if defined(__ppc__) || defined(__ppc64__)
131 #define PROF_ARTIFICIAL_FRAMES 8
132 #elif defined(__i386__) || defined(__x86_64__)
133 #define PROF_ARTIFICIAL_FRAMES 9
135 #error Unknown architecture
138 #endif /* __APPLE__ */
140 #define PROF_NAMELEN 15
142 #define PROF_PROFILE 0
144 #define PROF_PREFIX_PROFILE "profile-"
145 #define PROF_PREFIX_TICK "tick-"
147 typedef struct profile_probe
{
148 char prof_name
[PROF_NAMELEN
];
151 hrtime_t prof_interval
;
152 cyclic_id_t prof_cyclic
;
155 typedef struct profile_probe_percpu
{
156 hrtime_t profc_expected
;
157 hrtime_t profc_interval
;
158 profile_probe_t
*profc_probe
;
159 } profile_probe_percpu_t
;
161 hrtime_t profile_interval_min
= NANOSEC
/ 5000; /* 5000 hz */
162 int profile_aframes
= 0; /* override */
164 static int profile_rates
[] = {
165 97, 199, 499, 997, 1999,
171 static int profile_ticks
[] = {
172 1, 10, 100, 500, 1000,
178 * profile_max defines the upper bound on the number of profile probes that
179 * can exist (this is to prevent malicious or clumsy users from exhausing
180 * system resources by creating a slew of profile probes). At mod load time,
181 * this gets its value from PROFILE_MAX_DEFAULT or profile-max-probes if it's
182 * present in the profile.conf file.
184 #define PROFILE_MAX_DEFAULT 1000 /* default max. number of probes */
185 static uint32_t profile_max
; /* maximum number of profile probes */
186 static uint32_t profile_total
; /* current number of profile probes */
190 profile_fire(void *arg
)
192 profile_probe_percpu_t
*pcpu
= arg
;
193 profile_probe_t
*prof
= pcpu
->profc_probe
;
196 late
= dtrace_gethrtime() - pcpu
->profc_expected
;
197 pcpu
->profc_expected
+= pcpu
->profc_interval
;
199 #if !defined(__APPLE__)
200 dtrace_probe(prof
->prof_id
, CPU
->cpu_profile_pc
,
201 CPU
->cpu_profile_upc
, late
, 0, 0);
203 #if defined(__ppc__) || defined(__ppc64__)
205 struct savearea
*sv
= find_kern_regs(current_thread());
208 if (USERMODE(sv
->save_srr1
)) {
209 dtrace_probe(prof
->prof_id
, 0x0, sv
->save_srr0
, late
, 0, 0);
211 dtrace_probe(prof
->prof_id
, sv
->save_srr0
, 0x0, late
, 0, 0);
214 dtrace_probe(prof
->prof_id
, 0xcafebabe,
215 0x0, late
, 0, 0); /* XXX_BOGUS also see profile_usermode() below. */
218 #elif defined(__i386__) || defined(__x86_64__)
219 x86_saved_state_t
*kern_regs
= find_kern_regs(current_thread());
221 if (NULL
!= kern_regs
) {
222 /* Kernel was interrupted. */
223 #if defined(__i386__)
224 dtrace_probe(prof
->prof_id
, saved_state32(kern_regs
)->eip
, 0x0, 0, 0, 0);
225 #elif defined(__x86_64__)
226 dtrace_probe(prof
->prof_id
, saved_state64(kern_regs
)->isf
.rip
, 0x0, 0, 0, 0);
231 /* Possibly a user interrupt */
232 x86_saved_state_t
*tagged_regs
= (x86_saved_state_t
*)find_user_regs(current_thread());
234 if (NULL
== tagged_regs
) {
235 /* Too bad, so sad, no useful interrupt state. */
236 dtrace_probe(prof
->prof_id
, 0xcafebabe,
237 0x0, 0, 0, 0); /* XXX_BOGUS also see profile_usermode() below. */
238 } else if (is_saved_state64(tagged_regs
)) {
239 x86_saved_state64_t
*regs
= saved_state64(tagged_regs
);
241 dtrace_probe(prof
->prof_id
, 0x0, regs
->isf
.rip
, 0, 0, 0);
243 x86_saved_state32_t
*regs
= saved_state32(tagged_regs
);
245 dtrace_probe(prof
->prof_id
, 0x0, regs
->eip
, 0, 0, 0);
249 #error Unknown architecture
251 #endif /* __APPLE__ */
255 profile_tick(void *arg
)
257 profile_probe_t
*prof
= arg
;
259 #if !defined(__APPLE__)
260 dtrace_probe(prof
->prof_id
, CPU
->cpu_profile_pc
,
261 CPU
->cpu_profile_upc
, 0, 0, 0);
263 #if defined(__ppc__) || defined(__ppc64__)
265 struct savearea
*sv
= find_kern_regs(current_thread());
268 if (USERMODE(sv
->save_srr1
)) {
269 dtrace_probe(prof
->prof_id
, 0x0, sv
->save_srr0
, 0, 0, 0);
271 dtrace_probe(prof
->prof_id
, sv
->save_srr0
, 0x0, 0, 0, 0);
274 dtrace_probe(prof
->prof_id
, 0xcafebabe,
275 0x0, 0, 0, 0); /* XXX_BOGUS also see profile_usermode() below. */
278 #elif defined(__i386__) || defined(__x86_64__)
279 x86_saved_state_t
*kern_regs
= find_kern_regs(current_thread());
281 if (NULL
!= kern_regs
) {
282 /* Kernel was interrupted. */
283 #if defined(__i386__)
284 dtrace_probe(prof
->prof_id
, saved_state32(kern_regs
)->eip
, 0x0, 0, 0, 0);
285 #elif defined(__x86_64__)
286 dtrace_probe(prof
->prof_id
, saved_state64(kern_regs
)->isf
.rip
, 0x0, 0, 0, 0);
291 /* Possibly a user interrupt */
292 x86_saved_state_t
*tagged_regs
= (x86_saved_state_t
*)find_user_regs(current_thread());
294 if (NULL
== tagged_regs
) {
295 /* Too bad, so sad, no useful interrupt state. */
296 dtrace_probe(prof
->prof_id
, 0xcafebabe,
297 0x0, 0, 0, 0); /* XXX_BOGUS also see profile_usermode() below. */
298 } else if (is_saved_state64(tagged_regs
)) {
299 x86_saved_state64_t
*regs
= saved_state64(tagged_regs
);
301 dtrace_probe(prof
->prof_id
, 0x0, regs
->isf
.rip
, 0, 0, 0);
303 x86_saved_state32_t
*regs
= saved_state32(tagged_regs
);
305 dtrace_probe(prof
->prof_id
, 0x0, regs
->eip
, 0, 0, 0);
309 #error Unknown architecture
311 #endif /* __APPLE__ */
315 profile_create(hrtime_t interval
, const char *name
, int kind
)
317 profile_probe_t
*prof
;
319 if (interval
< profile_interval_min
)
322 if (dtrace_probe_lookup(profile_id
, NULL
, NULL
, name
) != 0)
325 atomic_add_32(&profile_total
, 1);
326 if (profile_total
> profile_max
) {
327 atomic_add_32(&profile_total
, -1);
331 #if !defined(__APPLE__)
332 prof
= kmem_zalloc(sizeof (profile_probe_t
), KM_SLEEP
);
334 if (PROF_TICK
== kind
)
335 prof
= kmem_zalloc(sizeof (profile_probe_t
), KM_SLEEP
);
337 prof
= kmem_zalloc(sizeof (profile_probe_t
) + NCPU
*sizeof(profile_probe_percpu_t
), KM_SLEEP
);
338 #endif /* __APPLE__ */
339 (void) strlcpy(prof
->prof_name
, name
, sizeof(prof
->prof_name
));
340 prof
->prof_interval
= interval
;
341 prof
->prof_cyclic
= CYCLIC_NONE
;
342 prof
->prof_kind
= kind
;
343 prof
->prof_id
= dtrace_probe_create(profile_id
,
345 profile_aframes
? profile_aframes
: PROF_ARTIFICIAL_FRAMES
, prof
);
350 profile_provide(void *arg
, const dtrace_probedesc_t
*desc
)
352 #pragma unused(arg) /* __APPLE__ */
353 int i
, j
, rate
, kind
;
354 hrtime_t val
= 0, mult
= 1, len
;
355 const char *name
, *suffix
= NULL
;
357 #if !defined(__APPLE__)
362 { PROF_PREFIX_PROFILE
, PROF_PROFILE
},
363 { PROF_PREFIX_TICK
, PROF_TICK
},
371 { "ns", NANOSEC
/ NANOSEC
},
372 { "nsec", NANOSEC
/ NANOSEC
},
373 { "us", NANOSEC
/ MICROSEC
},
374 { "usec", NANOSEC
/ MICROSEC
},
375 { "ms", NANOSEC
/ MILLISEC
},
376 { "msec", NANOSEC
/ MILLISEC
},
377 { "s", NANOSEC
/ SEC
},
378 { "sec", NANOSEC
/ SEC
},
379 { "m", NANOSEC
* (hrtime_t
)60 },
380 { "min", NANOSEC
* (hrtime_t
)60 },
381 { "h", NANOSEC
* (hrtime_t
)(60 * 60) },
382 { "hour", NANOSEC
* (hrtime_t
)(60 * 60) },
383 { "d", NANOSEC
* (hrtime_t
)(24 * 60 * 60) },
384 { "day", NANOSEC
* (hrtime_t
)(24 * 60 * 60) },
393 { PROF_PREFIX_PROFILE
, PROF_PROFILE
},
394 { PROF_PREFIX_TICK
, PROF_TICK
},
402 { "ns", NANOSEC
/ NANOSEC
},
403 { "nsec", NANOSEC
/ NANOSEC
},
404 { "us", NANOSEC
/ MICROSEC
},
405 { "usec", NANOSEC
/ MICROSEC
},
406 { "ms", NANOSEC
/ MILLISEC
},
407 { "msec", NANOSEC
/ MILLISEC
},
408 { "s", NANOSEC
/ SEC
},
409 { "sec", NANOSEC
/ SEC
},
410 { "m", NANOSEC
* (hrtime_t
)60 },
411 { "min", NANOSEC
* (hrtime_t
)60 },
412 { "h", NANOSEC
* (hrtime_t
)(60 * 60) },
413 { "hour", NANOSEC
* (hrtime_t
)(60 * 60) },
414 { "d", NANOSEC
* (hrtime_t
)(24 * 60 * 60) },
415 { "day", NANOSEC
* (hrtime_t
)(24 * 60 * 60) },
419 #endif /* __APPLE__ */
423 char n
[PROF_NAMELEN
];
426 * If no description was provided, provide all of our probes.
428 #if !defined(__APPLE__)
429 for (i
= 0; i
< sizeof (profile_rates
) / sizeof (int); i
++) {
431 for (i
= 0; i
< (int)(sizeof (profile_rates
) / sizeof (int)); i
++) {
432 #endif /* __APPLE__ */
433 if ((rate
= profile_rates
[i
]) == 0)
436 (void) snprintf(n
, PROF_NAMELEN
, "%s%d",
437 PROF_PREFIX_PROFILE
, rate
);
438 profile_create(NANOSEC
/ rate
, n
, PROF_PROFILE
);
441 #if !defined(__APPLE__)
442 for (i
= 0; i
< sizeof (profile_ticks
) / sizeof (int); i
++) {
444 for (i
= 0; i
< (int)(sizeof (profile_ticks
) / sizeof (int)); i
++) {
445 #endif /* __APPLE__ */
446 if ((rate
= profile_ticks
[i
]) == 0)
449 (void) snprintf(n
, PROF_NAMELEN
, "%s%d",
450 PROF_PREFIX_TICK
, rate
);
451 profile_create(NANOSEC
/ rate
, n
, PROF_TICK
);
457 name
= desc
->dtpd_name
;
459 for (i
= 0; types
[i
].prefix
!= NULL
; i
++) {
460 len
= strlen(types
[i
].prefix
);
462 if (strncmp(name
, types
[i
].prefix
, len
) != 0)
467 if (types
[i
].prefix
== NULL
)
470 kind
= types
[i
].kind
;
471 j
= strlen(name
) - len
;
474 * We need to start before any time suffix.
476 for (j
= strlen(name
); j
>= len
; j
--) {
477 if (name
[j
] >= '0' && name
[j
] <= '9')
482 ASSERT(suffix
!= NULL
);
485 * Now determine the numerical value present in the probe name.
487 for (; j
>= len
; j
--) {
488 if (name
[j
] < '0' || name
[j
] > '9')
491 val
+= (name
[j
] - '0') * mult
;
492 mult
*= (hrtime_t
)10;
499 * Look-up the suffix to determine the multiplier.
501 for (i
= 0, mult
= 0; suffixes
[i
].name
!= NULL
; i
++) {
502 #if !defined(__APPLE__)
503 if (strcasecmp(suffixes
[i
].name
, suffix
) == 0) {
504 mult
= suffixes
[i
].mult
;
508 if (strncasecmp(suffixes
[i
].name
, suffix
, strlen(suffixes
[i
].name
) + 1) == 0) {
509 mult
= suffixes
[i
].mult
;
512 #endif /* __APPLE__ */
515 if (suffixes
[i
].name
== NULL
&& *suffix
!= '\0')
520 * The default is frequency-per-second.
527 profile_create(val
, name
, kind
);
532 profile_destroy(void *arg
, dtrace_id_t id
, void *parg
)
534 #pragma unused(arg,id) /* __APPLE__ */
535 profile_probe_t
*prof
= parg
;
537 ASSERT(prof
->prof_cyclic
== CYCLIC_NONE
);
538 #if !defined(__APPLE__)
539 kmem_free(prof
, sizeof (profile_probe_t
));
541 if (prof
->prof_kind
== PROF_TICK
)
542 kmem_free(prof
, sizeof (profile_probe_t
));
544 kmem_free(prof
, sizeof (profile_probe_t
) + NCPU
*sizeof(profile_probe_percpu_t
));
545 #endif /* __APPLE__ */
547 ASSERT(profile_total
>= 1);
548 atomic_add_32(&profile_total
, -1);
553 profile_online(void *arg
, cpu_t
*cpu
, cyc_handler_t
*hdlr
, cyc_time_t
*when
)
555 #pragma unused(cpu) /* __APPLE__ */
556 profile_probe_t
*prof
= arg
;
557 profile_probe_percpu_t
*pcpu
;
559 #if !defined(__APPLE__)
560 pcpu
= kmem_zalloc(sizeof (profile_probe_percpu_t
), KM_SLEEP
);
562 pcpu
= ((profile_probe_percpu_t
*)(&(prof
[1]))) + cpu_number();
563 #endif /* __APPLE__ */
564 pcpu
->profc_probe
= prof
;
566 hdlr
->cyh_func
= profile_fire
;
567 hdlr
->cyh_arg
= pcpu
;
568 hdlr
->cyh_level
= CY_HIGH_LEVEL
;
570 when
->cyt_interval
= prof
->prof_interval
;
571 #if !defined(__APPLE__)
572 when
->cyt_when
= dtrace_gethrtime() + when
->cyt_interval
;
575 #endif /* __APPLE__ */
577 pcpu
->profc_expected
= when
->cyt_when
;
578 pcpu
->profc_interval
= when
->cyt_interval
;
583 profile_offline(void *arg
, cpu_t
*cpu
, void *oarg
)
585 profile_probe_percpu_t
*pcpu
= oarg
;
587 ASSERT(pcpu
->profc_probe
== arg
);
588 #if !defined(__APPLE__)
589 kmem_free(pcpu
, sizeof (profile_probe_percpu_t
));
591 #pragma unused(pcpu,arg,cpu) /* __APPLE__ */
592 #endif /* __APPLE__ */
597 profile_enable(void *arg
, dtrace_id_t id
, void *parg
)
599 #pragma unused(arg,id) /* __APPLE__ */
600 profile_probe_t
*prof
= parg
;
601 cyc_omni_handler_t omni
;
605 ASSERT(prof
->prof_interval
!= 0);
606 ASSERT(MUTEX_HELD(&cpu_lock
));
608 if (prof
->prof_kind
== PROF_TICK
) {
609 hdlr
.cyh_func
= profile_tick
;
611 hdlr
.cyh_level
= CY_HIGH_LEVEL
;
613 when
.cyt_interval
= prof
->prof_interval
;
614 #if !defined(__APPLE__)
615 when
.cyt_when
= dtrace_gethrtime() + when
.cyt_interval
;
618 #endif /* __APPLE__ */
620 ASSERT(prof
->prof_kind
== PROF_PROFILE
);
621 omni
.cyo_online
= profile_online
;
622 omni
.cyo_offline
= profile_offline
;
626 #if !defined(__APPLE__)
627 if (prof
->prof_kind
== PROF_TICK
) {
628 prof
->prof_cyclic
= cyclic_add(&hdlr
, &when
);
630 prof
->prof_cyclic
= cyclic_add_omni(&omni
);
633 if (prof
->prof_kind
== PROF_TICK
) {
634 prof
->prof_cyclic
= cyclic_timer_add(&hdlr
, &when
);
636 prof
->prof_cyclic
= (cyclic_id_t
)cyclic_add_omni(&omni
); /* cast puns cyclic_id_list_t with cyclic_id_t */
638 #endif /* __APPLE__ */
643 profile_disable(void *arg
, dtrace_id_t id
, void *parg
)
645 profile_probe_t
*prof
= parg
;
647 ASSERT(prof
->prof_cyclic
!= CYCLIC_NONE
);
648 ASSERT(MUTEX_HELD(&cpu_lock
));
650 #if !defined(__APPLE__)
651 cyclic_remove(prof
->prof_cyclic
);
653 #pragma unused(arg,id)
654 if (prof
->prof_kind
== PROF_TICK
) {
655 cyclic_timer_remove(prof
->prof_cyclic
);
657 cyclic_remove_omni((cyclic_id_list_t
)prof
->prof_cyclic
); /* cast puns cyclic_id_list_t with cyclic_id_t */
659 #endif /* __APPLE__ */
660 prof
->prof_cyclic
= CYCLIC_NONE
;
663 #if !defined(__APPLE__)
666 profile_usermode(void *arg
, dtrace_id_t id
, void *parg
)
668 return (CPU
->cpu_profile_pc
== 0);
672 profile_usermode(void *arg
, dtrace_id_t id
, void *parg
)
674 #pragma unused(arg,id,parg)
675 return 1; /* XXX_BOGUS */
677 #endif /* __APPLE__ */
679 static dtrace_pattr_t profile_attr
= {
680 { DTRACE_STABILITY_EVOLVING
, DTRACE_STABILITY_EVOLVING
, DTRACE_CLASS_COMMON
},
681 { DTRACE_STABILITY_UNSTABLE
, DTRACE_STABILITY_UNSTABLE
, DTRACE_CLASS_UNKNOWN
},
682 { DTRACE_STABILITY_PRIVATE
, DTRACE_STABILITY_PRIVATE
, DTRACE_CLASS_UNKNOWN
},
683 { DTRACE_STABILITY_EVOLVING
, DTRACE_STABILITY_EVOLVING
, DTRACE_CLASS_COMMON
},
684 { DTRACE_STABILITY_EVOLVING
, DTRACE_STABILITY_EVOLVING
, DTRACE_CLASS_COMMON
},
687 static dtrace_pops_t profile_pops
= {
701 profile_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
707 return (DDI_SUCCESS
);
709 return (DDI_FAILURE
);
712 #if !defined(__APPLE__)
713 if (ddi_create_minor_node(devi
, "profile", S_IFCHR
, 0,
714 DDI_PSEUDO
, NULL
) == DDI_FAILURE
||
715 dtrace_register("profile", &profile_attr
,
716 DTRACE_PRIV_KERNEL
| DTRACE_PRIV_USER
, NULL
,
717 &profile_pops
, NULL
, &profile_id
) != 0) {
718 ddi_remove_minor_node(devi
, NULL
);
719 return (DDI_FAILURE
);
722 profile_max
= ddi_getprop(DDI_DEV_T_ANY
, devi
, DDI_PROP_DONTPASS
,
723 "profile-max-probes", PROFILE_MAX_DEFAULT
);
725 if (ddi_create_minor_node(devi
, "profile", S_IFCHR
, 0,
726 DDI_PSEUDO
, 0) == DDI_FAILURE
||
727 dtrace_register("profile", &profile_attr
,
728 DTRACE_PRIV_KERNEL
| DTRACE_PRIV_USER
, NULL
,
729 &profile_pops
, NULL
, &profile_id
) != 0) {
730 ddi_remove_minor_node(devi
, NULL
);
731 return (DDI_FAILURE
);
734 profile_max
= PROFILE_MAX_DEFAULT
;
735 #endif /* __APPLE__ */
737 ddi_report_dev(devi
);
739 return (DDI_SUCCESS
);
742 #if !defined(__APPLE__)
744 profile_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
)
750 return (DDI_SUCCESS
);
752 return (DDI_FAILURE
);
755 if (dtrace_unregister(profile_id
) != 0)
756 return (DDI_FAILURE
);
758 ddi_remove_minor_node(devi
, NULL
);
759 return (DDI_SUCCESS
);
764 profile_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
769 case DDI_INFO_DEVT2DEVINFO
:
770 *result
= (void *)profile_devi
;
773 case DDI_INFO_DEVT2INSTANCE
:
785 profile_open(dev_t
*devp
, int flag
, int otyp
, cred_t
*cred_p
)
790 static struct cb_ops profile_cb_ops
= {
791 profile_open
, /* open */
793 nulldev
, /* strategy */
803 ddi_prop_op
, /* cb_prop_op */
805 D_NEW
| D_MP
/* Driver compatibility flag */
808 static struct dev_ops profile_ops
= {
809 DEVO_REV
, /* devo_rev, */
811 profile_info
, /* get_dev_info */
812 nulldev
, /* identify */
814 profile_attach
, /* attach */
815 profile_detach
, /* detach */
817 &profile_cb_ops
, /* driver operations */
818 NULL
, /* bus operations */
819 nodev
/* dev power */
823 * Module linkage information for the kernel.
825 static struct modldrv modldrv
= {
826 &mod_driverops
, /* module type (this is a pseudo driver) */
827 "Profile Interrupt Tracing", /* name of module */
828 &profile_ops
, /* driver ops */
831 static struct modlinkage modlinkage
= {
840 return (mod_install(&modlinkage
));
844 _info(struct modinfo
*modinfop
)
846 return (mod_info(&modlinkage
, modinfop
));
852 return (mod_remove(&modlinkage
));
855 d_open_t _profile_open
;
857 int _profile_open(dev_t dev
, int flags
, int devtype
, struct proc
*p
)
859 #pragma unused(dev,flags,devtype,p)
863 #define PROFILE_MAJOR -24 /* let the kernel pick the device number */
866 * A struct describing which functions will get invoked for certain
869 static struct cdevsw profile_cdevsw
=
871 _profile_open
, /* open */
872 eno_opcl
, /* close */
873 eno_rdwrt
, /* read */
874 eno_rdwrt
, /* write */
875 eno_ioctl
, /* ioctl */
876 (stop_fcn_t
*)nulldev
, /* stop */
877 (reset_fcn_t
*)nulldev
, /* reset */
879 eno_select
, /* select */
881 eno_strat
, /* strategy */
887 static int gProfileInited
= 0;
889 void profile_init( void )
891 if (0 == gProfileInited
)
893 int majdevno
= cdevsw_add(PROFILE_MAJOR
, &profile_cdevsw
);
896 printf("profile_init: failed to allocate a major number!\n");
901 profile_attach( (dev_info_t
*)(uintptr_t)majdevno
, DDI_ATTACH
);
905 panic("profile_init: called twice!\n");
908 #endif /* __APPLE__ */