1/* $NetBSD: db_interface.c,v 1.24 2011/08/11 19:52:52 cherry Exp $ */
2
3/*
4 * Mach Operating System
5 * Copyright (c) 1991,1990 Carnegie Mellon University
6 * All Rights Reserved.
7 *
8 * Permission to use, copy, modify and distribute this software and its
9 * documentation is hereby granted, provided that both the copyright
10 * notice and this permission notice appear in all copies of the
11 * software, derivative works or modified versions, and any portions
12 * thereof, and that both notices appear in supporting documentation.
13 *
14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17 *
18 * Carnegie Mellon requests users of this software to return to
19 *
20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
21 * School of Computer Science
22 * Carnegie Mellon University
23 * Pittsburgh PA 15213-3890
24 *
25 * any improvements or extensions that they make and grant Carnegie the
26 * rights to redistribute these changes.
27 *
28 * db_interface.c,v 2.4 1991/02/05 17:11:13 mrt (CMU)
29 */
30
31/*
32 * Interface to new debugger.
33 */
34
35#include <sys/cdefs.h>
36__KERNEL_RCSID(0, "$NetBSD: db_interface.c,v 1.24 2011/08/11 19:52:52 cherry Exp $");
37
38#include "opt_ddb.h"
39#include "opt_multiprocessor.h"
40
41#include <sys/param.h>
42#include <sys/proc.h>
43#include <sys/reboot.h>
44#include <sys/systm.h>
45#include <sys/atomic.h>
46#include <sys/cpu.h>
47
48#include <dev/cons.h>
49
50#include <machine/cpufunc.h>
51#include <machine/db_machdep.h>
52#include <machine/cpuvar.h>
53#include <machine/i82093var.h>
54#include <machine/i82489reg.h>
55#include <machine/i82489var.h>
56
57#include <ddb/db_sym.h>
58#include <ddb/db_command.h>
59#include <ddb/db_extern.h>
60#include <ddb/db_access.h>
61#include <ddb/db_output.h>
62#include <ddb/ddbvar.h>
63
64extern const char *const trap_type[];
65extern int trap_types;
66
67int db_active;
68db_regs_t ddb_regs; /* register state */
69db_regs_t *ddb_regp;
70
71void db_mach_cpu (db_expr_t, bool, db_expr_t, const char *);
72
73const struct db_command db_machine_command_table[] = {
74#ifdef MULTIPROCESSOR
75 { DDB_ADD_CMD("cpu", db_mach_cpu, 0,
76 "switch to another cpu", "cpu-no", NULL) },
77#endif
78 { DDB_ADD_CMD(NULL, NULL, 0,NULL,NULL,NULL) },
79};
80
81void kdbprinttrap(int, int);
82#ifdef MULTIPROCESSOR
83extern void ddb_ipi(struct trapframe);
84static void ddb_suspend(struct trapframe *);
85#ifndef XEN
86int ddb_vec;
87#endif /* XEN */
88static bool ddb_mp_online;
89#endif
90
91#define NOCPU -1
92
93int ddb_cpu = NOCPU;
94
95typedef void (vector)(void);
96extern vector Xintrddb;
97
98void
99db_machine_init(void)
100{
101
102#ifdef MULTIPROCESSOR
103#ifndef XEN
104 ddb_vec = idt_vec_alloc(0xf0, 0xff);
105 setgate((struct gate_descriptor *)&idt[ddb_vec], &Xintrddb, 1,
106 SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
107#else
108 /* Initialised as part of xen_ipi_init() */
109#endif /* XEN */
110#endif
111}
112
113#ifdef MULTIPROCESSOR
114
115__cpu_simple_lock_t db_lock;
116
117static int
118db_suspend_others(void)
119{
120 int cpu_me = cpu_number();
121 int win;
122
123#ifndef XEN
124 if (ddb_vec == 0)
125 return 1;
126#endif /* XEN */
127
128 __cpu_simple_lock(&db_lock);
129 if (ddb_cpu == NOCPU)
130 ddb_cpu = cpu_me;
131 win = (ddb_cpu == cpu_me);
132 __cpu_simple_unlock(&db_lock);
133 if (win) {
134#ifdef XEN
135 xen_broadcast_ipi(XEN_IPI_DDB);
136#else
137 x86_ipi(ddb_vec, LAPIC_DEST_ALLEXCL, LAPIC_DLMODE_FIXED);
138#endif /* XEN */
139
140 }
141 ddb_mp_online = x86_mp_online;
142 x86_mp_online = false;
143 return win;
144}
145
146static void
147db_resume_others(void)
148{
149 CPU_INFO_ITERATOR cii;
150 struct cpu_info *ci;
151
152 x86_mp_online = ddb_mp_online;
153 __cpu_simple_lock(&db_lock);
154 ddb_cpu = NOCPU;
155 __cpu_simple_unlock(&db_lock);
156
157 for (CPU_INFO_FOREACH(cii, ci)) {
158 if (ci->ci_flags & CPUF_PAUSE)
159 atomic_and_32(&ci->ci_flags, ~CPUF_PAUSE);
160 }
161}
162
163#endif
164
165/*
166 * Print trap reason.
167 */
168void
169kdbprinttrap(int type, int code)
170{
171 db_printf("kernel: ");
172 if (type >= trap_types || type < 0)
173 db_printf("type %d", type);
174 else
175 db_printf("%s", trap_type[type]);
176 db_printf(" trap, code=%x\n", code);
177}
178
179/*
180 * kdb_trap - field a TRACE or BPT trap
181 */
182int
183kdb_trap(int type, int code, db_regs_t *regs)
184{
185 int s;
186 db_regs_t dbreg;
187
188 switch (type) {
189 case T_NMI: /* NMI */
190 printf("NMI ... going to debugger\n");
191 /*FALLTHROUGH*/
192 case T_BPTFLT: /* breakpoint */
193 case T_TRCTRAP: /* single_step */
194 case -1: /* keyboard interrupt */
195 break;
196 default:
197 if (!db_onpanic && db_recover==0)
198 return (0);
199
200 kdbprinttrap(type, code);
201 if (db_recover != 0) {
202 db_error("Faulted in DDB; continuing...\n");
203 /*NOTREACHED*/
204 }
205 }
206
207#ifdef MULTIPROCESSOR
208 if (!db_suspend_others()) {
209 ddb_suspend(regs);
210 } else {
211 curcpu()->ci_ddb_regs = &dbreg;
212 ddb_regp = &dbreg;
213#endif
214
215 ddb_regs = *regs;
216
217 ddb_regs.tf_cs &= 0xffff;
218 ddb_regs.tf_ds &= 0xffff;
219 ddb_regs.tf_es &= 0xffff;
220 ddb_regs.tf_fs &= 0xffff;
221 ddb_regs.tf_gs &= 0xffff;
222 ddb_regs.tf_ss &= 0xffff;
223
224 s = splhigh();
225 db_active++;
226 cnpollc(true);
227 db_trap(type, code);
228 cnpollc(false);
229 db_active--;
230 splx(s);
231#ifdef MULTIPROCESSOR
232 db_resume_others();
233 }
234#endif
235 ddb_regp = &dbreg;
236
237 *regs = ddb_regs;
238
239 return (1);
240}
241
242void
243cpu_Debugger(void)
244{
245 breakpoint();
246}
247
248#ifdef MULTIPROCESSOR
249
250/*
251 * Called when we receive a debugger IPI (inter-processor interrupt).
252 * As with trap() in trap.c, this function is called from an assembly
253 * language IDT gate entry routine which prepares a suitable stack frame,
254 * and restores this frame after the exception has been processed. Note
255 * that the effect is as if the arguments were passed call by reference.
256 */
257
258void
259ddb_ipi(struct trapframe frame)
260{
261
262 ddb_suspend(&frame);
263}
264
265static void
266ddb_suspend(struct trapframe *frame)
267{
268 volatile struct cpu_info *ci = curcpu();
269 db_regs_t regs;
270
271 regs = *frame;
272
273 ci->ci_ddb_regs = &regs;
274
275 atomic_or_32(&ci->ci_flags, CPUF_PAUSE);
276
277 while (ci->ci_flags & CPUF_PAUSE)
278 ;
279 ci->ci_ddb_regs = 0;
280 tlbflushg();
281}
282
283
284extern void cpu_debug_dump(void); /* XXX */
285
286void
287db_mach_cpu(db_expr_t addr, bool have_addr, db_expr_t count, const char *modif)
288{
289 struct cpu_info *ci;
290 if (!have_addr) {
291 cpu_debug_dump();
292 return;
293 }
294
295 if (addr < 0) {
296 db_printf("%ld: CPU out of range\n", addr);
297 return;
298 }
299 ci = cpu_lookup(addr);
300 if (ci == NULL) {
301 db_printf("CPU %ld not configured\n", addr);
302 return;
303 }
304 if (ci != curcpu()) {
305 if (!(ci->ci_flags & CPUF_PAUSE)) {
306 db_printf("CPU %ld not paused\n", addr);
307 return;
308 }
309 }
310 if (ci->ci_ddb_regs == 0) {
311 db_printf("CPU %ld has no saved regs\n", addr);
312 return;
313 }
314 db_printf("using CPU %ld", addr);
315 ddb_regp = ci->ci_ddb_regs;
316}
317
318#endif
319