FreeBSD/Linux Kernel Cross Reference
sys/ddb/db_mp.c
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 Software.Distribution@CS.CMU.EDU
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 /*
27 * HISTORY
28 * $Log: db_mp.c,v $
29 * Revision 2.4 93/11/17 16:23:28 dbg
30 * ANSI-fied. Include kern/machine.h for machine_slot.
31 * [93/11/03 dbg]
32 *
33 * Revision 2.3 93/01/19 09:00:53 danner
34 * More info in debugging printouts.
35 * [92/12/26 af]
36 *
37 * Revision 2.2 93/01/14 17:25:20 danner
38 * Made more machine-independent, as alpha and mips keep
39 * register states on stack. Spots.
40 * [92/12/16 12:44:42 af]
41 *
42 * Pulled code from OSF/Grenoble and restructured.
43 * [92/10/24 dbg]
44 *
45 */
46 #include <cpus.h>
47
48 #if NCPUS > 1
49
50 #include <mach/boolean.h>
51
52 #include <kern/cpu_number.h>
53 #include <kern/lock.h>
54 #include <kern/machine.h>
55
56 #include <machine/db_machdep.h>
57
58 #include <ddb/db_command.h>
59 #include <ddb/db_output.h>
60 #include <ddb/db_run.h>
61
62 /*
63 * Routines to interlock access to the kernel debugger on
64 * multiprocessors.
65 */
66
67 decl_simple_lock_data(,db_lock) /* lock to enter debugger */
68 volatile int db_cpu = -1; /* CPU currently in debugger */
69 /* -1 if none */
70 int db_active[NCPUS] = { 0 }; /* count recursive entries
71 into debugger */
72 int db_slave[NCPUS] = { 0 }; /* nonzero if cpu interrupted
73 by another cpu in debugger */
74
75 int db_enter_debug = 0;
76
77 void remote_db(void); /* forward */
78 void lock_db(void);
79 void unlock_db(void);
80
81
82 /*
83 * Called when entering kernel debugger.
84 * Takes db lock. If we were called remotely (slave state) we just
85 * wait for db_cpu to be equal to cpu_number(). Otherwise enter debugger
86 * if not active on another cpu
87 */
88
89 boolean_t
90 db_enter(void)
91 {
92 int mycpu = cpu_number();
93
94 /*
95 * Count recursive entries to debugger.
96 */
97 db_active[mycpu]++;
98
99 /*
100 * Wait for other CPUS to leave debugger.
101 */
102 lock_db();
103
104 if (db_enter_debug)
105 db_printf(
106 "db_enter: cpu %d[%d], master %d, db_cpu %d, run mode %d\n",
107 mycpu, db_slave[mycpu], master_cpu, db_cpu, db_run_mode);
108
109 /*
110 * If no CPU in debugger, and I am not being stopped,
111 * enter the debugger.
112 */
113 if (db_cpu == -1 && !db_slave[mycpu]) {
114 remote_db(); /* stop other cpus */
115 db_cpu = mycpu;
116 return TRUE;
117 }
118 /*
119 * If I am already in the debugger (recursive entry
120 * or returning from single step), enter debugger.
121 */
122 else if (db_cpu == mycpu)
123 return TRUE;
124 /*
125 * Otherwise, cannot enter debugger.
126 */
127 else
128 return FALSE;
129 }
130
131 /*
132 * Leave debugger.
133 */
134 void
135 db_leave(void)
136 {
137 int mycpu = cpu_number();
138
139 /*
140 * If continuing, give up debugger
141 */
142 if (db_run_mode == STEP_CONTINUE)
143 db_cpu = -1;
144
145 /*
146 * If I am a slave, drop my slave count.
147 */
148 if (db_slave[mycpu])
149 db_slave[mycpu]--;
150 if (db_enter_debug)
151 db_printf("db_leave: cpu %d[%d], db_cpu %d, run_mode %d\n",
152 mycpu, db_slave[mycpu], db_cpu, db_run_mode);
153 /*
154 * Unlock debugger.
155 */
156 unlock_db();
157
158 /*
159 * Drop recursive entry count.
160 */
161 db_active[mycpu]--;
162 }
163
164
165 /*
166 * invoke kernel debugger on slave processors
167 */
168
169 void
170 remote_db(void) {
171 int my_cpu = cpu_number();
172 register int i;
173
174 for (i = 0; i < NCPUS; i++) {
175 if (i != my_cpu &&
176 machine_slot[i].is_cpu &&
177 machine_slot[i].running)
178 {
179 cpu_interrupt_to_db(i);
180 }
181 }
182 }
183
184 /*
185 * Save and restore DB global registers.
186 *
187 * DB_SAVE_CTXT must be at the start of a block, and
188 * DB_RESTORE_CTXT must be in the same block.
189 */
190
191 #ifdef __STDC__
192 #define DB_SAVE(type, name) extern type name; type name##_save = name
193 #define DB_RESTORE(name) name = name##_save
194 #else /* __STDC__ */
195 #define DB_SAVE(type, name) extern type name; type name/**/_save = name
196 #define DB_RESTORE(name) name = name/**/_save
197 #endif /* __STDC__ */
198
199 #define DB_SAVE_CTXT() \
200 DB_SAVE(int, db_run_mode); \
201 DB_SAVE(boolean_t, db_sstep_print); \
202 DB_SAVE(int, db_loop_count); \
203 DB_SAVE(int, db_call_depth); \
204 DB_SAVE(int, db_inst_count); \
205 DB_SAVE(int, db_last_inst_count); \
206 DB_SAVE(int, db_load_count); \
207 DB_SAVE(int, db_store_count); \
208 DB_SAVE(boolean_t, db_cmd_loop_done); \
209 DB_SAVE(jmp_buf_t *, db_recover); \
210 DB_SAVE(db_addr_t, db_dot); \
211 DB_SAVE(db_addr_t, db_last_addr); \
212 DB_SAVE(db_addr_t, db_prev); \
213 DB_SAVE(db_addr_t, db_next); \
214 SAVE_DDB_REGS
215
216 #define DB_RESTORE_CTXT() \
217 DB_RESTORE(db_run_mode); \
218 DB_RESTORE(db_sstep_print); \
219 DB_RESTORE(db_loop_count); \
220 DB_RESTORE(db_call_depth); \
221 DB_RESTORE(db_inst_count); \
222 DB_RESTORE(db_last_inst_count); \
223 DB_RESTORE(db_load_count); \
224 DB_RESTORE(db_store_count); \
225 DB_RESTORE(db_cmd_loop_done); \
226 DB_RESTORE(db_recover); \
227 DB_RESTORE(db_dot); \
228 DB_RESTORE(db_last_addr); \
229 DB_RESTORE(db_prev); \
230 DB_RESTORE(db_next); \
231 RESTORE_DDB_REGS
232
233 /*
234 * switch to another cpu
235 */
236 void
237 db_on(
238 int cpu)
239 {
240 /*
241 * Save ddb global variables
242 */
243 DB_SAVE_CTXT();
244
245 /*
246 * Don`t do if bad CPU number.
247 * CPU must also be spinning in db_entry.
248 */
249 if (cpu < 0 || cpu >= NCPUS || !db_active[cpu])
250 return;
251
252 /*
253 * Give debugger to that CPU
254 */
255 db_cpu = cpu;
256 unlock_db();
257
258 /*
259 * Wait for it to come back again
260 */
261 lock_db();
262
263 /*
264 * Restore ddb globals
265 */
266 DB_RESTORE_CTXT();
267
268 if (db_cpu == -1) /* someone continued */
269 db_continue_cmd(0, 0, 0, "");
270 }
271
272 /*
273 * Called by interprocessor interrupt when one CPU is
274 * in kernel debugger and wants to stop other CPUs
275 */
276 void
277 remote_db_enter(void)
278 {
279 db_slave[cpu_number()]++;
280 kdb_kintr();
281 }
282
283 /*
284 * Acquire kernel debugger.
285 * Conditional code for forwarding characters from slave to console
286 * if console on master only.
287 */
288
289 /*
290 * As long as db_cpu is not -1 or cpu_number(), we know that debugger
291 * is active on another cpu.
292 */
293 void
294 lock_db(void)
295 {
296 int my_cpu = cpu_number();
297
298 for (;;) {
299 #if CONSOLE_ON_MASTER
300 if (my_cpu == master_cpu) {
301 db_console();
302 }
303 #endif
304 if (db_cpu != -1 && db_cpu != my_cpu)
305 continue;
306
307 #if CONSOLE_ON_MASTER
308 if (my_cpu == master_cpu) {
309 if (!simple_lock_try(&db_lock))
310 continue;
311 }
312 else {
313 simple_lock(&db_lock);
314 }
315 #else
316 simple_lock(&db_lock);
317 #endif
318 if (db_cpu == -1 || db_cpu == my_cpu)
319 break;
320 simple_unlock(&db_lock);
321 }
322 }
323
324 void
325 unlock_db(void)
326 {
327 simple_unlock(&db_lock);
328 }
329
330 #ifdef sketch
331 void
332 db_console()
333 {
334 if (i_bit(CBUS_PUT_CHAR, my_word)) {
335 volatile u_char c = cbus_ochar;
336 i_bit_clear(CBUS_PUT_CHAR, my_word);
337 cnputc(c);
338 } else if (i_bit(CBUS_GET_CHAR, my_word)) {
339 if (cbus_wait_char)
340 cbus_ichar = cngetc();
341 else
342 cbus_ichar = cnmaygetc();
343 i_bit_clear(CBUS_GET_CHAR, my_word);
344 #ifndef notdef
345 } else if (!cnmaygetc()) {
346 #else /* notdef */
347 } else if (com_is_char() && !com_getc(TRUE)) {
348 #endif /* notdef */
349 simple_unlock(&db_lock);
350 db_cpu = my_cpu;
351 }
352 }
353 #endif /* sketch */
354
355 #endif /* NCPUS > 1 */
Cache object: 394c5755254ea4d0708c8c299523484d
|