Print this page
8956 Implement KPTI
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
9210 remove KMDB branch debugging support
9211 ::crregs could do with cr2/cr3 support
9209 ::ttrace should be able to filter by thread
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Reviewed by: Yuri Pankov <yuripv@yuripv.net>
9207 kdi_idt: Cast GATESEG_GETOFFSET through uintptr_t
Reviewed by: Yuri Pankov <yuripv@yuripv.net>
@@ -19,10 +19,12 @@
* 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.
*
@@ -74,10 +76,11 @@
#include <sys/sunddi.h>
#include <sys/archsystm.h>
#include <sys/kdi_impl.h>
#include <sys/x_call.h>
#include <ia32/sys/psw.h>
+#include <vm/hat_i86.h>
#define KDI_GATE_NVECS 3
#define KDI_IDT_NOSAVE 0
#define KDI_IDT_SAVE 1
@@ -98,13 +101,10 @@
uint32_t kdi_ds;
uint32_t kdi_fs;
uint32_t kdi_gs;
#endif
-uint_t kdi_msr_wrexit_msr;
-uint64_t *kdi_msr_wrexit_valp;
-
uintptr_t kdi_kernel_handler;
int kdi_trap_switch;
#define KDI_MEMRANGES_MAX 2
@@ -115,15 +115,14 @@
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_trap17;
+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;
-extern char kdi_slave_entry_patch;
typedef struct kdi_gate_spec {
uint_t kgs_vec;
uint_t kgs_dpl;
} kdi_gate_spec_t;
@@ -137,11 +136,11 @@
{ T_DBGENTR, TRP_KPL }
};
static gate_desc_t kdi_kgates[KDI_GATE_NVECS];
-gate_desc_t kdi_idt[NIDT];
+extern gate_desc_t kdi_idt[NIDT];
struct idt_description {
uint_t id_low;
uint_t id_high;
idt_hdlr_f *id_basehdlr;
@@ -164,11 +163,11 @@
{ 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_trap17, 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 },
@@ -183,58 +182,24 @@
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, i);
+ SDT_SYSIGT, TRP_KPL, IST_DBG);
}
}
}
-/*
- * Patch caller-provided code into the debugger's IDT handlers. This code is
- * used to save MSRs that must be saved before the first branch. All handlers
- * are essentially the same, and end with a branch to kdi_cmnint. To save the
- * MSR, we need to patch in before the branch. The handlers have the following
- * structure: KDI_MSR_PATCHOFF bytes of code, KDI_MSR_PATCHSZ bytes of
- * patchable space, followed by more code.
- */
-void
-kdi_idt_patch(caddr_t code, size_t sz)
-{
- int i;
-
- ASSERT(sz <= KDI_MSR_PATCHSZ);
-
- for (i = 0; i < sizeof (kdi_idt) / sizeof (struct gate_desc); i++) {
- gate_desc_t *gd;
- uchar_t *patch;
-
- if (i == T_DBLFLT)
- continue; /* uses kernel's handler */
-
- gd = &kdi_idt[i];
- patch = (uchar_t *)GATESEG_GETOFFSET(gd) + KDI_MSR_PATCHOFF;
-
- /*
- * We can't ASSERT that there's a nop here, because this may be
- * a debugger restart. In that case, we're copying the new
- * patch point over the old one.
- */
- /* FIXME: dtrace fbt ... */
- bcopy(code, patch, sz);
-
- /* Fill the rest with nops to be sure */
- while (sz < KDI_MSR_PATCHSZ)
- patch[sz++] = 0x90; /* nop */
- }
-}
-
static void
kdi_idt_gates_install(selector_t sel, int saveold)
{
gate_desc_t gates[KDI_GATE_NVECS];
int i;
@@ -243,11 +208,11 @@
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, gs->kgs_vec);
+ gs->kgs_dpl, IST_DBG);
}
for (i = 0; i < KDI_GATE_NVECS; i++) {
uint_t vec = kdi_gate_specs[i].kgs_vec;
@@ -276,84 +241,11 @@
{
kdi_idt_init(KCS_SEL);
kdi_idt_gates_install(KCS_SEL, KDI_IDT_SAVE);
}
-/*
- * On some processors, we'll need to clear a certain MSR before proceeding into
- * the debugger. Complicating matters, this MSR must be cleared before we take
- * any branches. We have patch points in every trap handler, which will cover
- * all entry paths for master CPUs. We also have a patch point in the slave
- * entry code.
- */
-static void
-kdi_msr_add_clrentry(uint_t msr)
-{
-#ifdef __amd64
- uchar_t code[] = {
- 0x51, 0x50, 0x52, /* pushq %rcx, %rax, %rdx */
- 0xb9, 0x00, 0x00, 0x00, 0x00, /* movl $MSRNUM, %ecx */
- 0x31, 0xc0, /* clr %eax */
- 0x31, 0xd2, /* clr %edx */
- 0x0f, 0x30, /* wrmsr */
- 0x5a, 0x58, 0x59 /* popq %rdx, %rax, %rcx */
- };
- uchar_t *patch = &code[4];
-#else
- uchar_t code[] = {
- 0x60, /* pushal */
- 0xb9, 0x00, 0x00, 0x00, 0x00, /* movl $MSRNUM, %ecx */
- 0x31, 0xc0, /* clr %eax */
- 0x31, 0xd2, /* clr %edx */
- 0x0f, 0x30, /* wrmsr */
- 0x61 /* popal */
- };
- uchar_t *patch = &code[2];
-#endif
-
- bcopy(&msr, patch, sizeof (uint32_t));
-
- kdi_idt_patch((caddr_t)code, sizeof (code));
-
- bcopy(code, &kdi_slave_entry_patch, sizeof (code));
-}
-
-static void
-kdi_msr_add_wrexit(uint_t msr, uint64_t *valp)
-{
- kdi_msr_wrexit_msr = msr;
- kdi_msr_wrexit_valp = valp;
-}
-
void
-kdi_set_debug_msrs(kdi_msr_t *msrs)
-{
- int nmsrs, i;
-
- ASSERT(kdi_cpusave[0].krs_msr == NULL);
-
- /* Look in CPU0's MSRs for any special MSRs. */
- for (nmsrs = 0; msrs[nmsrs].msr_num != 0; nmsrs++) {
- switch (msrs[nmsrs].msr_type) {
- case KDI_MSR_CLEARENTRY:
- kdi_msr_add_clrentry(msrs[nmsrs].msr_num);
- break;
-
- case KDI_MSR_WRITEDELAY:
- kdi_msr_add_wrexit(msrs[nmsrs].msr_num,
- msrs[nmsrs].kdi_msr_valp);
- break;
- }
- }
-
- nmsrs++;
-
- for (i = 0; i < kdi_ncpusave; i++)
- kdi_cpusave[i].krs_msr = &msrs[nmsrs * i];
-}
-
-void
kdi_update_drreg(kdi_drreg_t *drreg)
{
kdi_drreg = *drreg;
}
@@ -392,11 +284,11 @@
*/
void
kdi_cpu_init(void)
{
kdi_idt_gates_install(KCS_SEL, KDI_IDT_NOSAVE);
- /* Load the debug registers and MSRs */
+ /* 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
@@ -446,13 +338,10 @@
kdi_nmemranges = 1;
kdi_drreg.dr_ctl = KDIREG_DRCTL_RESERVED;
kdi_drreg.dr_stat = KDIREG_DRSTAT_RESERVED;
- kdi_msr_wrexit_msr = 0;
- kdi_msr_wrexit_valp = NULL;
-
if (boothowto & RB_KMDB) {
kdi_idt_gates_install(KMDBCODE_SEL, KDI_IDT_NOSAVE);
} else {
xc_call(0, 0, 0, CPUSET2BV(cpuset),
(xc_func_t)kdi_cpu_activate);
@@ -505,13 +394,21 @@
/*
* 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)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);
}
/*