|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 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 [email protected] 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: #include <cpus.h> ! 61: ! 62: #include <kern/thread.h> ! 63: #include <machine/pmap.h> ! 64: #include <machine/mach_param.h> ! 65: #include <device/device_types.h> ! 66: ! 67: #include <mach/vm_param.h> ! 68: #include <mach/clock_types.h> ! 69: #include <mach/machine.h> ! 70: #include <ppc/boot.h> ! 71: ! 72: #include <kern/misc_protos.h> ! 73: #include <kern/startup.h> ! 74: #include <ppc/misc_protos.h> ! 75: #include <ppc/proc_reg.h> ! 76: #include <ppc/thread.h> ! 77: #include <ppc/asm.h> ! 78: #include <ppc/mem.h> ! 79: #include <ppc/Firmware.h> ! 80: #include <ppc/mappings.h> ! 81: #include <ppc/FirmwareCalls.h> ! 82: #include <ppc/setjmp.h> ! 83: #include <ppc/exception.h> ! 84: ! 85: #include <kern/clock.h> ! 86: #include <kern/debug.h> ! 87: #include <machine/trap.h> ! 88: #include <kern/spl.h> ! 89: #include <pexpert/pexpert.h> ! 90: #include <ppc/mp.h> ! 91: ! 92: #include <IOKit/IOPlatformExpert.h> ! 93: ! 94: #include <mach/vm_prot.h> ! 95: #include <vm/pmap.h> ! 96: #include <mach/time_value.h> ! 97: #include <machine/machparam.h> /* for btop */ ! 98: ! 99: #if MACH_KDB ! 100: #include <ddb/db_aout.h> ! 101: #include <ddb/db_output.h> ! 102: #include <ddb/db_command.h> ! 103: #include <machine/db_machdep.h> ! 104: ! 105: extern struct db_command ppc_db_commands[]; ! 106: #endif /* MACH_KDB */ ! 107: ! 108: char kernel_args_buf[256] = "/mach_kernel"; ! 109: char boot_args_buf[256] = "/mach_servers/bootstrap"; ! 110: char env_buf[256]; ! 111: ! 112: #define TRAP_DEBUGGER __asm__ volatile("tw 4,r3,r3"); ! 113: #define TRAP_DEBUGGER_INST 0x7c831808 ! 114: #define TRAP_DIRECT __asm__ volatile("tw 4,r4,r4"); ! 115: #define TRAP_DIRECT_INST 0x7c842008 ! 116: #define TRAP_INST_SIZE 4 ! 117: #define BREAK_TO_KDP0 0x7fe00008 ! 118: #define BREAK_TO_KDP1 0x7c800008 ! 119: #define BREAK_TO_KDB0 0x7c810808 ! 120: ! 121: /* ! 122: * Code used to synchronize debuggers among all cpus, one active at a time, switch ! 123: * from on to another using kdb_on! #cpu or cpu #cpu ! 124: */ ! 125: ! 126: decl_simple_lock_data(, debugger_lock) /* debugger lock */ ! 127: ! 128: int debugger_cpu = -1; /* current cpu running debugger */ ! 129: int debugger_debug = 0; /* Debug debugger */ ! 130: int debugger_is_slave[NCPUS]; /* Show that we were entered via sigp */ ! 131: int debugger_active[NCPUS]; /* Debugger active on CPU */ ! 132: int debugger_pending[NCPUS]; /* Debugger entry pending on CPU (this is a HACK) */ ! 133: int debugger_holdoff[NCPUS]; /* Holdoff debugger entry on this CPU (this is a HACK) */ ! 134: int db_run_mode; /* Debugger run mode */ ! 135: unsigned int debugger_sync = 0; /* Cross processor debugger entry sync */ ! 136: ! 137: unsigned int lastTrace; /* Value of low-level exception trace controls */ ! 138: ! 139: volatile unsigned int cpus_holding_bkpts; /* counter for number of cpus holding ! 140: breakpoints (ie: cpus that did not ! 141: insert back breakpoints) */ ! 142: void unlock_debugger(void); ! 143: void lock_debugger(void); ! 144: ! 145: #if !MACH_KDB ! 146: boolean_t db_breakpoints_inserted = TRUE; ! 147: jmp_buf_t *db_recover = 0; ! 148: #endif ! 149: ! 150: #if MACH_KDB ! 151: #include <ddb/db_run.h> ! 152: int kdb_flag=0; ! 153: extern boolean_t db_breakpoints_inserted; ! 154: extern jmp_buf_t *db_recover; ! 155: #define KDB_READY 0x1 ! 156: #endif ! 157: ! 158: #if MACH_KDP ! 159: extern int kdp_flag; ! 160: #define KDP_READY 0x1 ! 161: #endif ! 162: ! 163: extern const char version[]; ! 164: ! 165: #if !MACH_KDB ! 166: void kdb_trap(int type, struct ppc_saved_state *regs); ! 167: void kdb_trap(int type, struct ppc_saved_state *regs) { ! 168: return; ! 169: } ! 170: #endif ! 171: ! 172: #if !MACH_KDP ! 173: void kdp_trap(int type, struct ppc_saved_state *regs); ! 174: void kdp_trap(int type, struct ppc_saved_state *regs) { ! 175: return; ! 176: } ! 177: #endif ! 178: ! 179: void ! 180: machine_startup(boot_args *args) ! 181: { ! 182: int boot_arg; ! 183: ! 184: if (PE_parse_boot_arg("cpus", &wncpu)) { ! 185: if (!((wncpu > 0) && (wncpu < NCPUS))) ! 186: wncpu = NCPUS; ! 187: } else ! 188: wncpu = NCPUS; ! 189: ! 190: if( PE_get_hotkey( kPEControlKey )) ! 191: halt_in_debugger = halt_in_debugger ? 0 : 1; ! 192: ! 193: if (PE_parse_boot_arg("debug", &boot_arg)) { ! 194: if (boot_arg & DB_HALT) halt_in_debugger=1; ! 195: if (boot_arg & DB_PRT) disableDebugOuput=FALSE; ! 196: } ! 197: ! 198: hw_lock_init(&debugger_lock); /* initialized debugger lock */ ! 199: ! 200: #if MACH_KDB ! 201: /* ! 202: * Initialize KDB ! 203: */ ! 204: #if DB_MACHINE_COMMANDS ! 205: db_machine_commands_install(ppc_db_commands); ! 206: #endif /* DB_MACHINE_COMMANDS */ ! 207: ddb_init(); ! 208: ! 209: if (boot_arg & DB_KDB) ! 210: current_debugger = KDB_CUR_DB; ! 211: ! 212: /* ! 213: * Cause a breakpoint trap to the debugger before proceeding ! 214: * any further if the proper option bit was specified in ! 215: * the boot flags. ! 216: */ ! 217: if (halt_in_debugger && (current_debugger == KDB_CUR_DB)) { ! 218: Debugger("inline call to debugger(machine_startup)"); ! 219: halt_in_debugger = 0; ! 220: active_debugger =1; ! 221: } ! 222: #endif /* MACH_KDB */ ! 223: if (PE_parse_boot_arg("preempt", &boot_arg)) { ! 224: extern int default_preemption_rate; ! 225: ! 226: default_preemption_rate = boot_arg; ! 227: } ! 228: ! 229: machine_conf(); ! 230: ! 231: /* ! 232: * Start the system. ! 233: */ ! 234: setup_main(); ! 235: ! 236: /* Should never return */ ! 237: } ! 238: ! 239: char * ! 240: machine_boot_info( ! 241: char *buf, ! 242: vm_size_t size) ! 243: { ! 244: return(PE_boot_args()); ! 245: } ! 246: ! 247: const char * getenv(const char *name); ! 248: ! 249: const char * getenv(const char *name) ! 250: { ! 251: return NULL; ! 252: } ! 253: ! 254: void ! 255: machine_conf(void) ! 256: { ! 257: machine_info.max_cpus = NCPUS; ! 258: machine_info.avail_cpus = 1; ! 259: machine_info.memory_size = mem_size; ! 260: } ! 261: ! 262: void ! 263: machine_init(void) ! 264: { ! 265: clock_config(); ! 266: } ! 267: ! 268: void slave_machine_init(void) ! 269: { ! 270: clock_init(); ! 271: cpu_machine_init(); ! 272: } ! 273: ! 274: void ! 275: halt_all_cpus(boolean_t reboot) ! 276: { ! 277: if(reboot) ! 278: { ! 279: printf("MACH Reboot\n"); ! 280: PEHaltRestart(kPERestartCPU); ! 281: } ! 282: else ! 283: { ! 284: printf("CPU halted\n"); ! 285: PEHaltRestart(kPEHaltCPU); ! 286: } ! 287: while(1); ! 288: } ! 289: ! 290: void ! 291: halt_cpu(void) ! 292: { ! 293: halt_all_cpus(FALSE); ! 294: } ! 295: ! 296: #if MACH_ASSERT ! 297: /* ! 298: * Machine-dependent routine to fill in an array with up to callstack_max ! 299: * levels of return pc information. ! 300: */ ! 301: void machine_callstack( ! 302: natural_t *buf, ! 303: vm_size_t callstack_max) ! 304: { ! 305: } ! 306: #endif /* MACH_ASSERT */ ! 307: ! 308: void ! 309: print_backtrace(struct ppc_saved_state *ssp) ! 310: { ! 311: unsigned int *stackptr, *raddr, *rstack, trans; ! 312: int i, skip_top_frames; ! 313: unsigned int store[8]; /* Buffer for real storage reads */ ! 314: ! 315: printf("backtrace: "); ! 316: ! 317: /* Get our stackpointer for backtrace */ ! 318: if (ssp==NULL) { ! 319: __asm__ volatile("mr %0, r1" : "=r" (stackptr)); ! 320: skip_top_frames = 1; ! 321: } else { ! 322: stackptr = (unsigned int *)(ssp->r1); ! 323: skip_top_frames = 0; ! 324: printf("0x%08x ", ssp->srr0); ! 325: } ! 326: ! 327: for (i = 0; i < 32; i++) { ! 328: ! 329: if(!stackptr) break; /* No more to get... */ ! 330: ! 331: /* Avoid causing page fault */ ! 332: if (!(raddr = LRA(PPC_SID_KERNEL, (void *)((unsigned int)stackptr+FM_LR_SAVE)))) ! 333: break; ! 334: ReadReal((unsigned int)raddr, &store[0]); ! 335: if (skip_top_frames) ! 336: skip_top_frames--; ! 337: else ! 338: printf("0x%08x ",store[0]); ! 339: if (!(raddr = LRA(PPC_SID_KERNEL, (void *)stackptr))) ! 340: break; ! 341: ReadReal((unsigned int)raddr, &store[0]); ! 342: stackptr=(unsigned int *)store[0]; ! 343: } ! 344: printf("\n"); ! 345: } ! 346: ! 347: void ! 348: Debugger(const char *message) { ! 349: ! 350: int i; ! 351: unsigned int store[8]; ! 352: spl_t spl; ! 353: ! 354: spl = splhigh(); /* No interruptions from here on */ ! 355: ! 356: /* ! 357: * backtrace for Debugger() call from panic() if no current debugger ! 358: * backtrace and return for double panic() call ! 359: */ ! 360: if ((panicstr != (char *)0) && ! 361: (((nestedpanic != 0) && (current_debugger == 1)) || (active_debugger == 0))) { ! 362: print_backtrace(NULL); ! 363: if (nestedpanic != 0) { ! 364: splx(spl); ! 365: return; /* Yeah, don't enter again... */ ! 366: } ! 367: } ! 368: ! 369: if (debug_mode && debugger_active[cpu_number()]) { /* Are we already on debugger on this processor? */ ! 370: splx(spl); ! 371: return; /* Yeah, don't do it again... */ ! 372: } ! 373: ! 374: if ((current_debugger != NO_CUR_DB)) { /* If there is a debugger configured, enter it */ ! 375: printf("Debugger(%s)\n", message); ! 376: TRAP_DEBUGGER; ! 377: splx(spl); ! 378: return; /* Done debugging for a while */ ! 379: } ! 380: ! 381: printf("\nNo debugger configured - dumping debug information\n"); ! 382: printf("\nversion string : %s\n",version); ! 383: mfdbatu(store[0],0); ! 384: mfdbatl(store[1],0); ! 385: mfdbatu(store[2],1); ! 386: mfdbatl(store[3],1); ! 387: mfdbatu(store[4],2); ! 388: mfdbatl(store[5],2); ! 389: mfdbatu(store[6],3); ! 390: mfdbatl(store[7],3); ! 391: printf("DBAT0: %08X %08X\n", store[0], store[1]); ! 392: printf("DBAT1: %08X %08X\n", store[2], store[3]); ! 393: printf("DBAT2: %08X %08X\n", store[4], store[5]); ! 394: printf("DBAT3: %08X %08X\n", store[6], store[7]); ! 395: printf("MSR=%08X\n",mfmsr()); ! 396: print_backtrace(NULL); ! 397: splx(spl); ! 398: return; ! 399: } ! 400: ! 401: /* ! 402: * When we get here, interruptions are disabled and we are on the debugger stack ! 403: * Never, ever, ever, ever enable interruptions from here on ! 404: */ ! 405: ! 406: int Call_DebuggerC( ! 407: int type, ! 408: struct ppc_saved_state *saved_state) ! 409: { ! 410: int directcall, wait; ! 411: vm_offset_t instr_ptr; ! 412: unsigned int instr; ! 413: int my_cpu, tcpu; ! 414: ! 415: my_cpu = cpu_number(); /* Get our CPU */ ! 416: ! 417: #if MACH_KDB ! 418: if((debugger_cpu == my_cpu) && /* Do we already own debugger? */ ! 419: debugger_active[my_cpu] && /* and are we really active? */ ! 420: db_recover && /* and have we set up recovery? */ ! 421: (current_debugger == KDB_CUR_DB)) { /* and are we in KDB (only it handles recovery) */ ! 422: kdb_trap(type, saved_state); /* Then reenter it... */ ! 423: } ! 424: #endif ! 425: ! 426: ! 427: hw_atomic_add(&debug_mode, 1); /* Indicate we are in debugger */ ! 428: debugger_active[my_cpu]++; /* Show active on our CPU */ ! 429: lock_debugger(); /* Insure that only one CPU is in debugger */ ! 430: ! 431: if (debugger_debug) { ! 432: #if 0 ! 433: kprintf("Call_DebuggerC(%d): %08X %08X, debact = %d\n", my_cpu, type, saved_state, debug_mode); /* (TEST/DEBUG) */ ! 434: #endif ! 435: printf("Call_Debugger: enter - cpu %d, is_slave %d, debugger_cpu %d, pc %08X\n", ! 436: my_cpu, debugger_is_slave[my_cpu], debugger_cpu, saved_state->srr0); ! 437: } ! 438: ! 439: if (instr_ptr = (vm_offset_t)LRA(PPC_SID_KERNEL, (void *)(saved_state->srr0))) { ! 440: instr = ml_phys_read(instr_ptr); /* Get the trap that caused entry */ ! 441: } ! 442: else instr = 0; ! 443: ! 444: #if 0 ! 445: if (debugger_debug) kprintf("Call_DebuggerC(%d): instr_ptr = %08X, instr = %08X\n", my_cpu, instr_ptr, instr); /* (TEST/DEBUG) */ ! 446: #endif ! 447: ! 448: if (db_breakpoints_inserted) cpus_holding_bkpts++; /* Bump up the holding count */ ! 449: if (debugger_cpu == -1 && !debugger_is_slave[my_cpu]) { ! 450: #if 0 ! 451: if (debugger_debug) kprintf("Call_DebuggerC(%d): lasttrace = %08X\n", my_cpu, lastTrace); /* (TEST/DEBUG) */ ! 452: #endif ! 453: debugger_cpu = my_cpu; /* Show that we are debugger */ ! 454: lastTrace = LLTraceSet(0); /* Disable low-level tracing */ ! 455: ! 456: for(tcpu = 0; tcpu < NCPUS; tcpu++) { /* Stop all the other guys */ ! 457: if(tcpu == my_cpu) continue; /* Don't diddle ourselves */ ! 458: hw_atomic_add(&debugger_sync, 1); /* Count signal sent */ ! 459: (void)cpu_signal(tcpu, SIGPdebug); /* Tell 'em to enter debugger */ ! 460: } ! 461: (void)hw_cpu_sync(&debugger_sync, LockTimeOut); /* Wait for the other processors to enter debug */ ! 462: debugger_sync = 0; /* We're done with it */ ! 463: } ! 464: else if (debugger_cpu != my_cpu) goto debugger_exit; /* We are not debugger, don't continue... */ ! 465: ! 466: ! 467: if (instr == TRAP_DIRECT_INST) { ! 468: disableDebugOuput = FALSE; ! 469: print_backtrace(saved_state); ! 470: } ! 471: ! 472: switch_debugger = 0; /* Make sure switch request is off */ ! 473: directcall = 1; /* Assume direct call */ ! 474: ! 475: if (saved_state->srr1 & MASK(SRR1_PRG_TRAP)) { /* Trap instruction? */ ! 476: ! 477: directcall = 0; /* We had a trap not a direct call */ ! 478: ! 479: switch (instr) { /* Select trap type */ ! 480: ! 481: #if MACH_KDP ! 482: case BREAK_TO_KDP0: /* Breakpoint into KDP? */ ! 483: case BREAK_TO_KDP1: /* Breakpoint into KDP? */ ! 484: current_debugger = KDP_CUR_DB; /* Yes, set KDP */ ! 485: kdp_trap(type, saved_state); /* Enter it */ ! 486: break; ! 487: #endif ! 488: ! 489: #if MACH_KDB ! 490: case BREAK_TO_KDB0: /* Breakpoint to KDB (the "good" debugger)? */ ! 491: current_debugger = KDB_CUR_DB; /* Yes, set it */ ! 492: kdb_trap(type, saved_state); /* Enter it */ ! 493: break; ! 494: #endif ! 495: ! 496: case TRAP_DEBUGGER_INST: /* Should we enter the current debugger? */ ! 497: case TRAP_DIRECT_INST: /* Should we enter the current debugger? */ ! 498: if (current_debugger == KDP_CUR_DB) /* Is current KDP? */ ! 499: kdp_trap(type, saved_state); /* Yes, enter it */ ! 500: else if (current_debugger == KDB_CUR_DB) /* Is this KDB? */ ! 501: kdb_trap(type, saved_state); /* Yes, go ahead and enter */ ! 502: else goto debugger_error; /* No debugger active */ ! 503: break; ! 504: ! 505: default: /* Unknown/bogus trap type */ ! 506: goto debugger_error; ! 507: } ! 508: } ! 509: ! 510: while(1) { /* We are here to handle debugger switches */ ! 511: ! 512: if(!directcall) { /* Was this a direct call? */ ! 513: if(!switch_debugger) break; /* No, then leave if no switch requested... */ ! 514: ! 515: /* ! 516: * Note: we can only switch to a debugger we have. Ignore bogus switch requests. ! 517: */ ! 518: #if 0 ! 519: if (debugger_debug) kprintf("Call_DebuggerC(%d): switching debuggers\n", my_cpu); /* (TEST/DEBUG) */ ! 520: #endif ! 521: #if MACH_KDB ! 522: if(current_debugger == KDP_CUR_DB) current_debugger = KDB_CUR_DB; /* Switch to KDB */ ! 523: #if MACH_KDP ! 524: else ! 525: #endif ! 526: #endif ! 527: #if MACH_KDP ! 528: if(current_debugger == KDB_CUR_DB) current_debugger = KDP_CUR_DB; /* Switch to KDP */ ! 529: #endif ! 530: } ! 531: ! 532: switch_debugger = 0; /* Clear request */ ! 533: directcall = 0; /* Clear first-time direct call indication */ ! 534: ! 535: switch (current_debugger) { /* Enter correct debugger */ ! 536: ! 537: case KDP_CUR_DB: /* Enter KDP */ ! 538: kdp_trap(type, saved_state); ! 539: break; ! 540: ! 541: case KDB_CUR_DB: /* Enter KDB */ ! 542: kdb_trap(type, saved_state); ! 543: break; ! 544: ! 545: default: /* No debugger installed */ ! 546: goto debugger_error; ! 547: break; ! 548: } ! 549: } ! 550: ! 551: debugger_exit: ! 552: #if 0 ! 553: if (debugger_debug) kprintf("Call_DebuggerC(%d): exit - inst = %08X, cpu=%d(%d), run=%d\n", my_cpu, ! 554: instr, my_cpu, debugger_cpu, db_run_mode); /* (TEST/DEBUG) */ ! 555: #endif ! 556: if ((instr == TRAP_DEBUGGER_INST) || /* Did we trap to enter debugger? */ ! 557: (instr == TRAP_DIRECT_INST)) saved_state->srr0 += TRAP_INST_SIZE; /* Yes, point past trap */ ! 558: ! 559: if(debugger_cpu == my_cpu) LLTraceSet(lastTrace); /* Enable tracing on the way out if we are debugger */ ! 560: ! 561: wait = FALSE; /* Assume we are not going to wait */ ! 562: if (db_run_mode == STEP_CONTINUE) { /* Are we going to run? */ ! 563: wait = TRUE; /* Yeah, remember to wait for breakpoints to clear */ ! 564: debugger_cpu = -1; /* Release other processor's debuggers */ ! 565: debugger_pending[0] = 0; /* Release request (this is a HACK) */ ! 566: debugger_pending[1] = 0; /* Release request (this is a HACK) */ ! 567: } ! 568: ! 569: if (db_breakpoints_inserted) cpus_holding_bkpts--; /* If any breakpoints, back off count */ ! 570: if (debugger_is_slave[my_cpu]) debugger_is_slave[my_cpu]--; /* If we were a slove, uncount us */ ! 571: if (debugger_debug) ! 572: printf("Call_Debugger: exit - cpu %d, debugger_cpu %d, run_mode %d holds %d\n", ! 573: my_cpu, debugger_cpu, db_run_mode, ! 574: cpus_holding_bkpts); ! 575: ! 576: unlock_debugger(); /* Release the lock */ ! 577: debugger_active[my_cpu]--; /* Say we aren't active anymore */ ! 578: ! 579: if (wait) while(cpus_holding_bkpts); /* Wait for breakpoints to clear */ ! 580: ! 581: hw_atomic_sub(&debug_mode, 1); /* Set out of debug now */ ! 582: ! 583: return(1); /* Exit debugger normally */ ! 584: ! 585: debugger_error: ! 586: hw_atomic_sub(&debug_mode, 1); /* Set out of debug now */ ! 587: return(0); /* Return in shame... */ ! 588: ! 589: } ! 590: ! 591: void lock_debugger(void) { ! 592: int my_cpu; ! 593: register int i; ! 594: ! 595: my_cpu = cpu_number(); /* Get our CPU number */ ! 596: ! 597: while(1) { /* Check until we get it */ ! 598: ! 599: if (debugger_cpu != -1 && debugger_cpu != my_cpu) continue; /* Someone, not us, is debugger... */ ! 600: if (hw_lock_try(&debugger_lock)) { /* Get the debug lock */ ! 601: if (debugger_cpu == -1 || debugger_cpu == my_cpu) break; /* Is it us? */ ! 602: hw_lock_unlock(&debugger_lock); /* Not us, release lock */ ! 603: } ! 604: } ! 605: } ! 606: ! 607: void unlock_debugger(void) { ! 608: ! 609: hw_lock_unlock(&debugger_lock); ! 610: ! 611: } ! 612: ! 613:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.