]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/ppc/model_dep.c
xnu-344.32.tar.gz
[apple/xnu.git] / osfmk / ppc / model_dep.c
index 970e9b1567371fc677a47bf7183b7542312df99f..05eb00f1f6620761d27c25a9041ed17f87674a1f 100644 (file)
@@ -125,7 +125,8 @@ char env_buf[256];
  * from on to another using kdb_on! #cpu or cpu #cpu
  */
 
-decl_simple_lock_data(, debugger_lock) /* debugger lock */
+hw_lock_data_t debugger_lock;  /* debugger lock */
+hw_lock_data_t pbtlock;                /* backtrace print lock */
 
 int                    debugger_cpu = -1;                      /* current cpu running debugger */
 int                    debugger_debug = 0;                     /* Debug debugger */
@@ -137,6 +138,10 @@ int                db_run_mode;                            /* Debugger run mode */
 unsigned int debugger_sync = 0;                        /* Cross processor debugger entry sync */
 extern                 unsigned int NMIss;                     /* NMI debounce switch */
 
+extern volatile int panicwait;
+volatile unsigned int pbtcnt = 0;
+volatile unsigned int pbtcpu = -1;
+
 unsigned int lastTrace;                                        /* Value of low-level exception trace controls */
 
 volatile unsigned int  cpus_holding_bkpts;     /* counter for number of cpus holding
@@ -144,6 +149,8 @@ volatile unsigned int       cpus_holding_bkpts;     /* counter for number of cpus holding
                                                                                           insert back breakpoints) */
 void unlock_debugger(void);
 void lock_debugger(void);
+void dump_backtrace(unsigned int stackptr, unsigned int fence);
+void dump_savearea(savearea *sv, unsigned int fence);
 
 #if !MACH_KDB
 boolean_t      db_breakpoints_inserted = TRUE;
@@ -165,18 +172,35 @@ extern int        kdp_flag;
 
 boolean_t db_im_stepping = 0xFFFFFFFF; /* Remember if we were stepping */
 
+
+char *failNames[] = {  
+
+       "Debugging trap",                       /* failDebug */
+       "Corrupt stack",                        /* failStack */
+       "Corrupt mapping tables",       /* failMapping */
+       "Corrupt context",                      /* failContext */
+       "No saveareas",                         /* failNoSavearea */
+       "Savearea corruption",          /* failSaveareaCorr */
+       "Invalid live context",         /* failBadLiveContext */
+       "Unknown failure code"          /* Unknown failure code - must always be last */
+};
+
+char *invxcption = "Unknown code";
+
 extern const char version[];
+extern char *trap_type[];
+extern vm_offset_t mem_actual;
 
 #if !MACH_KDB
-void kdb_trap(int type, struct ppc_saved_state *regs);
-void kdb_trap(int type, struct ppc_saved_state *regs) {
+void kdb_trap(int type, struct savearea *regs);
+void kdb_trap(int type, struct savearea *regs) {
        return;
 }
 #endif
 
 #if !MACH_KDP
-void kdp_trap(int type, struct ppc_saved_state *regs);
-void kdp_trap(int type, struct ppc_saved_state *regs) {
+void kdp_trap(int type, struct savearea *regs);
+void kdp_trap(int type, struct savearea *regs) {
        return;
 }
 #endif
@@ -199,9 +223,12 @@ machine_startup(boot_args *args)
                if (boot_arg & DB_HALT) halt_in_debugger=1;
                if (boot_arg & DB_PRT) disableDebugOuput=FALSE; 
                if (boot_arg & DB_SLOG) systemLogDiags=TRUE; 
+               if (boot_arg & DB_NMI) panicDebugging=TRUE; 
+               if (boot_arg & DB_LOG_PI_SCRN) logPanicDataToScreen=TRUE; 
        }
 
-       hw_lock_init(&debugger_lock);                           /* initialized debugger lock */
+       hw_lock_init(&debugger_lock);                           /* initialize debugger lock */
+       hw_lock_init(&pbtlock);                                         /* initialize print backtrace lock */
 
 #if    MACH_KDB
        /*
@@ -231,12 +258,20 @@ machine_startup(boot_args *args)
 
                default_preemption_rate = boot_arg;
        }
-       if (PE_parse_boot_arg("kpreempt", &boot_arg)) {
-               extern int kernel_preemption_mode;
-               extern boolean_t zone_gc_allowed;
+       if (PE_parse_boot_arg("unsafe", &boot_arg)) {
+               extern int max_unsafe_quanta;
+
+               max_unsafe_quanta = boot_arg;
+       }
+       if (PE_parse_boot_arg("poll", &boot_arg)) {
+               extern int max_poll_quanta;
 
-               kernel_preemption_mode = boot_arg;
-               zone_gc_allowed = FALSE; /* XXX: TO BE REMOVED  */
+               max_poll_quanta = boot_arg;
+       }
+       if (PE_parse_boot_arg("yield", &boot_arg)) {
+               extern int sched_poll_yield_shift;
+
+               sched_poll_yield_shift = boot_arg;
        }
 
        machine_conf();
