summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Levon <john.levon@joyent.com>2018-07-30 08:39:37 +0000
committerJohn Levon <john.levon@joyent.com>2018-07-30 08:52:35 +0000
commit1d0338f3f33eec2ed45ec5a6cae30c399a3ef769 (patch)
tree17d963f3fc9f20d729955159bc70802e40fbbd14
parent5a38f11740e61db1a5560cc3bb03bebdbd684845 (diff)
downloadillumos-joyent-1d0338f3f33eec2ed45ec5a6cae30c399a3ef769.tar.gz
OS-7090 GDT limit reset to 0xffff
Reviewed by: Robert Mustacchi <rm@joyent.com> Reviewed by: Patrick Mooney <patrick.mooney@joyent.com> Approved by: Robert Mustacchi <rm@joyent.com>
-rw-r--r--usr/src/cmd/mdb/i86pc/modules/unix/unix.c12
-rw-r--r--usr/src/cmd/mdb/i86pc/modules/unix/unix_sup.h2
-rw-r--r--usr/src/cmd/mdb/i86pc/modules/unix/unix_sup.s47
-rw-r--r--usr/src/pkg/manifests/system-test-ostest.mf1
-rw-r--r--usr/src/test/os-tests/runfiles/default.run2
-rw-r--r--usr/src/test/os-tests/tests/i386/Makefile15
-rw-r--r--usr/src/test/os-tests/tests/i386/badseg.c146
-rw-r--r--usr/src/uts/i86pc/io/vmm/intel/vmx.c2
-rw-r--r--usr/src/uts/i86pc/io/vmm/vmm.c30
-rw-r--r--usr/src/uts/intel/ia32/os/desctbls.c22
-rw-r--r--usr/src/uts/intel/sys/x86_archext.h4
11 files changed, 216 insertions, 67 deletions
diff --git a/usr/src/cmd/mdb/i86pc/modules/unix/unix.c b/usr/src/cmd/mdb/i86pc/modules/unix/unix.c
index 224cfb4a18..a66ecbe8a3 100644
--- a/usr/src/cmd/mdb/i86pc/modules/unix/unix.c
+++ b/usr/src/cmd/mdb/i86pc/modules/unix/unix.c
@@ -961,9 +961,11 @@ x86_featureset_cmd(uintptr_t addr, uint_t flags, int argc,
#ifdef _KMDB
/* ARGSUSED */
static int
-crregs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+sysregs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
ulong_t cr0, cr2, cr3, cr4;
+ desctbr_t gdtr;
+
static const mdb_bitmask_t cr0_flag_bits[] = {
{ "PE", CR0_PE, CR0_PE },
{ "MP", CR0_MP, CR0_MP },
@@ -1010,6 +1012,9 @@ crregs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
cr2 = kmdb_unix_getcr2();
cr3 = kmdb_unix_getcr3();
cr4 = kmdb_unix_getcr4();
+
+ kmdb_unix_getgdtr(&gdtr);
+
mdb_printf("%%cr0 = 0x%lx <%b>\n", cr0, cr0, cr0_flag_bits);
mdb_printf("%%cr2 = 0x%lx <%a>\n", cr2, cr2);
@@ -1023,6 +1028,9 @@ crregs_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
mdb_printf("%%cr4 = 0x%lx <%b>\n", cr4, cr4, cr4_flag_bits);
+ mdb_printf("%%gdtr.base = 0x%lx, %%gdtr.limit = 0x%hx\n",
+ gdtr.dtr_base, gdtr.dtr_limit);
+
return (DCMD_OK);
}
#endif
@@ -1054,7 +1062,7 @@ static const mdb_dcmd_t dcmds[] = {
{ "x86_featureset", NULL, "dump the x86_featureset vector",
x86_featureset_cmd },
#ifdef _KMDB
- { "crregs", NULL, "dump control registers", crregs_dcmd },
+ { "sysregs", NULL, "dump system registers", sysregs_dcmd },
#endif
{ NULL }
};
diff --git a/usr/src/cmd/mdb/i86pc/modules/unix/unix_sup.h b/usr/src/cmd/mdb/i86pc/modules/unix/unix_sup.h
index 4c155373ea..0c9d2e68ec 100644
--- a/usr/src/cmd/mdb/i86pc/modules/unix/unix_sup.h
+++ b/usr/src/cmd/mdb/i86pc/modules/unix/unix_sup.h
@@ -21,6 +21,7 @@
*/
#include <sys/types.h>
+#include <sys/segments.h>
#ifdef __cplusplus
extern "C" {
@@ -30,6 +31,7 @@ extern ulong_t kmdb_unix_getcr0(void);
extern ulong_t kmdb_unix_getcr2(void);
extern ulong_t kmdb_unix_getcr3(void);
extern ulong_t kmdb_unix_getcr4(void);
+extern void kmdb_unix_getgdtr(desctbr_t *);
#ifdef __cplusplus
}
diff --git a/usr/src/cmd/mdb/i86pc/modules/unix/unix_sup.s b/usr/src/cmd/mdb/i86pc/modules/unix/unix_sup.s
index 38ddf5cf44..5984a12132 100644
--- a/usr/src/cmd/mdb/i86pc/modules/unix/unix_sup.s
+++ b/usr/src/cmd/mdb/i86pc/modules/unix/unix_sup.s
@@ -13,35 +13,20 @@
* Copyright 2018 Joyent, Inc.
*/
-#if !defined(__lint)
- .file "unix_sup.s"
-#endif /* __lint */
-
/*
* Support routines for the unix kmdb module
*/
-#include <sys/asm_linkage.h>
-
#if defined(__lint)
#include <sys/types.h>
-ulong_t
-kmdb_unix_getcr0(void)
-{ return (0); }
-
-ulong_t
-kmdb_unix_getcr3(void)
-{ return (0); }
+#else
-ulong_t
-kmdb_unix_getcr4(void)
-{ return (0); }
+#include <sys/asm_linkage.h>
-#else /* __lint */
+ .file "unix_sup.s"
-#if defined(__amd64)
ENTRY(kmdb_unix_getcr0)
movq %cr0, %rax
ret
@@ -62,27 +47,9 @@ kmdb_unix_getcr4(void)
ret
SET_SIZE(kmdb_unix_getcr4)
-#elif defined (__i386)
- ENTRY(kmdb_unix_getcr0)
- movl %cr0, %eax
- ret
- SET_SIZE(kmdb_unix_getcr0)
-
- ENTRY(kmdb_unix_getcr2)
- movl %cr2, %eax
- ret
- SET_SIZE(kmdb_unix_getcr2)
-
- ENTRY(kmdb_unix_getcr3)
- movl %cr3, %eax
+ ENTRY(kmdb_unix_getgdtr)
+ sgdt (%rdi)
ret
- SET_SIZE(kmdb_unix_getcr3)
-
- ENTRY(kmdb_unix_getcr4)
- movl %cr4, %eax
- ret
- SET_SIZE(kmdb_unix_getcr4)
-
-#endif /* __i386 */
+ SET_SIZE(kmdb_unix_getgdtr)
-#endif /* __lint */
+#endif /* !__lint */
diff --git a/usr/src/pkg/manifests/system-test-ostest.mf b/usr/src/pkg/manifests/system-test-ostest.mf
index c2fda43f31..70e9d378c1 100644
--- a/usr/src/pkg/manifests/system-test-ostest.mf
+++ b/usr/src/pkg/manifests/system-test-ostest.mf
@@ -41,6 +41,7 @@ file path=opt/os-tests/tests/file-locking/acquire-lock.32 mode=0555
file path=opt/os-tests/tests/file-locking/acquire-lock.64 mode=0555
file path=opt/os-tests/tests/file-locking/runtests.32 mode=0555
file path=opt/os-tests/tests/file-locking/runtests.64 mode=0555
+$(i386_ONLY)file path=opt/os-tests/tests/i386/badseg mode=0555
$(i386_ONLY)file path=opt/os-tests/tests/i386/ldt mode=0555
file path=opt/os-tests/tests/pf_key/acquire-compare mode=0555
file path=opt/os-tests/tests/pf_key/acquire-spray mode=0555
diff --git a/usr/src/test/os-tests/runfiles/default.run b/usr/src/test/os-tests/runfiles/default.run
index fb79a8de19..974829b1f6 100644
--- a/usr/src/test/os-tests/runfiles/default.run
+++ b/usr/src/test/os-tests/runfiles/default.run
@@ -77,4 +77,4 @@ tests = ['acquire-compare', 'acquire-spray']
[/opt/os-tests/tests/i386]
user = root
arch = i86pc
-tests = ['ldt']
+tests = ['ldt', 'badseg']
diff --git a/usr/src/test/os-tests/tests/i386/Makefile b/usr/src/test/os-tests/tests/i386/Makefile
index 6c1f480b88..4933cf6e02 100644
--- a/usr/src/test/os-tests/tests/i386/Makefile
+++ b/usr/src/test/os-tests/tests/i386/Makefile
@@ -16,28 +16,29 @@
include $(SRC)/cmd/Makefile.cmd
include $(SRC)/test/Makefile.com
-PROG += ldt
+PROGS += ldt badseg
ROOTOPTPKG = $(ROOT)/opt/os-tests
TESTDIR = $(ROOTOPTPKG)/tests/i386
+ROOTOPTPROGS = $(PROGS:%=$(TESTDIR)/%)
CSTD = $(CSTD_GNU99)
-CMDS = $(PROG:%=$(TESTDIR)/%)
-$(CMDS) := FILEMODE = 0555
+# for badseg
+COPTFLAG =
-all: $(PROG)
+all: $(PROGS)
-install: all $(CMDS)
+install: all $(ROOTOPTPROGS)
lint:
clobber: clean
- -$(RM) $(PROG)
+ -$(RM) $(PROGS)
clean:
-$(CMDS): $(TESTDIR) $(PROG)
+$(ROOTOPTPROGS): $(TESTDIR) $(PROGS)
$(TESTDIR):
$(INS.dir)
diff --git a/usr/src/test/os-tests/tests/i386/badseg.c b/usr/src/test/os-tests/tests/i386/badseg.c
new file mode 100644
index 0000000000..6bf4e0260f
--- /dev/null
+++ b/usr/src/test/os-tests/tests/i386/badseg.c
@@ -0,0 +1,146 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2018 Joyent, Inc.
+ */
+
+#include <stdlib.h>
+#include <ucontext.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/regset.h>
+
+/*
+ * Load a bunch of bad selectors into the seg regs: this will typically cause
+ * the child process to core dump, but it shouldn't panic the kernel...
+ *
+ * It's especially interesting to run this on CPU0.
+ */
+
+unsigned short selector;
+
+static void badds(void)
+{
+ __asm__ volatile("movw %0, %%ds" : : "r" (selector));
+}
+
+static void bades(void)
+{
+ __asm__ volatile("movw %0, %%es" : : "r" (selector));
+}
+
+static void badfs(void)
+{
+ __asm__ volatile("movw %0, %%fs" : : "r" (selector));
+}
+
+static void badgs(void)
+{
+ __asm__ volatile("movw %0, %%gs" : : "r" (selector));
+}
+
+static void badss(void)
+{
+ __asm__ volatile("movw %0, %%ss" : : "r" (selector));
+}
+
+static void
+resetseg(uint_t seg)
+{
+ ucontext_t ucp;
+ int done = 0;
+
+ int rc = getcontext(&ucp);
+ if (done) {
+ rc = getcontext(&ucp);
+ return;
+ }
+
+ done = 1;
+ ucp.uc_mcontext.gregs[seg] = selector;
+ setcontext(&ucp);
+ abort();
+}
+
+static void
+resetcs(void)
+{
+ return (resetseg(CS));
+}
+
+static void
+resetds(void)
+{
+ return (resetseg(DS));
+}
+
+static void
+resetes(void)
+{
+ return (resetseg(ES));
+}
+
+static void
+resetfs(void)
+{
+ return (resetseg(FS));
+}
+
+static void
+resetgs(void)
+{
+ return (resetseg(GS));
+}
+
+static void
+resetss(void)
+{
+ return (resetseg(SS));
+}
+
+static void
+inchild(void (*func)())
+{
+ pid_t pid;
+
+ switch ((pid = fork())) {
+ case 0:
+ func();
+ exit(0);
+ case -1:
+ exit(1);
+ default:
+ (void) waitpid(pid, NULL, 0);
+ return;
+ }
+
+}
+
+int
+main(int argc, char *argv[])
+{
+ for (selector = 0; selector < 8194; selector++) {
+ inchild(resetcs);
+ inchild(resetds);
+ inchild(resetes);
+ inchild(resetfs);
+ inchild(resetgs);
+ inchild(resetss);
+ inchild(badds);
+ inchild(bades);
+ inchild(badfs);
+ inchild(badgs);
+ inchild(badss);
+ }
+
+ exit(0);
+}
diff --git a/usr/src/uts/i86pc/io/vmm/intel/vmx.c b/usr/src/uts/i86pc/io/vmm/intel/vmx.c
index eaad8864c2..9ad232a612 100644
--- a/usr/src/uts/i86pc/io/vmm/intel/vmx.c
+++ b/usr/src/uts/i86pc/io/vmm/intel/vmx.c
@@ -3942,6 +3942,8 @@ vmx_savectx(void *arg, int vcpu)
VERIFY3U(vmclear(vmcs), ==, 0);
vmx_msr_guest_exit(vmx, vcpu);
}
+
+ reset_gdtr_limit();
}
static void
diff --git a/usr/src/uts/i86pc/io/vmm/vmm.c b/usr/src/uts/i86pc/io/vmm/vmm.c
index a4b669ab81..bcb6b77cea 100644
--- a/usr/src/uts/i86pc/io/vmm/vmm.c
+++ b/usr/src/uts/i86pc/io/vmm/vmm.c
@@ -1932,7 +1932,7 @@ vm_localize_resources(struct vm *vm, struct vcpu *vcpu)
vcpu->lastloccpu = curcpu;
}
-void
+static void
vmm_savectx(void *arg)
{
vm_thread_ctx_t *vtc = arg;
@@ -1955,7 +1955,7 @@ vmm_savectx(void *arg)
}
}
-void
+static void
vmm_restorectx(void *arg)
{
vm_thread_ctx_t *vtc = arg;
@@ -1986,6 +1986,15 @@ vmm_restorectx(void *arg)
}
+/*
+ * If we're in removectx(), we might still have state to tidy up.
+ */
+static void
+vmm_freectx(void *arg, int isexec)
+{
+ vmm_savectx(arg);
+}
+
#endif /* __FreeBSD */
@@ -2030,7 +2039,7 @@ vm_run(struct vm *vm, struct vm_run *vmrun)
vtc.vtc_status = 0;
installctx(curthread, &vtc, vmm_savectx, vmm_restorectx, NULL, NULL,
- NULL, NULL);
+ NULL, vmm_freectx);
#endif
restart:
@@ -2147,21 +2156,8 @@ restart:
goto restart;
#ifndef __FreeBSD__
- /*
- * Before returning to userspace, explicitly restore the host FPU state
- * (saving the guest state). This is done with kpreempt disabled to
- * ensure it is not interrupted, potentially confusing the soon-to-be
- * removed savectx/restorectx handlers.
- */
- kpreempt_disable();
- if ((vtc.vtc_status & VTCS_FPU_RESTORED) != 0) {
- save_guest_fpustate(vcpu);
- vtc.vtc_status &= ~VTCS_FPU_RESTORED;
- }
- kpreempt_enable();
-
removectx(curthread, &vtc, vmm_savectx, vmm_restorectx, NULL, NULL,
- NULL, NULL);
+ NULL, vmm_freectx);
#endif
VCPU_CTR2(vm, vcpuid, "retu %d/%d", error, vme->exitcode);
diff --git a/usr/src/uts/intel/ia32/os/desctbls.c b/usr/src/uts/intel/ia32/os/desctbls.c
index 66b14377a6..8e0a4edd61 100644
--- a/usr/src/uts/intel/ia32/os/desctbls.c
+++ b/usr/src/uts/intel/ia32/os/desctbls.c
@@ -1304,6 +1304,28 @@ init_desctbls(void)
#endif /* __xpv */
+#ifndef __xpv
+/*
+ * As per Intel Vol 3 27.5.2, the GDTR limit is reset to 64Kb on a VM exit, so
+ * we have to manually fix it up ourselves.
+ *
+ * The caller may still need to make sure that it can't go off-CPU with the
+ * incorrect limit, before calling this (such as disabling pre-emption).
+ */
+void
+reset_gdtr_limit(void)
+{
+ ulong_t flags = intr_clear();
+ desctbr_t gdtr;
+
+ rd_gdtr(&gdtr);
+ gdtr.dtr_limit = (sizeof (user_desc_t) * NGDT) - 1;
+ wr_gdtr(&gdtr);
+
+ intr_restore(flags);
+}
+#endif /* __xpv */
+
/*
* In the early kernel, we need to set up a simple GDT to run on.
*
diff --git a/usr/src/uts/intel/sys/x86_archext.h b/usr/src/uts/intel/sys/x86_archext.h
index 07f88edd01..c6d696dc6e 100644
--- a/usr/src/uts/intel/sys/x86_archext.h
+++ b/usr/src/uts/intel/sys/x86_archext.h
@@ -961,6 +961,10 @@ extern void enable_pcid(void);
extern void xsave_setup_msr(struct cpu *);
+#if !defined(__xpv)
+extern void reset_gdtr_limit(void);
+#endif
+
/*
* Hypervisor signatures
*/