X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/89b3af67bb32e691275bf6fa803d1834b2284115..6d2010ae8f7a6078e10b361c6962983bab233e0f:/bsd/dev/chud/chud_bsd_callback.c diff --git a/bsd/dev/chud/chud_bsd_callback.c b/bsd/dev/chud/chud_bsd_callback.c index 68daf186d..a28bebf46 100644 --- a/bsd/dev/chud/chud_bsd_callback.c +++ b/bsd/dev/chud/chud_bsd_callback.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2003-2006 Apple Computer, Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -32,28 +32,40 @@ #include #include /* u_int */ -#include /* struct proc */ +#include /* proc_t */ #include /* struct sysent */ #include +#include /* KDEBUG_ENABLE_CHUD */ +#include /* kauth_cred_get */ +#include +#if CONFIG_MACF +#include /* mac_system_check_chud */ +#endif #pragma mark **** kern debug **** -typedef void (*chudxnu_kdebug_callback_func_t)(uint32_t debugid, uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4); -static chudxnu_kdebug_callback_func_t kdebug_callback_fn = NULL; +typedef void (*chudxnu_kdebug_callback_func_t)(uint32_t debugid, uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4); +static void chud_null_kdebug(uint32_t debugid, uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t arg4); +static chudxnu_kdebug_callback_func_t kdebug_callback_fn = chud_null_kdebug; kern_return_t chudxnu_kdebug_callback_enter(chudxnu_kdebug_callback_func_t); kern_return_t chudxnu_kdebug_callback_cancel(void); extern void kdbg_control_chud(int val, void *fn); -extern unsigned int kdebug_enable; + +static void chud_null_kdebug(uint32_t debugid __unused, uintptr_t arg0 __unused, + uintptr_t arg1 __unused, uintptr_t arg2 __unused, uintptr_t arg3 __unused, + uintptr_t arg4 __unused) { + return; +} static void chudxnu_private_kdebug_callback( - unsigned int debugid, - unsigned int arg0, - unsigned int arg1, - unsigned int arg2, - unsigned int arg3, - unsigned int arg4) + uint32_t debugid, + uintptr_t arg0, + uintptr_t arg1, + uintptr_t arg2, + uintptr_t arg3, + uintptr_t arg4) { chudxnu_kdebug_callback_func_t fn = kdebug_callback_fn; @@ -65,59 +77,192 @@ chudxnu_private_kdebug_callback( __private_extern__ kern_return_t chudxnu_kdebug_callback_enter(chudxnu_kdebug_callback_func_t func) { - kdebug_callback_fn = func; - - kdbg_control_chud(TRUE, (void *)chudxnu_private_kdebug_callback); - kdebug_enable |= 0x10; - - return KERN_SUCCESS; + /* Atomically set the callback. */ + if(OSCompareAndSwapPtr(chud_null_kdebug, func, + (void * volatile *)&kdebug_callback_fn)) { + + kdbg_control_chud(TRUE, (void *)chudxnu_private_kdebug_callback); + return KERN_SUCCESS; + } + return KERN_FAILURE; } __private_extern__ kern_return_t chudxnu_kdebug_callback_cancel(void) { - kdebug_callback_fn = NULL; - kdbg_control_chud(FALSE, NULL); - kdebug_enable &= ~(0x10); + kdbg_control_chud(FALSE, NULL); + + chudxnu_kdebug_callback_func_t old = kdebug_callback_fn; + + while(!OSCompareAndSwapPtr(old, chud_null_kdebug, + (void * volatile *)&kdebug_callback_fn)) { + old = kdebug_callback_fn; + } return KERN_SUCCESS; } #pragma mark **** CHUD syscall **** -typedef kern_return_t (*chudxnu_syscall_callback_func_t)(uint32_t code, uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4); -static chudxnu_syscall_callback_func_t syscall_callback_fn = NULL; +typedef kern_return_t (*chudxnu_syscall_callback_func_t)(uint64_t code, uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4); + +static kern_return_t chud_null_syscall(uint64_t code, uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4); +static chudxnu_syscall_callback_func_t syscall_callback_fn = chud_null_syscall; kern_return_t chudxnu_syscall_callback_enter(chudxnu_syscall_callback_func_t func); kern_return_t chudxnu_syscall_callback_cancel(void); -int chud(p, uap, retval) - struct proc *p; - struct chud_args *uap; - register_t *retval; +static kern_return_t chud_null_syscall(uint64_t code __unused, + uint64_t arg0 __unused, uint64_t arg1 __unused, uint64_t arg2 __unused, + uint64_t arg3 __unused, uint64_t arg4 __unused) { + return (kern_return_t)EINVAL; +} + +/* + * chud + * + * Performs performance-related tasks. A private interface registers a handler for this + * system call. The implementation is in the CHUDProf kernel extension. + * + * chud() is a callback style system call used by the CHUD Tools suite of performance tools. If the CHUD + * kexts are not loaded, this system call will always return EINVAL. The CHUD kexts contain the + * implementation of the system call. + * + * The current behavior of the chud() system call is as follows: + * + * Parameters: p (ignored) + * uap User argument descriptor (see below) + * retval return value of fn (the function returned by syscall_callback_fn) + * + * Indirect parameters: uap->code Selects the operation to do. This is broken down into a + * 16-bit facility and a 16-bit action. + * + * The rest of the indirect parameters depend on the facility and the action that is selected: + * + * Facility: 1 Amber instruction tracer + * Action: 1 Indicate that a new thread has been created. No arguments are used. + * + * Action: 2 Indicate that a thread is about to exit. No arguments are used. + * + * Facility: 2 Not Supported for this system call + * + * Facility: 3 CHUD Trace facility + * Action: 1 Record a backtrace of the calling process into the CHUD Trace facility sample + * buffer. + * + * uap->arg1 Number of frames to skip + * uap->arg2 Pointer to a uint64_t containing a timestamp for the + * beginning of the sample. NULL uses the current time. + * uap->arg3 Pointer to a uint64_t containing a timestamp for the end + * of the sample. NULL uses the current time. + * uap->arg4 Pointer to auxiliary data to be recorded with the sample + * uap->arg5 Size of the auxiliary data pointed to by arg4. + * + * Returns: EINVAL If syscall_callback_fn returns an invalid function + * KERN_SUCCESS Success + * KERN_FAILURE Generic failure + * KERN_NO_SPACE Auxiliary data is too large (only used by Facility: 3) + * + * Implicit returns: retval return value of fn (the function returned by syscall_callback_fn) + */ +int +chud(__unused proc_t p, struct chud_args *uap, int32_t *retval) { -#pragma unused (p) +#if CONFIG_MACF + int error = mac_system_check_chud(kauth_cred_get()); + if (error) + return error; +#endif chudxnu_syscall_callback_func_t fn = syscall_callback_fn; if(!fn) { return EINVAL; } - + *retval = fn(uap->code, uap->arg1, uap->arg2, uap->arg3, uap->arg4, uap->arg5); return 0; } -__private_extern__ -kern_return_t chudxnu_syscall_callback_enter(chudxnu_syscall_callback_func_t func) +__private_extern__ kern_return_t +chudxnu_syscall_callback_enter(chudxnu_syscall_callback_func_t func) { - syscall_callback_fn = func; - return KERN_SUCCESS; + if(OSCompareAndSwapPtr(chud_null_syscall, func, + (void * volatile *)&syscall_callback_fn)) { + return KERN_SUCCESS; + } + return KERN_FAILURE; } -__private_extern__ -kern_return_t chudxnu_syscall_callback_cancel(void) +__private_extern__ kern_return_t +chudxnu_syscall_callback_cancel(void) { - syscall_callback_fn = NULL; + chudxnu_syscall_callback_func_t old = syscall_callback_fn; + + while(!OSCompareAndSwapPtr(old, chud_null_syscall, + (void * volatile *)&syscall_callback_fn)) { + old = syscall_callback_fn; + } + return KERN_SUCCESS; } + +/* DTrace callback */ +typedef kern_return_t (*chudxnu_dtrace_callback_t)(uint64_t selector, + uint64_t *args, uint32_t count); +int chudxnu_dtrace_callback(uint64_t selector, uint64_t *args, uint32_t count); +kern_return_t chudxnu_dtrace_callback_enter(chudxnu_dtrace_callback_t fn); +void chudxnu_dtrace_callback_cancel(void); + +int +chud_null_dtrace(uint64_t selector, uint64_t *args, uint32_t count); + +static chudxnu_dtrace_callback_t + dtrace_callback = (chudxnu_dtrace_callback_t) chud_null_dtrace; + +int +chud_null_dtrace(uint64_t selector __unused, uint64_t *args __unused, + uint32_t count __unused) { + return ENXIO; +} + +int +chudxnu_dtrace_callback(uint64_t selector, uint64_t *args, uint32_t count) +{ + /* If no callback is hooked up, let's return ENXIO */ + int ret = ENXIO; + + /* Make a local stack copy of the function ptr */ + chudxnu_dtrace_callback_t fn = dtrace_callback; + + if(fn) { + ret = fn(selector, args, count); + } + + return ret; +} + +__private_extern__ kern_return_t +chudxnu_dtrace_callback_enter(chudxnu_dtrace_callback_t fn) +{ + /* Atomically enter the call back */ + if(!OSCompareAndSwapPtr(chud_null_dtrace, fn, + (void * volatile *) &dtrace_callback)) { + return KERN_FAILURE; + } + + return KERN_SUCCESS; +} + +__private_extern__ void +chudxnu_dtrace_callback_cancel(void) +{ + chudxnu_dtrace_callback_t old_fn = dtrace_callback; + + /* Atomically clear the call back */ + while(!OSCompareAndSwapPtr(old_fn, chud_null_dtrace, + (void * volatile *) &dtrace_callback)) { + old_fn = dtrace_callback; + } +} +