@@ -316,64 +351,177 @@ void machine_callstack(
 
 
 void
-print_backtrace(struct ppc_saved_state *ssp)
+print_backtrace(struct savearea *ssp)
 {
-       unsigned int *stackptr, *raddr, *rstack, trans;
+       unsigned int stackptr, *raddr, *rstack, trans, fence;
        int i, frames_cnt, skip_top_frames, frames_max;
        unsigned int store[8];                  /* Buffer for real storage reads */
        vm_offset_t backtrace_entries[32];
+       thread_act_t *act;
+       savearea *sv, *svssp;
+       int cpu;
 
-       printf("backtrace: ");
-       frames_cnt =0;
-
-       /* Get our stackpointer for backtrace */
-       if (ssp==NULL) {
-               __asm__ volatile("mr %0,        r1" : "=r" (stackptr));
-               skip_top_frames = 1;
-       } else {
-               stackptr = (unsigned int *)(ssp->r1);
-               skip_top_frames = 0;
-               backtrace_entries[frames_cnt] = ssp->srr0;
-               frames_cnt++;
-               printf("0x%08x ", ssp->srr0);
-       }
+/*
+ *     We need this lock to make sure we don't hang up when we double panic on an MP.
+ */
 
-       frames_max = 32-frames_cnt;
-       for (i = 0; i < frames_max; i++) {
+       cpu  = cpu_number();                                    /* Just who are we anyways? */
+       if(pbtcpu != cpu) {                                             /* Allow recursion */
+               hw_atomic_add(&pbtcnt, 1);                      /* Remember we are trying */
+               while(!hw_lock_try(&pbtlock));          /* Spin here until we can get in. If we never do, well, we're crashing anyhow... */     
+               pbtcpu = cpu;                                           /* Mark it as us */     
+       }       
 
-               if(!stackptr) break;    /* No more to get... */
+       svssp = (savearea *)ssp;                                /* Make this easier */
+       sv = 0;
+       if(current_thread()) sv = (savearea *)current_act()->mact.pcb;  /* Find most current savearea if system has started */
 
-               /* Avoid causing page fault */
-               if (!(raddr = LRA(PPC_SID_KERNEL, (void *)((unsigned int)stackptr+FM_LR_SAVE))))
+       fence = 0xFFFFFFFF;                                             /* Show we go all the way */
+       if(sv) fence = sv->save_r1;                             /* Stop at previous exception point */
+       
+       if(!svssp) {                                                    /* Should we start from stack? */
+               kdb_printf("Latest stack backtrace for cpu %d:\n", cpu_number());
+               __asm__ volatile("mr %0,r1" : "=r" (stackptr)); /* Get current stack */
+               dump_backtrace(stackptr, fence);        /* Dump the backtrace */
+               if(!sv) {                                                       /* Leave if no saveareas */
+                       kdb_printf("\nKernel version:\n%s\n",version);  /* Print kernel version */
+                       hw_lock_unlock(&pbtlock);               /* Allow another back trace to happen */
+                       return; 
+               }
+       }
+       else {                                                                  /* Were we passed an exception? */
+               fence = 0xFFFFFFFF;                                     /* Show we go all the way */
+               if(svssp->save_hdr.save_prev) {
+                       if((svssp->save_hdr.save_prev <= VM_MAX_KERNEL_ADDRESS) && ((unsigned int)LRA(PPC_SID_KERNEL, (void *)svssp->save_hdr.save_prev))) {    /* Valid address? */    
+                               fence = svssp->save_hdr.save_prev->save_r1;     /* Stop at previous exception point */
+                       }
+               }
+       
+               kdb_printf("Latest crash info for cpu %d:\n", cpu_number());
+               kdb_printf("   Exception state (sv=0x%08X)\n", sv);
+               dump_savearea(svssp, fence);            /* Dump this savearea */        
+       }
+
+       if(!sv) {                                                               /* Leave if no saveareas */
+               kdb_printf("\nKernel version:\n%s\n",version);  /* Print kernel version */
+               hw_lock_unlock(&pbtlock);                       /* Allow another back trace to happen */
+               return; 
+       }
+       
+       kdb_printf("Proceeding back via exception chain:\n");
+
+       while(sv) {                                                             /* Do them all... */
+               if(!((sv <= VM_MAX_KERNEL_ADDRESS) && (unsigned int)LRA(PPC_SID_KERNEL, (void *)sv))) { /* Valid address? */    
+                       kdb_printf("   Exception state (sv=0x%08X) Not mapped or invalid. stopping...\n", sv);
                        break;
-               ReadReal((unsigned int)raddr, &store[0]);
-               if (skip_top_frames)
-                       skip_top_frames--;
+               }
+               
+               kdb_printf("   Exception state (sv=0x%08X)\n", sv);
+               if(sv == svssp) {                                       /* Did we dump it already? */
+                       kdb_printf("      previously dumped as \"Latest\" state. skipping...\n");
+               }
                else {
-                       backtrace_entries[frames_cnt] = store[0];
-                       frames_cnt++;
-                       printf("0x%08x ",store[0]);
+                       fence = 0xFFFFFFFF;                             /* Show we go all the way */
+                       if(sv->save_hdr.save_prev) {
+                               if((sv->save_hdr.save_prev <= VM_MAX_KERNEL_ADDRESS) && ((unsigned int)LRA(PPC_SID_KERNEL, (void *)sv->save_hdr.save_prev))) {  /* Valid address? */    
+                                       fence = sv->save_hdr.save_prev->save_r1;        /* Stop at previous exception point */
+                               }
+                       }
+                       dump_savearea(sv, fence);               /* Dump this savearea */        
+               }       
+               
+               sv = sv->save_hdr.save_prev;            /* Back chain */
+       }
+       
+       kdb_printf("\nKernel version:\n%s\n",version);  /* Print kernel version */
+
+       pbtcpu = -1;                                                    /* Mark as unowned */
+       hw_lock_unlock(&pbtlock);                               /* Allow another back trace to happen */
+       hw_atomic_sub(&pbtcnt, 1);                              /* Show we are done */
+
+       while(pbtcnt);                                                  /* Wait for completion */
+
+       return;
+}
+
+void dump_savearea(savearea *sv, unsigned int fence) {
+
+       char *xcode;
+       
+       if(sv->save_exception > T_MAX) xcode = invxcption;      /* Too big for table */
+       else xcode = trap_type[sv->save_exception / 4];         /* Point to the type */
+       
+       kdb_printf("      PC=0x%08X; MSR=0x%08X; DAR=0x%08X; DSISR=0x%08X; LR=0x%08X; R1=0x%08X; XCP=0x%08X (%s)\n",
+               sv->save_srr0, sv->save_srr1, sv->save_dar, sv->save_dsisr,
+               sv->save_lr, sv->save_r1, sv->save_exception, xcode);
+       
+       if(!(sv->save_srr1 & MASK(MSR_PR))) {           /* Are we in the kernel? */
+               dump_backtrace(sv->save_r1, fence);             /* Dump the stack back trace from  here if not user state */
+       }
+       
+       return;
+}
+
+
+
+#define DUMPFRAMES 32
+#define LRindex 2
+
+void dump_backtrace(unsigned int stackptr, unsigned int fence) {
+
+       unsigned int bframes[DUMPFRAMES];
+       unsigned int  sframe[8], raddr, dumbo;
+       int i;
+       
+       kdb_printf("      Backtrace:\n");
+       for(i = 0; i < DUMPFRAMES; i++) {                       /* Dump up to max frames */
+       
+               if(!stackptr || (stackptr == fence)) break;             /* Hit stop point or end... */
+               
+               if(stackptr & 0x0000000f) {                             /* Is stack pointer valid? */
+                       kdb_printf("\n         backtrace terminated - unaligned frame address: 0x%08X\n", stackptr);    /* No, tell 'em */
+                       break;
                }
-               if (!(raddr = LRA(PPC_SID_KERNEL, (void *)stackptr))) 
+
+               raddr = (unsigned int)LRA(PPC_SID_KERNEL, (void *)stackptr);    /* Get physical frame address */
+               if(!raddr || (stackptr > VM_MAX_KERNEL_ADDRESS)) {              /* Is it mapped? */
+                       kdb_printf("\n         backtrace terminated - frame not mapped or invalid: 0x%08X\n", stackptr);        /* No, tell 'em */
                        break;
-               ReadReal((unsigned int)raddr, &store[0]);
-               stackptr=(unsigned int *)store[0];
-       }
-       printf("\n");
+               }
+       
+               if(raddr >= mem_actual) {                                       /* Is it within physical RAM? */
+                       kdb_printf("\n         backtrace terminated - frame outside of RAM: v=0x%08X, p=%08X\n", stackptr, raddr);      /* No, tell 'em */
+                       break;
+               }
+       
+               ReadReal(raddr, &sframe[0]);                            /* Fetch the stack frame */
 
-       if (frames_cnt)
-               kmod_dump((vm_offset_t *)&backtrace_entries[0], frames_cnt);
+               bframes[i] = sframe[LRindex];                           /* Save the link register */
+               
+               if(!i) kdb_printf("         ");                         /* Indent first time */
+               else if(!(i & 7)) kdb_printf("\n         ");    /* Skip to new line every 8 */
+               kdb_printf("0x%08X ", bframes[i]);                      /* Dump the link register */
+               
+               stackptr = sframe[0];                                           /* Chain back */
+       }
+       kdb_printf("\n");
+       if(i >= DUMPFRAMES) kdb_printf("      backtrace continues...\n");       /* Say we terminated early */
+       if(i) kmod_dump((vm_offset_t *)&bframes[0], i); /* Show what kmods are in trace */
+       
 }
+       
+
 
 void 
 Debugger(const char    *message) {
 
        int i;
        unsigned int store[8];
+       unsigned long pi_size = 0;
        spl_t spl;
        
        spl = splhigh();                                                                /* No interruptions from here on */
-
+       
 /*
  *     backtrace for Debugger() call  from panic() if no current debugger
  *     backtrace and return for double panic() call
@@ -383,15 +531,58 @@ Debugger(const char       *message) {
                print_backtrace(NULL);
                if (nestedpanic != 0)  {
                        splx(spl);
-                       return;                                                                         /* Yeah, don't enter again... */
+                       return;                                                                 /* Yeah, don't enter again... */
                }
        }
