1/*
2 * Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29
30/*
31 * APPLE NOTE: This file is compiled even if dtrace is unconfig'd. A symbol
32 * from this file (_dtrace_register_anon_DOF) always needs to be exported for
33 * an external kext to link against.
34 */
35
36#if CONFIG_DTRACE
37
38#define MACH__POSIX_C_SOURCE_PRIVATE 1 /* pulls in suitable savearea from mach/ppc/thread_status.h */
39#include <kern/thread.h>
40#include <mach/thread_status.h>
41
42#include <stdarg.h>
43#include <string.h>
44#include <sys/malloc.h>
45#include <sys/time.h>
46#include <sys/proc.h>
47#include <sys/proc_internal.h>
48#include <sys/kauth.h>
49#include <sys/user.h>
50#include <sys/systm.h>
51#include <sys/dtrace.h>
52#include <sys/dtrace_impl.h>
53#include <libkern/OSAtomic.h>
54#include <kern/thread_call.h>
55#include <kern/task.h>
56#include <kern/sched_prim.h>
57#include <kern/queue.h>
58#include <miscfs/devfs/devfs.h>
59#include <kern/kalloc.h>
60
61#include <mach/vm_param.h>
62#include <mach/mach_vm.h>
63#include <mach/task.h>
64#include <vm/pmap.h>
65#include <vm/vm_map.h> /* All the bits we care about are guarded by MACH_KERNEL_PRIVATE :-( */
66
67/*
68 * pid/proc
69 */
70/* Solaris proc_t is the struct. Darwin's proc_t is a pointer to it. */
71#define proc_t struct proc /* Steer clear of the Darwin typedef for proc_t */
72
73/* Not called from probe context */
74proc_t *
75sprlock(pid_t pid)
76{
77	proc_t* p;
78
79	if ((p = proc_find(pid)) == PROC_NULL) {
80		return PROC_NULL;
81	}
82
83	task_suspend(p->task);
84
85	proc_lock(p);
86
87	lck_mtx_lock(&p->p_dtrace_sprlock);
88
89	return p;
90}
91
92/* Not called from probe context */
93void
94sprunlock(proc_t *p)
95{
96	if (p != PROC_NULL) {
97		lck_mtx_unlock(&p->p_dtrace_sprlock);
98
99		proc_unlock(p);
100
101		task_resume(p->task);
102
103		proc_rele(p);
104	}
105}
106
107/*
108 * uread/uwrite
109 */
110
111// These are not exported from vm_map.h.
112extern kern_return_t vm_map_read_user(vm_map_t map, vm_map_address_t src_addr, void *dst_p, vm_size_t size);
113extern kern_return_t vm_map_write_user(vm_map_t map, void *src_p, vm_map_address_t dst_addr, vm_size_t size);
114
115/* Not called from probe context */
116int
117uread(proc_t *p, void *buf, user_size_t len, user_addr_t a)
118{
119	kern_return_t ret;
120
121	ASSERT(p != PROC_NULL);
122	ASSERT(p->task != NULL);
123
124	task_t task = p->task;
125
126	/*
127	 * Grab a reference to the task vm_map_t to make sure
128	 * the map isn't pulled out from under us.
129	 *
130	 * Because the proc_lock is not held at all times on all code
131	 * paths leading here, it is possible for the proc to have
132	 * exited. If the map is null, fail.
133	 */
134	vm_map_t map = get_task_map_reference(task);
135	if (map) {
136		ret = vm_map_read_user( map, (vm_map_address_t)a, buf, (vm_size_t)len);
137		vm_map_deallocate(map);
138	} else
139		ret = KERN_TERMINATED;
140
141	return (int)ret;
142}
143
144
145/* Not called from probe context */
146int
147uwrite(proc_t *p, void *buf, user_size_t len, user_addr_t a)
148{
149	kern_return_t ret;
150
151	ASSERT(p != NULL);
152	ASSERT(p->task != NULL);
153
154	task_t task = p->task;
155
156	/*
157	 * Grab a reference to the task vm_map_t to make sure
158	 * the map isn't pulled out from under us.
159	 *
160	 * Because the proc_lock is not held at all times on all code
161	 * paths leading here, it is possible for the proc to have
162	 * exited. If the map is null, fail.
163	 */
164	vm_map_t map = get_task_map_reference(task);
165	if (map) {
166		/* Find the memory permissions. */
167		uint32_t nestingDepth=999999;
168		vm_region_submap_short_info_data_64_t info;
169		mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
170		mach_vm_address_t address = (mach_vm_address_t)a;
171		mach_vm_size_t sizeOfRegion = (mach_vm_size_t)len;
172
173		ret = mach_vm_region_recurse(map, &address, &sizeOfRegion, &nestingDepth, (vm_region_recurse_info_t)&info, &count);
174		if (ret != KERN_SUCCESS)
175			goto done;
176
177		vm_prot_t reprotect;
178
179		if (!(info.protection & VM_PROT_WRITE)) {
180			/* Save the original protection values for restoration later */
181			reprotect = info.protection;
182
183			if (info.max_protection & VM_PROT_WRITE) {
184				/* The memory is not currently writable, but can be made writable. */
185				ret = mach_vm_protect (map, (mach_vm_offset_t)a, (mach_vm_size_t)len, 0, reprotect | VM_PROT_WRITE);
186			} else {
187				/*
188				 * The memory is not currently writable, and cannot be made writable. We need to COW this memory.
189				 *
190				 * Strange, we can't just say "reprotect | VM_PROT_COPY", that fails.
191				 */
192				ret = mach_vm_protect (map, (mach_vm_offset_t)a, (mach_vm_size_t)len, 0, VM_PROT_COPY | VM_PROT_READ | VM_PROT_WRITE);
193			}
194
195			if (ret != KERN_SUCCESS)
196				goto done;
197
198		} else {
199			/* The memory was already writable. */
200			reprotect = VM_PROT_NONE;
201		}
202
203		ret = vm_map_write_user( map,
204					 buf,
205					 (vm_map_address_t)a,
206					 (vm_size_t)len);
207
208		if (ret != KERN_SUCCESS)
209			goto done;
210
211		if (reprotect != VM_PROT_NONE) {
212			ASSERT(reprotect & VM_PROT_EXECUTE);
213			ret = mach_vm_protect (map, (mach_vm_offset_t)a, (mach_vm_size_t)len, 0, reprotect);
214		}
215
216done:
217		vm_map_deallocate(map);
218	} else
219		ret = KERN_TERMINATED;
220
221	return (int)ret;
222}
223
224/*
225 * cpuvar
226 */
227lck_mtx_t cpu_lock;
228lck_mtx_t mod_lock;
229
230dtrace_cpu_t *cpu_list;
231cpu_core_t *cpu_core; /* XXX TLB lockdown? */
232
233/*
234 * cred_t
235 */
236
237/*
238 * dtrace_CRED() can be called from probe context. We cannot simply call kauth_cred_get() since
239 * that function may try to resolve a lazy credential binding, which entails taking the proc_lock.
240 */
241cred_t *
242dtrace_CRED(void)
243{
244	struct uthread *uthread = get_bsdthread_info(current_thread());
245
246	if (uthread == NULL)
247		return NULL;
248	else
249		return uthread->uu_ucred; /* May return NOCRED which is defined to be 0 */
250}
251
252#define	HAS_ALLPRIVS(cr)	priv_isfullset(&CR_OEPRIV(cr))
253#define	HAS_PRIVILEGE(cr, pr)	((pr) == PRIV_ALL ? \
254					HAS_ALLPRIVS(cr) : \
255					PRIV_ISASSERT(&CR_OEPRIV(cr), pr))
256
257int PRIV_POLICY_CHOICE(void* cred, int priv, int all)
258{
259#pragma unused(priv, all)
260	return kauth_cred_issuser(cred); /* XXX TODO: How is this different from PRIV_POLICY_ONLY? */
261}
262
263int
264PRIV_POLICY_ONLY(void *cr, int priv, int boolean)
265{
266#pragma unused(priv, boolean)
267	return kauth_cred_issuser(cr); /* XXX TODO: HAS_PRIVILEGE(cr, priv); */
268}
269
270/* XXX Get around const poisoning using structure assigns */
271gid_t
272crgetgid(const cred_t *cr) { cred_t copy_cr = *cr; return kauth_cred_getgid(&copy_cr); }
273
274uid_t
275crgetuid(const cred_t *cr) { cred_t copy_cr = *cr; return kauth_cred_getuid(&copy_cr); }
276
277/*
278 * "cyclic"
279 */
280
281/* osfmk/kern/timer_call.h */
282typedef void                *timer_call_param_t;
283typedef void                (*timer_call_func_t)(
284	timer_call_param_t      param0,
285	timer_call_param_t      param1);
286
287typedef struct timer_call {
288	queue_chain_t       q_link;
289	queue_t             queue;
290	timer_call_func_t   func;
291	timer_call_param_t  param0;
292	timer_call_param_t  param1;
293	decl_simple_lock_data(,lock);
294	uint64_t            deadline;
295	uint64_t            soft_deadline;
296	uint32_t            flags;
297	boolean_t	    async_dequeue;
298} timer_call_data_t;
299
300typedef struct timer_call   *timer_call_t;
301
302extern void
303timer_call_setup(
304	timer_call_t            call,
305	timer_call_func_t       func,
306	timer_call_param_t      param0);
307
308extern boolean_t
309timer_call_enter1(
310	timer_call_t            call,
311	timer_call_param_t      param1,
312	uint64_t                deadline,
313	uint32_t		flags);
314
315#ifndef TIMER_CALL_CRITICAL
316#define TIMER_CALL_CRITICAL 0x1
317#define TIMER_CALL_LOCAL    0x2
318#endif /* TIMER_CALL_CRITICAL */
319
320extern boolean_t
321timer_call_cancel(
322	timer_call_t            call);
323
324typedef struct wrap_timer_call {
325	cyc_handler_t hdlr;
326	cyc_time_t when;
327	uint64_t deadline;
328	struct timer_call call;
329} wrap_timer_call_t;
330
331#define WAKEUP_REAPER 0x7FFFFFFFFFFFFFFFLL
332#define NEARLY_FOREVER 0x7FFFFFFFFFFFFFFELL
333
334static void
335_timer_call_apply_cyclic( void *ignore, void *vTChdl )
336{
337#pragma unused(ignore)
338	wrap_timer_call_t *wrapTC = (wrap_timer_call_t *)vTChdl;
339
340	(*(wrapTC->hdlr.cyh_func))( wrapTC->hdlr.cyh_arg );
341
342	clock_deadline_for_periodic_event( wrapTC->when.cyt_interval, mach_absolute_time(), &(wrapTC->deadline) );
343	timer_call_enter1( &(wrapTC->call), (void *)wrapTC, wrapTC->deadline, TIMER_CALL_CRITICAL | TIMER_CALL_LOCAL );
344
345	/* Did timer_call_remove_cyclic request a wakeup call when this timer call was re-armed? */
346	if (wrapTC->when.cyt_interval == WAKEUP_REAPER)
347		thread_wakeup((event_t)wrapTC);
348}
349
350static cyclic_id_t
351timer_call_add_cyclic(wrap_timer_call_t *wrapTC, cyc_handler_t *handler, cyc_time_t *when)
352{
353	uint64_t now;
354
355	timer_call_setup( &(wrapTC->call),  _timer_call_apply_cyclic, NULL );
356	wrapTC->hdlr = *handler;
357	wrapTC->when = *when;
358
359	nanoseconds_to_absolutetime( wrapTC->when.cyt_interval, (uint64_t *)&wrapTC->when.cyt_interval );
360
361	now = mach_absolute_time();
362	wrapTC->deadline = now;
363
364	clock_deadline_for_periodic_event( wrapTC->when.cyt_interval, now, &(wrapTC->deadline) );
365	timer_call_enter1( &(wrapTC->call), (void *)wrapTC, wrapTC->deadline, TIMER_CALL_CRITICAL | TIMER_CALL_LOCAL );
366
367	return (cyclic_id_t)wrapTC;
368}
369
370static void
371timer_call_remove_cyclic(cyclic_id_t cyclic)
372{
373	wrap_timer_call_t *wrapTC = (wrap_timer_call_t *)cyclic;
374
375	while (!timer_call_cancel(&(wrapTC->call))) {
376		int ret = assert_wait(wrapTC, THREAD_UNINT);
377		ASSERT(ret == THREAD_WAITING);
378
379		wrapTC->when.cyt_interval = WAKEUP_REAPER;
380
381		ret = thread_block(THREAD_CONTINUE_NULL);
382		ASSERT(ret == THREAD_AWAKENED);
383	}
384}
385
386static void *
387timer_call_get_cyclic_arg(cyclic_id_t cyclic)
388{
389	wrap_timer_call_t *wrapTC = (wrap_timer_call_t *)cyclic;
390
391	return (wrapTC ? wrapTC->hdlr.cyh_arg : NULL);
392}
393
394cyclic_id_t
395cyclic_timer_add(cyc_handler_t *handler, cyc_time_t *when)
396{
397	wrap_timer_call_t *wrapTC = _MALLOC(sizeof(wrap_timer_call_t), M_TEMP, M_ZERO | M_WAITOK);
398	if (NULL == wrapTC)
399		return CYCLIC_NONE;
400	else
401		return timer_call_add_cyclic( wrapTC, handler, when );
402}
403
404void
405cyclic_timer_remove(cyclic_id_t cyclic)
406{
407	ASSERT( cyclic != CYCLIC_NONE );
408
409	timer_call_remove_cyclic( cyclic );
410	_FREE((void *)cyclic, M_TEMP);
411}
412
413static void
414_cyclic_add_omni(cyclic_id_list_t cyc_list)
415{
416	cyc_time_t cT;
417	cyc_handler_t cH;
418	wrap_timer_call_t *wrapTC;
419	cyc_omni_handler_t *omni = (cyc_omni_handler_t *)cyc_list;
420	char *t;
421
422	(omni->cyo_online)(omni->cyo_arg, CPU, &cH, &cT);
423
424	t = (char *)cyc_list;
425	t += sizeof(cyc_omni_handler_t);
426	cyc_list = (cyclic_id_list_t)(uintptr_t)t;
427
428	t += sizeof(cyclic_id_t)*NCPU;
429	t += (sizeof(wrap_timer_call_t))*cpu_number();
430	wrapTC = (wrap_timer_call_t *)(uintptr_t)t;
431
432	cyc_list[cpu_number()] = timer_call_add_cyclic(wrapTC, &cH, &cT);
433}
434
435cyclic_id_list_t
436cyclic_add_omni(cyc_omni_handler_t *omni)
437{
438	cyclic_id_list_t cyc_list =
439		_MALLOC( (sizeof(wrap_timer_call_t))*NCPU +
440				 sizeof(cyclic_id_t)*NCPU +
441				 sizeof(cyc_omni_handler_t), M_TEMP, M_ZERO | M_WAITOK);
442	if (NULL == cyc_list)
443		return (cyclic_id_list_t)CYCLIC_NONE;
444
445	*(cyc_omni_handler_t *)cyc_list = *omni;
446	dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)_cyclic_add_omni, (void *)cyc_list);
447
448	return cyc_list;
449}
450
451static void
452_cyclic_remove_omni(cyclic_id_list_t cyc_list)
453{
454	cyc_omni_handler_t *omni = (cyc_omni_handler_t *)cyc_list;
455	void *oarg;
456	cyclic_id_t cid;
457	char *t;
458
459	t = (char *)cyc_list;
460	t += sizeof(cyc_omni_handler_t);
461	cyc_list = (cyclic_id_list_t)(uintptr_t)t;
462
463	cid = cyc_list[cpu_number()];
464	oarg = timer_call_get_cyclic_arg(cid);
465
466	timer_call_remove_cyclic( cid );
467	(omni->cyo_offline)(omni->cyo_arg, CPU, oarg);
468}
469
470void
471cyclic_remove_omni(cyclic_id_list_t cyc_list)
472{
473	ASSERT( cyc_list != (cyclic_id_list_t)CYCLIC_NONE );
474
475	dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)_cyclic_remove_omni, (void *)cyc_list);
476	_FREE(cyc_list, M_TEMP);
477}
478
479typedef struct wrap_thread_call {
480	thread_call_t TChdl;
481	cyc_handler_t hdlr;
482	cyc_time_t when;
483	uint64_t deadline;
484} wrap_thread_call_t;
485
486/*
487 * _cyclic_apply will run on some thread under kernel_task. That's OK for the
488 * cleaner and the deadman, but too distant in time and place for the profile provider.
489 */
490static void
491_cyclic_apply( void *ignore, void *vTChdl )
492{
493#pragma unused(ignore)
494	wrap_thread_call_t *wrapTC = (wrap_thread_call_t *)vTChdl;
495
496	(*(wrapTC->hdlr.cyh_func))( wrapTC->hdlr.cyh_arg );
497
498	clock_deadline_for_periodic_event( wrapTC->when.cyt_interval, mach_absolute_time(), &(wrapTC->deadline) );
499	(void)thread_call_enter1_delayed( wrapTC->TChdl, (void *)wrapTC, wrapTC->deadline );
500
501	/* Did cyclic_remove request a wakeup call when this thread call was re-armed? */
502	if (wrapTC->when.cyt_interval == WAKEUP_REAPER)
503		thread_wakeup((event_t)wrapTC);
504}
505
506cyclic_id_t
507cyclic_add(cyc_handler_t *handler, cyc_time_t *when)
508{
509	uint64_t now;
510
511	wrap_thread_call_t *wrapTC = _MALLOC(sizeof(wrap_thread_call_t), M_TEMP, M_ZERO | M_WAITOK);
512	if (NULL == wrapTC)
513		return CYCLIC_NONE;
514
515	wrapTC->TChdl = thread_call_allocate( _cyclic_apply, NULL );
516	wrapTC->hdlr = *handler;
517	wrapTC->when = *when;
518
519	ASSERT(when->cyt_when == 0);
520	ASSERT(when->cyt_interval < WAKEUP_REAPER);
521
522	nanoseconds_to_absolutetime(wrapTC->when.cyt_interval, (uint64_t *)&wrapTC->when.cyt_interval);
523
524	now = mach_absolute_time();
525	wrapTC->deadline = now;
526
527	clock_deadline_for_periodic_event( wrapTC->when.cyt_interval, now, &(wrapTC->deadline) );
528	(void)thread_call_enter1_delayed( wrapTC->TChdl, (void *)wrapTC, wrapTC->deadline );
529
530	return (cyclic_id_t)wrapTC;
531}
532
533static void
534noop_cyh_func(void * ignore)
535{
536#pragma unused(ignore)
537}
538
539void
540cyclic_remove(cyclic_id_t cyclic)
541{
542	wrap_thread_call_t *wrapTC = (wrap_thread_call_t *)cyclic;
543
544	ASSERT(cyclic != CYCLIC_NONE);
545
546	while (!thread_call_cancel(wrapTC->TChdl)) {
547		int ret = assert_wait(wrapTC, THREAD_UNINT);
548		ASSERT(ret == THREAD_WAITING);
549
550		wrapTC->when.cyt_interval = WAKEUP_REAPER;
551
552		ret = thread_block(THREAD_CONTINUE_NULL);
553		ASSERT(ret == THREAD_AWAKENED);
554	}
555
556	if (thread_call_free(wrapTC->TChdl))
557		_FREE(wrapTC, M_TEMP);
558	else {
559		/* Gut this cyclic and move on ... */
560		wrapTC->hdlr.cyh_func = noop_cyh_func;
561		wrapTC->when.cyt_interval = NEARLY_FOREVER;
562	}
563}
564
565/*
566 * timeout / untimeout (converted to dtrace_timeout / dtrace_untimeout due to name collision)
567 */
568
569thread_call_t
570dtrace_timeout(void (*func)(void *, void *), void* arg, uint64_t nanos)
571{
572#pragma unused(arg)
573	thread_call_t call = thread_call_allocate(func, NULL);
574
575	nanoseconds_to_absolutetime(nanos, &nanos);
576
577	/*
578	 * This method does not use clock_deadline_for_periodic_event() because it is a one-shot,
579	 * and clock drift on later invocations is not a worry.
580	 */
581	uint64_t deadline = mach_absolute_time() + nanos;
582
583	thread_call_enter_delayed(call, deadline);
584
585	return call;
586}
587
588/*
589 * ddi
590 */
591void
592ddi_report_dev(dev_info_t *devi)
593{
594#pragma unused(devi)
595}
596
597#define NSOFT_STATES 32 /* XXX No more than 32 clients at a time, please. */
598static void *soft[NSOFT_STATES];
599
600int
601ddi_soft_state_init(void **state_p, size_t size, size_t n_items)
602{
603#pragma unused(n_items)
604	int i;
605
606	for (i = 0; i < NSOFT_STATES; ++i) soft[i] = _MALLOC(size, M_TEMP, M_ZERO | M_WAITOK);
607	*(size_t *)state_p = size;
608	return 0;
609}
610
611int
612ddi_soft_state_zalloc(void *state, int item)
613{
614#pragma unused(state)
615	if (item < NSOFT_STATES)
616		return DDI_SUCCESS;
617	else
618		return DDI_FAILURE;
619}
620
621void *
622ddi_get_soft_state(void *state, int item)
623{
624#pragma unused(state)
625	ASSERT(item < NSOFT_STATES);
626	return soft[item];
627}
628
629int
630ddi_soft_state_free(void *state, int item)
631{
632	ASSERT(item < NSOFT_STATES);
633	bzero( soft[item], (size_t)state );
634	return DDI_SUCCESS;
635}
636
637void
638ddi_soft_state_fini(void **state_p)
639{
640#pragma unused(state_p)
641	int i;
642
643	for (i = 0; i < NSOFT_STATES; ++i) _FREE( soft[i], M_TEMP );
644}
645
646static unsigned int gRegisteredProps = 0;
647static struct {
648	char name[32];		/* enough for "dof-data-" + digits */
649	int *data;
650	uint_t nelements;
651} gPropTable[16];
652
653kern_return_t _dtrace_register_anon_DOF(char *, uchar_t *, uint_t);
654
655kern_return_t
656_dtrace_register_anon_DOF(char *name, uchar_t *data, uint_t nelements)
657{
658	if (gRegisteredProps < sizeof(gPropTable)/sizeof(gPropTable[0])) {
659		int *p = (int *)_MALLOC(nelements*sizeof(int), M_TEMP, M_WAITOK);
660
661		if (NULL == p)
662			return KERN_FAILURE;
663
664		strlcpy(gPropTable[gRegisteredProps].name, name, sizeof(gPropTable[0].name));
665		gPropTable[gRegisteredProps].nelements = nelements;
666		gPropTable[gRegisteredProps].data = p;
667
668		while (nelements-- > 0) {
669			*p++ = (int)(*data++);
670		}
671
672		gRegisteredProps++;
673		return KERN_SUCCESS;
674	}
675	else
676		return KERN_FAILURE;
677}
678
679int
680ddi_prop_lookup_int_array(dev_t match_dev, dev_info_t *dip, uint_t flags,
681    const char *name, int **data, uint_t *nelements)
682{
683#pragma unused(match_dev,dip,flags)
684	unsigned int i;
685	for (i = 0; i < gRegisteredProps; ++i)
686	{
687		if (0 == strncmp(name, gPropTable[i].name,
688					sizeof(gPropTable[i].name))) {
689			*data = gPropTable[i].data;
690			*nelements = gPropTable[i].nelements;
691			return DDI_SUCCESS;
692		}
693	}
694	return DDI_FAILURE;
695}
696
697int
698ddi_prop_free(void *buf)
699{
700	_FREE(buf, M_TEMP);
701	return DDI_SUCCESS;
702}
703
704int
705ddi_driver_major(dev_info_t	*devi) { return (int)major(CAST_DOWN_EXPLICIT(int,devi)); }
706
707int
708ddi_create_minor_node(dev_info_t *dip, const char *name, int spec_type,
709    minor_t minor_num, const char *node_type, int flag)
710{
711#pragma unused(spec_type,node_type,flag)
712	dev_t dev = makedev( ddi_driver_major(dip), minor_num );
713
714	if (NULL == devfs_make_node( dev, DEVFS_CHAR, UID_ROOT, GID_WHEEL, 0666, name, 0 ))
715		return DDI_FAILURE;
716	else
717		return DDI_SUCCESS;
718}
719
720void
721ddi_remove_minor_node(dev_info_t *dip, char *name)
722{
723#pragma unused(dip,name)
724/* XXX called from dtrace_detach, so NOTREACHED for now. */
725}
726
727major_t
728getemajor( dev_t d )
729{
730	return (major_t) major(d);
731}
732
733minor_t
734getminor ( dev_t d )
735{
736	return (minor_t) minor(d);
737}
738
739dev_t
740makedevice(major_t major, minor_t minor)
741{
742	return makedev( major, minor );
743}
744
745int ddi_getprop(dev_t dev, dev_info_t *dip, int flags, const char *name, int defvalue)
746{
747#pragma unused(dev, dip, flags, name)
748
749	return defvalue;
750}
751
752/*
753 * Kernel Debug Interface
754 */
755int
756kdi_dtrace_set(kdi_dtrace_set_t ignore)
757{
758#pragma unused(ignore)
759	return 0; /* Success */
760}
761
762extern void Debugger(const char*);
763
764void
765debug_enter(char *c) { Debugger(c); }
766
767/*
768 * kmem
769 */
770
771void *
772dt_kmem_alloc(size_t size, int kmflag)
773{
774#pragma unused(kmflag)
775
776/*
777 * We ignore the M_NOWAIT bit in kmflag (all of kmflag, in fact).
778 * Requests larger than 8K with M_NOWAIT fail in kalloc_canblock.
779 */
780#if defined(DTRACE_MEMORY_ZONES)
781	return dtrace_alloc(size);
782#else
783	return kalloc(size);
784#endif
785}
786
787void *
788dt_kmem_zalloc(size_t size, int kmflag)
789{
790#pragma unused(kmflag)
791
792/*
793 * We ignore the M_NOWAIT bit in kmflag (all of kmflag, in fact).
794 * Requests larger than 8K with M_NOWAIT fail in kalloc_canblock.
795 */
796#if defined(DTRACE_MEMORY_ZONES)
797	void* buf = dtrace_alloc(size);
798#else
799	void* buf = kalloc(size);
800#endif
801
802	if(!buf)
803		return NULL;
804
805	bzero(buf, size);
806
807	return buf;
808}
809
810void
811dt_kmem_free(void *buf, size_t size)
812{
813#pragma unused(size)
814	/*
815	 * DTrace relies on this, its doing a lot of NULL frees.
816	 * A null free causes the debug builds to panic.
817	 */
818	if (buf == NULL) return;
819
820	ASSERT(size > 0);
821
822#if defined(DTRACE_MEMORY_ZONES)
823	dtrace_free(buf, size);
824#else
825	kfree(buf, size);
826#endif
827}
828
829
830
831/*
832 * aligned kmem allocator
833 * align should be a power of two
834 */
835
836void* dt_kmem_alloc_aligned(size_t size, size_t align, int kmflag)
837{
838	void* buf;
839	intptr_t p;
840	void** buf_backup;
841
842	buf = dt_kmem_alloc(align + sizeof(void*) + size, kmflag);
843
844	if(!buf)
845		return NULL;
846
847	p = (intptr_t)buf;
848	p += sizeof(void*);				/* now we have enough room to store the backup */
849	p = P2ROUNDUP(p, align);			/* and now we're aligned */
850
851	buf_backup = (void**)(p - sizeof(void*));
852	*buf_backup = buf;				/* back up the address we need to free */
853
854	return (void*)p;
855}
856
857void* dt_kmem_zalloc_aligned(size_t size, size_t align, int kmflag)
858{
859	void* buf;
860
861	buf = dt_kmem_alloc_aligned(size, align, kmflag);
862
863	if(!buf)
864		return NULL;
865
866	bzero(buf, size);
867
868	return buf;
869}
870
871void dt_kmem_free_aligned(void* buf, size_t size)
872{
873#pragma unused(size)
874	intptr_t p;
875	void** buf_backup;
876
877	p = (intptr_t)buf;
878	p -= sizeof(void*);
879	buf_backup = (void**)(p);
880
881	dt_kmem_free(*buf_backup, size + ((char*)buf - (char*)*buf_backup));
882}
883
884/*
885 * dtrace wants to manage just a single block: dtrace_state_percpu_t * NCPU, and
886 * doesn't specify constructor, destructor, or reclaim methods.
887 * At present, it always zeroes the block it obtains from kmem_cache_alloc().
888 * We'll manage this constricted use of kmem_cache with ordinary _MALLOC and _FREE.
889 */
890kmem_cache_t *
891kmem_cache_create(
892    const char *name,		/* descriptive name for this cache */
893    size_t bufsize,		/* size of the objects it manages */
894    size_t align,		/* required object alignment */
895    int (*constructor)(void *, void *, int), /* object constructor */
896    void (*destructor)(void *, void *),	/* object destructor */
897    void (*reclaim)(void *), /* memory reclaim callback */
898    void *private,		/* pass-thru arg for constr/destr/reclaim */
899    vmem_t *vmp,		/* vmem source for slab allocation */
900    int cflags)		/* cache creation flags */
901{
902#pragma unused(name,align,constructor,destructor,reclaim,private,vmp,cflags)
903	return (kmem_cache_t *)bufsize; /* A cookie that tracks the single object size. */
904}
905
906void *
907kmem_cache_alloc(kmem_cache_t *cp, int kmflag)
908{
909#pragma unused(kmflag)
910	size_t bufsize = (size_t)cp;
911	return (void *)_MALLOC(bufsize, M_TEMP, M_WAITOK);
912}
913
914void
915kmem_cache_free(kmem_cache_t *cp, void *buf)
916{
917#pragma unused(cp)
918	_FREE(buf, M_TEMP);
919}
920
921void
922kmem_cache_destroy(kmem_cache_t *cp)
923{
924#pragma unused(cp)
925}
926
927/*
928 * taskq
929 */
930extern void thread_call_setup(thread_call_t, thread_call_func_t, thread_call_param_t); /* XXX MACH_KERNEL_PRIVATE */
931
932static void
933_taskq_apply( task_func_t func, thread_call_param_t arg )
934{
935	func( (void *)arg );
936}
937
938taskq_t *
939taskq_create(const char *name, int nthreads, pri_t pri, int minalloc,
940    int maxalloc, uint_t flags)
941{
942#pragma unused(name,nthreads,pri,minalloc,maxalloc,flags)
943
944	return (taskq_t *)thread_call_allocate( (thread_call_func_t)_taskq_apply, NULL );
945}
946
947taskqid_t
948taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t flags)
949{
950#pragma unused(flags)
951	thread_call_setup( (thread_call_t) tq, (thread_call_func_t)_taskq_apply, (thread_call_param_t)func );
952	thread_call_enter1( (thread_call_t) tq, (thread_call_param_t)arg );
953	return (taskqid_t) tq /* for lack of anything better */;
954}
955
956void
957taskq_destroy(taskq_t *tq)
958{
959	thread_call_cancel( (thread_call_t) tq );
960	thread_call_free( (thread_call_t) tq );
961}
962
963pri_t maxclsyspri;
964
965/*
966 * vmem (Solaris "slab" allocator) used by DTrace solely to hand out resource ids
967 */
968typedef unsigned int u_daddr_t;
969#include "blist.h"
970
971/* By passing around blist *handles*, the underlying blist can be resized as needed. */
972struct blist_hdl {
973	blist_t blist;
974};
975
976vmem_t *
977vmem_create(const char *name, void *base, size_t size, size_t quantum, void *ignore5,
978					void *ignore6, vmem_t *source, size_t qcache_max, int vmflag)
979{
980#pragma unused(name,quantum,ignore5,ignore6,source,qcache_max,vmflag)
981	blist_t bl;
982	struct blist_hdl *p = _MALLOC(sizeof(struct blist_hdl), M_TEMP, M_WAITOK);
983
984	ASSERT(quantum == 1);
985	ASSERT(NULL == ignore5);
986	ASSERT(NULL == ignore6);
987	ASSERT(NULL == source);
988	ASSERT(0 == qcache_max);
989	ASSERT(vmflag & VMC_IDENTIFIER);
990
991	size = MIN(128, size); /* Clamp to 128 initially, since the underlying data structure is pre-allocated */
992
993	p->blist = bl = blist_create( size );
994	blist_free(bl, 0, size);
995	if (base) blist_alloc( bl, (daddr_t)(uintptr_t)base ); /* Chomp off initial ID(s) */
996
997	return (vmem_t *)p;
998}
999
1000void *
1001vmem_alloc(vmem_t *vmp, size_t size, int vmflag)
1002{
1003#pragma unused(vmflag)
1004	struct blist_hdl *q = (struct blist_hdl *)vmp;
1005	blist_t bl = q->blist;
1006	daddr_t p;
1007
1008	p = blist_alloc(bl, (daddr_t)size);
1009
1010	if ((daddr_t)-1 == p) {
1011		blist_resize(&bl, (bl->bl_blocks) << 1, 1);
1012		q->blist = bl;
1013		p = blist_alloc(bl, (daddr_t)size);
1014		if ((daddr_t)-1 == p)
1015			panic("vmem_alloc: failure after blist_resize!");
1016	}
1017
1018	return (void *)(uintptr_t)p;
1019}
1020
1021void
1022vmem_free(vmem_t *vmp, void *vaddr, size_t size)
1023{
1024	struct blist_hdl *p = (struct blist_hdl *)vmp;
1025
1026	blist_free( p->blist, (daddr_t)(uintptr_t)vaddr, (daddr_t)size );
1027}
1028
1029void
1030vmem_destroy(vmem_t *vmp)
1031{
1032	struct blist_hdl *p = (struct blist_hdl *)vmp;
1033
1034	blist_destroy( p->blist );
1035	_FREE( p, sizeof(struct blist_hdl) );
1036}
1037
1038/*
1039 * Timing
1040 */
1041
1042/*
1043 * dtrace_gethrestime() provides the "walltimestamp", a value that is anchored at
1044 * January 1, 1970. Because it can be called from probe context, it must take no locks.
1045 */
1046
1047hrtime_t
1048dtrace_gethrestime(void)
1049{
1050	clock_sec_t		secs;
1051	clock_nsec_t	nanosecs;
1052	uint64_t		secs64, ns64;
1053
1054	clock_get_calendar_nanotime_nowait(&secs, &nanosecs);
1055	secs64 = (uint64_t)secs;
1056	ns64 = (uint64_t)nanosecs;
1057
1058	ns64 = ns64 + (secs64 * 1000000000LL);
1059	return ns64;
1060}
1061
1062/*
1063 * dtrace_gethrtime() provides high-resolution timestamps with machine-dependent origin.
1064 * Hence its primary use is to specify intervals.
1065 */
1066
1067hrtime_t
1068dtrace_abs_to_nano(uint64_t elapsed)
1069{
1070	static mach_timebase_info_data_t    sTimebaseInfo = { 0, 0 };
1071
1072	/*
1073	 * If this is the first time we've run, get the timebase.
1074	 * We can use denom == 0 to indicate that sTimebaseInfo is
1075	 * uninitialised because it makes no sense to have a zero
1076	 * denominator in a fraction.
1077	 */
1078
1079	if ( sTimebaseInfo.denom == 0 ) {
1080		(void) clock_timebase_info(&sTimebaseInfo);
1081	}
1082
1083	/*
1084	 * Convert to nanoseconds.
1085	 * return (elapsed * (uint64_t)sTimebaseInfo.numer)/(uint64_t)sTimebaseInfo.denom;
1086	 *
1087	 * Provided the final result is representable in 64 bits the following maneuver will
1088	 * deliver that result without intermediate overflow.
1089	 */
1090	if (sTimebaseInfo.denom == sTimebaseInfo.numer)
1091		return elapsed;
1092	else if (sTimebaseInfo.denom == 1)
1093		return elapsed * (uint64_t)sTimebaseInfo.numer;
1094	else {
1095		/* Decompose elapsed = eta32 * 2^32 + eps32: */
1096		uint64_t eta32 = elapsed >> 32;
1097		uint64_t eps32 = elapsed & 0x00000000ffffffffLL;
1098
1099		uint32_t numer = sTimebaseInfo.numer, denom = sTimebaseInfo.denom;
1100
1101		/* Form product of elapsed64 (decomposed) and numer: */
1102		uint64_t mu64 = numer * eta32;
1103		uint64_t lambda64 = numer * eps32;
1104
1105		/* Divide the constituents by denom: */
1106		uint64_t q32 = mu64/denom;
1107		uint64_t r32 = mu64 - (q32 * denom); /* mu64 % denom */
1108
1109		return (q32 << 32) + ((r32 << 32) + lambda64)/denom;
1110	}
1111}
1112
1113hrtime_t
1114dtrace_gethrtime(void)
1115{
1116    static uint64_t        start = 0;
1117
1118	if (start == 0)
1119		start = mach_absolute_time();
1120
1121    return dtrace_abs_to_nano(mach_absolute_time() - start);
1122}
1123
1124/*
1125 * Atomicity and synchronization
1126 */
1127uint32_t
1128dtrace_cas32(uint32_t *target, uint32_t cmp, uint32_t new)
1129{
1130    if (OSCompareAndSwap( (UInt32)cmp, (UInt32)new, (volatile UInt32 *)target ))
1131		return cmp;
1132	else
1133		return ~cmp; /* Must return something *other* than cmp */
1134}
1135
1136void *
1137dtrace_casptr(void *target, void *cmp, void *new)
1138{
1139	if (OSCompareAndSwapPtr( cmp, new, (void**)target ))
1140		return cmp;
1141	else
1142		return (void *)(~(uintptr_t)cmp); /* Must return something *other* than cmp */
1143}
1144
1145/*
1146 * Interrupt manipulation
1147 */
1148dtrace_icookie_t
1149dtrace_interrupt_disable(void)
1150{
1151	return (dtrace_icookie_t)ml_set_interrupts_enabled(FALSE);
1152}
1153
1154void
1155dtrace_interrupt_enable(dtrace_icookie_t reenable)
1156{
1157	(void)ml_set_interrupts_enabled((boolean_t)reenable);
1158}
1159
1160/*
1161 * MP coordination
1162 */
1163static void
1164dtrace_sync_func(void) {}
1165
1166/*
1167 * dtrace_sync() is not called from probe context.
1168 */
1169void
1170dtrace_sync(void)
1171{
1172	dtrace_xcall(DTRACE_CPUALL, (dtrace_xcall_t)dtrace_sync_func, NULL);
1173}
1174
1175/*
1176 * The dtrace_copyin/out/instr and dtrace_fuword* routines can be called from probe context.
1177 */
1178
1179extern kern_return_t dtrace_copyio_preflight(addr64_t);
1180extern kern_return_t dtrace_copyio_postflight(addr64_t);
1181
1182static int
1183dtrace_copycheck(user_addr_t uaddr, uintptr_t kaddr, size_t size)
1184{
1185#pragma unused(kaddr)
1186
1187	vm_offset_t recover = dtrace_set_thread_recover( current_thread(), 0 ); /* Snare any extant recovery point. */
1188	dtrace_set_thread_recover( current_thread(), recover ); /* Put it back. We *must not* re-enter and overwrite. */
1189
1190	ASSERT(kaddr + size >= kaddr);
1191
1192	if (ml_at_interrupt_context() ||	/* Avoid possible copyio page fault on int stack, which panics! */
1193		0 != recover ||					/* Avoid reentrancy into copyio facility. */
1194		uaddr + size < uaddr ||			/* Avoid address wrap. */
1195		KERN_FAILURE == dtrace_copyio_preflight(uaddr)) /* Machine specific setup/constraints. */
1196	{
1197		DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1198		cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1199		return (0);
1200	}
1201	return (1);
1202}
1203
1204void
1205dtrace_copyin(user_addr_t src, uintptr_t dst, size_t len, volatile uint16_t *flags)
1206{
1207#pragma unused(flags)
1208
1209	if (dtrace_copycheck( src, dst, len )) {
1210		if (copyin((const user_addr_t)src, (char *)dst, (vm_size_t)len)) {
1211			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1212			cpu_core[CPU->cpu_id].cpuc_dtrace_illval = src;
1213		}
1214		dtrace_copyio_postflight(src);
1215	}
1216}
1217
1218void
1219dtrace_copyinstr(user_addr_t src, uintptr_t dst, size_t len, volatile uint16_t *flags)
1220{
1221#pragma unused(flags)
1222
1223	size_t actual;
1224
1225	if (dtrace_copycheck( src, dst, len )) {
1226		/*  copyin as many as 'len' bytes. */
1227		int error = copyinstr((const user_addr_t)src, (char *)dst, (vm_size_t)len, &actual);
1228
1229		/*
1230		 * ENAMETOOLONG is returned when 'len' bytes have been copied in but the NUL terminator was
1231		 * not encountered. That does not require raising CPU_DTRACE_BADADDR, and we press on.
1232		 * Note that we do *not* stuff a NUL terminator when returning ENAMETOOLONG, that's left
1233		 * to the caller.
1234		 */
1235		if (error && error != ENAMETOOLONG) {
1236			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1237			cpu_core[CPU->cpu_id].cpuc_dtrace_illval = src;
1238		}
1239		dtrace_copyio_postflight(src);
1240	}
1241}
1242
1243void
1244dtrace_copyout(uintptr_t src, user_addr_t dst, size_t len, volatile uint16_t *flags)
1245{
1246#pragma unused(flags)
1247
1248	if (dtrace_copycheck( dst, src, len )) {
1249		if (copyout((const void *)src, dst, (vm_size_t)len)) {
1250			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1251			cpu_core[CPU->cpu_id].cpuc_dtrace_illval = dst;
1252		}
1253		dtrace_copyio_postflight(dst);
1254	}
1255}
1256
1257void
1258dtrace_copyoutstr(uintptr_t src, user_addr_t dst, size_t len, volatile uint16_t *flags)
1259{
1260#pragma unused(flags)
1261
1262	size_t actual;
1263
1264	if (dtrace_copycheck( dst, src, len )) {
1265
1266		/*
1267		 * ENAMETOOLONG is returned when 'len' bytes have been copied out but the NUL terminator was
1268		 * not encountered. We raise CPU_DTRACE_BADADDR in that case.
1269		 * Note that we do *not* stuff a NUL terminator when returning ENAMETOOLONG, that's left
1270		 * to the caller.
1271		 */
1272		if (copyoutstr((const void *)src, dst, (size_t)len, &actual)) {
1273			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1274			cpu_core[CPU->cpu_id].cpuc_dtrace_illval = dst;
1275		}
1276		dtrace_copyio_postflight(dst);
1277	}
1278}
1279
1280uint8_t
1281dtrace_fuword8(user_addr_t uaddr)
1282{
1283	uint8_t ret = 0;
1284
1285	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
1286	if (dtrace_copycheck( uaddr, (uintptr_t)&ret, sizeof(ret))) {
1287		if (copyin((const user_addr_t)uaddr, (char *)&ret, sizeof(ret))) {
1288			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1289			cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1290		}
1291		dtrace_copyio_postflight(uaddr);
1292	}
1293	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
1294
1295	return(ret);
1296}
1297
1298uint16_t
1299dtrace_fuword16(user_addr_t uaddr)
1300{
1301	uint16_t ret = 0;
1302
1303	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
1304	if (dtrace_copycheck( uaddr, (uintptr_t)&ret, sizeof(ret))) {
1305		if (copyin((const user_addr_t)uaddr, (char *)&ret, sizeof(ret))) {
1306			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1307			cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1308		}
1309		dtrace_copyio_postflight(uaddr);
1310	}
1311	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
1312
1313	return(ret);
1314}
1315
1316uint32_t
1317dtrace_fuword32(user_addr_t uaddr)
1318{
1319	uint32_t ret = 0;
1320
1321	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
1322	if (dtrace_copycheck( uaddr, (uintptr_t)&ret, sizeof(ret))) {
1323		if (copyin((const user_addr_t)uaddr, (char *)&ret, sizeof(ret))) {
1324			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1325			cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1326		}
1327		dtrace_copyio_postflight(uaddr);
1328	}
1329	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
1330
1331	return(ret);
1332}
1333
1334uint64_t
1335dtrace_fuword64(user_addr_t uaddr)
1336{
1337	uint64_t ret = 0;
1338
1339	DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
1340	if (dtrace_copycheck( uaddr, (uintptr_t)&ret, sizeof(ret))) {
1341		if (copyin((const user_addr_t)uaddr, (char *)&ret, sizeof(ret))) {
1342			DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1343			cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1344		}
1345		dtrace_copyio_postflight(uaddr);
1346	}
1347	DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
1348
1349	return(ret);
1350}
1351
1352/*
1353 * Emulation of Solaris fuword / suword
1354 * Called from the fasttrap provider, so the use of copyin/out requires fewer safegaurds.
1355 */
1356
1357int
1358fuword8(user_addr_t uaddr, uint8_t *value)
1359{
1360	if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint8_t)) != 0) {
1361		return -1;
1362	}
1363
1364	return 0;
1365}
1366
1367int
1368fuword16(user_addr_t uaddr, uint16_t *value)
1369{
1370	if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint16_t)) != 0) {
1371		return -1;
1372	}
1373
1374	return 0;
1375}
1376
1377int
1378fuword32(user_addr_t uaddr, uint32_t *value)
1379{
1380	if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint32_t)) != 0) {
1381		return -1;
1382	}
1383
1384	return 0;
1385}
1386
1387int
1388fuword64(user_addr_t uaddr, uint64_t *value)
1389{
1390	if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint64_t)) != 0) {
1391		return -1;
1392	}
1393
1394	return 0;
1395}
1396
1397void
1398fuword8_noerr(user_addr_t uaddr, uint8_t *value)
1399{
1400	if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint8_t))) {
1401		*value = 0;
1402	}
1403}
1404
1405void
1406fuword16_noerr(user_addr_t uaddr, uint16_t *value)
1407{
1408	if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint16_t))) {
1409		*value = 0;
1410	}
1411}
1412
1413void
1414fuword32_noerr(user_addr_t uaddr, uint32_t *value)
1415{
1416	if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint32_t))) {
1417		*value = 0;
1418	}
1419}
1420
1421void
1422fuword64_noerr(user_addr_t uaddr, uint64_t *value)
1423{
1424	if (copyin((const user_addr_t)uaddr, (char *)value, sizeof(uint64_t))) {
1425		*value = 0;
1426	}
1427}
1428
1429int
1430suword64(user_addr_t addr, uint64_t value)
1431{
1432	if (copyout((const void *)&value, addr, sizeof(value)) != 0) {
1433		return -1;
1434	}
1435
1436	return 0;
1437}
1438
1439int
1440suword32(user_addr_t addr, uint32_t value)
1441{
1442	if (copyout((const void *)&value, addr, sizeof(value)) != 0) {
1443		return -1;
1444	}
1445
1446	return 0;
1447}
1448
1449int
1450suword16(user_addr_t addr, uint16_t value)
1451{
1452	if (copyout((const void *)&value, addr, sizeof(value)) != 0) {
1453		return -1;
1454	}
1455
1456	return 0;
1457}
1458
1459int
1460suword8(user_addr_t addr, uint8_t value)
1461{
1462	if (copyout((const void *)&value, addr, sizeof(value)) != 0) {
1463		return -1;
1464	}
1465
1466	return 0;
1467}
1468
1469
1470/*
1471 * Miscellaneous
1472 */
1473extern boolean_t dtrace_tally_fault(user_addr_t);
1474
1475boolean_t
1476dtrace_tally_fault(user_addr_t uaddr)
1477{
1478	DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
1479	cpu_core[CPU->cpu_id].cpuc_dtrace_illval = uaddr;
1480	return( DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT) ? TRUE : FALSE );
1481}
1482
1483#define TOTTY   0x02
1484extern int prf(const char *, va_list, int, struct tty *); /* bsd/kern/subr_prf.h */
1485
1486int
1487vuprintf(const char *format, va_list ap)
1488{
1489	return prf(format, ap, TOTTY, NULL);
1490}
1491
1492/* Not called from probe context */
1493void cmn_err( int level, const char *format, ... )
1494{
1495#pragma unused(level)
1496	va_list alist;
1497
1498	va_start(alist, format);
1499	vuprintf(format, alist);
1500	va_end(alist);
1501	uprintf("\n");
1502}
1503
1504/*
1505 * History:
1506 *  2002-01-24 	gvdl	Initial implementation of strstr
1507 */
1508
1509__private_extern__ const char *
1510strstr(const char *in, const char *str)
1511{
1512    char c;
1513    size_t len;
1514
1515    c = *str++;
1516    if (!c)
1517        return (const char *) in;	// Trivial empty string case
1518
1519    len = strlen(str);
1520    do {
1521        char sc;
1522
1523        do {
1524            sc = *in++;
1525            if (!sc)
1526                return (char *) 0;
1527        } while (sc != c);
1528    } while (strncmp(in, str, len) != 0);
1529
1530    return (const char *) (in - 1);
1531}
1532
1533/*
1534 * Runtime and ABI
1535 */
1536uintptr_t
1537dtrace_caller(int ignore)
1538{
1539#pragma unused(ignore)
1540	return -1; /* Just as in Solaris dtrace_asm.s */
1541}
1542
1543int
1544dtrace_getstackdepth(int aframes)
1545{
1546	struct frame *fp = (struct frame *)__builtin_frame_address(0);
1547	struct frame *nextfp, *minfp, *stacktop;
1548	int depth = 0;
1549	int on_intr;
1550
1551	if ((on_intr = CPU_ON_INTR(CPU)) != 0)
1552		stacktop = (struct frame *)dtrace_get_cpu_int_stack_top();
1553	else
1554		stacktop = (struct frame *)(dtrace_get_kernel_stack(current_thread()) + kernel_stack_size);
1555
1556	minfp = fp;
1557
1558	aframes++;
1559
1560	for (;;) {
1561		depth++;
1562
1563		nextfp = *(struct frame **)fp;
1564
1565		if (nextfp <= minfp || nextfp >= stacktop) {
1566			if (on_intr) {
1567				/*
1568				 * Hop from interrupt stack to thread stack.
1569				 */
1570                                vm_offset_t kstack_base = dtrace_get_kernel_stack(current_thread());
1571
1572                                minfp = (struct frame *)kstack_base;
1573                                stacktop = (struct frame *)(kstack_base + kernel_stack_size);
1574
1575				on_intr = 0;
1576				continue;
1577			}
1578			break;
1579		}
1580
1581		fp = nextfp;
1582		minfp = fp;
1583	}
1584
1585	if (depth <= aframes)
1586		return (0);
1587
1588	return (depth - aframes);
1589}
1590
1591/*
1592 * Unconsidered
1593 */
1594void
1595dtrace_vtime_enable(void) {}
1596
1597void
1598dtrace_vtime_disable(void) {}
1599
1600#else /* else ! CONFIG_DTRACE */
1601
1602#include <sys/types.h>
1603#include <mach/vm_types.h>
1604#include <mach/kmod.h>
1605
1606/*
1607 * This exists to prevent build errors when dtrace is unconfigured.
1608 */
1609
1610kern_return_t _dtrace_register_anon_DOF(char *, unsigned char *, uint32_t);
1611
1612kern_return_t _dtrace_register_anon_DOF(char *arg1, unsigned char *arg2, uint32_t arg3) {
1613#pragma unused(arg1, arg2, arg3)
1614
1615        return KERN_FAILURE;
1616}
1617
1618#endif /* CONFIG_DTRACE */
1619