]> git.saurik.com Git - apple/xnu.git/blob - osfmk/ppc/trap.c
xnu-792.18.15.tar.gz
[apple/xnu.git] / osfmk / ppc / trap.c
1 /*
2 * Copyright (c) 2000-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 * @OSF_COPYRIGHT@
30 */
31
32 #include <mach_kdb.h>
33 #include <mach_kdp.h>
34 #include <debug.h>
35
36 #include <mach/mach_types.h>
37 #include <mach/mach_traps.h>
38 #include <mach/thread_status.h>
39
40 #include <kern/processor.h>
41 #include <kern/thread.h>
42 #include <kern/exception.h>
43 #include <kern/syscall_sw.h>
44 #include <kern/cpu_data.h>
45 #include <kern/debug.h>
46
47 #include <vm/vm_fault.h>
48 #include <vm/vm_kern.h> /* For kernel_map */
49
50 #include <ppc/misc_protos.h>
51 #include <ppc/trap.h>
52 #include <ppc/exception.h>
53 #include <ppc/proc_reg.h> /* for SR_xxx definitions */
54 #include <ppc/pmap.h>
55 #include <ppc/mem.h>
56 #include <ppc/mappings.h>
57 #include <ppc/Firmware.h>
58 #include <ppc/low_trace.h>
59 #include <ppc/Diagnostics.h>
60 #include <ppc/hw_perfmon.h>
61
62 #include <sys/kdebug.h>
63
64 perfCallback perfTrapHook = 0; /* Pointer to CHUD trap hook routine */
65 perfCallback perfASTHook = 0; /* Pointer to CHUD AST hook routine */
66
67 #if MACH_KDB
68 #include <ddb/db_watch.h>
69 #include <ddb/db_run.h>
70 #include <ddb/db_break.h>
71 #include <ddb/db_trap.h>
72
73 boolean_t let_ddb_vm_fault = FALSE;
74 boolean_t debug_all_traps_with_kdb = FALSE;
75 extern struct db_watchpoint *db_watchpoint_list;
76 extern boolean_t db_watchpoints_inserted;
77 extern boolean_t db_breakpoints_inserted;
78
79
80
81 #endif /* MACH_KDB */
82
83 extern task_t bsd_init_task;
84 extern char init_task_failure_data[];
85 extern int not_in_kdp;
86
87 #define PROT_EXEC (VM_PROT_EXECUTE)
88 #define PROT_RO (VM_PROT_READ)
89 #define PROT_RW (VM_PROT_READ|VM_PROT_WRITE)
90
91
92 /* A useful macro to update the ppc_exception_state in the PCB
93 * before calling doexception
94 */
95 #define UPDATE_PPC_EXCEPTION_STATE { \
96 thread_t _thread = current_thread(); \
97 _thread->machine.pcb->save_dar = (uint64_t)dar; \
98 _thread->machine.pcb->save_dsisr = dsisr; \
99 _thread->machine.pcb->save_exception = trapno / T_VECTOR_SIZE; /* back to powerpc */ \
100 }
101
102 void unresolved_kernel_trap(int trapno,
103 struct savearea *ssp,
104 unsigned int dsisr,
105 addr64_t dar,
106 const char *message);
107
108 static void handleMck(struct savearea *ssp); /* Common machine check handler */
109
110 #ifdef MACH_BSD
111 extern void get_procrustime(time_value_t *);
112 extern void bsd_uprofil(time_value_t *, user_addr_t);
113 #endif /* MACH_BSD */
114
115
116 struct savearea *trap(int trapno,
117 struct savearea *ssp,
118 unsigned int dsisr,
119 addr64_t dar)
120 {
121 int exception;
122 int code;
123 int subcode;
124 vm_map_t map;
125 unsigned int sp;
126 unsigned int space, space2;
127 vm_map_offset_t offset;
128 thread_t thread = current_thread();
129 boolean_t intr;
130 ast_t *myast;
131
132 #ifdef MACH_BSD
133 time_value_t tv;
134 #endif /* MACH_BSD */
135
136 myast = ast_pending();
137 if(perfASTHook) {
138 if(*myast & AST_CHUD_ALL) {
139 perfASTHook(trapno, ssp, dsisr, (unsigned int)dar);
140 }
141 } else {
142 *myast &= ~AST_CHUD_ALL;
143 }
144
145 if(perfTrapHook) { /* Is there a hook? */
146 if(perfTrapHook(trapno, ssp, dsisr, (unsigned int)dar) == KERN_SUCCESS) return ssp; /* If it succeeds, we are done... */
147 }
148
149 #if 0
150 {
151 extern void fctx_text(void);
152 fctx_test();
153 }
154 #endif
155
156 exception = 0; /* Clear exception for now */
157
158 /*
159 * Remember that we are disabled for interruptions when we come in here. Because
160 * of latency concerns, we need to enable interruptions in the interrupted process
161 * was enabled itself as soon as we can.
162 */
163
164 intr = (ssp->save_srr1 & MASK(MSR_EE)) != 0; /* Remember if we were enabled */
165
166 /* Handle kernel traps first */
167
168 if (!USER_MODE(ssp->save_srr1)) {
169 /*
170 * Trap came from kernel
171 */
172 switch (trapno) {
173
174 case T_PREEMPT: /* Handle a preempt trap */
175 ast_taken(AST_PREEMPTION, FALSE);
176 break;
177
178 case T_PERF_MON:
179 perfmon_handle_pmi(ssp);
180 break;
181
182 case T_RESET: /* Reset interruption */
183 if (!Call_Debugger(trapno, ssp))
184 unresolved_kernel_trap(trapno, ssp, dsisr, dar, NULL);
185 break; /* We just ignore these */
186
187 /*
188 * These trap types should never be seen by trap()
189 * in kernel mode, anyway.
190 * Some are interrupts that should be seen by
191 * interrupt() others just don't happen because they
192 * are handled elsewhere. Some could happen but are
193 * considered to be fatal in kernel mode.
194 */
195 case T_DECREMENTER:
196 case T_IN_VAIN: /* Shouldn't ever see this, lowmem_vectors eats it */
197 case T_SYSTEM_MANAGEMENT:
198 case T_ALTIVEC_ASSIST:
199 case T_INTERRUPT:
200 case T_FP_UNAVAILABLE:
201 case T_IO_ERROR:
202 case T_RESERVED:
203 default:
204 unresolved_kernel_trap(trapno, ssp, dsisr, dar, NULL);
205 break;
206
207
208 /*
209 * Here we handle a machine check in the kernel
210 */
211
212 case T_MACHINE_CHECK:
213 handleMck(ssp); /* Common to both user and kernel */
214 break;
215
216
217 case T_ALIGNMENT:
218 /*
219 * If enaNotifyEMb is set, we get here, and
220 * we have actually already emulated the unaligned access.
221 * All that we want to do here is to ignore the interrupt. This is to allow logging or
222 * tracing of unaligned accesses.
223 */
224
225 if(ssp->save_hdr.save_misc3) { /* Was it a handled exception? */
226 unresolved_kernel_trap(trapno, ssp, dsisr, dar, NULL); /* Go panic */
227 break;
228 }
229 KERNEL_DEBUG_CONSTANT(
230 MACHDBG_CODE(DBG_MACH_EXCP_ALNG, 0) | DBG_FUNC_NONE,
231 (int)ssp->save_srr0 - 4, (int)dar, (int)dsisr, (int)ssp->save_lr, 0);
232 break;
233
234 case T_EMULATE:
235 /*
236 * If enaNotifyEMb is set we get here, and
237 * we have actually already emulated the instruction.
238 * All that we want to do here is to ignore the interrupt. This is to allow logging or
239 * tracing of emulated instructions.
240 */
241
242 KERNEL_DEBUG_CONSTANT(
243 MACHDBG_CODE(DBG_MACH_EXCP_EMUL, 0) | DBG_FUNC_NONE,
244 (int)ssp->save_srr0 - 4, (int)((savearea_comm *)ssp)->save_misc2, (int)dsisr, (int)ssp->save_lr, 0);
245 break;
246
247
248
249
250
251 case T_TRACE:
252 case T_RUNMODE_TRACE:
253 case T_INSTRUCTION_BKPT:
254 if (!Call_Debugger(trapno, ssp))
255 unresolved_kernel_trap(trapno, ssp, dsisr, dar, NULL);
256 break;
257
258 case T_PROGRAM:
259 if (ssp->save_srr1 & MASK(SRR1_PRG_TRAP)) {
260 if (!Call_Debugger(trapno, ssp))
261 unresolved_kernel_trap(trapno, ssp, dsisr, dar, NULL);
262 } else {
263 unresolved_kernel_trap(trapno, ssp,
264 dsisr, dar, NULL);
265 }
266 break;
267
268 case T_DATA_ACCESS:
269 #if MACH_KDB
270 mp_disable_preemption();
271 if (debug_mode
272 && getPerProc()->debugger_active
273 && !let_ddb_vm_fault) {
274 /*
275 * Force kdb to handle this one.
276 */
277 kdb_trap(trapno, ssp);
278 }
279 mp_enable_preemption();
280 #endif /* MACH_KDB */
281 /* can we take this during normal panic dump operation? */
282 if (debug_mode
283 && getPerProc()->debugger_active
284 && !not_in_kdp) {
285 /*
286 * Access fault while in kernel core dump.
287 */
288 kdp_dump_trap(trapno, ssp);
289 }
290
291
292 if(ssp->save_dsisr & dsiInvMode) { /* Did someone try to reserve cache inhibited? */
293 panic("trap: disallowed access to cache inhibited memory - %016llX\n", dar);
294 }
295
296 if(intr) ml_set_interrupts_enabled(TRUE); /* Enable if we were */
297
298 if(((dar >> 28) < 0xE) | ((dar >> 28) > 0xF)) { /* User memory window access? */
299
300 offset = (vm_map_offset_t)dar; /* Set the failing address */
301 map = kernel_map; /* No, this is a normal kernel access */
302
303 /*
304 * Note: Some ROM device drivers will access page 0 when they start. The IOKit will
305 * set a flag to tell us to ignore any access fault on page 0. After the driver is
306 * opened, it will clear the flag.
307 */
308 if((0 == (offset & -PAGE_SIZE)) && /* Check for access of page 0 and */
309 ((thread->machine.specFlags) & ignoreZeroFault)) { /* special case of ignoring page zero faults */
310 ssp->save_srr0 += 4; /* Point to next instruction */
311 break;
312 }
313
314 code = vm_fault(map, vm_map_trunc_page(offset),
315 dsisr & MASK(DSISR_WRITE) ? PROT_RW : PROT_RO,
316 FALSE, THREAD_UNINT, NULL, vm_map_trunc_page(0));
317
318 if (code != KERN_SUCCESS) {
319 unresolved_kernel_trap(trapno, ssp, dsisr, dar, NULL);
320 } else {
321 ssp->save_hdr.save_flags |= SAVredrive; /* Tell low-level to re-try fault */
322 ssp->save_dsisr = (ssp->save_dsisr &
323 ~((MASK(DSISR_NOEX) | MASK(DSISR_PROT)))) | MASK(DSISR_HASH); /* Make sure this is marked as a miss */
324 }
325 break;
326 }
327
328 /* If we get here, the fault was due to a user memory window access */
329
330 map = thread->map;
331
332 offset = (vm_map_offset_t)(thread->machine.umwRelo + dar); /* Compute the user space address */
333
334 code = vm_fault(map, vm_map_trunc_page(offset),
335 dsisr & MASK(DSISR_WRITE) ? PROT_RW : PROT_RO,
336 FALSE, THREAD_UNINT, NULL, vm_map_trunc_page(0));
337
338 /* If we failed, there should be a recovery
339 * spot to rfi to.
340 */
341 if (code != KERN_SUCCESS) {
342 if (thread->recover) {
343 ssp->save_srr0 = thread->recover;
344 thread->recover = (vm_offset_t)NULL;
345 } else {
346 unresolved_kernel_trap(trapno, ssp, dsisr, dar, "copyin/out has no recovery point");
347 }
348 }
349 else {
350 ssp->save_hdr.save_flags |= SAVredrive; /* Tell low-level to re-try fault */
351 ssp->save_dsisr = (ssp->save_dsisr &
352 ~((MASK(DSISR_NOEX) | MASK(DSISR_PROT)))) | MASK(DSISR_HASH); /* Make sure this is marked as a miss */
353 }
354
355 break;
356
357 case T_INSTRUCTION_ACCESS:
358
359 #if MACH_KDB
360 if (debug_mode
361 && getPerProc()->debugger_active
362 && !let_ddb_vm_fault) {
363 /*
364 * Force kdb to handle this one.
365 */
366 kdb_trap(trapno, ssp);
367 }
368 #endif /* MACH_KDB */
369
370 /* Same as for data access, except fault type
371 * is PROT_EXEC and addr comes from srr0
372 */
373
374 if(intr) ml_set_interrupts_enabled(TRUE); /* Enable if we were */
375
376 map = kernel_map;
377
378 code = vm_fault(map, vm_map_trunc_page(ssp->save_srr0),
379 (PROT_EXEC | PROT_RO), FALSE, THREAD_UNINT, NULL, vm_map_trunc_page(0));
380
381 if (code != KERN_SUCCESS) {
382 unresolved_kernel_trap(trapno, ssp, dsisr, dar, NULL);
383 } else {
384 ssp->save_hdr.save_flags |= SAVredrive; /* Tell low-level to re-try fault */
385 ssp->save_srr1 = (ssp->save_srr1 &
386 ~((unsigned long long)(MASK(DSISR_NOEX) | MASK(DSISR_PROT)))) | MASK(DSISR_HASH); /* Make sure this is marked as a miss */
387 }
388 break;
389
390 /* Usually shandler handles all the system calls, but the
391 * atomic thread switcher may throwup (via thandler) and
392 * have to pass it up to the exception handler.
393 */
394
395 case T_SYSTEM_CALL:
396 unresolved_kernel_trap(trapno, ssp, dsisr, dar, NULL);
397 break;
398
399 case T_AST:
400 unresolved_kernel_trap(trapno, ssp, dsisr, dar, NULL);
401 break;
402 }
403 } else {
404
405 /*
406 * Processing for user state traps with interrupt enabled
407 * For T_AST, interrupts are enabled in the AST delivery
408 */
409 if (trapno != T_AST)
410 ml_set_interrupts_enabled(TRUE);
411
412 #ifdef MACH_BSD
413 {
414 get_procrustime(&tv);
415 }
416 #endif /* MACH_BSD */
417
418
419 /*
420 * Trap came from user task
421 */
422
423 switch (trapno) {
424
425 case T_PREEMPT:
426 unresolved_kernel_trap(trapno, ssp, dsisr, dar, NULL);
427 break;
428
429 case T_PERF_MON:
430 perfmon_handle_pmi(ssp);
431 break;
432
433 /*
434 * These trap types should never be seen by trap()
435 * Some are interrupts that should be seen by
436 * interrupt() others just don't happen because they
437 * are handled elsewhere.
438 */
439 case T_DECREMENTER:
440 case T_IN_VAIN: /* Shouldn't ever see this, lowmem_vectors eats it */
441 case T_INTERRUPT:
442 case T_FP_UNAVAILABLE:
443 case T_SYSTEM_MANAGEMENT:
444 case T_RESERVED:
445 case T_IO_ERROR:
446
447 default:
448
449 ml_set_interrupts_enabled(FALSE); /* Turn off interruptions */
450
451 panic("Unexpected user state trap(cpu %d): 0x%08X DSISR=0x%08X DAR=0x%016llX PC=0x%016llX, MSR=0x%016llX\n",
452 cpu_number(), trapno, dsisr, dar, ssp->save_srr0, ssp->save_srr1);
453 break;
454
455
456 /*
457 * Here we handle a machine check in user state
458 */
459
460 case T_MACHINE_CHECK:
461 handleMck(ssp); /* Common to both user and kernel */
462 break;
463
464 case T_RESET:
465 ml_set_interrupts_enabled(FALSE); /* Turn off interruptions */
466 if (!Call_Debugger(trapno, ssp))
467 panic("Unexpected Reset exception: srr0 = %016llx, srr1 = %016llx\n",
468 ssp->save_srr0, ssp->save_srr1);
469 break; /* We just ignore these */
470
471 case T_ALIGNMENT:
472 /*
473 * If enaNotifyEMb is set, we get here, and
474 * we have actually already emulated the unaligned access.
475 * All that we want to do here is to ignore the interrupt. This is to allow logging or
476 * tracing of unaligned accesses.
477 */
478
479 KERNEL_DEBUG_CONSTANT(
480 MACHDBG_CODE(DBG_MACH_EXCP_ALNG, 0) | DBG_FUNC_NONE,
481 (int)ssp->save_srr0 - 4, (int)dar, (int)dsisr, (int)ssp->save_lr, 0);
482
483 if(ssp->save_hdr.save_misc3) { /* Was it a handled exception? */
484 exception = EXC_BAD_ACCESS; /* Yes, throw exception */
485 code = EXC_PPC_UNALIGNED;
486 subcode = (unsigned int)dar;
487 }
488 break;
489
490 case T_EMULATE:
491 /*
492 * If enaNotifyEMb is set we get here, and
493 * we have actually already emulated the instruction.
494 * All that we want to do here is to ignore the interrupt. This is to allow logging or
495 * tracing of emulated instructions.
496 */
497
498 KERNEL_DEBUG_CONSTANT(
499 MACHDBG_CODE(DBG_MACH_EXCP_EMUL, 0) | DBG_FUNC_NONE,
500 (int)ssp->save_srr0 - 4, (int)((savearea_comm *)ssp)->save_misc2, (int)dsisr, (int)ssp->save_lr, 0);
501 break;
502
503 case T_TRACE: /* Real PPC chips */
504 if (be_tracing()) {
505 add_pcbuffer();
506 return ssp;
507 }
508 /* fall through */
509
510 case T_INSTRUCTION_BKPT:
511 exception = EXC_BREAKPOINT;
512 code = EXC_PPC_TRACE;
513 subcode = (unsigned int)ssp->save_srr0;
514 break;
515
516 case T_PROGRAM:
517 if (ssp->save_srr1 & MASK(SRR1_PRG_FE)) {
518 fpu_save(thread->machine.curctx);
519 UPDATE_PPC_EXCEPTION_STATE;
520 exception = EXC_ARITHMETIC;
521 code = EXC_ARITHMETIC;
522
523 mp_disable_preemption();
524 subcode = ssp->save_fpscr;
525 mp_enable_preemption();
526 }
527 else if (ssp->save_srr1 & MASK(SRR1_PRG_ILL_INS)) {
528
529 UPDATE_PPC_EXCEPTION_STATE
530 exception = EXC_BAD_INSTRUCTION;
531 code = EXC_PPC_UNIPL_INST;
532 subcode = (unsigned int)ssp->save_srr0;
533 } else if ((unsigned int)ssp->save_srr1 & MASK(SRR1_PRG_PRV_INS)) {
534
535 UPDATE_PPC_EXCEPTION_STATE;
536 exception = EXC_BAD_INSTRUCTION;
537 code = EXC_PPC_PRIVINST;
538 subcode = (unsigned int)ssp->save_srr0;
539 } else if (ssp->save_srr1 & MASK(SRR1_PRG_TRAP)) {
540 unsigned int inst;
541 //char *iaddr;
542
543 //iaddr = CAST_DOWN(char *, ssp->save_srr0); /* Trim from long long and make a char pointer */
544 if (copyin(ssp->save_srr0, (char *) &inst, 4 )) panic("copyin failed\n");
545
546 if(dgWork.dgFlags & enaDiagTrap) { /* Is the diagnostic trap enabled? */
547 if((inst & 0xFFFFFFF0) == 0x0FFFFFF0) { /* Is this a TWI 31,R31,0xFFFx? */
548 if(diagTrap(ssp, inst & 0xF)) { /* Call the trap code */
549 ssp->save_srr0 += 4ULL; /* If we eat the trap, bump pc */
550 exception = 0; /* Clear exception */
551 break; /* All done here */
552 }
553 }
554 }
555
556 UPDATE_PPC_EXCEPTION_STATE;
557
558 if (inst == 0x7FE00008) {
559 exception = EXC_BREAKPOINT;
560 code = EXC_PPC_BREAKPOINT;
561 } else {
562 exception = EXC_SOFTWARE;
563 code = EXC_PPC_TRAP;
564 }
565 subcode = (unsigned int)ssp->save_srr0;
566 }
567 break;
568
569 case T_ALTIVEC_ASSIST:
570 UPDATE_PPC_EXCEPTION_STATE;
571 exception = EXC_ARITHMETIC;
572 code = EXC_PPC_ALTIVECASSIST;
573 subcode = (unsigned int)ssp->save_srr0;
574 break;
575
576 case T_DATA_ACCESS:
577 map = thread->map;
578
579 if(ssp->save_dsisr & dsiInvMode) { /* Did someone try to reserve cache inhibited? */
580 UPDATE_PPC_EXCEPTION_STATE; /* Don't even bother VM with this one */
581 exception = EXC_BAD_ACCESS;
582 subcode = (unsigned int)dar;
583 break;
584 }
585
586 code = vm_fault(map, vm_map_trunc_page(dar),
587 dsisr & MASK(DSISR_WRITE) ? PROT_RW : PROT_RO,
588 FALSE, THREAD_ABORTSAFE, NULL, vm_map_trunc_page(0));
589
590 if ((code != KERN_SUCCESS) && (code != KERN_ABORTED)) {
591 UPDATE_PPC_EXCEPTION_STATE;
592 exception = EXC_BAD_ACCESS;
593 subcode = (unsigned int)dar;
594 } else {
595 ssp->save_hdr.save_flags |= SAVredrive; /* Tell low-level to re-try fault */
596 ssp->save_dsisr = (ssp->save_dsisr &
597 ~((MASK(DSISR_NOEX) | MASK(DSISR_PROT)))) | MASK(DSISR_HASH); /* Make sure this is marked as a miss */
598 }
599 break;
600
601 case T_INSTRUCTION_ACCESS:
602 /* Same as for data access, except fault type
603 * is PROT_EXEC and addr comes from srr0
604 */
605 map = thread->map;
606
607 code = vm_fault(map, vm_map_trunc_page(ssp->save_srr0),
608 (PROT_EXEC | PROT_RO), FALSE, THREAD_ABORTSAFE, NULL, vm_map_trunc_page(0));
609
610 if ((code != KERN_SUCCESS) && (code != KERN_ABORTED)) {
611 UPDATE_PPC_EXCEPTION_STATE;
612 exception = EXC_BAD_ACCESS;
613 subcode = (unsigned int)ssp->save_srr0;
614 } else {
615 ssp->save_hdr.save_flags |= SAVredrive; /* Tell low-level to re-try fault */
616 ssp->save_srr1 = (ssp->save_srr1 &
617 ~((unsigned long long)(MASK(DSISR_NOEX) | MASK(DSISR_PROT)))) | MASK(DSISR_HASH); /* Make sure this is marked as a miss */
618 }
619 break;
620
621 case T_AST:
622 /* AST delivery is done below */
623 break;
624
625 }
626 #ifdef MACH_BSD
627 {
628 bsd_uprofil(&tv, ssp->save_srr0);
629 }
630 #endif /* MACH_BSD */
631 }
632
633 if (exception) {
634 /* if this is the init task, save the exception information */
635 /* this probably is a fatal exception */
636 #if 0
637 if(bsd_init_task == current_task()) {
638 char *buf;
639 int i;
640
641 buf = init_task_failure_data;
642
643
644 buf += sprintf(buf, "Exception Code = 0x%x, Subcode = 0x%x\n", code, subcode);
645 buf += sprintf(buf, "DSISR = 0x%08x, DAR = 0x%016llx\n"
646 , dsisr, dar);
647
648 for (i=0; i<32; i++) {
649 if ((i % 8) == 0) {
650 buf += sprintf(buf, "\n%4d :",i);
651 }
652 buf += sprintf(buf, " %08x",*(&ssp->save_r0+i));
653 }
654
655 buf += sprintf(buf, "\n\n");
656 buf += sprintf(buf, "cr = 0x%08X\t\t",ssp->save_cr);
657 buf += sprintf(buf, "xer = 0x%08X\n",ssp->save_xer);
658 buf += sprintf(buf, "lr = 0x%016llX\t\t",ssp->save_lr);
659 buf += sprintf(buf, "ctr = 0x%016llX\n",ssp->save_ctr);
660 buf += sprintf(buf, "srr0(iar) = 0x%016llX\t\t",ssp->save_srr0);
661 buf += sprintf(buf, "srr1(msr) = 0x%016llX\n",ssp->save_srr1,
662 "\x10\x11""EE\x12PR\x13""FP\x14ME\x15""FE0\x16SE\x18"
663 "FE1\x19""AL\x1a""EP\x1bIT\x1c""DT");
664 buf += sprintf(buf, "\n\n");
665
666 /* generate some stack trace */
667 buf += sprintf(buf, "Application level back trace:\n");
668 if (ssp->save_srr1 & MASK(MSR_PR)) {
669 char *addr = (char*)ssp->save_r1;
670 unsigned int stack_buf[3];
671 for (i = 0; i < 8; i++) {
672 if (addr == (char*)NULL)
673 break;
674 if (!copyin(ssp->save_r1,(char*)stack_buf,
675 3 * sizeof(int))) {
676 buf += sprintf(buf, "0x%08X : 0x%08X\n"
677 ,addr,stack_buf[2]);
678 addr = (char*)stack_buf[0];
679 } else {
680 break;
681 }
682 }
683 }
684 buf[0] = '\0';
685 }
686 #endif
687 doexception(exception, code, subcode);
688 }
689 /* AST delivery
690 * Check to see if we need an AST, if so take care of it here
691 */
692 ml_set_interrupts_enabled(FALSE);
693
694 if (USER_MODE(ssp->save_srr1)) {
695 myast = ast_pending();
696 while (*myast & AST_ALL) {
697 ast_taken(AST_ALL, intr);
698 ml_set_interrupts_enabled(FALSE);
699 myast = ast_pending();
700 }
701 }
702
703 return ssp;
704 }
705
706 /* This routine is called from assembly before each and every system call.
707 * It must preserve r3.
708 */
709
710 extern int syscall_trace(int, struct savearea *);
711
712
713 extern int pmdebug;
714
715 int syscall_trace(int retval, struct savearea *ssp)
716 {
717 int i, argc;
718 int kdarg[3];
719 /* Always prepare to trace mach system calls */
720
721 kdarg[0]=0;
722 kdarg[1]=0;
723 kdarg[2]=0;
724
725 argc = mach_trap_table[-((unsigned int)ssp->save_r0)].mach_trap_arg_count;
726
727 if (argc > 3)
728 argc = 3;
729
730 for (i=0; i < argc; i++)
731 kdarg[i] = (int)*(&ssp->save_r3 + i);
732
733 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC, (-(ssp->save_r0))) | DBG_FUNC_START,
734 kdarg[0], kdarg[1], kdarg[2], 0, 0);
735
736 return retval;
737 }
738
739 /* This routine is called from assembly after each mach system call
740 * It must preserve r3.
741 */
742
743 extern int syscall_trace_end(int, struct savearea *);
744
745 int syscall_trace_end(int retval, struct savearea *ssp)
746 {
747 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC,(-((unsigned int)ssp->save_r0))) | DBG_FUNC_END,
748 retval, 0, 0, 0, 0);
749 return retval;
750 }
751
752 /*
753 * called from syscall if there is an error
754 */
755
756 int syscall_error(
757 int exception,
758 int code,
759 int subcode,
760 struct savearea *ssp)
761 {
762 register thread_t thread;
763
764 thread = current_thread();
765
766 if (thread == 0)
767 panic("syscall error in boot phase");
768
769 if (!USER_MODE(ssp->save_srr1))
770 panic("system call called from kernel");
771
772 doexception(exception, code, subcode);
773
774 return 0;
775 }
776
777 /* Pass up a server syscall/exception */
778 void
779 doexception(
780 int exc,
781 int code,
782 int sub)
783 {
784 exception_data_type_t codes[EXCEPTION_CODE_MAX];
785
786 codes[0] = code;
787 codes[1] = sub;
788 exception_triage(exc, codes, 2);
789 }
790
791 char *trap_type[] = {
792 "Unknown",
793 "0x100 - System reset",
794 "0x200 - Machine check",
795 "0x300 - Data access",
796 "0x400 - Inst access",
797 "0x500 - Ext int",
798 "0x600 - Alignment",
799 "0x700 - Program",
800 "0x800 - Floating point",
801 "0x900 - Decrementer",
802 "0xA00 - n/a",
803 "0xB00 - n/a",
804 "0xC00 - System call",
805 "0xD00 - Trace",
806 "0xE00 - FP assist",
807 "0xF00 - Perf mon",
808 "0xF20 - VMX",
809 "INVALID EXCEPTION",
810 "INVALID EXCEPTION",
811 "INVALID EXCEPTION",
812 "0x1300 - Inst bkpnt",
813 "0x1400 - Sys mgmt",
814 "0x1600 - Altivec Assist",
815 "0x1700 - Thermal",
816 "INVALID EXCEPTION",
817 "INVALID EXCEPTION",
818 "INVALID EXCEPTION",
819 "INVALID EXCEPTION",
820 "INVALID EXCEPTION",
821 "INVALID EXCEPTION",
822 "INVALID EXCEPTION",
823 "INVALID EXCEPTION",
824 "Emulate",
825 "0x2000 - Run Mode/Trace",
826 "Signal Processor",
827 "Preemption",
828 "Context Switch",
829 "Shutdown",
830 "System Failure"
831 };
832 int TRAP_TYPES = sizeof (trap_type) / sizeof (trap_type[0]);
833
834 void unresolved_kernel_trap(int trapno,
835 struct savearea *ssp,
836 unsigned int dsisr,
837 addr64_t dar,
838 const char *message)
839 {
840 char *trap_name;
841 extern void print_backtrace(struct savearea *);
842 extern unsigned int debug_mode, disableDebugOuput;
843 extern unsigned long panic_caller;
844
845 ml_set_interrupts_enabled(FALSE); /* Turn off interruptions */
846 lastTrace = LLTraceSet(0); /* Disable low-level tracing */
847
848 if( logPanicDataToScreen )
849 disableDebugOuput = FALSE;
850
851 debug_mode++;
852 if ((unsigned)trapno <= T_MAX)
853 trap_name = trap_type[trapno / T_VECTOR_SIZE];
854 else
855 trap_name = "???? unrecognized exception";
856 if (message == NULL)
857 message = trap_name;
858
859 kdb_printf("\n\nUnresolved kernel trap(cpu %d): %s DAR=0x%016llX PC=0x%016llX\n",
860 cpu_number(), trap_name, dar, ssp->save_srr0);
861
862 print_backtrace(ssp);
863
864 panic_caller = (0xFFFF0000 | (trapno / T_VECTOR_SIZE) );
865 draw_panic_dialog();
866
867 if( panicDebugging )
868 (void *)Call_Debugger(trapno, ssp);
869 panic(message);
870 }
871
872 const char *corr[2] = {"uncorrected", "corrected "};
873
874 void handleMck(struct savearea *ssp) { /* Common machine check handler */
875
876 int cpu;
877
878 cpu = cpu_number();
879
880 printf("Machine check (%d) - %s - pc = %016llX, msr = %016llX, dsisr = %08X, dar = %016llX\n",
881 cpu, corr[ssp->save_hdr.save_misc3], ssp->save_srr0, ssp->save_srr1, ssp->save_dsisr, ssp->save_dar); /* Tell us about it */
882 printf("Machine check (%d) - AsyncSrc = %016llX, CoreFIR = %016llx\n", cpu, ssp->save_xdat0, ssp->save_xdat1);
883 printf("Machine check (%d) - L2FIR = %016llX, BusFir = %016llx\n", cpu, ssp->save_xdat2, ssp->save_xdat3);
884
885 if(ssp->save_hdr.save_misc3) return; /* Leave the the machine check was recovered */
886
887 panic("Uncorrectable machine check: pc = %016llX, msr = %016llX, dsisr = %08X, dar = %016llX\n"
888 " AsyncSrc = %016llX, CoreFIR = %016llx\n"
889 " L2FIR = %016llX, BusFir = %016llx\n",
890 ssp->save_srr0, ssp->save_srr1, ssp->save_dsisr, ssp->save_dar,
891 ssp->save_xdat0, ssp->save_xdat1, ssp->save_xdat2, ssp->save_xdat3);
892
893 return;
894 }
895
896 void
897 thread_syscall_return(
898 kern_return_t ret)
899 {
900 register thread_t thread = current_thread();
901 register struct savearea *regs = USER_REGS(thread);
902
903 if (kdebug_enable && ((unsigned int)regs->save_r0 & 0x80000000)) {
904 /* Mach trap */
905 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC,(-(regs->save_r0))) | DBG_FUNC_END,
906 ret, 0, 0, 0, 0);
907 }
908 regs->save_r3 = ret;
909
910 thread_exception_return();
911 /*NOTREACHED*/
912 }
913
914
915 #if MACH_KDB
916 void
917 thread_kdb_return(void)
918 {
919 register thread_t thread = current_thread();
920 register struct savearea *regs = USER_REGS(thread);
921
922 Call_Debugger(thread->machine.pcb->save_exception, regs);
923 thread_exception_return();
924 /*NOTREACHED*/
925 }
926 #endif /* MACH_KDB */