|
|
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: #include <cpus.h> ! 27: #include <platforms.h> ! 28: #include <time_stamp.h> ! 29: #include <mach_mp_debug.h> ! 30: #include <mach_ldebug.h> ! 31: #include <db_machine_commands.h> ! 32: ! 33: #include <kern/spl.h> ! 34: #include <kern/cpu_number.h> ! 35: #include <kern/kern_types.h> ! 36: #include <kern/misc_protos.h> ! 37: #include <vm/pmap.h> ! 38: ! 39: #include <ppc/mem.h> ! 40: #include <ppc/thread.h> ! 41: #include <ppc/db_machdep.h> ! 42: #include <ppc/trap.h> ! 43: #include <ppc/setjmp.h> ! 44: #include <ppc/pmap.h> ! 45: #include <ppc/misc_protos.h> ! 46: #include <ppc/exception.h> ! 47: #include <ppc/db_machdep.h> ! 48: #include <ppc/mappings.h> ! 49: #include <ppc/Firmware.h> ! 50: ! 51: #include <mach/vm_param.h> ! 52: #include <mach/machine/vm_types.h> ! 53: #include <vm/vm_map.h> ! 54: #include <kern/thread.h> ! 55: #include <kern/task.h> ! 56: #include <kern/debug.h> ! 57: ! 58: #include <ddb/db_command.h> ! 59: #include <ddb/db_task_thread.h> ! 60: #include <ddb/db_run.h> ! 61: #include <ddb/db_trap.h> ! 62: #include <ddb/db_output.h> ! 63: #include <ddb/db_access.h> ! 64: #include <ddb/db_sym.h> ! 65: #include <ddb/db_break.h> ! 66: #include <ddb/db_watch.h> ! 67: ! 68: struct ppc_saved_state *ppc_last_saved_statep; ! 69: struct ppc_saved_state ppc_nested_saved_state; ! 70: unsigned ppc_last_kdb_sp; ! 71: ! 72: extern int debugger_active[NCPUS]; /* Debugger active on CPU */ ! 73: extern int debugger_cpu; /* Current cpu running debugger */ ! 74: ! 75: int db_all_set_up = 0; ! 76: ! 77: ! 78: #if !MACH_KDP ! 79: void kdp_register_send_receive(void); ! 80: #endif ! 81: ! 82: /* ! 83: * Enter KDB through a keyboard trap. ! 84: * We show the registers as of the keyboard interrupt ! 85: * instead of those at its call to KDB. ! 86: */ ! 87: struct int_regs { ! 88: /* XXX more registers ? */ ! 89: struct ppc_interrupt_state *is; ! 90: }; ! 91: ! 92: extern char * trap_type[]; ! 93: extern int TRAP_TYPES; ! 94: ! 95: /* ! 96: * Code used to synchronize kdb among all cpus, one active at a time, switch ! 97: * from on to another using kdb_on! #cpu or cpu #cpu ! 98: */ ! 99: ! 100: decl_simple_lock_data(, kdb_lock) /* kdb lock */ ! 101: ! 102: #define db_simple_lock_init(l, e) hw_lock_init(&((l)->interlock)) ! 103: #define db_simple_lock_try(l) hw_lock_try(&((l)->interlock)) ! 104: #define db_simple_unlock(l) hw_lock_unlock(&((l)->interlock)) ! 105: ! 106: extern volatile unsigned int cpus_holding_bkpts; /* counter for number of cpus holding ! 107: breakpoints (ie: cpus that did not ! 108: insert back breakpoints) */ ! 109: extern boolean_t db_breakpoints_inserted; ! 110: ! 111: /* Forward */ ! 112: ! 113: extern void kdbprinttrap( ! 114: int type, ! 115: int code, ! 116: int *pc, ! 117: int sp); ! 118: extern int db_user_to_kernel_address( ! 119: task_t task, ! 120: vm_offset_t addr, ! 121: unsigned *kaddr, ! 122: int flag); ! 123: extern void db_write_bytes_user_space( ! 124: vm_offset_t addr, ! 125: int size, ! 126: char *data, ! 127: task_t task); ! 128: extern int db_search_null( ! 129: task_t task, ! 130: unsigned *svaddr, ! 131: unsigned evaddr, ! 132: unsigned *skaddr, ! 133: int flag); ! 134: extern int kdb_enter(int); ! 135: extern void kdb_leave(void); ! 136: extern void lock_kdb(void); ! 137: extern void unlock_kdb(void); ! 138: ! 139: #if DB_MACHINE_COMMANDS ! 140: struct db_command ppc_db_commands[] = { ! 141: { "lt", db_low_trace, CS_MORE|CS_SET_DOT, 0 }, ! 142: { (char *)0, 0, 0, 0 } ! 143: }; ! 144: #endif /* DB_MACHINE_COMMANDS */ ! 145: ! 146: #if !MACH_KDP ! 147: void kdp_register_send_receive(void) {} ! 148: #endif ! 149: ! 150: extern jmp_buf_t *db_recover; ! 151: spl_t saved_ipl[NCPUS]; /* just to know what IPL was before trap */ ! 152: struct ppc_saved_state *saved_state[NCPUS]; ! 153: ! 154: /* ! 155: * kdb_trap - field a TRACE or BPT trap ! 156: */ ! 157: void ! 158: kdb_trap( ! 159: int type, ! 160: struct ppc_saved_state *regs) ! 161: { ! 162: boolean_t trap_from_user; ! 163: int previous_console_device; ! 164: int code=0; ! 165: ! 166: previous_console_device=switch_to_serial_console(); ! 167: ! 168: switch (type) { ! 169: case T_TRACE: /* single_step */ ! 170: case T_PROGRAM: /* breakpoint */ ! 171: #if 0 ! 172: case T_WATCHPOINT: /* watchpoint */ ! 173: #endif ! 174: case -1: /* keyboard interrupt */ ! 175: break; ! 176: ! 177: default: ! 178: if (db_recover) { ! 179: ppc_nested_saved_state = *regs; ! 180: db_printf("Caught "); ! 181: if (type > TRAP_TYPES) ! 182: db_printf("type %d", type); ! 183: else ! 184: db_printf("%s", trap_type[type]); ! 185: db_printf(" trap, pc = %x\n", ! 186: regs->srr0); ! 187: db_error(""); ! 188: /*NOTREACHED*/ ! 189: } ! 190: kdbprinttrap(type, code, (int *)®s->srr0, regs->r1); ! 191: } ! 192: ! 193: saved_state[cpu_number()] = regs; ! 194: ! 195: ppc_last_saved_statep = regs; ! 196: ppc_last_kdb_sp = (unsigned) &type; ! 197: ! 198: if (!IS_USER_TRAP(regs)) { ! 199: bzero((char *)&ddb_regs, sizeof (ddb_regs)); ! 200: ddb_regs = *regs; ! 201: trap_from_user = FALSE; ! 202: ! 203: } ! 204: else { ! 205: ddb_regs = *regs; ! 206: trap_from_user = TRUE; ! 207: } ! 208: ! 209: db_task_trap(type, code, trap_from_user); ! 210: ! 211: *regs = ddb_regs; ! 212: ! 213: if ((type == T_PROGRAM) && ! 214: (db_get_task_value(regs->srr0, ! 215: BKPT_SIZE, ! 216: FALSE, ! 217: db_target_space(current_act(), ! 218: trap_from_user)) ! 219: == BKPT_INST)) ! 220: regs->srr0 += BKPT_SIZE; ! 221: ! 222: kdb_exit: ! 223: saved_state[cpu_number()] = 0; ! 224: switch_to_old_console(previous_console_device); ! 225: ! 226: } ! 227: ! 228: ! 229: /* ! 230: * Print trap reason. ! 231: */ ! 232: ! 233: void ! 234: kdbprinttrap( ! 235: int type, ! 236: int code, ! 237: int *pc, ! 238: int sp) ! 239: { ! 240: printf("kernel: "); ! 241: if (type > TRAP_TYPES) ! 242: db_printf("type %d", type); ! 243: else ! 244: db_printf("%s", trap_type[type]); ! 245: db_printf(" trap, code=%x pc@%x = %x sp=%x\n", ! 246: code, pc, *(int *)pc, sp); ! 247: db_run_mode = STEP_CONTINUE; ! 248: } ! 249: ! 250: /* ! 251: * ! 252: */ ! 253: vm_offset_t db_vtophys( ! 254: space_t space, ! 255: vm_offset_t va) ! 256: { ! 257: register mapping *mp; ! 258: register vm_offset_t pa; ! 259: ! 260: pa = (vm_offset_t)LRA(space,(void *)va); ! 261: ! 262: if (pa != 0) ! 263: return(pa); ! 264: ! 265: mp = hw_lock_phys_vir(space, va); ! 266: if((unsigned int)mp&1) { ! 267: return 0; ! 268: } ! 269: ! 270: if(!mp) { ! 271: return 0; ! 272: } ! 273: ! 274: mp = hw_cpv(mp); /* Convert to virtual address */ ! 275: ! 276: if(!mp->physent) { ! 277: pa = (vm_offset_t)((mp->PTEr & -PAGE_SIZE) | ((unsigned int)va & (PAGE_SIZE-1))); ! 278: } else { ! 279: pa = (vm_offset_t)((mp->physent->pte1 & -PAGE_SIZE) | ((unsigned int)va & (PAGE_SIZE-1))); ! 280: hw_unlock_bit((unsigned int *)&mp->physent->phys_link, PHYS_LOCK); ! 281: } ! 282: ! 283: return(pa); ! 284: } ! 285: ! 286: int ! 287: db_user_to_kernel_address( ! 288: task_t task, ! 289: vm_offset_t addr, ! 290: unsigned *kaddr, ! 291: int flag) ! 292: { ! 293: unsigned int sr_val, raddr; ! 294: ! 295: raddr = (unsigned int)db_vtophys(task->map->pmap->space, trunc_page(addr)); /* Get the real address */ ! 296: ! 297: if (!raddr) { ! 298: if (flag) { ! 299: db_printf("\nno memory is assigned to address %08x\n", addr); ! 300: db_error(0); ! 301: /* NOTREACHED */ ! 302: } ! 303: return -1; ! 304: } ! 305: sr_val = SEG_REG_PROT | task->map->pmap->space ! 306: | ((addr >> 8) & 0x00F00000); ! 307: ! 308: mtsr(SR_COPYIN_NUM, sr_val); ! 309: sync(); ! 310: *kaddr = (addr & 0x0fffffff) | (SR_COPYIN_NUM << 28); ! 311: return(0); ! 312: } ! 313: ! 314: /* ! 315: * Read bytes from task address space for debugger. ! 316: */ ! 317: void ! 318: db_read_bytes( ! 319: vm_offset_t addr, ! 320: int size, ! 321: char *data, ! 322: task_t task) ! 323: { ! 324: int n,max; ! 325: unsigned phys_dst; ! 326: unsigned phys_src; ! 327: unsigned int space; ! 328: ! 329: while (size > 0) { ! 330: if (task != NULL) ! 331: space = task->map->pmap->space; ! 332: else ! 333: space = PPC_SID_KERNEL; ! 334: ! 335: phys_src = (unsigned int)db_vtophys(space, trunc_page(addr)); ! 336: if (phys_src == 0) { ! 337: db_printf("\nno memory is assigned to src address %08x\n", ! 338: addr); ! 339: db_error(0); ! 340: /* NOTREACHED */ ! 341: } ! 342: phys_src = phys_src| (addr & page_mask); ! 343: ! 344: space = PPC_SID_KERNEL; ! 345: ! 346: phys_dst = (unsigned int)db_vtophys(space, trunc_page(data)); ! 347: if (phys_dst == 0) { ! 348: db_printf("\nno memory is assigned to dst address %08x\n", ! 349: data); ! 350: db_error(0); ! 351: /* NOTREACHED */ ! 352: } ! 353: ! 354: phys_dst = phys_dst | (((vm_offset_t) data) & page_mask); ! 355: ! 356: /* don't over-run any page boundaries - check src range */ ! 357: max = ppc_round_page(phys_src) - phys_src; ! 358: if (max > size) ! 359: max = size; ! 360: /* Check destination won't run over boundary either */ ! 361: n = ppc_round_page(phys_dst) - phys_dst; ! 362: if (n < max) ! 363: max = n; ! 364: size -= max; ! 365: addr += max; ! 366: phys_copy(phys_src, phys_dst, max); ! 367: ! 368: /* resync I+D caches */ ! 369: sync_cache(phys_dst, max); ! 370: ! 371: phys_src += max; ! 372: phys_dst += max; ! 373: } ! 374: } ! 375: ! 376: /* ! 377: * Write bytes to task address space for debugger. ! 378: */ ! 379: void ! 380: db_write_bytes( ! 381: vm_offset_t addr, ! 382: int size, ! 383: char *data, ! 384: task_t task) ! 385: { ! 386: int n,max; ! 387: unsigned phys_dst; ! 388: unsigned phys_src; ! 389: unsigned int space; ! 390: ! 391: while (size > 0) { ! 392: space = PPC_SID_KERNEL; ! 393: ! 394: phys_src = (unsigned int)db_vtophys(space, trunc_page(data)); ! 395: if (phys_src == 0) { ! 396: db_printf("\nno memory is assigned to src address %08x\n", ! 397: data); ! 398: db_error(0); ! 399: /* NOTREACHED */ ! 400: } ! 401: ! 402: phys_src = phys_src | (((vm_offset_t) data) & page_mask); ! 403: ! 404: /* space stays as kernel space unless in another task */ ! 405: if (task != NULL) ! 406: space = task->map->pmap->space; ! 407: ! 408: phys_dst = (unsigned int)db_vtophys(space, trunc_page(addr)); ! 409: if (phys_dst == 0) { ! 410: db_printf("\nno memory is assigned to dst address %08x\n", ! 411: addr); ! 412: db_error(0); ! 413: /* NOTREACHED */ ! 414: } ! 415: phys_dst = phys_dst| (addr & page_mask); ! 416: ! 417: /* don't over-run any page boundaries - check src range */ ! 418: max = ppc_round_page(phys_src) - phys_src; ! 419: if (max > size) ! 420: max = size; ! 421: /* Check destination won't run over boundary either */ ! 422: n = ppc_round_page(phys_dst) - phys_dst; ! 423: if (n < max) ! 424: max = n; ! 425: size -= max; ! 426: addr += max; ! 427: phys_copy(phys_src, phys_dst, max); ! 428: ! 429: /* resync I+D caches */ ! 430: sync_cache(phys_dst, max); ! 431: ! 432: phys_src += max; ! 433: phys_dst += max; ! 434: } ! 435: } ! 436: ! 437: boolean_t ! 438: db_check_access( ! 439: vm_offset_t addr, ! 440: int size, ! 441: task_t task) ! 442: { ! 443: register int n; ! 444: unsigned int kern_addr; ! 445: ! 446: if (task == kernel_task || task == TASK_NULL) { ! 447: if (kernel_task == TASK_NULL) ! 448: return(TRUE); ! 449: task = kernel_task; ! 450: } else if (task == TASK_NULL) { ! 451: if (current_act() == THR_ACT_NULL) ! 452: return(FALSE); ! 453: task = current_act()->task; ! 454: } ! 455: while (size > 0) { ! 456: if (db_user_to_kernel_address(task, addr, &kern_addr, 0) < 0) ! 457: return(FALSE); ! 458: n = ppc_trunc_page(addr+PPC_PGBYTES) - addr; ! 459: if (n > size) ! 460: n = size; ! 461: size -= n; ! 462: addr += n; ! 463: } ! 464: return(TRUE); ! 465: } ! 466: ! 467: boolean_t ! 468: db_phys_eq( ! 469: task_t task1, ! 470: vm_offset_t addr1, ! 471: task_t task2, ! 472: vm_offset_t addr2) ! 473: { ! 474: vm_offset_t *physa, *physb; ! 475: ! 476: if ((addr1 & (PPC_PGBYTES-1)) != (addr2 & (PPC_PGBYTES-1))) /* Is byte displacement the same? */ ! 477: return FALSE; ! 478: ! 479: if (task1 == TASK_NULL) { /* See if there is a task active */ ! 480: if (current_act() == THR_ACT_NULL) /* See if there is a current task */ ! 481: return FALSE; ! 482: task1 = current_act()->task; /* If so, use that one */ ! 483: } ! 484: ! 485: if(!(physa = db_vtophys(task1->map->pmap->space, trunc_page(addr1)))) return FALSE; /* Get real address of the first */ ! 486: if(!(physb = db_vtophys(task2->map->pmap->space, trunc_page(addr2)))) return FALSE; /* Get real address of the second */ ! 487: ! 488: return (physa == physb); /* Check if they are equal, then return... */ ! 489: } ! 490: ! 491: #define DB_USER_STACK_ADDR (0xc0000000) ! 492: #define DB_NAME_SEARCH_LIMIT (DB_USER_STACK_ADDR-(PPC_PGBYTES*3)) ! 493: ! 494: int ! 495: db_search_null( ! 496: task_t task, ! 497: unsigned *svaddr, ! 498: unsigned evaddr, ! 499: unsigned *skaddr, ! 500: int flag) ! 501: { ! 502: register unsigned vaddr; ! 503: register unsigned *kaddr; ! 504: ! 505: kaddr = (unsigned *)*skaddr; ! 506: for (vaddr = *svaddr; vaddr > evaddr; ) { ! 507: if (vaddr % PPC_PGBYTES == 0) { ! 508: vaddr -= sizeof(unsigned); ! 509: if (db_user_to_kernel_address(task, vaddr, skaddr, 0) < 0) ! 510: return(-1); ! 511: kaddr = (unsigned *)*skaddr; ! 512: } else { ! 513: vaddr -= sizeof(unsigned); ! 514: kaddr--; ! 515: } ! 516: if ((*kaddr == 0) ^ (flag == 0)) { ! 517: *svaddr = vaddr; ! 518: *skaddr = (unsigned)kaddr; ! 519: return(0); ! 520: } ! 521: } ! 522: return(-1); ! 523: } ! 524: ! 525: void ! 526: db_task_name( ! 527: task_t task) ! 528: { ! 529: register char *p; ! 530: register int n; ! 531: unsigned int vaddr, kaddr; ! 532: ! 533: vaddr = DB_USER_STACK_ADDR; ! 534: kaddr = 0; ! 535: ! 536: /* ! 537: * skip nulls at the end ! 538: */ ! 539: if (db_search_null(task, &vaddr, DB_NAME_SEARCH_LIMIT, &kaddr, 0) < 0) { ! 540: db_printf(DB_NULL_TASK_NAME); ! 541: return; ! 542: } ! 543: /* ! 544: * search start of args ! 545: */ ! 546: if (db_search_null(task, &vaddr, DB_NAME_SEARCH_LIMIT, &kaddr, 1) < 0) { ! 547: db_printf(DB_NULL_TASK_NAME); ! 548: return; ! 549: } ! 550: ! 551: n = DB_TASK_NAME_LEN-1; ! 552: p = (char *)kaddr + sizeof(unsigned); ! 553: for (vaddr += sizeof(int); vaddr < DB_USER_STACK_ADDR && n > 0; ! 554: vaddr++, p++, n--) { ! 555: if (vaddr % PPC_PGBYTES == 0) { ! 556: if (db_user_to_kernel_address(task, vaddr, &kaddr, 0) <0) ! 557: return; ! 558: p = (char*)kaddr; ! 559: } ! 560: db_printf("%c", (*p < ' ' || *p > '~')? ' ': *p); ! 561: } ! 562: while (n-- >= 0) /* compare with >= 0 for one more space */ ! 563: db_printf(" "); ! 564: } ! 565: ! 566: void ! 567: db_machdep_init(void) { ! 568: #define KDB_READY 0x1 ! 569: extern int kdb_flag; ! 570: ! 571: kdb_flag |= KDB_READY; ! 572: } ! 573: ! 574: ! 575: #ifdef __STDC__ ! 576: #define KDB_SAVE(type, name) extern type name; type name##_save = name ! 577: #define KDB_RESTORE(name) name = name##_save ! 578: #else /* __STDC__ */ ! 579: #define KDB_SAVE(type, name) extern type name; type name/**/_save = name ! 580: #define KDB_RESTORE(name) name = name/**/_save ! 581: #endif /* __STDC__ */ ! 582: ! 583: #define KDB_SAVE_CTXT() \ ! 584: KDB_SAVE(int, db_run_mode); \ ! 585: KDB_SAVE(boolean_t, db_sstep_print); \ ! 586: KDB_SAVE(int, db_loop_count); \ ! 587: KDB_SAVE(int, db_call_depth); \ ! 588: KDB_SAVE(int, db_inst_count); \ ! 589: KDB_SAVE(int, db_last_inst_count); \ ! 590: KDB_SAVE(int, db_load_count); \ ! 591: KDB_SAVE(int, db_store_count); \ ! 592: KDB_SAVE(boolean_t, db_cmd_loop_done); \ ! 593: KDB_SAVE(jmp_buf_t *, db_recover); \ ! 594: KDB_SAVE(db_addr_t, db_dot); \ ! 595: KDB_SAVE(db_addr_t, db_last_addr); \ ! 596: KDB_SAVE(db_addr_t, db_prev); \ ! 597: KDB_SAVE(db_addr_t, db_next); \ ! 598: KDB_SAVE(db_regs_t, ddb_regs); ! 599: ! 600: #define KDB_RESTORE_CTXT() \ ! 601: KDB_RESTORE(db_run_mode); \ ! 602: KDB_RESTORE(db_sstep_print); \ ! 603: KDB_RESTORE(db_loop_count); \ ! 604: KDB_RESTORE(db_call_depth); \ ! 605: KDB_RESTORE(db_inst_count); \ ! 606: KDB_RESTORE(db_last_inst_count); \ ! 607: KDB_RESTORE(db_load_count); \ ! 608: KDB_RESTORE(db_store_count); \ ! 609: KDB_RESTORE(db_cmd_loop_done); \ ! 610: KDB_RESTORE(db_recover); \ ! 611: KDB_RESTORE(db_dot); \ ! 612: KDB_RESTORE(db_last_addr); \ ! 613: KDB_RESTORE(db_prev); \ ! 614: KDB_RESTORE(db_next); \ ! 615: KDB_RESTORE(ddb_regs); ! 616: ! 617: /* ! 618: * switch to another cpu ! 619: */ ! 620: void ! 621: kdb_on( ! 622: int cpu) ! 623: { ! 624: KDB_SAVE_CTXT(); ! 625: if (cpu < 0 || cpu >= NCPUS || !debugger_active[cpu]) ! 626: return; ! 627: db_set_breakpoints(); ! 628: db_set_watchpoints(); ! 629: debugger_cpu = cpu; ! 630: unlock_debugger(); ! 631: lock_debugger(); ! 632: db_clear_breakpoints(); ! 633: db_clear_watchpoints(); ! 634: KDB_RESTORE_CTXT(); ! 635: if (debugger_cpu == -1) {/* someone continued */ ! 636: debugger_cpu = cpu_number(); ! 637: db_continue_cmd(0, 0, 0, ""); ! 638: } ! 639: } ! 640: ! 641: /* ! 642: * system reboot ! 643: */ ! 644: void db_reboot( ! 645: db_expr_t addr, ! 646: boolean_t have_addr, ! 647: db_expr_t count, ! 648: char *modif) ! 649: { ! 650: boolean_t reboot = TRUE; ! 651: char *cp, c; ! 652: ! 653: cp = modif; ! 654: while ((c = *cp++) != 0) { ! 655: if (c == 'r') /* reboot */ ! 656: reboot = TRUE; ! 657: if (c == 'h') /* halt */ ! 658: reboot = FALSE; ! 659: } ! 660: halt_all_cpus(reboot); ! 661: } ! 662: ! 663: /* ! 664: * Switch to gdb ! 665: */ ! 666: void ! 667: db_to_gdb( ! 668: void) ! 669: { ! 670: extern unsigned int switch_debugger; ! 671: ! 672: switch_debugger=1; ! 673: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.