|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1993,1992 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: #include "mach_kdb.h" ! 27: #if MACH_KDB ! 28: ! 29: #include <cpus.h> ! 30: ! 31: #if NCPUS > 1 ! 32: ! 33: #include <mach/boolean.h> ! 34: #include <mach/machine.h> ! 35: ! 36: #include <kern/cpu_number.h> ! 37: #include <kern/lock.h> ! 38: ! 39: #include <machine/db_machdep.h> ! 40: ! 41: #include <ddb/db_command.h> ! 42: #include <ddb/db_run.h> ! 43: ! 44: /* ! 45: * Routines to interlock access to the kernel debugger on ! 46: * multiprocessors. ! 47: */ ! 48: ! 49: decl_simple_lock_data(,db_lock) /* lock to enter debugger */ ! 50: volatile int db_cpu = -1; /* CPU currently in debugger */ ! 51: /* -1 if none */ ! 52: int db_active[NCPUS] = { 0 }; /* count recursive entries ! 53: into debugger */ ! 54: int db_slave[NCPUS] = { 0 }; /* nonzero if cpu interrupted ! 55: by another cpu in debugger */ ! 56: ! 57: int db_enter_debug = 0; ! 58: ! 59: void remote_db(); /* forward */ ! 60: void lock_db(); ! 61: void unlock_db(); ! 62: ! 63: ! 64: /* ! 65: * Called when entering kernel debugger. ! 66: * Takes db lock. If we were called remotely (slave state) we just ! 67: * wait for db_cpu to be equal to cpu_number(). Otherwise enter debugger ! 68: * if not active on another cpu ! 69: */ ! 70: ! 71: boolean_t ! 72: db_enter() ! 73: { ! 74: int mycpu = cpu_number(); ! 75: ! 76: /* ! 77: * Count recursive entries to debugger. ! 78: */ ! 79: db_active[mycpu]++; ! 80: ! 81: /* ! 82: * Wait for other CPUS to leave debugger. ! 83: */ ! 84: lock_db(); ! 85: ! 86: if (db_enter_debug) ! 87: db_printf( ! 88: "db_enter: cpu %d[%d], master %d, db_cpu %d, run mode %d\n", ! 89: mycpu, db_slave[mycpu], master_cpu, db_cpu, db_run_mode); ! 90: ! 91: /* ! 92: * If no CPU in debugger, and I am not being stopped, ! 93: * enter the debugger. ! 94: */ ! 95: if (db_cpu == -1 && !db_slave[mycpu]) { ! 96: remote_db(); /* stop other cpus */ ! 97: db_cpu = mycpu; ! 98: return TRUE; ! 99: } ! 100: /* ! 101: * If I am already in the debugger (recursive entry ! 102: * or returning from single step), enter debugger. ! 103: */ ! 104: else if (db_cpu == mycpu) ! 105: return TRUE; ! 106: /* ! 107: * Otherwise, cannot enter debugger. ! 108: */ ! 109: else ! 110: return FALSE; ! 111: } ! 112: ! 113: /* ! 114: * Leave debugger. ! 115: */ ! 116: void ! 117: db_leave() ! 118: { ! 119: int mycpu = cpu_number(); ! 120: ! 121: /* ! 122: * If continuing, give up debugger ! 123: */ ! 124: if (db_run_mode == STEP_CONTINUE) ! 125: db_cpu = -1; ! 126: ! 127: /* ! 128: * If I am a slave, drop my slave count. ! 129: */ ! 130: if (db_slave[mycpu]) ! 131: db_slave[mycpu]--; ! 132: if (db_enter_debug) ! 133: db_printf("db_leave: cpu %d[%d], db_cpu %d, run_mode %d\n", ! 134: mycpu, db_slave[mycpu], db_cpu, db_run_mode); ! 135: /* ! 136: * Unlock debugger. ! 137: */ ! 138: unlock_db(); ! 139: ! 140: /* ! 141: * Drop recursive entry count. ! 142: */ ! 143: db_active[mycpu]--; ! 144: } ! 145: ! 146: ! 147: /* ! 148: * invoke kernel debugger on slave processors ! 149: */ ! 150: ! 151: void ! 152: remote_db() { ! 153: int my_cpu = cpu_number(); ! 154: register int i; ! 155: ! 156: for (i = 0; i < NCPUS; i++) { ! 157: if (i != my_cpu && ! 158: machine_slot[i].is_cpu && ! 159: machine_slot[i].running) ! 160: { ! 161: cpu_interrupt_to_db(i); ! 162: } ! 163: } ! 164: } ! 165: ! 166: /* ! 167: * Save and restore DB global registers. ! 168: * ! 169: * DB_SAVE_CTXT must be at the start of a block, and ! 170: * DB_RESTORE_CTXT must be in the same block. ! 171: */ ! 172: ! 173: #ifdef __STDC__ ! 174: #define DB_SAVE(type, name) extern type name; type name##_save = name ! 175: #define DB_RESTORE(name) name = name##_save ! 176: #else /* __STDC__ */ ! 177: #define DB_SAVE(type, name) extern type name; type name/**/_save = name ! 178: #define DB_RESTORE(name) name = name/**/_save ! 179: #endif /* __STDC__ */ ! 180: ! 181: #define DB_SAVE_CTXT() \ ! 182: DB_SAVE(int, db_run_mode); \ ! 183: DB_SAVE(boolean_t, db_sstep_print); \ ! 184: DB_SAVE(int, db_loop_count); \ ! 185: DB_SAVE(int, db_call_depth); \ ! 186: DB_SAVE(int, db_inst_count); \ ! 187: DB_SAVE(int, db_last_inst_count); \ ! 188: DB_SAVE(int, db_load_count); \ ! 189: DB_SAVE(int, db_store_count); \ ! 190: DB_SAVE(boolean_t, db_cmd_loop_done); \ ! 191: DB_SAVE(jmp_buf_t *, db_recover); \ ! 192: DB_SAVE(db_addr_t, db_dot); \ ! 193: DB_SAVE(db_addr_t, db_last_addr); \ ! 194: DB_SAVE(db_addr_t, db_prev); \ ! 195: DB_SAVE(db_addr_t, db_next); \ ! 196: SAVE_DDB_REGS ! 197: ! 198: #define DB_RESTORE_CTXT() \ ! 199: DB_RESTORE(db_run_mode); \ ! 200: DB_RESTORE(db_sstep_print); \ ! 201: DB_RESTORE(db_loop_count); \ ! 202: DB_RESTORE(db_call_depth); \ ! 203: DB_RESTORE(db_inst_count); \ ! 204: DB_RESTORE(db_last_inst_count); \ ! 205: DB_RESTORE(db_load_count); \ ! 206: DB_RESTORE(db_store_count); \ ! 207: DB_RESTORE(db_cmd_loop_done); \ ! 208: DB_RESTORE(db_recover); \ ! 209: DB_RESTORE(db_dot); \ ! 210: DB_RESTORE(db_last_addr); \ ! 211: DB_RESTORE(db_prev); \ ! 212: DB_RESTORE(db_next); \ ! 213: RESTORE_DDB_REGS ! 214: ! 215: /* ! 216: * switch to another cpu ! 217: */ ! 218: void ! 219: db_on(cpu) ! 220: int cpu; ! 221: { ! 222: /* ! 223: * Save ddb global variables ! 224: */ ! 225: DB_SAVE_CTXT(); ! 226: ! 227: /* ! 228: * Don`t do if bad CPU number. ! 229: * CPU must also be spinning in db_entry. ! 230: */ ! 231: if (cpu < 0 || cpu >= NCPUS || !db_active[cpu]) ! 232: return; ! 233: ! 234: /* ! 235: * Give debugger to that CPU ! 236: */ ! 237: db_cpu = cpu; ! 238: unlock_db(); ! 239: ! 240: /* ! 241: * Wait for it to come back again ! 242: */ ! 243: lock_db(); ! 244: ! 245: /* ! 246: * Restore ddb globals ! 247: */ ! 248: DB_RESTORE_CTXT(); ! 249: ! 250: if (db_cpu == -1) /* someone continued */ ! 251: db_continue_cmd(0, 0, 0, ""); ! 252: } ! 253: ! 254: /* ! 255: * Called by interprocessor interrupt when one CPU is ! 256: * in kernel debugger and wants to stop other CPUs ! 257: */ ! 258: void ! 259: remote_db_enter() ! 260: { ! 261: db_slave[cpu_number()]++; ! 262: kdb_kintr(); ! 263: } ! 264: ! 265: /* ! 266: * Acquire kernel debugger. ! 267: * Conditional code for forwarding characters from slave to console ! 268: * if console on master only. ! 269: */ ! 270: ! 271: /* ! 272: * As long as db_cpu is not -1 or cpu_number(), we know that debugger ! 273: * is active on another cpu. ! 274: */ ! 275: void ! 276: lock_db() ! 277: { ! 278: int my_cpu = cpu_number(); ! 279: ! 280: for (;;) { ! 281: #if CONSOLE_ON_MASTER ! 282: if (my_cpu == master_cpu) { ! 283: db_console(); ! 284: } ! 285: #endif ! 286: if (db_cpu != -1 && db_cpu != my_cpu) ! 287: continue; ! 288: ! 289: #if CONSOLE_ON_MASTER ! 290: if (my_cpu == master_cpu) { ! 291: if (!simple_lock_try(&db_lock)) ! 292: continue; ! 293: } ! 294: else { ! 295: simple_lock(&db_lock); ! 296: } ! 297: #else ! 298: simple_lock(&db_lock); ! 299: #endif ! 300: if (db_cpu == -1 || db_cpu == my_cpu) ! 301: break; ! 302: simple_unlock(&db_lock); ! 303: } ! 304: } ! 305: ! 306: void ! 307: unlock_db() ! 308: { ! 309: simple_unlock(&db_lock); ! 310: } ! 311: ! 312: #ifdef sketch ! 313: void ! 314: db_console() ! 315: { ! 316: if (i_bit(CBUS_PUT_CHAR, my_word)) { ! 317: volatile u_char c = cbus_ochar; ! 318: i_bit_clear(CBUS_PUT_CHAR, my_word); ! 319: cnputc(c); ! 320: } else if (i_bit(CBUS_GET_CHAR, my_word)) { ! 321: if (cbus_wait_char) ! 322: cbus_ichar = cngetc(); ! 323: else ! 324: cbus_ichar = cnmaygetc(); ! 325: i_bit_clear(CBUS_GET_CHAR, my_word); ! 326: #ifndef notdef ! 327: } else if (!cnmaygetc()) { ! 328: #else /* notdef */ ! 329: } else if (com_is_char() && !com_getc(TRUE)) { ! 330: #endif /* notdef */ ! 331: simple_unlock(&db_lock); ! 332: db_cpu = my_cpu; ! 333: } ! 334: } ! 335: #endif /* sketch */ ! 336: ! 337: #endif /* NCPUS > 1 */ ! 338: ! 339: #endif MACH_KDB
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.