1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
|
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Copyright 2018 Joyent, Inc.
*/
/*
* Management of KMDB's IDT, which is installed upon KMDB activation.
*
* Debugger activation has two flavors, which cover the cases where KMDB is
* loaded at boot, and when it is loaded after boot. In brief, in both cases,
* the KDI needs to interpose upon several handlers in the IDT. When
* mod-loaded KMDB is deactivated, we undo the IDT interposition, restoring the
* handlers to what they were before we started.
*
* We also take over the entirety of IDT (except the double-fault handler) on
* the active CPU when we're in kmdb so we can handle things like page faults
* sensibly.
*
* Boot-loaded KMDB
*
* When we're first activated, we're running on boot's IDT. We need to be able
* to function in this world, so we'll install our handlers into boot's IDT.
* This is a little complicated: we're using the fake cpu_t set up by
* boot_kdi_tmpinit(), so we can't access cpu_idt directly. Instead,
* kdi_idt_write() notices that cpu_idt is NULL, and works around this problem.
*
* Later, when we're about to switch to the kernel's IDT, it'll call us via
* kdi_idt_sync(), allowing us to add our handlers to the new IDT. While
* boot-loaded KMDB can't be unloaded, we still need to save the descriptors we
* replace so we can pass traps back to the kernel as necessary.
*
* The last phase of boot-loaded KMDB activation occurs at non-boot CPU
* startup. We will be called on each non-boot CPU, thus allowing us to set up
* any watchpoints that may have been configured on the boot CPU and interpose
* on the given CPU's IDT. We don't save the interposed descriptors in this
* case -- see kdi_cpu_init() for details.
*
* Mod-loaded KMDB
*
* This style of activation is much simpler, as the CPUs are already running,
* and are using their own copy of the kernel's IDT. We simply interpose upon
* each CPU's IDT. We save the handlers we replace, both for deactivation and
* for passing traps back to the kernel. Note that for the hypervisors'
* benefit, we need to xcall to the other CPUs to do this, since we need to
* actively set the trap entries in its virtual IDT from that vcpu's context
* rather than just modifying the IDT table from the CPU running kdi_activate().
*/
#include <sys/types.h>
#include <sys/segments.h>
#include <sys/trap.h>
#include <sys/cpuvar.h>
#include <sys/reboot.h>
#include <sys/sunddi.h>
#include <sys/archsystm.h>
#include <sys/kdi_impl.h>
#include <sys/x_call.h>
#include <sys/psw.h>
#include <vm/hat_i86.h>
#define KDI_GATE_NVECS 3
#define KDI_IDT_NOSAVE 0
#define KDI_IDT_SAVE 1
#define KDI_IDT_DTYPE_KERNEL 0
#define KDI_IDT_DTYPE_BOOT 1
/* Solely to keep kdiregs_t in the CTF, otherwise unused. */
kdiregs_t kdi_regs;
kdi_cpusave_t *kdi_cpusave;
int kdi_ncpusave;
static kdi_main_t kdi_kmdb_main;
kdi_drreg_t kdi_drreg;
uintptr_t kdi_kernel_handler;
int kdi_trap_switch;
#define KDI_MEMRANGES_MAX 2
kdi_memrange_t kdi_memranges[KDI_MEMRANGES_MAX];
int kdi_nmemranges;
typedef void idt_hdlr_f(void);
extern idt_hdlr_f kdi_trap0, kdi_trap1, kdi_int2, kdi_trap3, kdi_trap4;
extern idt_hdlr_f kdi_trap5, kdi_trap6, kdi_trap7, kdi_trap9;
extern idt_hdlr_f kdi_traperr10, kdi_traperr11, kdi_traperr12;
extern idt_hdlr_f kdi_traperr13, kdi_traperr14, kdi_trap16, kdi_traperr17;
extern idt_hdlr_f kdi_trap18, kdi_trap19, kdi_trap20, kdi_ivct32;
extern idt_hdlr_f kdi_invaltrap;
extern size_t kdi_ivct_size;
typedef struct kdi_gate_spec {
uint_t kgs_vec;
uint_t kgs_dpl;
} kdi_gate_spec_t;
/*
* Beware: kdi_pass_to_kernel() has unpleasant knowledge of this list.
*/
static const kdi_gate_spec_t kdi_gate_specs[KDI_GATE_NVECS] = {
{ T_SGLSTP, TRP_KPL },
{ T_BPTFLT, TRP_UPL },
{ T_DBGENTR, TRP_KPL }
};
static gate_desc_t kdi_kgates[KDI_GATE_NVECS];
extern gate_desc_t kdi_idt[NIDT];
struct idt_description {
uint_t id_low;
uint_t id_high;
idt_hdlr_f *id_basehdlr;
size_t *id_incrp;
} idt_description[] = {
{ T_ZERODIV, 0, kdi_trap0, NULL },
{ T_SGLSTP, 0, kdi_trap1, NULL },
{ T_NMIFLT, 0, kdi_int2, NULL },
{ T_BPTFLT, 0, kdi_trap3, NULL },
{ T_OVFLW, 0, kdi_trap4, NULL },
{ T_BOUNDFLT, 0, kdi_trap5, NULL },
{ T_ILLINST, 0, kdi_trap6, NULL },
{ T_NOEXTFLT, 0, kdi_trap7, NULL },
#if !defined(__xpv)
{ T_DBLFLT, 0, syserrtrap, NULL },
#endif
{ T_EXTOVRFLT, 0, kdi_trap9, NULL },
{ T_TSSFLT, 0, kdi_traperr10, NULL },
{ T_SEGFLT, 0, kdi_traperr11, NULL },
{ T_STKFLT, 0, kdi_traperr12, NULL },
{ T_GPFLT, 0, kdi_traperr13, NULL },
{ T_PGFLT, 0, kdi_traperr14, NULL },
{ 15, 0, kdi_invaltrap, NULL },
{ T_EXTERRFLT, 0, kdi_trap16, NULL },
{ T_ALIGNMENT, 0, kdi_traperr17, NULL },
{ T_MCE, 0, kdi_trap18, NULL },
{ T_SIMDFPE, 0, kdi_trap19, NULL },
{ T_DBGENTR, 0, kdi_trap20, NULL },
{ 21, 31, kdi_invaltrap, NULL },
{ 32, 255, kdi_ivct32, &kdi_ivct_size },
{ 0, 0, NULL },
};
void
kdi_idt_init(selector_t sel)
{
struct idt_description *id;
int i;
for (id = idt_description; id->id_basehdlr != NULL; id++) {
uint_t high = id->id_high != 0 ? id->id_high : id->id_low;
size_t incr = id->id_incrp != NULL ? *id->id_incrp : 0;
#if !defined(__xpv)
if (kpti_enable && sel == KCS_SEL && id->id_low == T_DBLFLT)
id->id_basehdlr = tr_syserrtrap;
#endif
for (i = id->id_low; i <= high; i++) {
caddr_t hdlr = (caddr_t)id->id_basehdlr +
incr * (i - id->id_low);
set_gatesegd(&kdi_idt[i], (void (*)())hdlr, sel,
SDT_SYSIGT, TRP_KPL, IST_DBG);
}
}
}
static void
kdi_idt_gates_install(selector_t sel, int saveold)
{
gate_desc_t gates[KDI_GATE_NVECS];
int i;
bzero(gates, sizeof (*gates));
for (i = 0; i < KDI_GATE_NVECS; i++) {
const kdi_gate_spec_t *gs = &kdi_gate_specs[i];
uintptr_t func = GATESEG_GETOFFSET(&kdi_idt[gs->kgs_vec]);
set_gatesegd(&gates[i], (void (*)())func, sel, SDT_SYSIGT,
gs->kgs_dpl, IST_DBG);
}
for (i = 0; i < KDI_GATE_NVECS; i++) {
uint_t vec = kdi_gate_specs[i].kgs_vec;
if (saveold)
kdi_kgates[i] = CPU->cpu_m.mcpu_idt[vec];
kdi_idt_write(&gates[i], vec);
}
}
static void
kdi_idt_gates_restore(void)
{
int i;
for (i = 0; i < KDI_GATE_NVECS; i++)
kdi_idt_write(&kdi_kgates[i], kdi_gate_specs[i].kgs_vec);
}
/*
* Called when we switch to the kernel's IDT. We need to interpose on the
* kernel's IDT entries and stop using KMDBCODE_SEL.
*/
void
kdi_idt_sync(void)
{
kdi_idt_init(KCS_SEL);
kdi_idt_gates_install(KCS_SEL, KDI_IDT_SAVE);
}
void
kdi_update_drreg(kdi_drreg_t *drreg)
{
kdi_drreg = *drreg;
}
void
kdi_memrange_add(caddr_t base, size_t len)
{
kdi_memrange_t *mr = &kdi_memranges[kdi_nmemranges];
ASSERT(kdi_nmemranges != KDI_MEMRANGES_MAX);
mr->mr_base = base;
mr->mr_lim = base + len - 1;
kdi_nmemranges++;
}
void
kdi_idt_switch(kdi_cpusave_t *cpusave)
{
if (cpusave == NULL)
kdi_idtr_set(kdi_idt, sizeof (kdi_idt) - 1);
else
kdi_idtr_set(cpusave->krs_idt, (sizeof (*idt0) * NIDT) - 1);
}
/*
* Activation for CPUs other than the boot CPU, called from that CPU's
* mp_startup(). We saved the kernel's descriptors when we initialized the
* boot CPU, so we don't want to do it again. Saving the handlers from this
* CPU's IDT would actually be dangerous with the CPU initialization method in
* use at the time of this writing. With that method, the startup code creates
* the IDTs for slave CPUs by copying the one used by the boot CPU, which has
* already been interposed upon by KMDB. Were we to interpose again, we'd
* replace the kernel's descriptors with our own in the save area. By not
* saving, but still overwriting, we'll work in the current world, and in any
* future world where the IDT is generated from scratch.
*/
void
kdi_cpu_init(void)
{
kdi_idt_gates_install(KCS_SEL, KDI_IDT_NOSAVE);
/* Load the debug registers. */
kdi_cpu_debug_init(&kdi_cpusave[CPU->cpu_id]);
}
/*
* Activation for all CPUs for mod-loaded kmdb, i.e. a kmdb that wasn't
* loaded at boot.
*/
static int
kdi_cpu_activate(xc_arg_t arg1 __unused, xc_arg_t arg2 __unused,
xc_arg_t arg3 __unused)
{
kdi_idt_gates_install(KCS_SEL, KDI_IDT_SAVE);
return (0);
}
void
kdi_activate(kdi_main_t main, kdi_cpusave_t *cpusave, uint_t ncpusave)
{
int i;
cpuset_t cpuset;
CPUSET_ALL(cpuset);
kdi_cpusave = cpusave;
kdi_ncpusave = ncpusave;
kdi_kmdb_main = main;
for (i = 0; i < kdi_ncpusave; i++) {
kdi_cpusave[i].krs_cpu_id = i;
kdi_cpusave[i].krs_curcrumb =
&kdi_cpusave[i].krs_crumbs[KDI_NCRUMBS - 1];
kdi_cpusave[i].krs_curcrumbidx = KDI_NCRUMBS - 1;
}
if (boothowto & RB_KMDB)
kdi_idt_init(KMDBCODE_SEL);
else
kdi_idt_init(KCS_SEL);
kdi_memranges[0].mr_base = kdi_segdebugbase;
kdi_memranges[0].mr_lim = kdi_segdebugbase + kdi_segdebugsize - 1;
kdi_nmemranges = 1;
kdi_drreg.dr_ctl = KDIREG_DRCTL_RESERVED;
kdi_drreg.dr_stat = KDIREG_DRSTAT_RESERVED;
if (boothowto & RB_KMDB) {
kdi_idt_gates_install(KMDBCODE_SEL, KDI_IDT_NOSAVE);
} else {
xc_call(0, 0, 0, CPUSET2BV(cpuset), kdi_cpu_activate);
}
}
static int
kdi_cpu_deactivate(xc_arg_t arg1 __unused, xc_arg_t arg2 __unused,
xc_arg_t arg3 __unused)
{
kdi_idt_gates_restore();
return (0);
}
void
kdi_deactivate(void)
{
cpuset_t cpuset;
CPUSET_ALL(cpuset);
xc_call(0, 0, 0, CPUSET2BV(cpuset), kdi_cpu_deactivate);
kdi_nmemranges = 0;
}
/*
* We receive all breakpoints and single step traps. Some of them, including
* those from userland and those induced by DTrace providers, are intended for
* the kernel, and must be processed there. We adopt this
* ours-until-proven-otherwise position due to the painful consequences of
* sending the kernel an unexpected breakpoint or single step. Unless someone
* can prove to us that the kernel is prepared to handle the trap, we'll assume
* there's a problem and will give the user a chance to debug it.
*
* If we return 2, then the calling code should restore the trap-time %cr3: that
* is, it really is a kernel-originated trap.
*/
int
kdi_trap_pass(kdi_cpusave_t *cpusave)
{
greg_t tt = cpusave->krs_gregs[KDIREG_TRAPNO];
greg_t pc = cpusave->krs_gregs[KDIREG_PC];
greg_t cs = cpusave->krs_gregs[KDIREG_CS];
if (USERMODE(cs))
return (1);
if (tt != T_BPTFLT && tt != T_SGLSTP)
return (0);
if (tt == T_BPTFLT && kdi_dtrace_get_state() ==
KDI_DTSTATE_DTRACE_ACTIVE)
return (2);
/*
* See the comments in the kernel's T_SGLSTP handler for why we need to
* do this.
*/
#if !defined(__xpv)
if (tt == T_SGLSTP &&
(pc == (greg_t)sys_sysenter || pc == (greg_t)brand_sys_sysenter ||
pc == (greg_t)tr_sys_sysenter ||
pc == (greg_t)tr_brand_sys_sysenter)) {
#else
if (tt == T_SGLSTP &&
(pc == (greg_t)sys_sysenter || pc == (greg_t)brand_sys_sysenter)) {
#endif
return (1);
}
return (0);
}
/*
* State has been saved, and all CPUs are on the CPU-specific stacks. All
* CPUs enter here, and head off into the debugger proper.
*/
void
kdi_debugger_entry(kdi_cpusave_t *cpusave)
{
/*
* BPTFLT gives us control with %eip set to the instruction *after*
* the int 3. Back it off, so we're looking at the instruction that
* triggered the fault.
*/
if (cpusave->krs_gregs[KDIREG_TRAPNO] == T_BPTFLT)
cpusave->krs_gregs[KDIREG_PC]--;
kdi_kmdb_main(cpusave);
}
|