-
+       
        if (debug_mode && debugger_active[cpu_number()]) {      /* Are we already on debugger on this processor? */
                splx(spl);
                return;                                                                         /* Yeah, don't do it again... */
        }
 
+
+/*
+ * The above stuff catches the double panic case so we shouldn't have to worry about that here.
+ */
+       if ( panicstr != (char *)0 )
+       {
+               /* diable kernel preemptions */
+               disable_preemption();
+       
+               /* everything should be printed now so copy to NVRAM
+               */
+               if( debug_buf_size > 0)
+                       pi_size = PESavePanicInfo( debug_buf, debug_buf_ptr - debug_buf);
+                       
+               if( !panicDebugging && (pi_size != 0) ) {
+                       int     my_cpu, debugger_cpu;
+                       int     tcpu;
+
+                       my_cpu = cpu_number();
+                       debugger_cpu = my_cpu;
+
+                       hw_atomic_add(&debug_mode, 1);
+                       debugger_active[my_cpu]++;
+                       lock_debugger();
+
+                       for(tcpu = 0; tcpu < NCPUS; tcpu++) {
+                               if(tcpu == my_cpu) continue;
+                               hw_atomic_add(&debugger_sync, 1);
+                               (void)cpu_signal(tcpu, SIGPdebug, 0 ,0);
+                       }
+                       (void)hw_cpu_sync(&debugger_sync, LockTimeOut);
+                       debugger_sync = 0;
+               }
+
+               draw_panic_dialog();
+               
+               if( !panicDebugging && (pi_size != 0))
+                                       PEHaltRestart( kPEHangCPU );
+
+               enable_preemption();
+       }
+
+
        if ((current_debugger != NO_CUR_DB)) {                  /* If there is a debugger configured, enter it */
                printf("Debugger(%s)\n", message);
                TRAP_DEBUGGER;
@@ -400,25 +591,46 @@ Debugger(const char       *message) {
        }
 
        printf("\nNo debugger configured - dumping debug information\n");
-       printf("\nversion string : %s\n",version);
-       mfdbatu(store[0],0);
-       mfdbatl(store[1],0);    
-       mfdbatu(store[2],1);                                    
-       mfdbatl(store[3],1);                                    
-       mfdbatu(store[4],2);                            
-       mfdbatl(store[5],2);                                    
-       mfdbatu(store[6],3);                            
-       mfdbatl(store[7],3);                                    
-       printf("DBAT0: %08X %08X\n", store[0], store[1]);
-       printf("DBAT1: %08X %08X\n", store[2], store[3]);
-       printf("DBAT2: %08X %08X\n", store[4], store[5]);
-       printf("DBAT3: %08X %08X\n", store[6], store[7]);
        printf("MSR=%08X\n",mfmsr());
        print_backtrace(NULL);
        splx(spl);
        return;
 }
 
