/*
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2003-2009 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <kern/kalloc.h>
#include <kern/thread.h>
+#include <libkern/OSAtomic.h>
+
#include <machine/machine_routines.h>
#include <machine/cpu_data.h>
#include <machine/trap.h>
#include <chud/chud_xnu_private.h>
#include <i386/misc_protos.h>
+#include <i386/lapic.h>
#include <i386/mp.h>
#include <i386/machine_cpu.h>
chudxnu_interrupt_callback_cancel();
chudxnu_perfmon_ast_callback_cancel();
chudxnu_kdebug_callback_cancel();
- chudxnu_thread_timer_callback_cancel();
chudxnu_trap_callback_cancel();
-#if XXX
chudxnu_syscall_callback_cancel();
-#endif
+ chudxnu_dtrace_callback_cancel();
}
static chudcpu_data_t chudcpu_boot_cpu;
{
chudcpu_data_t *chud_proc_info;
-
if (boot_processor) {
chud_proc_info = &chudcpu_boot_cpu;
} else {
FALSE) == KERN_SUCCESS) {
fn = chud_proc_info->cpu_timer_callback_fn;
if (fn) {
- KERNEL_DEBUG_CONSTANT(
- MACHDBG_CODE(DBG_MACH_CHUD,
- CHUD_TIMER_CALLBACK) | DBG_FUNC_NONE,
- (uint32_t)fn, 0,0,0,0);
- //state.eip, state.cs, 0, 0);
(fn)(
x86_THREAD_STATE,
(thread_state_t)&state,
timer_call_enter(&(chud_proc_info->cpu_timer_call),
chud_proc_info->t_deadline);
- KERNEL_DEBUG_CONSTANT(
- MACHDBG_CODE(DBG_MACH_CHUD,
- CHUD_TIMER_CALLBACK_ENTER) | DBG_FUNC_NONE,
- (uint32_t) func, time, units, 0, 0);
-
ml_set_interrupts_enabled(oldlevel);
return KERN_SUCCESS;
}
timer_call_cancel(&(chud_proc_info->cpu_timer_call));
- KERNEL_DEBUG_CONSTANT(
- MACHDBG_CODE(DBG_MACH_CHUD,
- CHUD_TIMER_CALLBACK_CANCEL) | DBG_FUNC_NONE,
- 0, 0, 0, 0, 0);
-
// set to max value:
chud_proc_info->t_deadline |= ~(chud_proc_info->t_deadline);
chud_proc_info->cpu_timer_callback_fn = NULL;
return KERN_SUCCESS;
}
+#if 0
#pragma mark **** trap ****
-static chudxnu_trap_callback_func_t trap_callback_fn = NULL;
+#endif
+static kern_return_t chud_null_trap(uint32_t trapentry, thread_flavor_t flavor,
+ thread_state_t tstate, mach_msg_type_number_t count);
+static chudxnu_trap_callback_func_t trap_callback_fn = chud_null_trap;
+
+static kern_return_t chud_null_trap(uint32_t trapentry __unused, thread_flavor_t flavor __unused,
+ thread_state_t tstate __unused, mach_msg_type_number_t count __unused) {
+ return KERN_FAILURE;
+}
static kern_return_t
chudxnu_private_trap_callback(
- int trapno,
+ int trapno,
void *regs,
int unused1,
int unused2)
#pragma unused (regs)
#pragma unused (unused1)
#pragma unused (unused2)
- kern_return_t retval = KERN_FAILURE;
+ kern_return_t retval = KERN_FAILURE;
chudxnu_trap_callback_func_t fn = trap_callback_fn;
- if(fn) {
- boolean_t oldlevel;
- x86_thread_state_t state; // once we have an 64bit- independent way to determine if a thread is
- // running kernel code, we'll switch to x86_thread_state_t.
- mach_msg_type_number_t count;
-
+ if(fn) {
+ boolean_t oldlevel;
+ x86_thread_state_t state;
+ mach_msg_type_number_t count;
+ thread_t thread = current_thread();
+
oldlevel = ml_set_interrupts_enabled(FALSE);
+
+ /* prevent reentry into CHUD when dtracing */
+ if(thread->t_chud & T_IN_CHUD) {
+ /* restore interrupts */
+ ml_set_interrupts_enabled(oldlevel);
+
+ return KERN_FAILURE; // not handled - pass off to dtrace
+ }
+
+ /* update the chud state bits */
+ thread->t_chud |= T_IN_CHUD;
count = x86_THREAD_STATE_COUNT;
- if(chudxnu_thread_get_state(current_thread(),
+
+ if(chudxnu_thread_get_state(thread,
x86_THREAD_STATE,
(thread_state_t)&state,
&count,
FALSE) == KERN_SUCCESS) {
-
- retval = (fn)(
- trapno,
- x86_THREAD_STATE,
- (thread_state_t)&state,
- count);
+
+ retval = (fn)(
+ trapno,
+ x86_THREAD_STATE,
+ (thread_state_t)&state,
+ count);
}
- ml_set_interrupts_enabled(oldlevel);
+
+ /* no longer in CHUD */
+ thread->t_chud &= ~(T_IN_CHUD);
+
+ ml_set_interrupts_enabled(oldlevel);
}
- return retval;
+ return retval;
}
__private_extern__ kern_return_t
chudxnu_trap_callback_enter(chudxnu_trap_callback_func_t func)
{
- trap_callback_fn = func;
- perfTrapHook = chudxnu_private_trap_callback;
- return KERN_SUCCESS;
+ if(OSCompareAndSwapPtr(NULL, chudxnu_private_trap_callback,
+ (void * volatile *)&perfTrapHook)) {
+
+ chudxnu_trap_callback_func_t old = trap_callback_fn;
+ while(!OSCompareAndSwapPtr(old, func,
+ (void * volatile *)&trap_callback_fn)) {
+ old = trap_callback_fn;
+ }
+ return KERN_SUCCESS;
+ }
+ return KERN_FAILURE;
}
__private_extern__ kern_return_t
chudxnu_trap_callback_cancel(void)
{
- trap_callback_fn = NULL;
- perfTrapHook = NULL;
- return KERN_SUCCESS;
+ if(OSCompareAndSwapPtr(chudxnu_private_trap_callback, NULL,
+ (void * volatile *)&perfTrapHook)) {
+
+ chudxnu_trap_callback_func_t old = trap_callback_fn;
+ while(!OSCompareAndSwapPtr(old, chud_null_trap,
+ (void * volatile *)&trap_callback_fn)) {
+ old = trap_callback_fn;
+ }
+ return KERN_SUCCESS;
+ }
+ return KERN_FAILURE;
}
+#if 0
#pragma mark **** ast ****
-static
-chudxnu_perfmon_ast_callback_func_t perfmon_ast_callback_fn = NULL;
+#endif
+static kern_return_t chud_null_ast(thread_flavor_t flavor, thread_state_t tstate,
+ mach_msg_type_number_t count);
+static chudxnu_perfmon_ast_callback_func_t perfmon_ast_callback_fn = chud_null_ast;
+
+static kern_return_t chud_null_ast(thread_flavor_t flavor __unused,
+ thread_state_t tstate __unused, mach_msg_type_number_t count __unused) {
+ return KERN_FAILURE;
+}
static kern_return_t
chudxnu_private_chud_ast_callback(
x86_thread_state_t state;
mach_msg_type_number_t count;
count = x86_THREAD_STATE_COUNT;
-
+
if (chudxnu_thread_get_state(
current_thread(),
x86_THREAD_STATE,
(thread_state_t) &state, &count,
TRUE) == KERN_SUCCESS) {
- KERNEL_DEBUG_CONSTANT(
- MACHDBG_CODE(DBG_MACH_CHUD,
- CHUD_AST_CALLBACK) | DBG_FUNC_NONE,
- (uint32_t) fn, 0, 0, 0, 0);
-
(fn)(
x86_THREAD_STATE,
(thread_state_t) &state,
__private_extern__ kern_return_t
chudxnu_perfmon_ast_callback_enter(chudxnu_perfmon_ast_callback_func_t func)
{
- perfmon_ast_callback_fn = func;
- perfASTHook = chudxnu_private_chud_ast_callback;
- return KERN_SUCCESS;
+ if(OSCompareAndSwapPtr(NULL, chudxnu_private_chud_ast_callback,
+ (void * volatile *)&perfASTHook)) {
+ chudxnu_perfmon_ast_callback_func_t old = perfmon_ast_callback_fn;
+
+ while(!OSCompareAndSwapPtr(old, func,
+ (void * volatile *)&perfmon_ast_callback_fn)) {
+ old = perfmon_ast_callback_fn;
+ }
+
+ return KERN_SUCCESS;
+ }
+ return KERN_FAILURE;
}
__private_extern__ kern_return_t
chudxnu_perfmon_ast_callback_cancel(void)
{
- perfmon_ast_callback_fn = NULL;
- perfASTHook = NULL;
- return KERN_SUCCESS;
+ if(OSCompareAndSwapPtr(chudxnu_private_chud_ast_callback, NULL,
+ (void * volatile *)&perfASTHook)) {
+ chudxnu_perfmon_ast_callback_func_t old = perfmon_ast_callback_fn;
+
+ while(!OSCompareAndSwapPtr(old, chud_null_ast,
+ (void * volatile *)&perfmon_ast_callback_fn)) {
+ old = perfmon_ast_callback_fn;
+ }
+
+ return KERN_SUCCESS;
+ }
+ return KERN_FAILURE;
}
__private_extern__ kern_return_t
*myast |= (AST_CHUD);
}
- KERNEL_DEBUG_CONSTANT(
- MACHDBG_CODE(DBG_MACH_CHUD, CHUD_AST_SEND) | DBG_FUNC_NONE,
- urgent, 0, 0, 0, 0);
-
ml_set_interrupts_enabled(oldlevel);
return KERN_SUCCESS;
}
-__private_extern__ kern_return_t
-chudxnu_perfmon_ast_send(void)
-{
- return chudxnu_perfmon_ast_send_urgent(TRUE);
-}
-
+#if 0
#pragma mark **** interrupt ****
-static chudxnu_interrupt_callback_func_t interrupt_callback_fn = NULL;
+#endif
+static kern_return_t chud_null_int(uint32_t trapentry, thread_flavor_t flavor,
+ thread_state_t tstate, mach_msg_type_number_t count);
+static chudxnu_interrupt_callback_func_t interrupt_callback_fn = chud_null_int;
+
+static kern_return_t chud_null_int(uint32_t trapentry __unused, thread_flavor_t flavor __unused,
+ thread_state_t tstate __unused, mach_msg_type_number_t count __unused) {
+ return KERN_FAILURE;
+}
static void
chudxnu_private_interrupt_callback(void *foo)
__private_extern__ kern_return_t
chudxnu_interrupt_callback_enter(chudxnu_interrupt_callback_func_t func)
{
- interrupt_callback_fn = func;
- lapic_set_pmi_func((i386_intr_func_t)chudxnu_private_interrupt_callback);
- return KERN_SUCCESS;
+ if(OSCompareAndSwapPtr(chud_null_int, func,
+ (void * volatile *)&interrupt_callback_fn)) {
+ lapic_set_pmi_func((i386_intr_func_t)chudxnu_private_interrupt_callback);
+
+ return KERN_SUCCESS;
+ }
+ return KERN_FAILURE;
}
__private_extern__ kern_return_t
chudxnu_interrupt_callback_cancel(void)
{
- interrupt_callback_fn = NULL;
+ chudxnu_interrupt_callback_func_t old = interrupt_callback_fn;
+
+ while(!OSCompareAndSwapPtr(old, chud_null_int,
+ (void * volatile *)&interrupt_callback_fn)) {
+ old = interrupt_callback_fn;
+ }
+
lapic_set_pmi_func(NULL);
return KERN_SUCCESS;
}
+#if 0
#pragma mark **** cpu signal ****
+#endif
static chudxnu_cpusig_callback_func_t cpusig_callback_fn = NULL;
static kern_return_t
x86_THREAD_STATE,
(thread_state_t) &state, &count,
FALSE) == KERN_SUCCESS) {
- KERNEL_DEBUG_CONSTANT(
- MACHDBG_CODE(DBG_MACH_CHUD,
- CHUD_CPUSIG_CALLBACK) | DBG_FUNC_NONE,
- (uint32_t)fn, request, 0, 0, 0);
return (fn)(
request, x86_THREAD_STATE,
(thread_state_t) &state, count);
__private_extern__ kern_return_t
chudxnu_cpusig_callback_enter(chudxnu_cpusig_callback_func_t func)
{
- cpusig_callback_fn = func;
- return KERN_SUCCESS;
+ if(OSCompareAndSwapPtr(NULL, func,
+ (void * volatile *)&cpusig_callback_fn)) {
+ return KERN_SUCCESS;
+ }
+ return KERN_FAILURE;
}
__private_extern__ kern_return_t
chudxnu_cpusig_callback_cancel(void)
{
- cpusig_callback_fn = NULL;
+ chudxnu_cpusig_callback_func_t old = cpusig_callback_fn;
+
+ while(!OSCompareAndSwapPtr(old, NULL,
+ (void * volatile *)&cpusig_callback_fn)) {
+ old = cpusig_callback_fn;
+ }
+
return KERN_SUCCESS;
}
//request.req_type = CPRQchud; /* set request type */
request.req_code = request_code; /* set request */
- KERNEL_DEBUG_CONSTANT(
- MACHDBG_CODE(DBG_MACH_CHUD,
- CHUD_CPUSIG_SEND) | DBG_FUNC_NONE,
- otherCPU, request_code, 0, 0, 0);
-
/*
* Insert the new request in the target cpu's request queue
* and signal target cpu.
enable_preemption();
return retval;
}
-
-#ifdef XXX
-#pragma mark **** CHUD syscall (PPC) ****
-
-typedef int (*PPCcallEnt)(struct savearea *save);
-extern PPCcallEnt PPCcalls[];
-
-static chudxnu_syscall_callback_func_t syscall_callback_fn = NULL;
-
-static int
-chudxnu_private_syscall_callback(struct savearea *ssp)
-{
- if(ssp) {
- if(syscall_callback_fn) {
- struct ppc_thread_state64 state;
- kern_return_t retval;
- mach_msg_type_number_t count = PPC_THREAD_STATE64_COUNT;
- chudxnu_copy_savearea_to_threadstate(PPC_THREAD_STATE64, (thread_state_t)&state, &count, ssp);
- ssp->save_r3 = (syscall_callback_fn)(PPC_THREAD_STATE64, (thread_state_t)&state, count);
- } else {
- ssp->save_r3 = KERN_FAILURE;
- }
- }
-
- return 1; // check for ASTs (always)
-}
-
-__private_extern__ kern_return_t
-chudxnu_syscall_callback_enter(chudxnu_syscall_callback_func_t func)
-{
- syscall_callback_fn = func;
- PPCcalls[9] = chudxnu_private_syscall_callback;
- __asm__ volatile("eieio"); /* force order */
- __asm__ volatile("sync"); /* force to memory */
- return KERN_SUCCESS;
-}
-
-__private_extern__ kern_return_t
-chudxnu_syscall_callback_cancel(void)
-{
- syscall_callback_fn = NULL;
- PPCcalls[9] = NULL;
- __asm__ volatile("eieio"); /* force order */
- __asm__ volatile("sync"); /* force to memory */
- return KERN_SUCCESS;
-}
-#endif