| 1 | /* |
| 2 | * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved. |
| 3 | * |
| 4 | * @APPLE_LICENSE_HEADER_START@ |
| 5 | * |
| 6 | * The contents of this file constitute Original Code as defined in and |
| 7 | * are subject to the Apple Public Source License Version 1.1 (the |
| 8 | * "License"). You may not use this file except in compliance with the |
| 9 | * License. Please obtain a copy of the License at |
| 10 | * http://www.apple.com/publicsource and read it before using this file. |
| 11 | * |
| 12 | * This Original Code and all software distributed under the License are |
| 13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
| 14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
| 15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, |
| 16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the |
| 17 | * License for the specific language governing rights and limitations |
| 18 | * under the License. |
| 19 | * |
| 20 | * @APPLE_LICENSE_HEADER_END@ |
| 21 | */ |
| 22 | /* |
| 23 | * @OSF_COPYRIGHT@ |
| 24 | */ |
| 25 | /* |
| 26 | * @APPLE_FREE_COPYRIGHT@ |
| 27 | */ |
| 28 | /* |
| 29 | * (c) Copyright 1988 HEWLETT-PACKARD COMPANY |
| 30 | * |
| 31 | * To anyone who acknowledges that this file is provided "AS IS" |
| 32 | * without any express or implied warranty: |
| 33 | * permission to use, copy, modify, and distribute this file |
| 34 | * for any purpose is hereby granted without fee, provided that |
| 35 | * the above copyright notice and this notice appears in all |
| 36 | * copies, and that the name of Hewlett-Packard Company not be |
| 37 | * used in advertising or publicity pertaining to distribution |
| 38 | * of the software without specific, written prior permission. |
| 39 | * Hewlett-Packard Company makes no representations about the |
| 40 | * suitability of this software for any purpose. |
| 41 | */ |
| 42 | /* |
| 43 | * Copyright (c) 1990,1991,1992,1994 The University of Utah and |
| 44 | * the Computer Systems Laboratory (CSL). All rights reserved. |
| 45 | * |
| 46 | * THE UNIVERSITY OF UTAH AND CSL PROVIDE THIS SOFTWARE IN ITS "AS IS" |
| 47 | * CONDITION, AND DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES |
| 48 | * WHATSOEVER RESULTING FROM ITS USE. |
| 49 | * |
| 50 | * CSL requests users of this software to return to csl-dist@cs.utah.edu any |
| 51 | * improvements that they make and grant CSL redistribution rights. |
| 52 | * |
| 53 | * Utah $Hdr: model_dep.c 1.34 94/12/14$ |
| 54 | */ |
| 55 | |
| 56 | #include <debug.h> |
| 57 | #include <mach_kdb.h> |
| 58 | #include <mach_kdp.h> |
| 59 | #include <db_machine_commands.h> |
| 60 | |
| 61 | #include <kern/thread.h> |
| 62 | #include <machine/pmap.h> |
| 63 | #include <device/device_types.h> |
| 64 | |
| 65 | #include <mach/vm_param.h> |
| 66 | #include <mach/clock_types.h> |
| 67 | #include <mach/machine.h> |
| 68 | #include <mach/kmod.h> |
| 69 | #include <ppc/boot.h> |
| 70 | |
| 71 | #include <kern/misc_protos.h> |
| 72 | #include <kern/startup.h> |
| 73 | #include <ppc/misc_protos.h> |
| 74 | #include <ppc/proc_reg.h> |
| 75 | #include <ppc/thread.h> |
| 76 | #include <ppc/asm.h> |
| 77 | #include <ppc/mem.h> |
| 78 | #include <ppc/Firmware.h> |
| 79 | #include <ppc/low_trace.h> |
| 80 | #include <ppc/mappings.h> |
| 81 | #include <ppc/FirmwareCalls.h> |
| 82 | #include <ppc/cpu_internal.h> |
| 83 | #include <ppc/exception.h> |
| 84 | #include <ppc/hw_perfmon.h> |
| 85 | #include <ppc/lowglobals.h> |
| 86 | |
| 87 | #include <kern/clock.h> |
| 88 | #include <kern/debug.h> |
| 89 | #include <machine/trap.h> |
| 90 | #include <kern/spl.h> |
| 91 | #include <pexpert/pexpert.h> |
| 92 | |
| 93 | #include <IOKit/IOPlatformExpert.h> |
| 94 | |
| 95 | #include <mach/vm_prot.h> |
| 96 | #include <vm/pmap.h> |
| 97 | #include <mach/time_value.h> |
| 98 | #include <machine/machparam.h> /* for btop */ |
| 99 | |
| 100 | #if MACH_KDB |
| 101 | #include <ddb/db_aout.h> |
| 102 | #include <ddb/db_output.h> |
| 103 | #include <ddb/db_command.h> |
| 104 | #include <machine/db_machdep.h> |
| 105 | |
| 106 | extern struct db_command ppc_db_commands[]; |
| 107 | #endif /* MACH_KDB */ |
| 108 | |
| 109 | char kernel_args_buf[256] = "/mach_kernel"; |
| 110 | char boot_args_buf[256] = "/mach_servers/bootstrap"; |
| 111 | char env_buf[256]; |
| 112 | |
| 113 | #define TRAP_DEBUGGER __asm__ volatile("tw 4,r3,r3"); |
| 114 | #define TRAP_DEBUGGER_INST 0x7c831808 |
| 115 | #define TRAP_DIRECT __asm__ volatile("tw 4,r4,r4"); |
| 116 | #define TRAP_DIRECT_INST 0x7c842008 |
| 117 | #define TRAP_INST_SIZE 4 |
| 118 | #define BREAK_TO_KDP0 0x7fe00008 |
| 119 | #define BREAK_TO_KDP1 0x7c800008 |
| 120 | #define BREAK_TO_KDB0 0x7c810808 |
| 121 | |
| 122 | /* |
| 123 | * Code used to synchronize debuggers among all cpus, one active at a time, switch |
| 124 | * from on to another using kdb_on! #cpu or cpu #cpu |
| 125 | */ |
| 126 | |
| 127 | hw_lock_data_t debugger_lock; /* debugger lock */ |
| 128 | hw_lock_data_t pbtlock; /* backtrace print lock */ |
| 129 | |
| 130 | int debugger_cpu = -1; /* current cpu running debugger */ |
| 131 | int debugger_debug = 0; /* Debug debugger */ |
| 132 | int db_run_mode; /* Debugger run mode */ |
| 133 | unsigned int debugger_sync = 0; /* Cross processor debugger entry sync */ |
| 134 | extern unsigned int NMIss; /* NMI debounce switch */ |
| 135 | |
| 136 | extern volatile int panicwait; |
| 137 | volatile unsigned int pbtcnt = 0; |
| 138 | volatile unsigned int pbtcpu = -1; |
| 139 | |
| 140 | unsigned int lastTrace; /* Value of low-level exception trace controls */ |
| 141 | |
| 142 | |
| 143 | volatile unsigned int cpus_holding_bkpts; /* counter for number of cpus holding |
| 144 | breakpoints (ie: cpus that did not |
| 145 | insert back breakpoints) */ |
| 146 | void unlock_debugger(void); |
| 147 | void lock_debugger(void); |
| 148 | void dump_backtrace(savearea *sv, unsigned int stackptr, unsigned int fence); |
| 149 | void dump_savearea(savearea *sv, unsigned int fence); |
| 150 | |
| 151 | int packAsc (unsigned char *inbuf, unsigned int length); |
| 152 | |
| 153 | #if !MACH_KDB |
| 154 | boolean_t db_breakpoints_inserted = TRUE; |
| 155 | jmp_buf_t *db_recover = 0; |
| 156 | #endif |
| 157 | |
| 158 | #if MACH_KDB |
| 159 | #include <ddb/db_run.h> |
| 160 | int kdb_flag=0; |
| 161 | extern boolean_t db_breakpoints_inserted; |
| 162 | extern jmp_buf_t *db_recover; |
| 163 | #define KDB_READY 0x1 |
| 164 | #endif |
| 165 | |
| 166 | #if MACH_KDP |
| 167 | extern int kdp_flag; |
| 168 | #define KDP_READY 0x1 |
| 169 | #endif |
| 170 | |
| 171 | boolean_t db_im_stepping = 0xFFFFFFFF; /* Remember if we were stepping */ |
| 172 | |
| 173 | |
| 174 | char *failNames[] = { |
| 175 | |
| 176 | "Debugging trap", /* failDebug */ |
| 177 | "Corrupt stack", /* failStack */ |
| 178 | "Corrupt mapping tables", /* failMapping */ |
| 179 | "Corrupt context", /* failContext */ |
| 180 | "No saveareas", /* failNoSavearea */ |
| 181 | "Savearea corruption", /* failSaveareaCorr */ |
| 182 | "Invalid live context", /* failBadLiveContext */ |
| 183 | "Corrupt skip lists", /* failSkipLists */ |
| 184 | "Unaligned stack", /* failUnalignedStk */ |
| 185 | "Invalid pmap", /* failPmap */ |
| 186 | "Lock timeout", /* failTimeout */ |
| 187 | "Unknown failure code" /* Unknown failure code - must always be last */ |
| 188 | }; |
| 189 | |
| 190 | char *invxcption = "Unknown code"; |
| 191 | |
| 192 | extern const char version[]; |
| 193 | extern char *trap_type[]; |
| 194 | |
| 195 | #if !MACH_KDB |
| 196 | void kdb_trap(int type, struct savearea *regs); |
| 197 | void kdb_trap(int type, struct savearea *regs) { |
| 198 | return; |
| 199 | } |
| 200 | #endif |
| 201 | |
| 202 | #if !MACH_KDP |
| 203 | void kdp_trap(int type, struct savearea *regs); |
| 204 | void kdp_trap(int type, struct savearea *regs) { |
| 205 | return; |
| 206 | } |
| 207 | #endif |
| 208 | |
| 209 | void |
| 210 | machine_startup(boot_args *args) |
| 211 | { |
| 212 | int boot_arg; |
| 213 | unsigned int wncpu; |
| 214 | unsigned int vmm_arg; |
| 215 | |
| 216 | if (PE_parse_boot_arg("cpus", &wncpu)) { |
| 217 | if ((wncpu > 0) && (wncpu < MAX_CPUS)) |
| 218 | max_ncpus = wncpu; |
| 219 | } |
| 220 | |
| 221 | if( PE_get_hotkey( kPEControlKey )) |
| 222 | halt_in_debugger = halt_in_debugger ? 0 : 1; |
| 223 | |
| 224 | if (PE_parse_boot_arg("debug", &boot_arg)) { |
| 225 | if (boot_arg & DB_HALT) halt_in_debugger=1; |
| 226 | if (boot_arg & DB_PRT) disableDebugOuput=FALSE; |
| 227 | if (boot_arg & DB_SLOG) systemLogDiags=TRUE; |
| 228 | if (boot_arg & DB_NMI) panicDebugging=TRUE; |
| 229 | if (boot_arg & DB_LOG_PI_SCRN) logPanicDataToScreen=TRUE; |
| 230 | } |
| 231 | |
| 232 | PE_parse_boot_arg("vmmforce", &lowGlo.lgVMMforcedFeats); |
| 233 | |
| 234 | hw_lock_init(&debugger_lock); /* initialize debugger lock */ |
| 235 | hw_lock_init(&pbtlock); /* initialize print backtrace lock */ |
| 236 | |
| 237 | #if MACH_KDB |
| 238 | /* |
| 239 | * Initialize KDB |
| 240 | */ |
| 241 | #if DB_MACHINE_COMMANDS |
| 242 | db_machine_commands_install(ppc_db_commands); |
| 243 | #endif /* DB_MACHINE_COMMANDS */ |
| 244 | ddb_init(); |
| 245 | |
| 246 | if (boot_arg & DB_KDB) |
| 247 | current_debugger = KDB_CUR_DB; |
| 248 | |
| 249 | /* |
| 250 | * Cause a breakpoint trap to the debugger before proceeding |
| 251 | * any further if the proper option bit was specified in |
| 252 | * the boot flags. |
| 253 | */ |
| 254 | if (halt_in_debugger && (current_debugger == KDB_CUR_DB)) { |
| 255 | Debugger("inline call to debugger(machine_startup)"); |
| 256 | halt_in_debugger = 0; |
| 257 | active_debugger =1; |
| 258 | } |
| 259 | #endif /* MACH_KDB */ |
| 260 | if (PE_parse_boot_arg("preempt", &boot_arg)) { |
| 261 | extern int default_preemption_rate; |
| 262 | |
| 263 | default_preemption_rate = boot_arg; |
| 264 | } |
| 265 | if (PE_parse_boot_arg("unsafe", &boot_arg)) { |
| 266 | extern int max_unsafe_quanta; |
| 267 | |
| 268 | max_unsafe_quanta = boot_arg; |
| 269 | } |
| 270 | if (PE_parse_boot_arg("poll", &boot_arg)) { |
| 271 | extern int max_poll_quanta; |
| 272 | |
| 273 | max_poll_quanta = boot_arg; |
| 274 | } |
| 275 | if (PE_parse_boot_arg("yield", &boot_arg)) { |
| 276 | extern int sched_poll_yield_shift; |
| 277 | |
| 278 | sched_poll_yield_shift = boot_arg; |
| 279 | } |
| 280 | |
| 281 | machine_conf(); |
| 282 | |
| 283 | /* |
| 284 | * Kick off the kernel bootstrap. |
| 285 | */ |
| 286 | kernel_bootstrap(); |
| 287 | /*NOTREACHED*/ |
| 288 | } |
| 289 | |
| 290 | char * |
| 291 | machine_boot_info( |
| 292 | char *buf, |
| 293 | vm_size_t size) |
| 294 | { |
| 295 | return(PE_boot_args()); |
| 296 | } |
| 297 | |
| 298 | void |
| 299 | machine_conf(void) |
| 300 | { |
| 301 | machine_info.memory_size = mem_size; /* Note that this will be 2 GB for >= 2 GB machines */ |
| 302 | } |
| 303 | |
| 304 | void |
| 305 | machine_init(void) |
| 306 | { |
| 307 | clock_config(); |
| 308 | perfmon_init(); |
| 309 | } |
| 310 | |
| 311 | void slave_machine_init(void) |
| 312 | { |
| 313 | cpu_machine_init(); /* Initialize the processor */ |
| 314 | clock_init(); /* Init the clock */ |
| 315 | } |
| 316 | |
| 317 | void |
| 318 | halt_all_cpus(boolean_t reboot) |
| 319 | { |
| 320 | if(reboot) |
| 321 | { |
| 322 | printf("MACH Reboot\n"); |
| 323 | PEHaltRestart(kPERestartCPU); |
| 324 | } |
| 325 | else |
| 326 | { |
| 327 | printf("CPU halted\n"); |
| 328 | PEHaltRestart(kPEHaltCPU); |
| 329 | } |
| 330 | while(1); |
| 331 | } |
| 332 | |
| 333 | void |
| 334 | halt_cpu(void) |
| 335 | { |
| 336 | halt_all_cpus(FALSE); |
| 337 | } |
| 338 | |
| 339 | #if MACH_ASSERT |
| 340 | /* |
| 341 | * Machine-dependent routine to fill in an array with up to callstack_max |
| 342 | * levels of return pc information. |
| 343 | */ |
| 344 | void machine_callstack( |
| 345 | natural_t *buf, |
| 346 | vm_size_t callstack_max) |
| 347 | { |
| 348 | } |
| 349 | #endif /* MACH_ASSERT */ |
| 350 | |
| 351 | |
| 352 | void |
| 353 | print_backtrace(struct savearea *ssp) |
| 354 | { |
| 355 | unsigned int stackptr, *raddr, *rstack, trans, fence; |
| 356 | int i, frames_cnt, skip_top_frames, frames_max; |
| 357 | unsigned int store[8]; /* Buffer for real storage reads */ |
| 358 | vm_offset_t backtrace_entries[32]; |
| 359 | savearea *sv, *svssp; |
| 360 | int cpu; |
| 361 | savearea *psv; |
| 362 | |
| 363 | /* |
| 364 | * We need this lock to make sure we don't hang up when we double panic on an MP. |
| 365 | */ |
| 366 | |
| 367 | cpu = cpu_number(); /* Just who are we anyways? */ |
| 368 | if(pbtcpu != cpu) { /* Allow recursion */ |
| 369 | hw_atomic_add((uint32_t *)&pbtcnt, 1); /* Remember we are trying */ |
| 370 | while(!hw_lock_try(&pbtlock)); /* Spin here until we can get in. If we never do, well, we're crashing anyhow... */ |
| 371 | pbtcpu = cpu; /* Mark it as us */ |
| 372 | } |
| 373 | |
| 374 | svssp = (savearea *)ssp; /* Make this easier */ |
| 375 | sv = 0; |
| 376 | if(current_thread()) sv = (savearea *)current_thread()->machine.pcb; /* Find most current savearea if system has started */ |
| 377 | |
| 378 | fence = 0xFFFFFFFF; /* Show we go all the way */ |
| 379 | if(sv) fence = (unsigned int)sv->save_r1; /* Stop at previous exception point */ |
| 380 | |
| 381 | if(!svssp) { /* Should we start from stack? */ |
| 382 | kdb_printf("Latest stack backtrace for cpu %d:\n", cpu_number()); |
| 383 | __asm__ volatile("mr %0,r1" : "=r" (stackptr)); /* Get current stack */ |
| 384 | dump_backtrace((savearea *)0,stackptr, fence); /* Dump the backtrace */ |
| 385 | if(!sv) { /* Leave if no saveareas */ |
| 386 | kdb_printf("\nKernel version:\n%s\n",version); /* Print kernel version */ |
| 387 | hw_lock_unlock(&pbtlock); /* Allow another back trace to happen */ |
| 388 | return; |
| 389 | } |
| 390 | } |
| 391 | else { /* Were we passed an exception? */ |
| 392 | fence = 0xFFFFFFFF; /* Show we go all the way */ |
| 393 | if(svssp->save_hdr.save_prev) { |
| 394 | if((svssp->save_hdr.save_prev <= vm_last_addr) && ((unsigned int)pmap_find_phys(kernel_pmap, (addr64_t)svssp->save_hdr.save_prev))) { /* Valid address? */ |
| 395 | psv = (savearea *)((unsigned int)svssp->save_hdr.save_prev); /* Get the 64-bit back chain converted to a regualr pointer */ |
| 396 | fence = (unsigned int)psv->save_r1; /* Stop at previous exception point */ |
| 397 | } |
| 398 | } |
| 399 | |
| 400 | kdb_printf("Latest crash info for cpu %d:\n", cpu_number()); |
| 401 | kdb_printf(" Exception state (sv=0x%08X)\n", sv); |
| 402 | dump_savearea(svssp, fence); /* Dump this savearea */ |
| 403 | } |
| 404 | |
| 405 | if(!sv) { /* Leave if no saveareas */ |
| 406 | kdb_printf("\nKernel version:\n%s\n",version); /* Print kernel version */ |
| 407 | hw_lock_unlock(&pbtlock); /* Allow another back trace to happen */ |
| 408 | return; |
| 409 | } |
| 410 | |
| 411 | kdb_printf("Proceeding back via exception chain:\n"); |
| 412 | |
| 413 | while(sv) { /* Do them all... */ |
| 414 | if(!(((addr64_t)((uintptr_t)sv) <= vm_last_addr) && |
| 415 | (unsigned int)pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)sv)))) { /* Valid address? */ |
| 416 | kdb_printf(" Exception state (sv=0x%08X) Not mapped or invalid. stopping...\n", sv); |
| 417 | break; |
| 418 | } |
| 419 | |
| 420 | kdb_printf(" Exception state (sv=0x%08X)\n", sv); |
| 421 | if(sv == svssp) { /* Did we dump it already? */ |
| 422 | kdb_printf(" previously dumped as \"Latest\" state. skipping...\n"); |
| 423 | } |
| 424 | else { |
| 425 | fence = 0xFFFFFFFF; /* Show we go all the way */ |
| 426 | if(sv->save_hdr.save_prev) { |
| 427 | if((sv->save_hdr.save_prev <= vm_last_addr) && ((unsigned int)pmap_find_phys(kernel_pmap, (addr64_t)sv->save_hdr.save_prev))) { /* Valid address? */ |
| 428 | psv = (savearea *)((unsigned int)sv->save_hdr.save_prev); /* Get the 64-bit back chain converted to a regualr pointer */ |
| 429 | fence = (unsigned int)psv->save_r1; /* Stop at previous exception point */ |
| 430 | } |
| 431 | } |
| 432 | dump_savearea(sv, fence); /* Dump this savearea */ |
| 433 | } |
| 434 | |
| 435 | sv = CAST_DOWN(savearea *, sv->save_hdr.save_prev); /* Back chain */ |
| 436 | } |
| 437 | |
| 438 | kdb_printf("\nKernel version:\n%s\n",version); /* Print kernel version */ |
| 439 | |
| 440 | pbtcpu = -1; /* Mark as unowned */ |
| 441 | hw_lock_unlock(&pbtlock); /* Allow another back trace to happen */ |
| 442 | hw_atomic_sub((uint32_t *) &pbtcnt, 1); /* Show we are done */ |
| 443 | |
| 444 | while(pbtcnt); /* Wait for completion */ |
| 445 | |
| 446 | return; |
| 447 | } |
| 448 | |
| 449 | void dump_savearea(savearea *sv, unsigned int fence) { |
| 450 | |
| 451 | char *xcode; |
| 452 | |
| 453 | if(sv->save_exception > T_MAX) xcode = invxcption; /* Too big for table */ |
| 454 | else xcode = trap_type[sv->save_exception / 4]; /* Point to the type */ |
| 455 | |
| 456 | 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", |
| 457 | (unsigned int)sv->save_srr0, (unsigned int)sv->save_srr1, (unsigned int)sv->save_dar, sv->save_dsisr, |
| 458 | (unsigned int)sv->save_lr, (unsigned int)sv->save_r1, sv->save_exception, xcode); |
| 459 | |
| 460 | if(!(sv->save_srr1 & MASK(MSR_PR))) { /* Are we in the kernel? */ |
| 461 | dump_backtrace(sv, (unsigned int)sv->save_r1, fence); /* Dump the stack back trace from here if not user state */ |
| 462 | } |
| 463 | |
| 464 | return; |
| 465 | } |
| 466 | |
| 467 | |
| 468 | |
| 469 | #define DUMPFRAMES 34 |
| 470 | #define LRindex 2 |
| 471 | |
| 472 | void dump_backtrace(savearea *sv, unsigned int stackptr, unsigned int fence) { |
| 473 | |
| 474 | unsigned int bframes[DUMPFRAMES]; |
| 475 | unsigned int sframe[8], raddr, dumbo; |
| 476 | int i, index=0; |
| 477 | |
| 478 | kdb_printf(" Backtrace:\n"); |
| 479 | if (sv != (savearea *)0) { |
| 480 | bframes[0] = (unsigned int)sv->save_srr0; |
| 481 | bframes[1] = (unsigned int)sv->save_lr; |
| 482 | index = 2; |
| 483 | } |
| 484 | for(i = index; i < DUMPFRAMES; i++) { /* Dump up to max frames */ |
| 485 | |
| 486 | if(!stackptr || (stackptr == fence)) break; /* Hit stop point or end... */ |
| 487 | |
| 488 | if(stackptr & 0x0000000F) { /* Is stack pointer valid? */ |
| 489 | kdb_printf("\n backtrace terminated - unaligned frame address: 0x%08X\n", stackptr); /* No, tell 'em */ |
| 490 | break; |
| 491 | } |
| 492 | |
| 493 | raddr = (unsigned int)pmap_find_phys(kernel_pmap, (addr64_t)stackptr); /* Get physical frame address */ |
| 494 | if(!raddr || (stackptr > vm_last_addr)) { /* Is it mapped? */ |
| 495 | kdb_printf("\n backtrace terminated - frame not mapped or invalid: 0x%08X\n", stackptr); /* No, tell 'em */ |
| 496 | break; |
| 497 | } |
| 498 | |
| 499 | if(!mapping_phys_lookup(raddr, &dumbo)) { /* Is it within physical RAM? */ |
| 500 | kdb_printf("\n backtrace terminated - frame outside of RAM: v=0x%08X, p=%08X\n", stackptr, raddr); /* No, tell 'em */ |
| 501 | break; |
| 502 | } |
| 503 | |
| 504 | ReadReal((addr64_t)((raddr << 12) | (stackptr & 4095)), &sframe[0]); /* Fetch the stack frame */ |
| 505 | |
| 506 | bframes[i] = sframe[LRindex]; /* Save the link register */ |
| 507 | |
| 508 | if(!i) kdb_printf(" "); /* Indent first time */ |
| 509 | else if(!(i & 7)) kdb_printf("\n "); /* Skip to new line every 8 */ |
| 510 | kdb_printf("0x%08X ", bframes[i]); /* Dump the link register */ |
| 511 | |
| 512 | stackptr = sframe[0]; /* Chain back */ |
| 513 | } |
| 514 | kdb_printf("\n"); |
| 515 | if(i >= DUMPFRAMES) kdb_printf(" backtrace continues...\n"); /* Say we terminated early */ |
| 516 | if(i) kmod_dump((vm_offset_t *)&bframes[0], i); /* Show what kmods are in trace */ |
| 517 | |
| 518 | } |
| 519 | |
| 520 | |
| 521 | |
| 522 | void |
| 523 | Debugger(const char *message) { |
| 524 | |
| 525 | int i; |
| 526 | unsigned int store[8]; |
| 527 | unsigned long pi_size = 0; |
| 528 | spl_t spl; |
| 529 | |
| 530 | spl = splhigh(); /* No interruptions from here on */ |
| 531 | |
| 532 | /* |
| 533 | * backtrace for Debugger() call from panic() if no current debugger |
| 534 | * backtrace and return for double panic() call |
| 535 | */ |
| 536 | if ((panicstr != (char *)0) && |
| 537 | (((nestedpanic != 0) && (current_debugger == 1)) || (active_debugger == 0))) { |
| 538 | print_backtrace(NULL); |
| 539 | if (nestedpanic != 0) { |
| 540 | splx(spl); |
| 541 | return; /* Yeah, don't enter again... */ |
| 542 | } |
| 543 | } |
| 544 | |
| 545 | if (debug_mode && getPerProc()->debugger_active) { /* Are we already on debugger on this processor? */ |
| 546 | splx(spl); |
| 547 | return; /* Yeah, don't do it again... */ |
| 548 | } |
| 549 | |
| 550 | |
| 551 | /* |
| 552 | * The above stuff catches the double panic case so we shouldn't have to worry about that here. |
| 553 | */ |
| 554 | if ( panicstr != (char *)0 ) |
| 555 | { |
| 556 | /* diable kernel preemptions */ |
| 557 | disable_preemption(); |
| 558 | |
| 559 | /* everything should be printed now so copy to NVRAM |
| 560 | */ |
| 561 | if( debug_buf_size > 0) |
| 562 | |
| 563 | { |
| 564 | /* Do not compress the panic log unless kernel debugging |
| 565 | * is disabled - the panic log isn't synced to NVRAM if |
| 566 | * debugging is enabled, and the panic log is valuable |
| 567 | * whilst debugging |
| 568 | */ |
| 569 | if (!panicDebugging) |
| 570 | { |
| 571 | unsigned int bufpos; |
| 572 | |
| 573 | /* Now call the compressor */ |
| 574 | bufpos = packAsc (debug_buf, (unsigned int) (debug_buf_ptr - debug_buf) ); |
| 575 | /* If compression was successful, use the compressed length */ |
| 576 | if (bufpos) |
| 577 | { |
| 578 | debug_buf_ptr = debug_buf + bufpos; |
| 579 | } |
| 580 | } |
| 581 | /* Truncate if the buffer is larger than a certain magic |
| 582 | * size - this really ought to be some appropriate fraction |
| 583 | * of the NVRAM image buffer, and is best done in the |
| 584 | * savePanicInfo() or PESavePanicInfo() calls |
| 585 | */ |
| 586 | pi_size = debug_buf_ptr - debug_buf; |
| 587 | pi_size = PESavePanicInfo( debug_buf, ((pi_size > 2040) ? 2040 : pi_size)); |
| 588 | } |
| 589 | |
| 590 | if( !panicDebugging && (pi_size != 0) ) { |
| 591 | int my_cpu; |
| 592 | int tcpu; |
| 593 | |
| 594 | my_cpu = cpu_number(); |
| 595 | debugger_cpu = my_cpu; |
| 596 | |
| 597 | hw_atomic_add(&debug_mode, 1); |
| 598 | PerProcTable[my_cpu].ppe_vaddr->debugger_active++; |
| 599 | lock_debugger(); |
| 600 | |
| 601 | for(tcpu = 0; tcpu < real_ncpus; tcpu++) { |
| 602 | if(tcpu == my_cpu) continue; |
| 603 | hw_atomic_add(&debugger_sync, 1); |
| 604 | (void)cpu_signal(tcpu, SIGPdebug, 0 ,0); |
| 605 | } |
| 606 | (void)hw_cpu_sync(&debugger_sync, LockTimeOut); |
| 607 | debugger_sync = 0; |
| 608 | } |
| 609 | |
| 610 | draw_panic_dialog(); |
| 611 | |
| 612 | if( !panicDebugging && (pi_size != 0)) |
| 613 | PEHaltRestart( kPEHangCPU ); |
| 614 | |
| 615 | enable_preemption(); |
| 616 | } |
| 617 | |
| 618 | |
| 619 | if ((current_debugger != NO_CUR_DB)) { /* If there is a debugger configured, enter it */ |
| 620 | printf("Debugger(%s)\n", message); |
| 621 | TRAP_DEBUGGER; |
| 622 | splx(spl); |
| 623 | return; /* Done debugging for a while */ |
| 624 | } |
| 625 | |
| 626 | printf("\nNo debugger configured - dumping debug information\n"); |
| 627 | printf("MSR=%08X\n",mfmsr()); |
| 628 | print_backtrace(NULL); |
| 629 | splx(spl); |
| 630 | return; |
| 631 | } |
| 632 | |
| 633 | /* |
| 634 | * Here's where we attempt to get some diagnostic information dumped out |
| 635 | * when the system is really confused. We will try to get into the |
| 636 | * debugger as well. |
| 637 | * |
| 638 | * We are here with interrupts disabled and on the debug stack. The savearea |
| 639 | * that was passed in is NOT chained to the activation. |
| 640 | * |
| 641 | * save_r3 contains the failure reason code. |
| 642 | */ |
| 643 | |
| 644 | void SysChoked(int type, savearea *sv) { /* The system is bad dead */ |
| 645 | |
| 646 | unsigned int failcode; |
| 647 | |
| 648 | mp_disable_preemption(); |
| 649 | disableDebugOuput = FALSE; |
| 650 | debug_mode = TRUE; |
| 651 | |
| 652 | failcode = (unsigned int)sv->save_r3; /* Get the failure code */ |
| 653 | if(failcode > failUnknown) failcode = failUnknown; /* Set unknown code code */ |
| 654 | |
| 655 | kprintf("System Failure: cpu=%d; code=%08X (%s)\n", cpu_number(), (unsigned int)sv->save_r3, failNames[failcode]); |
| 656 | kdb_printf("System Failure: cpu=%d; code=%08X (%s)\n", cpu_number(), (unsigned int)sv->save_r3, failNames[failcode]); |
| 657 | |
| 658 | print_backtrace(sv); /* Attempt to print backtrace */ |
| 659 | Call_DebuggerC(type, sv); /* Attempt to get into debugger */ |
| 660 | |
| 661 | if ((current_debugger != NO_CUR_DB)) Call_DebuggerC(type, sv); /* Attempt to get into debugger */ |
| 662 | |
| 663 | } |
| 664 | |
| 665 | |
| 666 | |
| 667 | /* |
| 668 | * When we get here, interruptions are disabled and we are on the debugger stack |
| 669 | * Never, ever, ever, ever enable interruptions from here on |
| 670 | */ |
| 671 | |
| 672 | int Call_DebuggerC( |
| 673 | int type, |
| 674 | struct savearea *saved_state) |
| 675 | { |
| 676 | int directcall, wait; |
| 677 | addr64_t instr_ptr; |
| 678 | ppnum_t instr_pp; |
| 679 | unsigned int instr; |
| 680 | int my_cpu, tcpu, wasdebugger; |
| 681 | struct per_proc_info *pp; |
| 682 | uint64_t nowtime, poptime; |
| 683 | |
| 684 | my_cpu = cpu_number(); /* Get our CPU */ |
| 685 | |
| 686 | #if MACH_KDB |
| 687 | if((debugger_cpu == my_cpu) && /* Do we already own debugger? */ |
| 688 | PerProcTable[my_cpu].ppe_vaddr->debugger_active && /* and are we really active? */ |
| 689 | db_recover && /* and have we set up recovery? */ |
| 690 | (current_debugger == KDB_CUR_DB)) { /* and are we in KDB (only it handles recovery) */ |
| 691 | kdb_trap(type, saved_state); /* Then reenter it... */ |
| 692 | } |
| 693 | #endif |
| 694 | |
| 695 | hw_atomic_add(&debug_mode, 1); /* Indicate we are in debugger */ |
| 696 | PerProcTable[my_cpu].ppe_vaddr->debugger_active++; /* Show active on our CPU */ |
| 697 | |
| 698 | lock_debugger(); /* Insure that only one CPU is in debugger */ |
| 699 | |
| 700 | if(db_im_stepping == my_cpu) { /* Are we just back from a step? */ |
| 701 | enable_preemption_no_check(); /* Enable preemption now */ |
| 702 | db_im_stepping = 0xFFFFFFFF; /* Nobody stepping right now */ |
| 703 | } |
| 704 | |
| 705 | if (debugger_debug) { |
| 706 | #if 0 |
| 707 | kprintf("Call_DebuggerC(%d): %08X %08X, debact = %d\n", my_cpu, type, saved_state, debug_mode); /* (TEST/DEBUG) */ |
| 708 | #endif |
| 709 | printf("Call_Debugger: enter - cpu %d, is_slave %d, debugger_cpu %d, pc %08X\n", |
| 710 | my_cpu, PerProcTable[my_cpu].ppe_vaddr->debugger_is_slave, debugger_cpu, saved_state->save_srr0); |
| 711 | } |
| 712 | |
| 713 | instr_pp = (vm_offset_t)pmap_find_phys(kernel_pmap, (addr64_t)(saved_state->save_srr0)); |
| 714 | |
| 715 | if (instr_pp) { |
| 716 | instr_ptr = (addr64_t)(((addr64_t)instr_pp << 12) | (saved_state->save_srr0 & 0xFFF)); /* Make physical address */ |
| 717 | instr = ml_phys_read_64(instr_ptr); /* Get the trap that caused entry */ |
| 718 | } |
| 719 | else instr = 0; |
| 720 | |
| 721 | #if 0 |
| 722 | if (debugger_debug) kprintf("Call_DebuggerC(%d): instr_pp = %08X, instr_ptr = %016llX, instr = %08X\n", my_cpu, instr_pp, instr_ptr, instr); /* (TEST/DEBUG) */ |
| 723 | #endif |
| 724 | |
| 725 | if (db_breakpoints_inserted) cpus_holding_bkpts++; /* Bump up the holding count */ |
| 726 | if (debugger_cpu == -1 && !PerProcTable[my_cpu].ppe_vaddr->debugger_is_slave) { |
| 727 | #if 0 |
| 728 | if (debugger_debug) kprintf("Call_DebuggerC(%d): lasttrace = %08X\n", my_cpu, lastTrace); /* (TEST/DEBUG) */ |
| 729 | #endif |
| 730 | debugger_cpu = my_cpu; /* Show that we are debugger */ |
| 731 | |
| 732 | |
| 733 | lastTrace = LLTraceSet(0); /* Disable low-level tracing */ |
| 734 | |
| 735 | for(tcpu = 0; tcpu < real_ncpus; tcpu++) { /* Stop all the other guys */ |
| 736 | if(tcpu == my_cpu) continue; /* Don't diddle ourselves */ |
| 737 | hw_atomic_add(&debugger_sync, 1); /* Count signal sent */ |
| 738 | (void)cpu_signal(tcpu, SIGPdebug, 0 ,0); /* Tell 'em to enter debugger */ |
| 739 | } |
| 740 | (void)hw_cpu_sync(&debugger_sync, LockTimeOut); /* Wait for the other processors to enter debug */ |
| 741 | debugger_sync = 0; /* We're done with it */ |
| 742 | } |
| 743 | else if (debugger_cpu != my_cpu) goto debugger_exit; /* We are not debugger, don't continue... */ |
| 744 | |
| 745 | |
| 746 | if (instr == TRAP_DIRECT_INST) { |
| 747 | disableDebugOuput = FALSE; |
| 748 | print_backtrace(saved_state); |
| 749 | } |
| 750 | |
| 751 | switch_debugger = 0; /* Make sure switch request is off */ |
| 752 | directcall = 1; /* Assume direct call */ |
| 753 | |
| 754 | if (saved_state->save_srr1 & MASK(SRR1_PRG_TRAP)) { /* Trap instruction? */ |
| 755 | |
| 756 | directcall = 0; /* We had a trap not a direct call */ |
| 757 | |
| 758 | switch (instr) { /* Select trap type */ |
| 759 | |
| 760 | #if MACH_KDP |
| 761 | case BREAK_TO_KDP0: /* Breakpoint into KDP? */ |
| 762 | case BREAK_TO_KDP1: /* Breakpoint into KDP? */ |
| 763 | current_debugger = KDP_CUR_DB; /* Yes, set KDP */ |
| 764 | kdp_trap(type, saved_state); /* Enter it */ |
| 765 | break; |
| 766 | #endif |
| 767 | |
| 768 | #if MACH_KDB |
| 769 | case BREAK_TO_KDB0: /* Breakpoint to KDB (the "good" debugger)? */ |
| 770 | current_debugger = KDB_CUR_DB; /* Yes, set it */ |
| 771 | kdb_trap(type, saved_state); /* Enter it */ |
| 772 | break; |
| 773 | #endif |
| 774 | |
| 775 | case TRAP_DEBUGGER_INST: /* Should we enter the current debugger? */ |
| 776 | case TRAP_DIRECT_INST: /* Should we enter the current debugger? */ |
| 777 | if (current_debugger == KDP_CUR_DB) /* Is current KDP? */ |
| 778 | kdp_trap(type, saved_state); /* Yes, enter it */ |
| 779 | else if (current_debugger == KDB_CUR_DB) /* Is this KDB? */ |
| 780 | kdb_trap(type, saved_state); /* Yes, go ahead and enter */ |
| 781 | else goto debugger_error; /* No debugger active */ |
| 782 | break; |
| 783 | |
| 784 | default: /* Unknown/bogus trap type */ |
| 785 | goto debugger_error; |
| 786 | } |
| 787 | } |
| 788 | |
| 789 | while(1) { /* We are here to handle debugger switches */ |
| 790 | |
| 791 | if(!directcall) { /* Was this a direct call? */ |
| 792 | if(!switch_debugger) break; /* No, then leave if no switch requested... */ |
| 793 | |
| 794 | /* |
| 795 | * Note: we can only switch to a debugger we have. Ignore bogus switch requests. |
| 796 | */ |
| 797 | #if 0 |
| 798 | if (debugger_debug) kprintf("Call_DebuggerC(%d): switching debuggers\n", my_cpu); /* (TEST/DEBUG) */ |
| 799 | #endif |
| 800 | #if MACH_KDB |
| 801 | if(current_debugger == KDP_CUR_DB) current_debugger = KDB_CUR_DB; /* Switch to KDB */ |
| 802 | #if MACH_KDP |
| 803 | else |
| 804 | #endif |
| 805 | #endif |
| 806 | #if MACH_KDP |
| 807 | if(current_debugger == KDB_CUR_DB) current_debugger = KDP_CUR_DB; /* Switch to KDP */ |
| 808 | #endif |
| 809 | } |
| 810 | |
| 811 | switch_debugger = 0; /* Clear request */ |
| 812 | directcall = 0; /* Clear first-time direct call indication */ |
| 813 | |
| 814 | switch (current_debugger) { /* Enter correct debugger */ |
| 815 | |
| 816 | case KDP_CUR_DB: /* Enter KDP */ |
| 817 | kdp_trap(type, saved_state); |
| 818 | break; |
| 819 | |
| 820 | case KDB_CUR_DB: /* Enter KDB */ |
| 821 | kdb_trap(type, saved_state); |
| 822 | break; |
| 823 | |
| 824 | default: /* No debugger installed */ |
| 825 | goto debugger_error; |
| 826 | break; |
| 827 | } |
| 828 | } |
| 829 | |
| 830 | debugger_exit: |
| 831 | #if 0 |
| 832 | if (debugger_debug) kprintf("Call_DebuggerC(%d): exit - inst = %08X, cpu=%d(%d), run=%d\n", my_cpu, |
| 833 | instr, my_cpu, debugger_cpu, db_run_mode); /* (TEST/DEBUG) */ |
| 834 | #endif |
| 835 | if ((instr == TRAP_DEBUGGER_INST) || /* Did we trap to enter debugger? */ |
| 836 | (instr == TRAP_DIRECT_INST)) saved_state->save_srr0 += TRAP_INST_SIZE; /* Yes, point past trap */ |
| 837 | |
| 838 | wasdebugger = 0; /* Assume not debugger */ |
| 839 | if(debugger_cpu == my_cpu) { /* Are the debugger processor? */ |
| 840 | wasdebugger = 1; /* Remember that we were the debugger */ |
| 841 | LLTraceSet(lastTrace); /* Enable tracing on the way out if we are debugger */ |
| 842 | } |
| 843 | |
| 844 | wait = FALSE; /* Assume we are not going to wait */ |
| 845 | if (db_run_mode == STEP_CONTINUE) { /* Are we going to run? */ |
| 846 | wait = TRUE; /* Yeah, remember to wait for breakpoints to clear */ |
| 847 | debugger_cpu = -1; /* Release other processor's debuggers */ |
| 848 | for(tcpu = 0; tcpu < real_ncpus; tcpu++) |
| 849 | PerProcTable[tcpu].ppe_vaddr->debugger_pending = 0; /* Release request (this is a HACK) */ |
| 850 | NMIss = 0; /* Let NMI bounce */ |
| 851 | } |
| 852 | |
| 853 | if(db_run_mode == STEP_ONCE) { /* Are we about to step? */ |
| 854 | disable_preemption(); /* Disable preemption for the step */ |
| 855 | db_im_stepping = my_cpu; /* Remember that I am about to step */ |
| 856 | } |
| 857 | |
| 858 | if (db_breakpoints_inserted) cpus_holding_bkpts--; /* If any breakpoints, back off count */ |
| 859 | if (PerProcTable[my_cpu].ppe_vaddr->debugger_is_slave) PerProcTable[my_cpu].ppe_vaddr->debugger_is_slave--; /* If we were a slove, uncount us */ |
| 860 | if (debugger_debug) |
| 861 | printf("Call_Debugger: exit - cpu %d, debugger_cpu %d, run_mode %d holds %d\n", |
| 862 | my_cpu, debugger_cpu, db_run_mode, |
| 863 | cpus_holding_bkpts); |
| 864 | |
| 865 | unlock_debugger(); /* Release the lock */ |
| 866 | PerProcTable[my_cpu].ppe_vaddr->debugger_active--; /* Say we aren't active anymore */ |
| 867 | |
| 868 | if (wait) while(cpus_holding_bkpts); /* Wait for breakpoints to clear */ |
| 869 | |
| 870 | |
| 871 | hw_atomic_sub(&debug_mode, 1); /* Set out of debug now */ |
| 872 | |
| 873 | return(1); /* Exit debugger normally */ |
| 874 | |
| 875 | debugger_error: |
| 876 | if(db_run_mode != STEP_ONCE) enable_preemption_no_check(); /* Enable preemption, but don't preempt here */ |
| 877 | hw_atomic_sub(&debug_mode, 1); /* Set out of debug now */ |
| 878 | return(0); /* Return in shame... */ |
| 879 | |
| 880 | } |
| 881 | |
| 882 | void lock_debugger(void) { |
| 883 | int my_cpu; |
| 884 | register int i; |
| 885 | |
| 886 | my_cpu = cpu_number(); /* Get our CPU number */ |
| 887 | |
| 888 | while(1) { /* Check until we get it */ |
| 889 | |
| 890 | if (debugger_cpu != -1 && debugger_cpu != my_cpu) continue; /* Someone, not us, is debugger... */ |
| 891 | if (hw_lock_try(&debugger_lock)) { /* Get the debug lock */ |
| 892 | if (debugger_cpu == -1 || debugger_cpu == my_cpu) break; /* Is it us? */ |
| 893 | hw_lock_unlock(&debugger_lock); /* Not us, release lock */ |
| 894 | } |
| 895 | } |
| 896 | } |
| 897 | |
| 898 | void unlock_debugger(void) { |
| 899 | |
| 900 | hw_lock_unlock(&debugger_lock); |
| 901 | |
| 902 | } |
| 903 | |
| 904 | struct pasc { |
| 905 | unsigned a: 7; |
| 906 | unsigned b: 7; |
| 907 | unsigned c: 7; |
| 908 | unsigned d: 7; |
| 909 | unsigned e: 7; |
| 910 | unsigned f: 7; |
| 911 | unsigned g: 7; |
| 912 | unsigned h: 7; |
| 913 | } __attribute__((packed)); |
| 914 | |
| 915 | typedef struct pasc pasc_t; |
| 916 | |
| 917 | int packAsc (unsigned char *inbuf, unsigned int length) |
| 918 | { |
| 919 | unsigned int i, j = 0; |
| 920 | pasc_t pack; |
| 921 | |
| 922 | for (i = 0; i < length; i+=8) |
| 923 | { |
| 924 | pack.a = inbuf[i]; |
| 925 | pack.b = inbuf[i+1]; |
| 926 | pack.c = inbuf[i+2]; |
| 927 | pack.d = inbuf[i+3]; |
| 928 | pack.e = inbuf[i+4]; |
| 929 | pack.f = inbuf[i+5]; |
| 930 | pack.g = inbuf[i+6]; |
| 931 | pack.h = inbuf[i+7]; |
| 932 | bcopy ((char *) &pack, inbuf + j, 7); |
| 933 | j += 7; |
| 934 | } |
| 935 | if (0 != (i - length)) |
| 936 | inbuf[j - (i - length)] &= 0xFF << (8-(i - length)); |
| 937 | return j-(((i-length) == 7) ? 6 : (i - length)); |
| 938 | } |