+/*
+ *             Here's where we attempt to get some diagnostic information dumped out
+ *             when the system is really confused.  We will try to get into the 
+ *             debugger as well.
+ *
+ *             We are here with interrupts disabled and on the debug stack.  The savearea
+ *             that was passed in is NOT chained to the activation.
+ *
+ *             save_r3 contains the failure reason code.
+ */
+
+void SysChoked(int type, savearea *sv) {                       /* The system is bad dead */
+
+       unsigned int failcode;
+       
+       mp_disable_preemption();
+       disableDebugOuput = FALSE;
+       debug_mode = TRUE;
+
+       failcode = sv->save_r3;                                                 /* Get the failure code */
+       if(failcode > failUnknown) failcode = failUnknown;      /* Set unknown code code */
+       
+       kprintf("System Failure: cpu=%d; code=%08X (%s)\n", cpu_number(), sv->save_r3, failNames[failcode]);
+       kdb_printf("System Failure: cpu=%d; code=%08X (%s)\n", cpu_number(), sv->save_r3, failNames[failcode]);
+
+       print_backtrace(sv);                                                    /* Attempt to print backtrace */
+       Call_DebuggerC(type, sv);                                               /* Attempt to get into debugger */
+
+       if ((current_debugger != NO_CUR_DB)) Call_DebuggerC(type, sv);  /* Attempt to get into debugger */
+
+}
+
+
+
 /*
  *     When we get here, interruptions are disabled and we are on the debugger stack
  *     Never, ever, ever, ever enable interruptions from here on
@@ -426,7 +638,7 @@ Debugger(const char *message) {
 
 int Call_DebuggerC(
         int    type,
-        struct ppc_saved_state *saved_state)
+        struct savearea *saved_state)
 {
        int                             directcall, wait;
        vm_offset_t             instr_ptr;
@@ -458,10 +670,10 @@ int Call_DebuggerC(
                kprintf("Call_DebuggerC(%d): %08X %08X, debact = %d\n", my_cpu, type, saved_state, debug_mode); /* (TEST/DEBUG) */
 #endif
                printf("Call_Debugger: enter - cpu %d, is_slave %d, debugger_cpu %d, pc %08X\n",
-                  my_cpu, debugger_is_slave[my_cpu], debugger_cpu, saved_state->srr0);
+                  my_cpu, debugger_is_slave[my_cpu], debugger_cpu, saved_state->save_srr0);
        }
        
