]> git.saurik.com Git - apple/xnu.git/blame - osfmk/chud/i386/chud_osfmk_callback_i386.c
xnu-792.22.5.tar.gz
[apple/xnu.git] / osfmk / chud / i386 / chud_osfmk_callback_i386.c
CommitLineData
4452a7af
A
1/*
2 * Copyright (c) 2003-2004 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#include <stdint.h>
30#include <mach/boolean.h>
31#include <mach/mach_types.h>
32
33#include <kern/kern_types.h>
34#include <kern/processor.h>
35#include <kern/timer_call.h>
36#include <kern/thread_call.h>
37#include <kern/kalloc.h>
38#include <kern/thread.h>
39
40#include <machine/machine_routines.h>
41#include <machine/cpu_data.h>
42#include <machine/trap.h>
43
44#include <chud/chud_xnu.h>
45#include <chud/chud_xnu_private.h>
46
47#include <i386/misc_protos.h>
48#include <i386/mp.h>
49#include <i386/machine_cpu.h>
50
51#include <sys/kdebug.h>
52#define CHUD_TIMER_CALLBACK_CANCEL 0
53#define CHUD_TIMER_CALLBACK_ENTER 1
54#define CHUD_TIMER_CALLBACK 2
55#define CHUD_AST_SEND 3
56#define CHUD_AST_CALLBACK 4
57#define CHUD_CPUSIG_SEND 5
58#define CHUD_CPUSIG_CALLBACK 6
59
60__private_extern__
61void chudxnu_cancel_all_callbacks(void)
62{
63 chudxnu_cpusig_callback_cancel();
64 chudxnu_cpu_timer_callback_cancel_all();
65 chudxnu_interrupt_callback_cancel();
66 chudxnu_perfmon_ast_callback_cancel();
67 chudxnu_kdebug_callback_cancel();
68 chudxnu_thread_timer_callback_cancel();
69 chudxnu_trap_callback_cancel();
70#if XXX
71 chudxnu_syscall_callback_cancel();
72#endif
73}
74
75static chudcpu_data_t chudcpu_boot_cpu;
76void *
77chudxnu_cpu_alloc(boolean_t boot_processor)
78{
79 chudcpu_data_t *chud_proc_info;
80
81
82 if (boot_processor) {
83 chud_proc_info = &chudcpu_boot_cpu;
84 } else {
85 chud_proc_info = (chudcpu_data_t *)
86 kalloc(sizeof(chudcpu_data_t));
87 if (chud_proc_info == (chudcpu_data_t *)NULL) {
88 return (void *)NULL;
89 }
90 }
91 bzero((char *)chud_proc_info, sizeof(chudcpu_data_t));
92 chud_proc_info->t_deadline = 0xFFFFFFFFFFFFFFFFULL;
93 mpqueue_init(&chud_proc_info->cpu_request_queue);
94
95
96 return (void *)chud_proc_info;
97}
98
99void
100chudxnu_cpu_free(void *cp)
101{
102 if (cp == NULL || cp == (void *)&chudcpu_boot_cpu) {
103 return;
104 } else {
105 kfree(cp,sizeof(chudcpu_data_t));
106 }
107}
108
109static void
110chudxnu_private_cpu_timer_callback(
111 timer_call_param_t param0,
112 timer_call_param_t param1)
113{
114#pragma unused (param0)
115#pragma unused (param1)
116 chudcpu_data_t *chud_proc_info;
117 boolean_t oldlevel;
118 x86_thread_state_t state;
119 mach_msg_type_number_t count;
120 chudxnu_cpu_timer_callback_func_t fn;
121
122 oldlevel = ml_set_interrupts_enabled(FALSE);
123 chud_proc_info = (chudcpu_data_t *)(current_cpu_datap()->cpu_chud);
124
125 count = x86_THREAD_STATE_COUNT;
126 if (chudxnu_thread_get_state(current_thread(),
127 x86_THREAD_STATE,
128 (thread_state_t)&state,
129 &count,
130 FALSE) == KERN_SUCCESS) {
131 fn = chud_proc_info->cpu_timer_callback_fn;
132 if (fn) {
133 KERNEL_DEBUG_CONSTANT(
134 MACHDBG_CODE(DBG_MACH_CHUD,
135 CHUD_TIMER_CALLBACK) | DBG_FUNC_NONE,
136 (uint32_t)fn, 0,0,0,0);
137 //state.eip, state.cs, 0, 0);
138 (fn)(
139 x86_THREAD_STATE,
140 (thread_state_t)&state,
141 count);
142 }
143 }
144
145 ml_set_interrupts_enabled(oldlevel);
146}
147
148__private_extern__ kern_return_t
149chudxnu_cpu_timer_callback_enter(
150 chudxnu_cpu_timer_callback_func_t func,
151 uint32_t time,
152 uint32_t units)
153{
154 chudcpu_data_t *chud_proc_info;
155 boolean_t oldlevel;
156
157 oldlevel = ml_set_interrupts_enabled(FALSE);
158 chud_proc_info = (chudcpu_data_t *)(current_cpu_datap()->cpu_chud);
159
160 // cancel any existing callback for this cpu
161 timer_call_cancel(&(chud_proc_info->cpu_timer_call));
162
163 chud_proc_info->cpu_timer_callback_fn = func;
164
165 clock_interval_to_deadline(time, units, &(chud_proc_info->t_deadline));
166 timer_call_setup(&(chud_proc_info->cpu_timer_call),
167 chudxnu_private_cpu_timer_callback, NULL);
168 timer_call_enter(&(chud_proc_info->cpu_timer_call),
169 chud_proc_info->t_deadline);
170
171 KERNEL_DEBUG_CONSTANT(
172 MACHDBG_CODE(DBG_MACH_CHUD,
173 CHUD_TIMER_CALLBACK_ENTER) | DBG_FUNC_NONE,
174 (uint32_t) func, time, units, 0, 0);
175
176 ml_set_interrupts_enabled(oldlevel);
177 return KERN_SUCCESS;
178}
179
180__private_extern__ kern_return_t
181chudxnu_cpu_timer_callback_cancel(void)
182{
183 chudcpu_data_t *chud_proc_info;
184 boolean_t oldlevel;
185
186 oldlevel = ml_set_interrupts_enabled(FALSE);
187 chud_proc_info = (chudcpu_data_t *)(current_cpu_datap()->cpu_chud);
188
189 timer_call_cancel(&(chud_proc_info->cpu_timer_call));
190
191 KERNEL_DEBUG_CONSTANT(
192 MACHDBG_CODE(DBG_MACH_CHUD,
193 CHUD_TIMER_CALLBACK_CANCEL) | DBG_FUNC_NONE,
194 0, 0, 0, 0, 0);
195
196 // set to max value:
197 chud_proc_info->t_deadline |= ~(chud_proc_info->t_deadline);
198 chud_proc_info->cpu_timer_callback_fn = NULL;
199
200 ml_set_interrupts_enabled(oldlevel);
201 return KERN_SUCCESS;
202}
203
204__private_extern__ kern_return_t
205chudxnu_cpu_timer_callback_cancel_all(void)
206{
207 unsigned int cpu;
208 chudcpu_data_t *chud_proc_info;
209
210 for(cpu=0; cpu < real_ncpus; cpu++) {
211 chud_proc_info = (chudcpu_data_t *) cpu_data_ptr[cpu]->cpu_chud;
212 if (chud_proc_info == NULL)
213 continue;
214 timer_call_cancel(&(chud_proc_info->cpu_timer_call));
215 chud_proc_info->t_deadline |= ~(chud_proc_info->t_deadline);
216 chud_proc_info->cpu_timer_callback_fn = NULL;
217 }
218 return KERN_SUCCESS;
219}
220
221#pragma mark **** trap ****
222static chudxnu_trap_callback_func_t trap_callback_fn = NULL;
223
224static kern_return_t
225chudxnu_private_trap_callback(
226 int trapno,
227 void *regs,
228 int unused1,
229 int unused2)
230{
231#pragma unused (regs)
232#pragma unused (unused1)
233#pragma unused (unused2)
234 kern_return_t retval = KERN_FAILURE;
235 chudxnu_trap_callback_func_t fn = trap_callback_fn;
236
237 if(fn) {
238 boolean_t oldlevel;
239 x86_thread_state_t state; // once we have an 64bit- independent way to determine if a thread is
240 // running kernel code, we'll switch to x86_thread_state_t.
241 mach_msg_type_number_t count;
242
243 oldlevel = ml_set_interrupts_enabled(FALSE);
244
245 count = x86_THREAD_STATE_COUNT;
246 if(chudxnu_thread_get_state(current_thread(),
247 x86_THREAD_STATE,
248 (thread_state_t)&state,
249 &count,
250 FALSE) == KERN_SUCCESS) {
251
252 retval = (fn)(
253 trapno,
254 x86_THREAD_STATE,
255 (thread_state_t)&state,
256 count);
257 }
258 ml_set_interrupts_enabled(oldlevel);
259 }
260
261 return retval;
262}
263
264__private_extern__ kern_return_t
265chudxnu_trap_callback_enter(chudxnu_trap_callback_func_t func)
266{
267 trap_callback_fn = func;
268 perfTrapHook = chudxnu_private_trap_callback;
269 return KERN_SUCCESS;
270}
271
272__private_extern__ kern_return_t
273chudxnu_trap_callback_cancel(void)
274{
275 trap_callback_fn = NULL;
276 perfTrapHook = NULL;
277 return KERN_SUCCESS;
278}
279
280#pragma mark **** ast ****
281static
282chudxnu_perfmon_ast_callback_func_t perfmon_ast_callback_fn = NULL;
283
284static kern_return_t
285chudxnu_private_chud_ast_callback(
286 int trapno,
287 void *regs,
288 int unused1,
289 int unused2)
290{
291#pragma unused (trapno)
292#pragma unused (regs)
293#pragma unused (unused1)
294#pragma unused (unused2)
295 boolean_t oldlevel = ml_set_interrupts_enabled(FALSE);
296 ast_t *myast = ast_pending();
297 kern_return_t retval = KERN_FAILURE;
298 chudxnu_perfmon_ast_callback_func_t fn = perfmon_ast_callback_fn;
299
300 if (*myast & AST_CHUD_URGENT) {
301 *myast &= ~(AST_CHUD_URGENT | AST_CHUD);
302 if ((*myast & AST_PREEMPTION) != AST_PREEMPTION)
303 *myast &= ~(AST_URGENT);
304 retval = KERN_SUCCESS;
305 } else if (*myast & AST_CHUD) {
306 *myast &= ~(AST_CHUD);
307 retval = KERN_SUCCESS;
308 }
309
310 if (fn) {
311 x86_thread_state_t state;
312 mach_msg_type_number_t count;
313 count = x86_THREAD_STATE_COUNT;
314
315 if (chudxnu_thread_get_state(
316 current_thread(),
317 x86_THREAD_STATE,
318 (thread_state_t) &state, &count,
319 TRUE) == KERN_SUCCESS) {
320
321 KERNEL_DEBUG_CONSTANT(
322 MACHDBG_CODE(DBG_MACH_CHUD,
323 CHUD_AST_CALLBACK) | DBG_FUNC_NONE,
324 (uint32_t) fn, 0, 0, 0, 0);
325
326 (fn)(
327 x86_THREAD_STATE,
328 (thread_state_t) &state,
329 count);
330 }
331 }
332
333 ml_set_interrupts_enabled(oldlevel);
334 return retval;
335}
336
337__private_extern__ kern_return_t
338chudxnu_perfmon_ast_callback_enter(chudxnu_perfmon_ast_callback_func_t func)
339{
340 perfmon_ast_callback_fn = func;
341 perfASTHook = chudxnu_private_chud_ast_callback;
342 return KERN_SUCCESS;
343}
344
345__private_extern__ kern_return_t
346chudxnu_perfmon_ast_callback_cancel(void)
347{
348 perfmon_ast_callback_fn = NULL;
349 perfASTHook = NULL;
350 return KERN_SUCCESS;
351}
352
353__private_extern__ kern_return_t
354chudxnu_perfmon_ast_send_urgent(boolean_t urgent)
355{
356 boolean_t oldlevel = ml_set_interrupts_enabled(FALSE);
357 ast_t *myast = ast_pending();
358
359 if(urgent) {
360 *myast |= (AST_CHUD_URGENT | AST_URGENT);
361 } else {
362 *myast |= (AST_CHUD);
363 }
364
365 KERNEL_DEBUG_CONSTANT(
366 MACHDBG_CODE(DBG_MACH_CHUD, CHUD_AST_SEND) | DBG_FUNC_NONE,
367 urgent, 0, 0, 0, 0);
368
369 ml_set_interrupts_enabled(oldlevel);
370 return KERN_SUCCESS;
371}
372
373__private_extern__ kern_return_t
374chudxnu_perfmon_ast_send(void)
375{
376 return chudxnu_perfmon_ast_send_urgent(TRUE);
377}
378
379#pragma mark **** interrupt ****
380static chudxnu_interrupt_callback_func_t interrupt_callback_fn = NULL;
381
382static void
383chudxnu_private_interrupt_callback(void *foo)
384{
385#pragma unused (foo)
386 chudxnu_interrupt_callback_func_t fn = interrupt_callback_fn;
387
388 if(fn) {
389 boolean_t oldlevel;
390 x86_thread_state_t state;
391 mach_msg_type_number_t count;
392
393 oldlevel = ml_set_interrupts_enabled(FALSE);
394
395 count = x86_THREAD_STATE_COUNT;
396 if(chudxnu_thread_get_state(current_thread(),
397 x86_THREAD_STATE,
398 (thread_state_t)&state,
399 &count,
400 FALSE) == KERN_SUCCESS) {
401 (fn)(
402 X86_INTERRUPT_PERFMON,
403 x86_THREAD_STATE,
404 (thread_state_t)&state,
405 count);
406 }
407 ml_set_interrupts_enabled(oldlevel);
408 }
409}
410
411__private_extern__ kern_return_t
412chudxnu_interrupt_callback_enter(chudxnu_interrupt_callback_func_t func)
413{
414 interrupt_callback_fn = func;
415 lapic_set_pmi_func((i386_intr_func_t)chudxnu_private_interrupt_callback);
416 return KERN_SUCCESS;
417}
418
419__private_extern__ kern_return_t
420chudxnu_interrupt_callback_cancel(void)
421{
422 interrupt_callback_fn = NULL;
423 lapic_set_pmi_func(NULL);
424 return KERN_SUCCESS;
425}
426
427#pragma mark **** cpu signal ****
428static chudxnu_cpusig_callback_func_t cpusig_callback_fn = NULL;
429
430static kern_return_t
431chudxnu_private_cpu_signal_handler(int request)
432{
433 chudxnu_cpusig_callback_func_t fn = cpusig_callback_fn;
434
435 if (fn) {
436 x86_thread_state_t state;
437 mach_msg_type_number_t count = x86_THREAD_STATE_COUNT;
438
439 if (chudxnu_thread_get_state(current_thread(),
440 x86_THREAD_STATE,
441 (thread_state_t) &state, &count,
442 FALSE) == KERN_SUCCESS) {
443 KERNEL_DEBUG_CONSTANT(
444 MACHDBG_CODE(DBG_MACH_CHUD,
445 CHUD_CPUSIG_CALLBACK) | DBG_FUNC_NONE,
446 (uint32_t)fn, request, 0, 0, 0);
447 return (fn)(
448 request, x86_THREAD_STATE,
449 (thread_state_t) &state, count);
450 } else {
451 return KERN_FAILURE;
452 }
453 }
454 return KERN_SUCCESS; //ignored
455}
456/*
457 * chudxnu_cpu_signal_handler() is called from the IPI handler
458 * when a CHUD signal arrives from another processor.
459 */
460__private_extern__ void
461chudxnu_cpu_signal_handler(void)
462{
463 chudcpu_signal_request_t *reqp;
464 chudcpu_data_t *chudinfop;
465
466 chudinfop = (chudcpu_data_t *) current_cpu_datap()->cpu_chud;
467
468 mpdequeue_head(&(chudinfop->cpu_request_queue),
469 (queue_entry_t *) &reqp);
470 while (reqp != NULL) {
471 chudxnu_private_cpu_signal_handler(reqp->req_code);
472 reqp->req_sync = 0;
473 mpdequeue_head(&(chudinfop->cpu_request_queue),
474 (queue_entry_t *) &reqp);
475 }
476}
477
478__private_extern__ kern_return_t
479chudxnu_cpusig_callback_enter(chudxnu_cpusig_callback_func_t func)
480{
481 cpusig_callback_fn = func;
482 return KERN_SUCCESS;
483}
484
485__private_extern__ kern_return_t
486chudxnu_cpusig_callback_cancel(void)
487{
488 cpusig_callback_fn = NULL;
489 return KERN_SUCCESS;
490}
491
492__private_extern__ kern_return_t
493chudxnu_cpusig_send(int otherCPU, uint32_t request_code)
494{
495 int thisCPU;
496 kern_return_t retval = KERN_FAILURE;
497 chudcpu_signal_request_t request;
498 uint64_t deadline;
499 chudcpu_data_t *target_chudp;
500 boolean_t old_level;
501
502 disable_preemption();
503 // force interrupts on for a cross CPU signal.
504 old_level = chudxnu_set_interrupts_enabled(TRUE);
505 thisCPU = cpu_number();
506
507 if ((unsigned) otherCPU < real_ncpus &&
508 thisCPU != otherCPU &&
509 cpu_data_ptr[otherCPU]->cpu_running) {
510
511 target_chudp = (chudcpu_data_t *)
512 cpu_data_ptr[otherCPU]->cpu_chud;
513
514 /* Fill out request */
515 request.req_sync = 0xFFFFFFFF; /* set sync flag */
516 //request.req_type = CPRQchud; /* set request type */
517 request.req_code = request_code; /* set request */
518
519 KERNEL_DEBUG_CONSTANT(
520 MACHDBG_CODE(DBG_MACH_CHUD,
521 CHUD_CPUSIG_SEND) | DBG_FUNC_NONE,
522 otherCPU, request_code, 0, 0, 0);
523
524 /*
525 * Insert the new request in the target cpu's request queue
526 * and signal target cpu.
527 */
528 mpenqueue_tail(&target_chudp->cpu_request_queue,
529 &request.req_entry);
530 i386_signal_cpu(otherCPU, MP_CHUD, ASYNC);
531
532 /* Wait for response or timeout */
533 deadline = mach_absolute_time() + LockTimeOut;
534 while (request.req_sync != 0) {
535 if (mach_absolute_time() > deadline) {
536 panic("chudxnu_cpusig_send(%d,%d) timed out\n",
537 otherCPU, request_code);
538 }
539 cpu_pause();
540 }
541 retval = KERN_SUCCESS;
542 } else {
543 retval = KERN_INVALID_ARGUMENT;
544 }
545
546 chudxnu_set_interrupts_enabled(old_level);
547 enable_preemption();
548 return retval;
549}
550
551#ifdef XXX
552#pragma mark **** CHUD syscall (PPC) ****
553
554typedef int (*PPCcallEnt)(struct savearea *save);
555extern PPCcallEnt PPCcalls[];
556
557static chudxnu_syscall_callback_func_t syscall_callback_fn = NULL;
558
559static int
560chudxnu_private_syscall_callback(struct savearea *ssp)
561{
562 if(ssp) {
563 if(syscall_callback_fn) {
564 struct ppc_thread_state64 state;
565 kern_return_t retval;
566 mach_msg_type_number_t count = PPC_THREAD_STATE64_COUNT;
567 chudxnu_copy_savearea_to_threadstate(PPC_THREAD_STATE64, (thread_state_t)&state, &count, ssp);
568 ssp->save_r3 = (syscall_callback_fn)(PPC_THREAD_STATE64, (thread_state_t)&state, count);
569 } else {
570 ssp->save_r3 = KERN_FAILURE;
571 }
572 }
573
574 return 1; // check for ASTs (always)
575}
576
577__private_extern__ kern_return_t
578chudxnu_syscall_callback_enter(chudxnu_syscall_callback_func_t func)
579{
580 syscall_callback_fn = func;
581 PPCcalls[9] = chudxnu_private_syscall_callback;
582 __asm__ volatile("eieio"); /* force order */
583 __asm__ volatile("sync"); /* force to memory */
584 return KERN_SUCCESS;
585}
586
587__private_extern__ kern_return_t
588chudxnu_syscall_callback_cancel(void)
589{
590 syscall_callback_fn = NULL;
591 PPCcalls[9] = NULL;
592 __asm__ volatile("eieio"); /* force order */
593 __asm__ volatile("sync"); /* force to memory */
594 return KERN_SUCCESS;
595}
596#endif