]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ppc/trap.c
xnu-792.22.5.tar.gz
[apple/xnu.git] / osfmk / ppc / trap.c
CommitLineData
1c79356b 1/*
91447636 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
8f6c56a5 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
8f6c56a5
A
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
8ad349bb 24 * limitations under the License.
8f6c56a5
A
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
31
32#include <mach_kdb.h>
33#include <mach_kdp.h>
34#include <debug.h>
91447636
A
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>
1c79356b
A
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>
91447636 46
1c79356b
A
47#include <vm/vm_fault.h>
48#include <vm/vm_kern.h> /* For kernel_map */
91447636 49
1c79356b
A
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>
55e303ae 56#include <ppc/mappings.h>
9bccf70c
A
57#include <ppc/Firmware.h>
58#include <ppc/low_trace.h>
55e303ae
A
59#include <ppc/Diagnostics.h>
60#include <ppc/hw_perfmon.h>
1c79356b
A
61
62#include <sys/kdebug.h>
63
91447636
A
64perfCallback perfTrapHook = 0; /* Pointer to CHUD trap hook routine */
65perfCallback perfASTHook = 0; /* Pointer to CHUD AST hook routine */
9bccf70c 66
1c79356b
A
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
73boolean_t let_ddb_vm_fault = FALSE;
74boolean_t debug_all_traps_with_kdb = FALSE;
75extern struct db_watchpoint *db_watchpoint_list;
76extern boolean_t db_watchpoints_inserted;
77extern boolean_t db_breakpoints_inserted;
78
79
80
81#endif /* MACH_KDB */
82
9bccf70c 83extern task_t bsd_init_task;
1c79356b 84extern char init_task_failure_data[];
55e303ae 85extern int not_in_kdp;
1c79356b 86
9bccf70c 87#define PROT_EXEC (VM_PROT_EXECUTE)
1c79356b
A
88#define PROT_RO (VM_PROT_READ)
89#define PROT_RW (VM_PROT_READ|VM_PROT_WRITE)
90
4452a7af 91
1c79356b
A
92/* A useful macro to update the ppc_exception_state in the PCB
93 * before calling doexception
94 */
9bccf70c 95#define UPDATE_PPC_EXCEPTION_STATE { \
91447636
A
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 */ \
1c79356b
A
100}
101
91447636 102void unresolved_kernel_trap(int trapno,
9bccf70c 103 struct savearea *ssp,
1c79356b 104 unsigned int dsisr,
55e303ae 105 addr64_t dar,
91447636 106 const char *message);
1c79356b 107
e5568f75
A
108static void handleMck(struct savearea *ssp); /* Common machine check handler */
109
91447636
A
110#ifdef MACH_BSD
111extern void get_procrustime(time_value_t *);
112extern void bsd_uprofil(time_value_t *, user_addr_t);
113#endif /* MACH_BSD */
114
e5568f75 115
9bccf70c
A
116struct savearea *trap(int trapno,
117 struct savearea *ssp,
1c79356b 118 unsigned int dsisr,
55e303ae 119 addr64_t dar)
1c79356b 120{
9bccf70c 121 int exception;
1c79356b
A
122 int code;
123 int subcode;
124 vm_map_t map;
9bccf70c
A
125 unsigned int sp;
126 unsigned int space, space2;
91447636
A
127 vm_map_offset_t offset;
128 thread_t thread = current_thread();
1c79356b 129 boolean_t intr;
91447636 130 ast_t *myast;
55e303ae 131
1c79356b
A
132#ifdef MACH_BSD
133 time_value_t tv;
134#endif /* MACH_BSD */
135
91447636
A
136 myast = ast_pending();
137 if(perfASTHook) {
4452a7af 138 if(*myast & AST_CHUD_ALL) {
91447636
A
139 perfASTHook(trapno, ssp, dsisr, (unsigned int)dar);
140 }
141 } else {
4452a7af 142 *myast &= ~AST_CHUD_ALL;
91447636
A
143 }
144
9bccf70c 145 if(perfTrapHook) { /* Is there a hook? */
55e303ae 146 if(perfTrapHook(trapno, ssp, dsisr, (unsigned int)dar) == KERN_SUCCESS) return ssp; /* If it succeeds, we are done... */
9bccf70c
A
147 }
148
149#if 0
150 {
151 extern void fctx_text(void);
152 fctx_test();
153 }
154#endif
155
9bccf70c
A
156 exception = 0; /* Clear exception for now */
157
1c79356b
A
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
9bccf70c 164 intr = (ssp->save_srr1 & MASK(MSR_EE)) != 0; /* Remember if we were enabled */
1c79356b
A
165
166 /* Handle kernel traps first */
167
9bccf70c 168 if (!USER_MODE(ssp->save_srr1)) {
1c79356b
A
169 /*
170 * Trap came from kernel
171 */
172 switch (trapno) {
173
174 case T_PREEMPT: /* Handle a preempt trap */
55e303ae 175 ast_taken(AST_PREEMPTION, FALSE);
1c79356b
A
176 break;
177
55e303ae
A
178 case T_PERF_MON:
179 perfmon_handle_pmi(ssp);
180 break;
181
1c79356b 182 case T_RESET: /* Reset interruption */
55e303ae
A
183 if (!Call_Debugger(trapno, ssp))
184 unresolved_kernel_trap(trapno, ssp, dsisr, dar, NULL);
1c79356b
A
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 */
1c79356b
A
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;
55e303ae
A
206
207
e5568f75
A
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
55e303ae
A
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
91447636
A
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 }
55e303ae
A
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
1c79356b
A
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:
9bccf70c 259 if (ssp->save_srr1 & MASK(SRR1_PRG_TRAP)) {
1c79356b
A
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
1c79356b 268 case T_DATA_ACCESS:
1c79356b
A
269#if MACH_KDB
270 mp_disable_preemption();
271 if (debug_mode
91447636 272 && getPerProc()->debugger_active
1c79356b
A
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 */
55e303ae
A
281 /* can we take this during normal panic dump operation? */
282 if (debug_mode
91447636 283 && getPerProc()->debugger_active
55e303ae
A
284 && !not_in_kdp) {
285 /*
286 * Access fault while in kernel core dump.
287 */
288 kdp_dump_trap(trapno, ssp);
289 }
1c79356b 290
de355530 291
55e303ae
A
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 }
de355530 295
55e303ae
A
296 if(intr) ml_set_interrupts_enabled(TRUE); /* Enable if we were */
297
91447636 298 if(((dar >> 28) < 0xE) | ((dar >> 28) > 0xF)) { /* User memory window access? */
55e303ae 299
91447636 300 offset = (vm_map_offset_t)dar; /* Set the failing address */
55e303ae 301 map = kernel_map; /* No, this is a normal kernel access */
1c79356b 302
1c79356b
A
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 */
55e303ae 308 if((0 == (offset & -PAGE_SIZE)) && /* Check for access of page 0 and */
91447636 309 ((thread->machine.specFlags) & ignoreZeroFault)) { /* special case of ignoring page zero faults */
55e303ae 310 ssp->save_srr0 += 4; /* Point to next instruction */
1c79356b
A
311 break;
312 }
313
91447636 314 code = vm_fault(map, vm_map_trunc_page(offset),
1c79356b 315 dsisr & MASK(DSISR_WRITE) ? PROT_RW : PROT_RO,
91447636 316 FALSE, THREAD_UNINT, NULL, vm_map_trunc_page(0));
1c79356b
A
317
318 if (code != KERN_SUCCESS) {
319 unresolved_kernel_trap(trapno, ssp, dsisr, dar, NULL);
320 } else {
9bccf70c 321 ssp->save_hdr.save_flags |= SAVredrive; /* Tell low-level to re-try fault */
55e303ae
A
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 */
1c79356b
A
324 }
325 break;
326 }
327
91447636 328 /* If we get here, the fault was due to a user memory window access */
1c79356b 329
91447636 330 map = thread->map;
55e303ae 331
91447636 332 offset = (vm_map_offset_t)(thread->machine.umwRelo + dar); /* Compute the user space address */
1c79356b 333
91447636 334 code = vm_fault(map, vm_map_trunc_page(offset),
1c79356b 335 dsisr & MASK(DSISR_WRITE) ? PROT_RW : PROT_RO,
91447636 336 FALSE, THREAD_UNINT, NULL, vm_map_trunc_page(0));
1c79356b
A
337
338 /* If we failed, there should be a recovery
339 * spot to rfi to.
340 */
341 if (code != KERN_SUCCESS) {
91447636
A
342 if (thread->recover) {
343 ssp->save_srr0 = thread->recover;
344 thread->recover = (vm_offset_t)NULL;
1c79356b
A
345 } else {
346 unresolved_kernel_trap(trapno, ssp, dsisr, dar, "copyin/out has no recovery point");
347 }
348 }
349 else {
9bccf70c 350 ssp->save_hdr.save_flags |= SAVredrive; /* Tell low-level to re-try fault */
55e303ae
A
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 */
1c79356b
A
353 }
354
355 break;
356
357 case T_INSTRUCTION_ACCESS:
358
359#if MACH_KDB
360 if (debug_mode
91447636 361 && getPerProc()->debugger_active
1c79356b
A
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
91447636 378 code = vm_fault(map, vm_map_trunc_page(ssp->save_srr0),
4452a7af 379 (PROT_EXEC | PROT_RO), FALSE, THREAD_UNINT, NULL, vm_map_trunc_page(0));
1c79356b
A
380
381 if (code != KERN_SUCCESS) {
382 unresolved_kernel_trap(trapno, ssp, dsisr, dar, NULL);
383 } else {
9bccf70c 384 ssp->save_hdr.save_flags |= SAVredrive; /* Tell low-level to re-try fault */
55e303ae
A
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 */
1c79356b
A
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
91447636
A
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);
1c79356b
A
411
412#ifdef MACH_BSD
413 {
1c79356b
A
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
55e303ae
A
429 case T_PERF_MON:
430 perfmon_handle_pmi(ssp);
431 break;
432
1c79356b
A
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 */
1c79356b
A
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
55e303ae 451 panic("Unexpected user state trap(cpu %d): 0x%08X DSISR=0x%08X DAR=0x%016llX PC=0x%016llX, MSR=0x%016llX\n",
9bccf70c 452 cpu_number(), trapno, dsisr, dar, ssp->save_srr0, ssp->save_srr1);
1c79356b
A
453 break;
454
e5568f75
A
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
1c79356b 464 case T_RESET:
55e303ae
A
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);
1c79356b
A
469 break; /* We just ignore these */
470
471 case T_ALIGNMENT:
9bccf70c 472/*
55e303ae
A
473* If enaNotifyEMb is set, we get here, and
474* we have actually already emulated the unaligned access.
d7e50217 475* All that we want to do here is to ignore the interrupt. This is to allow logging or
55e303ae 476* tracing of unaligned accesses.
d7e50217 477*/
de355530 478
55e303ae
A
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);
91447636
A
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 }
55e303ae
A
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);
1c79356b
A
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
55e303ae 510 case T_INSTRUCTION_BKPT:
1c79356b
A
511 exception = EXC_BREAKPOINT;
512 code = EXC_PPC_TRACE;
55e303ae 513 subcode = (unsigned int)ssp->save_srr0;
1c79356b
A
514 break;
515
516 case T_PROGRAM:
9bccf70c 517 if (ssp->save_srr1 & MASK(SRR1_PRG_FE)) {
91447636 518 fpu_save(thread->machine.curctx);
1c79356b
A
519 UPDATE_PPC_EXCEPTION_STATE;
520 exception = EXC_ARITHMETIC;
521 code = EXC_ARITHMETIC;
522
523 mp_disable_preemption();
9bccf70c 524 subcode = ssp->save_fpscr;
1c79356b
A
525 mp_enable_preemption();
526 }
9bccf70c 527 else if (ssp->save_srr1 & MASK(SRR1_PRG_ILL_INS)) {
1c79356b
A
528
529 UPDATE_PPC_EXCEPTION_STATE
530 exception = EXC_BAD_INSTRUCTION;
531 code = EXC_PPC_UNIPL_INST;
55e303ae
A
532 subcode = (unsigned int)ssp->save_srr0;
533 } else if ((unsigned int)ssp->save_srr1 & MASK(SRR1_PRG_PRV_INS)) {
1c79356b
A
534
535 UPDATE_PPC_EXCEPTION_STATE;
536 exception = EXC_BAD_INSTRUCTION;
537 code = EXC_PPC_PRIVINST;
55e303ae 538 subcode = (unsigned int)ssp->save_srr0;
9bccf70c 539 } else if (ssp->save_srr1 & MASK(SRR1_PRG_TRAP)) {
1c79356b 540 unsigned int inst;
91447636 541 //char *iaddr;
55e303ae 542
91447636
A
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");
55e303ae
A
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
1c79356b 556 UPDATE_PPC_EXCEPTION_STATE;
55e303ae 557
1c79356b
A
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 }
55e303ae 565 subcode = (unsigned int)ssp->save_srr0;
1c79356b
A
566 }
567 break;
568
569 case T_ALTIVEC_ASSIST:
570 UPDATE_PPC_EXCEPTION_STATE;
571 exception = EXC_ARITHMETIC;
572 code = EXC_PPC_ALTIVECASSIST;
55e303ae 573 subcode = (unsigned int)ssp->save_srr0;
1c79356b
A
574 break;
575
576 case T_DATA_ACCESS:
91447636 577 map = thread->map;
55e303ae
A
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 }
1c79356b 585
91447636 586 code = vm_fault(map, vm_map_trunc_page(dar),
1c79356b 587 dsisr & MASK(DSISR_WRITE) ? PROT_RW : PROT_RO,
91447636 588 FALSE, THREAD_ABORTSAFE, NULL, vm_map_trunc_page(0));
1c79356b
A
589
590 if ((code != KERN_SUCCESS) && (code != KERN_ABORTED)) {
591 UPDATE_PPC_EXCEPTION_STATE;
592 exception = EXC_BAD_ACCESS;
55e303ae 593 subcode = (unsigned int)dar;
1c79356b 594 } else {
9bccf70c 595 ssp->save_hdr.save_flags |= SAVredrive; /* Tell low-level to re-try fault */
55e303ae
A
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 */
1c79356b
A
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 */
91447636 605 map = thread->map;
1c79356b 606
91447636 607 code = vm_fault(map, vm_map_trunc_page(ssp->save_srr0),
4452a7af 608 (PROT_EXEC | PROT_RO), FALSE, THREAD_ABORTSAFE, NULL, vm_map_trunc_page(0));
1c79356b
A
609
610 if ((code != KERN_SUCCESS) && (code != KERN_ABORTED)) {
611 UPDATE_PPC_EXCEPTION_STATE;
612 exception = EXC_BAD_ACCESS;
55e303ae 613 subcode = (unsigned int)ssp->save_srr0;
1c79356b 614 } else {
9bccf70c 615 ssp->save_hdr.save_flags |= SAVredrive; /* Tell low-level to re-try fault */
55e303ae
A
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 */
1c79356b
A
618 }
619 break;
620
621 case T_AST:
91447636 622 /* AST delivery is done below */
1c79356b
A
623 break;
624
625 }
626#ifdef MACH_BSD
627 {
9bccf70c 628 bsd_uprofil(&tv, ssp->save_srr0);
1c79356b
A
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 */
55e303ae 636#if 0
1c79356b
A
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);
55e303ae 645 buf += sprintf(buf, "DSISR = 0x%08x, DAR = 0x%016llx\n"
1c79356b
A
646 , dsisr, dar);
647
648 for (i=0; i<32; i++) {
649 if ((i % 8) == 0) {
650 buf += sprintf(buf, "\n%4d :",i);
651 }
9bccf70c 652 buf += sprintf(buf, " %08x",*(&ssp->save_r0+i));
1c79356b
A
653 }
654
655 buf += sprintf(buf, "\n\n");
55e303ae
A
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,
1c79356b
A
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");
9bccf70c
A
668 if (ssp->save_srr1 & MASK(MSR_PR)) {
669 char *addr = (char*)ssp->save_r1;
1c79356b
A
670 unsigned int stack_buf[3];
671 for (i = 0; i < 8; i++) {
672 if (addr == (char*)NULL)
673 break;
91447636 674 if (!copyin(ssp->save_r1,(char*)stack_buf,
1c79356b 675 3 * sizeof(int))) {
55e303ae 676 buf += sprintf(buf, "0x%08X : 0x%08X\n"
1c79356b
A
677 ,addr,stack_buf[2]);
678 addr = (char*)stack_buf[0];
679 } else {
680 break;
681 }
682 }
683 }
684 buf[0] = '\0';
685 }
55e303ae 686#endif
1c79356b
A
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);
91447636
A
693
694 if (USER_MODE(ssp->save_srr1)) {
695 myast = ast_pending();
696 while (*myast & AST_ALL) {
0b4e3aa0 697 ast_taken(AST_ALL, intr);
1c79356b 698 ml_set_interrupts_enabled(FALSE);
91447636 699 myast = ast_pending();
1c79356b 700 }
91447636 701 }
1c79356b
A
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
9bccf70c 710extern int syscall_trace(int, struct savearea *);
1c79356b
A
711
712
713extern int pmdebug;
714
9bccf70c 715int syscall_trace(int retval, struct savearea *ssp)
1c79356b
A
716{
717 int i, argc;
de355530 718 int kdarg[3];
55e303ae
A
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);
1c79356b
A
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
9bccf70c 743extern int syscall_trace_end(int, struct savearea *);
1c79356b 744
9bccf70c 745int syscall_trace_end(int retval, struct savearea *ssp)
1c79356b 746{
55e303ae
A
747 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC,(-((unsigned int)ssp->save_r0))) | DBG_FUNC_END,
748 retval, 0, 0, 0, 0);
1c79356b
A
749 return retval;
750}
751
752/*
753 * called from syscall if there is an error
754 */
755
756int syscall_error(
757 int exception,
758 int code,
759 int subcode,
9bccf70c 760 struct savearea *ssp)
1c79356b
A
761{
762 register thread_t thread;
763
764 thread = current_thread();
765
766 if (thread == 0)
767 panic("syscall error in boot phase");
768
9bccf70c 769 if (!USER_MODE(ssp->save_srr1))
1c79356b
A
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 */
778void
779doexception(
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;
91447636 788 exception_triage(exc, codes, 2);
1c79356b
A
789}
790
791char *trap_type[] = {
0b4e3aa0
A
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",
55e303ae 824 "Emulate",
0b4e3aa0
A
825 "0x2000 - Run Mode/Trace",
826 "Signal Processor",
827 "Preemption",
828 "Context Switch",
829 "Shutdown",
830 "System Failure"
1c79356b
A
831};
832int TRAP_TYPES = sizeof (trap_type) / sizeof (trap_type[0]);
833
834void unresolved_kernel_trap(int trapno,
9bccf70c 835 struct savearea *ssp,
1c79356b 836 unsigned int dsisr,
55e303ae 837 addr64_t dar,
91447636 838 const char *message)
1c79356b
A
839{
840 char *trap_name;
9bccf70c 841 extern void print_backtrace(struct savearea *);
1c79356b 842 extern unsigned int debug_mode, disableDebugOuput;
91447636 843 extern unsigned long panic_caller;
1c79356b
A
844
845 ml_set_interrupts_enabled(FALSE); /* Turn off interruptions */
9bccf70c 846 lastTrace = LLTraceSet(0); /* Disable low-level tracing */
1c79356b 847
9bccf70c
A
848 if( logPanicDataToScreen )
849 disableDebugOuput = FALSE;
91447636 850
1c79356b
A
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
55e303ae 859 kdb_printf("\n\nUnresolved kernel trap(cpu %d): %s DAR=0x%016llX PC=0x%016llX\n",
9bccf70c 860 cpu_number(), trap_name, dar, ssp->save_srr0);
1c79356b
A
861
862 print_backtrace(ssp);
863
91447636 864 panic_caller = (0xFFFF0000 | (trapno / T_VECTOR_SIZE) );
9bccf70c
A
865 draw_panic_dialog();
866
867 if( panicDebugging )
868 (void *)Call_Debugger(trapno, ssp);
1c79356b
A
869 panic(message);
870}
871
91447636 872const char *corr[2] = {"uncorrected", "corrected "};
e5568f75
A
873
874void 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
1c79356b
A
896void
897thread_syscall_return(
898 kern_return_t ret)
899{
91447636
A
900 register thread_t thread = current_thread();
901 register struct savearea *regs = USER_REGS(thread);
1c79356b 902
55e303ae 903 if (kdebug_enable && ((unsigned int)regs->save_r0 & 0x80000000)) {
1c79356b 904 /* Mach trap */
9bccf70c 905 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_SC,(-(regs->save_r0))) | DBG_FUNC_END,
1c79356b
A
906 ret, 0, 0, 0, 0);
907 }
9bccf70c 908 regs->save_r3 = ret;
1c79356b
A
909
910 thread_exception_return();
911 /*NOTREACHED*/
912}
913
914
915#if MACH_KDB
916void
917thread_kdb_return(void)
918{
91447636
A
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);
1c79356b
A
923 thread_exception_return();
924 /*NOTREACHED*/
925}
926#endif /* MACH_KDB */