-       if (instr_ptr = (vm_offset_t)LRA(PPC_SID_KERNEL, (void *)(saved_state->srr0))) {
+       if (instr_ptr = (vm_offset_t)LRA(PPC_SID_KERNEL, (void *)(saved_state->save_srr0))) {
                instr = ml_phys_read(instr_ptr);                                /* Get the trap that caused entry */
        } 
        else instr = 0;
@@ -497,7 +709,7 @@ int Call_DebuggerC(
        switch_debugger = 0;                                                            /* Make sure switch request is off */
        directcall = 1;                                                                         /* Assume direct call */
 
-       if (saved_state->srr1 & MASK(SRR1_PRG_TRAP)) {          /* Trap instruction? */
+       if (saved_state->save_srr1 & MASK(SRR1_PRG_TRAP)) {     /* Trap instruction? */
                
                directcall = 0;                                                                 /* We had a trap not a direct call */
 
@@ -579,7 +791,7 @@ debugger_exit:
                instr, my_cpu, debugger_cpu, db_run_mode);      /* (TEST/DEBUG) */
 #endif
        if ((instr == TRAP_DEBUGGER_INST) ||                            /* Did we trap to enter debugger? */
-               (instr == TRAP_DIRECT_INST)) saved_state->srr0 += TRAP_INST_SIZE;       /* Yes, point past trap */
+               (instr == TRAP_DIRECT_INST)) saved_state->save_srr0 += TRAP_INST_SIZE;  /* Yes, point past trap */
 
        if(debugger_cpu == my_cpu) LLTraceSet(lastTrace);       /* Enable tracing on the way out if we are debugger */