]> git.saurik.com Git - apple/xnu.git/blame - osfmk/chud/ppc/chud_osfmk_callback_ppc.c
xnu-1228.9.59.tar.gz
[apple/xnu.git] / osfmk / chud / ppc / chud_osfmk_callback_ppc.c
CommitLineData
55e303ae 1/*
2d21ac55 2 * Copyright (c) 2003-2007 Apple Inc. All rights reserved.
55e303ae 3 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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@
55e303ae
A
27 */
28
29#include <stdint.h>
30#include <mach/boolean.h>
31#include <mach/mach_types.h>
32
91447636
A
33#include <kern/kern_types.h>
34#include <kern/processor.h>
91447636
A
35#include <kern/thread_call.h>
36#include <kern/kalloc.h>
37#include <kern/thread.h>
38
55e303ae 39#include <ppc/machine_routines.h>
91447636
A
40#include <ppc/cpu_data.h>
41#include <ppc/cpu_internal.h>
55e303ae 42#include <ppc/exception.h>
91447636
A
43#include <ppc/thread.h>
44#include <ppc/trap.h>
55e303ae 45
0c530ab8
A
46#include <chud/chud_xnu.h>
47#include <chud/chud_xnu_private.h>
55e303ae
A
48
49__private_extern__
50void chudxnu_cancel_all_callbacks(void)
51{
55e303ae
A
52 chudxnu_cpu_timer_callback_cancel_all();
53 chudxnu_trap_callback_cancel();
54 chudxnu_interrupt_callback_cancel();
55 chudxnu_perfmon_ast_callback_cancel();
56 chudxnu_cpusig_callback_cancel();
57 chudxnu_kdebug_callback_cancel();
91447636 58 chudxnu_syscall_callback_cancel();
2d21ac55 59 chudxnu_dtrace_callback_cancel();
55e303ae
A
60}
61
91447636
A
62static chudcpu_data_t chudcpu_boot_cpu;
63
64void *chudxnu_per_proc_alloc(boolean_t boot_processor)
65{
66 chudcpu_data_t *chud_proc_info;
67
68 if (boot_processor) {
69 chud_proc_info = &chudcpu_boot_cpu;
70 } else {
71 chud_proc_info = (chudcpu_data_t *)kalloc(sizeof(chudcpu_data_t));
72 if (chud_proc_info == (chudcpu_data_t *)NULL) {
73 return (void *)NULL;
74 }
75 }
76 bzero((char *)chud_proc_info, sizeof(chudcpu_data_t));
77 chud_proc_info->t_deadline = 0xFFFFFFFFFFFFFFFFULL;
78 return (void *)chud_proc_info;
79}
80
81void chudxnu_per_proc_free(void *per_proc_chud)
82{
83 if (per_proc_chud == (void *)&chudcpu_boot_cpu) {
84 return;
85 } else {
86 kfree(per_proc_chud,sizeof(chudcpu_data_t));
87 }
88}
55e303ae 89
2d21ac55
A
90static void
91chudxnu_private_cpu_timer_callback(__unused timer_call_param_t param0,
92 __unused timer_call_param_t param1)
55e303ae 93{
91447636 94 chudcpu_data_t *chud_proc_info;
55e303ae
A
95 boolean_t oldlevel;
96 struct ppc_thread_state64 state;
97 mach_msg_type_number_t count;
0c530ab8 98 chudxnu_cpu_timer_callback_func_t fn = NULL;
55e303ae
A
99
100 oldlevel = ml_set_interrupts_enabled(FALSE);
91447636 101 chud_proc_info = (chudcpu_data_t *)(getPerProc()->pp_chud);
55e303ae
A
102
103 count = PPC_THREAD_STATE64_COUNT;
91447636 104 if(chudxnu_thread_get_state(current_thread(), PPC_THREAD_STATE64, (thread_state_t)&state, &count, FALSE)==KERN_SUCCESS) {
0c530ab8
A
105 fn = chud_proc_info->cpu_timer_callback_fn;
106 if(fn) {
107 (fn)(PPC_THREAD_STATE64, (thread_state_t)&state, count);
55e303ae
A
108 }
109 }
110
111 ml_set_interrupts_enabled(oldlevel);
112}
113
114__private_extern__
115kern_return_t chudxnu_cpu_timer_callback_enter(chudxnu_cpu_timer_callback_func_t func, uint32_t time, uint32_t units)
116{
91447636 117 chudcpu_data_t *chud_proc_info;
55e303ae
A
118 boolean_t oldlevel;
119
120 oldlevel = ml_set_interrupts_enabled(FALSE);
91447636 121 chud_proc_info = (chudcpu_data_t *)(getPerProc()->pp_chud);
55e303ae 122
91447636 123 timer_call_cancel(&(chud_proc_info->cpu_timer_call)); // cancel any existing callback for this cpu
55e303ae 124
91447636 125 chud_proc_info->cpu_timer_callback_fn = func;
55e303ae 126
91447636
A
127 clock_interval_to_deadline(time, units, &(chud_proc_info->t_deadline));
128 timer_call_setup(&(chud_proc_info->cpu_timer_call), chudxnu_private_cpu_timer_callback, NULL);
129 timer_call_enter(&(chud_proc_info->cpu_timer_call), chud_proc_info->t_deadline);
55e303ae
A
130
131 ml_set_interrupts_enabled(oldlevel);
132 return KERN_SUCCESS;
133}
134
135__private_extern__
136kern_return_t chudxnu_cpu_timer_callback_cancel(void)
137{
91447636 138 chudcpu_data_t *chud_proc_info;
55e303ae
A
139 boolean_t oldlevel;
140
141 oldlevel = ml_set_interrupts_enabled(FALSE);
91447636 142 chud_proc_info = (chudcpu_data_t *)(getPerProc()->pp_chud);
55e303ae 143
91447636
A
144 timer_call_cancel(&(chud_proc_info->cpu_timer_call));
145 chud_proc_info->t_deadline = chud_proc_info->t_deadline | ~(chud_proc_info->t_deadline); // set to max value
146 chud_proc_info->cpu_timer_callback_fn = NULL;
55e303ae
A
147
148 ml_set_interrupts_enabled(oldlevel);
149 return KERN_SUCCESS;
150}
151
152__private_extern__
153kern_return_t chudxnu_cpu_timer_callback_cancel_all(void)
154{
91447636
A
155 unsigned int cpu;
156 chudcpu_data_t *chud_proc_info;
157
158 for(cpu=0; cpu<real_ncpus; cpu++) {
159 if ((PerProcTable[cpu].ppe_vaddr == 0)
160 || (PerProcTable[cpu].ppe_vaddr->pp_chud == 0))
161 continue;
162 chud_proc_info = (chudcpu_data_t *)PerProcTable[cpu].ppe_vaddr->pp_chud;
163 timer_call_cancel(&(chud_proc_info->cpu_timer_call));
164 chud_proc_info->t_deadline = chud_proc_info->t_deadline | ~(chud_proc_info->t_deadline); // set to max value
165 chud_proc_info->cpu_timer_callback_fn = NULL;
55e303ae
A
166 }
167 return KERN_SUCCESS;
168}
169
91447636 170#pragma mark **** trap ****
55e303ae
A
171static chudxnu_trap_callback_func_t trap_callback_fn = NULL;
172
55e303ae
A
173#define TRAP_ENTRY_POINT(t) ((t==T_RESET) ? 0x100 : \
174 (t==T_MACHINE_CHECK) ? 0x200 : \
175 (t==T_DATA_ACCESS) ? 0x300 : \
176 (t==T_DATA_SEGMENT) ? 0x380 : \
177 (t==T_INSTRUCTION_ACCESS) ? 0x400 : \
178 (t==T_INSTRUCTION_SEGMENT) ? 0x480 : \
179 (t==T_INTERRUPT) ? 0x500 : \
180 (t==T_ALIGNMENT) ? 0x600 : \
181 (t==T_PROGRAM) ? 0x700 : \
182 (t==T_FP_UNAVAILABLE) ? 0x800 : \
183 (t==T_DECREMENTER) ? 0x900 : \
184 (t==T_IO_ERROR) ? 0xa00 : \
185 (t==T_RESERVED) ? 0xb00 : \
186 (t==T_SYSTEM_CALL) ? 0xc00 : \
187 (t==T_TRACE) ? 0xd00 : \
188 (t==T_FP_ASSIST) ? 0xe00 : \
189 (t==T_PERF_MON) ? 0xf00 : \
190 (t==T_VMX) ? 0xf20 : \
191 (t==T_INVALID_EXCP0) ? 0x1000 : \
192 (t==T_INVALID_EXCP1) ? 0x1100 : \
193 (t==T_INVALID_EXCP2) ? 0x1200 : \
194 (t==T_INSTRUCTION_BKPT) ? 0x1300 : \
195 (t==T_SYSTEM_MANAGEMENT) ? 0x1400 : \
196 (t==T_SOFT_PATCH) ? 0x1500 : \
197 (t==T_ALTIVEC_ASSIST) ? 0x1600 : \
198 (t==T_THERMAL) ? 0x1700 : \
199 (t==T_ARCHDEP0) ? 0x1800 : \
200 (t==T_INSTRUMENTATION) ? 0x2000 : \
201 0x0)
202
2d21ac55
A
203static kern_return_t
204chudxnu_private_trap_callback(int trapno, struct savearea *ssp,
205 __unused unsigned int dsisr,
206 __unused addr64_t dar)
55e303ae
A
207{
208 boolean_t oldlevel = ml_set_interrupts_enabled(FALSE);
55e303ae
A
209 kern_return_t retval = KERN_FAILURE;
210 uint32_t trapentry = TRAP_ENTRY_POINT(trapno);
0c530ab8 211 chudxnu_trap_callback_func_t fn = trap_callback_fn;
55e303ae 212
55e303ae 213 if(trapentry!=0x0) {
0c530ab8 214 if(fn) {
55e303ae
A
215 struct ppc_thread_state64 state;
216 mach_msg_type_number_t count = PPC_THREAD_STATE64_COUNT;
217 chudxnu_copy_savearea_to_threadstate(PPC_THREAD_STATE64, (thread_state_t)&state, &count, ssp);
0c530ab8 218 retval = (fn)(trapentry, PPC_THREAD_STATE64, (thread_state_t)&state, count);
55e303ae
A
219 }
220 }
221
222 ml_set_interrupts_enabled(oldlevel);
223
224 return retval;
225}
226
227__private_extern__
228kern_return_t chudxnu_trap_callback_enter(chudxnu_trap_callback_func_t func)
229{
230 trap_callback_fn = func;
231 perfTrapHook = chudxnu_private_trap_callback;
232 __asm__ volatile("eieio"); /* force order */
233 __asm__ volatile("sync"); /* force to memory */
234 return KERN_SUCCESS;
235}
236
237__private_extern__
238kern_return_t chudxnu_trap_callback_cancel(void)
239{
240 trap_callback_fn = NULL;
55e303ae 241 perfTrapHook = NULL;
55e303ae
A
242 __asm__ volatile("eieio"); /* force order */
243 __asm__ volatile("sync"); /* force to memory */
244 return KERN_SUCCESS;
245}
246
91447636
A
247#pragma mark **** ast ****
248static chudxnu_perfmon_ast_callback_func_t perfmon_ast_callback_fn = NULL;
249
2d21ac55
A
250static kern_return_t
251chudxnu_private_chud_ast_callback(__unused int trapno,
252 __unused struct savearea *ssp,
253 __unused unsigned int dsisr,
254 __unused addr64_t dar)
91447636
A
255{
256 boolean_t oldlevel = ml_set_interrupts_enabled(FALSE);
257 ast_t *myast = ast_pending();
258 kern_return_t retval = KERN_FAILURE;
0c530ab8 259 chudxnu_perfmon_ast_callback_func_t fn = perfmon_ast_callback_fn;
91447636 260
0c530ab8
A
261 if(*myast & AST_CHUD_URGENT) {
262 *myast &= ~(AST_CHUD_URGENT | AST_CHUD);
91447636
A
263 if((*myast & AST_PREEMPTION) != AST_PREEMPTION) *myast &= ~(AST_URGENT);
264 retval = KERN_SUCCESS;
0c530ab8
A
265 } else if(*myast & AST_CHUD) {
266 *myast &= ~(AST_CHUD);
91447636
A
267 retval = KERN_SUCCESS;
268 }
269
0c530ab8 270 if(fn) {
91447636
A
271 struct ppc_thread_state64 state;
272 mach_msg_type_number_t count;
273 count = PPC_THREAD_STATE64_COUNT;
274
275 if(chudxnu_thread_get_state(current_thread(), PPC_THREAD_STATE64, (thread_state_t)&state, &count, FALSE)==KERN_SUCCESS) {
0c530ab8 276 (fn)(PPC_THREAD_STATE64, (thread_state_t)&state, count);
91447636
A
277 }
278 }
279
280#if 0
281 // ASTs from ihandler go through thandler and are made to look like traps
0c530ab8
A
282 // always handle AST_CHUD_URGENT if there's a callback
283 // only handle AST_CHUD if it's the only AST pending
284 if(perfmon_ast_callback_fn && ((*myast & AST_CHUD_URGENT) || ((*myast & AST_CHUD) && !(*myast & AST_URGENT)))) {
91447636
A
285 struct ppc_thread_state64 state;
286 mach_msg_type_number_t count = PPC_THREAD_STATE64_COUNT;
287 chudxnu_copy_savearea_to_threadstate(PPC_THREAD_STATE64, (thread_state_t)&state, &count, ssp);
0c530ab8
A
288 if(*myast & AST_CHUD_URGENT) {
289 *myast &= ~(AST_CHUD_URGENT | AST_CHUD);
91447636
A
290 if((*myast & AST_PREEMPTION) != AST_PREEMPTION) *myast &= ~(AST_URGENT);
291 retval = KERN_SUCCESS;
0c530ab8
A
292 } else if(*myast & AST_CHUD) {
293 *myast &= ~(AST_CHUD);
91447636
A
294 retval = KERN_SUCCESS;
295 }
296 (perfmon_ast_callback_fn)(PPC_THREAD_STATE64, (thread_state_t)&state, count);
297 }
298#endif
299
300 ml_set_interrupts_enabled(oldlevel);
301 return retval;
302}
303
55e303ae
A
304__private_extern__
305kern_return_t chudxnu_perfmon_ast_callback_enter(chudxnu_perfmon_ast_callback_func_t func)
306{
307 perfmon_ast_callback_fn = func;
91447636 308 perfASTHook = chudxnu_private_chud_ast_callback;
55e303ae
A
309 __asm__ volatile("eieio"); /* force order */
310 __asm__ volatile("sync"); /* force to memory */
311 return KERN_SUCCESS;
312}
313
314__private_extern__
315kern_return_t chudxnu_perfmon_ast_callback_cancel(void)
316{
317 perfmon_ast_callback_fn = NULL;
91447636 318 perfASTHook = NULL;
55e303ae
A
319 __asm__ volatile("eieio"); /* force order */
320 __asm__ volatile("sync"); /* force to memory */
321 return KERN_SUCCESS;
322}
323
324__private_extern__
91447636 325kern_return_t chudxnu_perfmon_ast_send_urgent(boolean_t urgent)
55e303ae 326{
91447636
A
327 boolean_t oldlevel = ml_set_interrupts_enabled(FALSE);
328 ast_t *myast = ast_pending();
55e303ae 329
91447636 330 if(urgent) {
0c530ab8 331 *myast |= (AST_CHUD_URGENT | AST_URGENT);
91447636 332 } else {
0c530ab8 333 *myast |= (AST_CHUD);
91447636 334 }
55e303ae
A
335
336 ml_set_interrupts_enabled(oldlevel);
337 return KERN_SUCCESS;
338}
339
91447636
A
340__private_extern__
341kern_return_t chudxnu_perfmon_ast_send(void)
342{
343 return chudxnu_perfmon_ast_send_urgent(TRUE);
344}
345
55e303ae 346#pragma mark **** interrupt ****
55e303ae 347static chudxnu_interrupt_callback_func_t interrupt_callback_fn = NULL;
91447636 348//extern perfCallback perfIntHook; /* function hook into interrupt() */
55e303ae 349
2d21ac55
A
350static kern_return_t
351chudxnu_private_interrupt_callback(int trapno, struct savearea *ssp,
352 __unused unsigned int dsisr,
353 __unused addr64_t dar)
55e303ae 354{
0c530ab8
A
355 chudxnu_interrupt_callback_func_t fn = interrupt_callback_fn;
356
357 if(fn) {
55e303ae
A
358 struct ppc_thread_state64 state;
359 mach_msg_type_number_t count = PPC_THREAD_STATE64_COUNT;
360 chudxnu_copy_savearea_to_threadstate(PPC_THREAD_STATE64, (thread_state_t)&state, &count, ssp);
0c530ab8 361 return (fn)(TRAP_ENTRY_POINT(trapno), PPC_THREAD_STATE64, (thread_state_t)&state, count);
55e303ae
A
362 } else {
363 return KERN_FAILURE;
364 }
365}
366
367__private_extern__
368kern_return_t chudxnu_interrupt_callback_enter(chudxnu_interrupt_callback_func_t func)
369{
370 interrupt_callback_fn = func;
371 perfIntHook = chudxnu_private_interrupt_callback;
372 __asm__ volatile("eieio"); /* force order */
373 __asm__ volatile("sync"); /* force to memory */
374 return KERN_SUCCESS;
375}
376
377__private_extern__
378kern_return_t chudxnu_interrupt_callback_cancel(void)
379{
380 interrupt_callback_fn = NULL;
381 perfIntHook = NULL;
382 __asm__ volatile("eieio"); /* force order */
383 __asm__ volatile("sync"); /* force to memory */
384 return KERN_SUCCESS;
385}
386
387#pragma mark **** cpu signal ****
55e303ae 388static chudxnu_cpusig_callback_func_t cpusig_callback_fn = NULL;
91447636 389extern perfCallback perfCpuSigHook; /* function hook into cpu_signal_handler() */
55e303ae 390
2d21ac55
A
391static kern_return_t
392chudxnu_private_cpu_signal_handler(int request, struct savearea *ssp,
393 __unused unsigned int arg0,
394 __unused addr64_t arg1)
55e303ae 395{
0c530ab8
A
396 chudxnu_cpusig_callback_func_t fn = cpusig_callback_fn;
397
398 if(fn) {
55e303ae
A
399 struct ppc_thread_state64 state;
400 mach_msg_type_number_t count = PPC_THREAD_STATE64_COUNT;
401 chudxnu_copy_savearea_to_threadstate(PPC_THREAD_STATE64, (thread_state_t)&state, &count, ssp);
0c530ab8 402 (fn)(request, PPC_THREAD_STATE64, (thread_state_t)&state, count);
55e303ae
A
403 }
404 return KERN_SUCCESS; // ignored
405}
406
407__private_extern__
408kern_return_t chudxnu_cpusig_callback_enter(chudxnu_cpusig_callback_func_t func)
409{
410 cpusig_callback_fn = func;
411 perfCpuSigHook = chudxnu_private_cpu_signal_handler;
412 __asm__ volatile("eieio"); /* force order */
413 __asm__ volatile("sync"); /* force to memory */
414 return KERN_SUCCESS;
415}
416
417__private_extern__
418kern_return_t chudxnu_cpusig_callback_cancel(void)
419{
420 cpusig_callback_fn = NULL;
421 perfCpuSigHook = NULL;
422 __asm__ volatile("eieio"); /* force order */
423 __asm__ volatile("sync"); /* force to memory */
424 return KERN_SUCCESS;
425}
426
427__private_extern__
428kern_return_t chudxnu_cpusig_send(int otherCPU, uint32_t request)
429{
430 int thisCPU;
431 kern_return_t retval = KERN_FAILURE;
432 int retries = 0;
433 boolean_t oldlevel;
434 uint32_t temp[2];
435
436 oldlevel = ml_set_interrupts_enabled(FALSE);
437 thisCPU = cpu_number();
438
439 if(thisCPU!=otherCPU) {
440 temp[0] = 0xFFFFFFFF; /* set sync flag */
441 temp[1] = request; /* set request */
442 __asm__ volatile("eieio"); /* force order */
443 __asm__ volatile("sync"); /* force to memory */
444
445 do {
446 retval=cpu_signal(otherCPU, SIGPcpureq, CPRQchud, (uint32_t)&temp);
447 } while(retval!=KERN_SUCCESS && (retries++)<16);
448
449 if(retries>=16) {
450 retval = KERN_FAILURE;
451 } else {
452 retval = hw_cpu_sync(temp, LockTimeOut); /* wait for the other processor */
453 if(!retval) {
454 retval = KERN_FAILURE;
455 } else {
456 retval = KERN_SUCCESS;
457 }
458 }
459 } else {
460 retval = KERN_INVALID_ARGUMENT;
461 }
462
463 ml_set_interrupts_enabled(oldlevel);
464 return retval;
465}