|
|
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.