From a0955b86cd77e22e80846428a5065e871b6d8eb8 Mon Sep 17 00:00:00 2001 From: John Levon Date: Thu, 14 Jun 2018 12:53:00 +0100 Subject: 9600 LDT still not happy under KPTI Reviewed by: Toomas Soome Reviewed by: Igor Kozhukhov Approved by: Dan McDonald --- usr/src/pkg/manifests/system-test-ostest.mf | 4 +- usr/src/test/os-tests/runfiles/default.run | 7 +- usr/src/test/os-tests/tests/Makefile | 6 +- usr/src/test/os-tests/tests/i386/Makefile | 46 ++++++++++ usr/src/test/os-tests/tests/i386/ldt.c | 80 +++++++++++++++++ usr/src/test/test-runner/cmd/run | 6 ++ usr/src/uts/common/sys/proc.h | 5 +- usr/src/uts/i86pc/ml/offsets.in | 2 - usr/src/uts/i86pc/os/mlsetup.c | 5 -- usr/src/uts/i86pc/os/mp_startup.c | 6 +- usr/src/uts/intel/ia32/os/desctbls.c | 109 +++++++++-------------- usr/src/uts/intel/ia32/os/sysi86.c | 128 ++++++++++++---------------- usr/src/uts/intel/sys/segments.h | 4 + usr/src/uts/intel/sys/x86_archext.h | 4 +- 14 files changed, 253 insertions(+), 159 deletions(-) create mode 100644 usr/src/test/os-tests/tests/i386/Makefile create mode 100755 usr/src/test/os-tests/tests/i386/ldt.c diff --git a/usr/src/pkg/manifests/system-test-ostest.mf b/usr/src/pkg/manifests/system-test-ostest.mf index 49cb93b4a6..1b7705e816 100644 --- a/usr/src/pkg/manifests/system-test-ostest.mf +++ b/usr/src/pkg/manifests/system-test-ostest.mf @@ -12,7 +12,7 @@ # # Copyright (c) 2012, 2016 by Delphix. All rights reserved. # Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved. -# Copyright 2017 Joyent, Inc. +# Copyright 2018 Joyent, Inc. # set name=pkg.fmri value=pkg:/system/test/ostest@$(PKGVERS) @@ -26,6 +26,7 @@ dir path=opt/os-tests/bin dir path=opt/os-tests/runfiles dir path=opt/os-tests/tests dir path=opt/os-tests/tests/file-locking +$(i386_ONLY)dir path=opt/os-tests/tests/i386 dir path=opt/os-tests/tests/pf_key dir path=opt/os-tests/tests/sdevfs dir path=opt/os-tests/tests/secflags @@ -40,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/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 file path=opt/os-tests/tests/pf_key/eacq-enabler mode=0555 diff --git a/usr/src/test/os-tests/runfiles/default.run b/usr/src/test/os-tests/runfiles/default.run index d029b75e7b..8279f588e3 100644 --- a/usr/src/test/os-tests/runfiles/default.run +++ b/usr/src/test/os-tests/runfiles/default.run @@ -11,7 +11,7 @@ # # Copyright (c) 2012 by Delphix. All rights reserved. -# Copyright 2017 Joyent, Inc. +# Copyright 2018 Joyent, Inc. # [DEFAULT] @@ -62,3 +62,8 @@ tests = ['conn', 'dgram', 'drop_priv', 'nosignal', 'sockpair'] [/opt/os-tests/tests/pf_key] user = root tests = ['acquire-compare', 'acquire-spray'] + +[/opt/os-tests/tests/i386] +user = root +arch = i86pc +tests = ['ldt'] diff --git a/usr/src/test/os-tests/tests/Makefile b/usr/src/test/os-tests/tests/Makefile index f3af454450..5de66f69e5 100644 --- a/usr/src/test/os-tests/tests/Makefile +++ b/usr/src/test/os-tests/tests/Makefile @@ -11,10 +11,12 @@ # # Copyright (c) 2012, 2016 by Delphix. All rights reserved. -# Copyright 2017 Joyent, Inc. +# Copyright 2018 Joyent, Inc. # +SUBDIRS_i386 = i386 + SUBDIRS = poll secflags sigqueue spoof-ras sdevfs sockfs stress file-locking \ - pf_key + pf_key $(SUBDIRS_$(MACH)) include $(SRC)/test/Makefile.com diff --git a/usr/src/test/os-tests/tests/i386/Makefile b/usr/src/test/os-tests/tests/i386/Makefile new file mode 100644 index 0000000000..6c1f480b88 --- /dev/null +++ b/usr/src/test/os-tests/tests/i386/Makefile @@ -0,0 +1,46 @@ +# +# 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 $(SRC)/cmd/Makefile.cmd +include $(SRC)/test/Makefile.com + +PROG += ldt + +ROOTOPTPKG = $(ROOT)/opt/os-tests +TESTDIR = $(ROOTOPTPKG)/tests/i386 + +CSTD = $(CSTD_GNU99) + +CMDS = $(PROG:%=$(TESTDIR)/%) +$(CMDS) := FILEMODE = 0555 + +all: $(PROG) + +install: all $(CMDS) + +lint: + +clobber: clean + -$(RM) $(PROG) + +clean: + +$(CMDS): $(TESTDIR) $(PROG) + +$(TESTDIR): + $(INS.dir) + +$(TESTDIR)/%: % + $(INS.file) diff --git a/usr/src/test/os-tests/tests/i386/ldt.c b/usr/src/test/os-tests/tests/i386/ldt.c new file mode 100755 index 0000000000..dbe816b19c --- /dev/null +++ b/usr/src/test/os-tests/tests/i386/ldt.c @@ -0,0 +1,80 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +char foo[4096]; + +static void * +donothing(void *nothing) +{ + sleep(5); + return (NULL); +} + +int +main(void) +{ + pthread_t tid; + + /* + * This first is similar to what sbcl does in some variants. Note the + * SDT_MEMRW (not SDT_MEMRWA) so we check that the kernel is forcing the + * 'accessed' bit too. + */ + int sel = SEL_LDT(7); + + struct ssd ssd = { sel, (unsigned long)&foo, 4096, + SDT_MEMRW | (SEL_UPL << 5) | (1 << 7), 0x4 }; + + if (sysi86(SI86DSCR, &ssd) < 0) + err(-1, "failed to setup segment"); + + __asm__ __volatile__("mov %0, %%fs" : : "r" (sel)); + + ssd.acc1 = 0; + + if (sysi86(SI86DSCR, &ssd) == 0) + errx(-1, "removed in-use segment?"); + + __asm__ __volatile__("mov %0, %%fs" : : "r" (0)); + + if (sysi86(SI86DSCR, &ssd) < 0) + err(-1, "failed to remove segment"); + + for (int i = 0; i < MAXNLDT; i++) { + ssd.sel = SEL_LDT(i); + (void) sysi86(SI86DSCR, &ssd); + } + + for (int i = 0; i < 10; i++) + pthread_create(&tid, NULL, donothing, NULL); + + if (forkall() == 0) { + sleep(2); + _exit(0); + } + + sleep(6); + return (0); +} diff --git a/usr/src/test/test-runner/cmd/run b/usr/src/test/test-runner/cmd/run index 1695d795b7..678f74f4e1 100644 --- a/usr/src/test/test-runner/cmd/run +++ b/usr/src/test/test-runner/cmd/run @@ -14,11 +14,13 @@ # # Copyright (c) 2012, 2016 by Delphix. All rights reserved. # Copyright (c) 2017, Chris Fraire . +# Copyright 2018 Joyent, Inc. # import ConfigParser import os import logging +import platform from logging.handlers import WatchedFileHandler from datetime import datetime from optparse import OptionParser @@ -564,6 +566,10 @@ class TestRun(object): self.outputdir = os.path.join(self.outputdir, self.timestamp) for section in config.sections(): + if ('arch' in config.options(section) and + platform.machine() != config.get(section, 'arch')): + continue + if 'tests' in config.options(section): testgroup = TestGroup(section) for prop in TestGroup.props: diff --git a/usr/src/uts/common/sys/proc.h b/usr/src/uts/common/sys/proc.h index f0b692813f..e1b1a2289f 100644 --- a/usr/src/uts/common/sys/proc.h +++ b/usr/src/uts/common/sys/proc.h @@ -21,7 +21,7 @@ /* * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2017 Joyent, Inc. + * Copyright 2018 Joyent, Inc. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ @@ -301,7 +301,8 @@ typedef struct proc { */ kmutex_t p_ldtlock; /* protects the following fields */ user_desc_t *p_ldt; /* Pointer to private LDT */ - system_desc_t p_ldt_desc; /* segment descriptor for private LDT */ + uint64_t p_unused1; /* no longer used */ + uint64_t p_unused2; /* no longer used */ ushort_t p_ldtlimit; /* highest selector used */ #endif size_t p_swrss; /* resident set size before last swap */ diff --git a/usr/src/uts/i86pc/ml/offsets.in b/usr/src/uts/i86pc/ml/offsets.in index 0e3c634507..7e4d2bdec3 100644 --- a/usr/src/uts/i86pc/ml/offsets.in +++ b/usr/src/uts/i86pc/ml/offsets.in @@ -75,8 +75,6 @@ proc PROCSIZE p_as p_lockp p_user - p_ldt - p_ldt_desc p_model p_pctx p_agenttp diff --git a/usr/src/uts/i86pc/os/mlsetup.c b/usr/src/uts/i86pc/os/mlsetup.c index 09bf07848c..601c6937fd 100644 --- a/usr/src/uts/i86pc/os/mlsetup.c +++ b/usr/src/uts/i86pc/os/mlsetup.c @@ -361,11 +361,6 @@ mlsetup(struct regs *rp) CPU->cpu_pri = 12; /* initial PIL for the boot CPU */ - /* - * The kernel doesn't use LDTs unless a process explicitly requests one. - */ - p0.p_ldt_desc = null_sdesc; - /* * Initialize thread/cpu microstate accounting */ diff --git a/usr/src/uts/i86pc/os/mp_startup.c b/usr/src/uts/i86pc/os/mp_startup.c index f1a243343a..b1100377eb 100644 --- a/usr/src/uts/i86pc/os/mp_startup.c +++ b/usr/src/uts/i86pc/os/mp_startup.c @@ -2054,9 +2054,8 @@ mp_cpu_faulted_exit(struct cpu *cp) * syscall features. */ -/*ARGSUSED*/ void -cpu_fast_syscall_disable(void *arg) +cpu_fast_syscall_disable(void) { if (is_x86_feature(x86_featureset, X86FSET_MSR) && is_x86_feature(x86_featureset, X86FSET_SEP)) @@ -2066,9 +2065,8 @@ cpu_fast_syscall_disable(void *arg) cpu_asysc_disable(); } -/*ARGSUSED*/ void -cpu_fast_syscall_enable(void *arg) +cpu_fast_syscall_enable(void) { if (is_x86_feature(x86_featureset, X86FSET_MSR) && is_x86_feature(x86_featureset, X86FSET_SEP)) diff --git a/usr/src/uts/intel/ia32/os/desctbls.c b/usr/src/uts/intel/ia32/os/desctbls.c index b24d4e5840..ef733f648f 100644 --- a/usr/src/uts/intel/ia32/os/desctbls.c +++ b/usr/src/uts/intel/ia32/os/desctbls.c @@ -178,8 +178,6 @@ static struct interposing_handler brand_tbl[2]; * can understand. */ -#if defined(__amd64) - /* * In long mode we have the new L or long mode attribute bit * for code segments. Only the conforming bit in type is used along @@ -193,6 +191,8 @@ set_usegd(user_desc_t *dp, uint_t lmode, void *base, size_t size, uint_t type, uint_t dpl, uint_t gran, uint_t defopsz) { ASSERT(lmode == SDP_SHORT || lmode == SDP_LONG); + /* This should never be a "system" segment. */ + ASSERT3U(type & SDT_S, !=, 0); /* * 64-bit long mode. @@ -205,6 +205,14 @@ set_usegd(user_desc_t *dp, uint_t lmode, void *base, size_t size, */ dp->usd_def32 = defopsz; /* 0 = 16, 1 = 32-bit ops */ + /* + * We should always set the "accessed" bit (SDT_A), otherwise the CPU + * will write to the GDT whenever we change segment registers around. + * With KPTI on, the GDT is read-only in the user page table, which + * causes crashes if we don't set this. + */ + ASSERT3U(type & SDT_A, !=, 0); + dp->usd_long = lmode; /* 64-bit mode */ dp->usd_type = type; dp->usd_dpl = dpl; @@ -218,37 +226,10 @@ set_usegd(user_desc_t *dp, uint_t lmode, void *base, size_t size, dp->usd_hilimit = (uintptr_t)size >> 16; } -#elif defined(__i386) - -/* - * Install user segment descriptor for code and data. - */ -void -set_usegd(user_desc_t *dp, void *base, size_t size, uint_t type, - uint_t dpl, uint_t gran, uint_t defopsz) -{ - dp->usd_lolimit = size; - dp->usd_hilimit = (uintptr_t)size >> 16; - - dp->usd_lobase = (uintptr_t)base; - dp->usd_midbase = (uintptr_t)base >> 16; - dp->usd_hibase = (uintptr_t)base >> (16 + 8); - - dp->usd_type = type; - dp->usd_dpl = dpl; - dp->usd_p = 1; - dp->usd_def32 = defopsz; /* 0 = 16, 1 = 32 bit operands */ - dp->usd_gran = gran; /* 0 = bytes, 1 = pages */ -} - -#endif /* __i386 */ - /* * Install system segment descriptor for LDT and TSS segments. */ -#if defined(__amd64) - void set_syssegd(system_desc_t *dp, void *base, size_t size, uint_t type, uint_t dpl) @@ -281,39 +262,6 @@ get_ssd_base(system_desc_t *dp) return ((void *)base); } -#elif defined(__i386) - -void -set_syssegd(system_desc_t *dp, void *base, size_t size, uint_t type, - uint_t dpl) -{ - dp->ssd_lolimit = size; - dp->ssd_hilimit = (uintptr_t)size >> 16; - - dp->ssd_lobase = (uintptr_t)base; - dp->ssd_midbase = (uintptr_t)base >> 16; - dp->ssd_hibase = (uintptr_t)base >> (16 + 8); - - dp->ssd_type = type; - dp->ssd_zero = 0; /* must be zero */ - dp->ssd_dpl = dpl; - dp->ssd_p = 1; - dp->ssd_gran = 0; /* force byte units */ -} - -void * -get_ssd_base(system_desc_t *dp) -{ - uintptr_t base; - - base = (uintptr_t)dp->ssd_lobase | - (uintptr_t)dp->ssd_midbase << 16 | - (uintptr_t)dp->ssd_hibase << (16 + 8); - return ((void *)base); -} - -#endif /* __i386 */ - /* * Install gate segment descriptor for interrupt, trap, call and task gates. * @@ -391,17 +339,30 @@ set_gatesegd(gate_desc_t *dp, void (*func)(void), selector_t sel, void gdt_update_usegd(uint_t sidx, user_desc_t *udp) { -#if defined(__xpv) +#if defined(DEBUG) + /* This should never be a "system" segment, but it might be null. */ + if (udp->usd_p != 0 || udp->usd_type != 0) { + ASSERT3U(udp->usd_type & SDT_S, !=, 0); + } + /* + * We should always set the "accessed" bit (SDT_A), otherwise the CPU + * will write to the GDT whenever we change segment registers around. + * With KPTI on, the GDT is read-only in the user page table, which + * causes crashes if we don't set this. + */ + if (udp->usd_p != 0 || udp->usd_type != 0) { + ASSERT3U(udp->usd_type & SDT_A, !=, 0); + } +#endif +#if defined(__xpv) uint64_t dpa = CPU->cpu_m.mcpu_gdtpa + sizeof (*udp) * sidx; if (HYPERVISOR_update_descriptor(pa_to_ma(dpa), *(uint64_t *)udp)) panic("gdt_update_usegd: HYPERVISOR_update_descriptor"); #else /* __xpv */ - CPU->cpu_gdt[sidx] = *udp; - #endif /* __xpv */ } @@ -412,8 +373,23 @@ gdt_update_usegd(uint_t sidx, user_desc_t *udp) int ldt_update_segd(user_desc_t *ldp, user_desc_t *udp) { -#if defined(__xpv) +#if defined(DEBUG) + /* This should never be a "system" segment, but it might be null. */ + if (udp->usd_p != 0 || udp->usd_type != 0) { + ASSERT3U(udp->usd_type & SDT_S, !=, 0); + } + /* + * We should always set the "accessed" bit (SDT_A), otherwise the CPU + * will write to the LDT whenever we change segment registers around. + * With KPTI on, the LDT is read-only in the user page table, which + * causes crashes if we don't set this. + */ + if (udp->usd_p != 0 || udp->usd_type != 0) { + ASSERT3U(udp->usd_type & SDT_A, !=, 0); + } +#endif +#if defined(__xpv) uint64_t dpa; dpa = mmu_ptob(hat_getpfnum(kas.a_hat, (caddr_t)ldp)) | @@ -427,7 +403,6 @@ ldt_update_segd(user_desc_t *ldp, user_desc_t *udp) return (EINVAL); #else /* __xpv */ - *ldp = *udp; #endif /* __xpv */ diff --git a/usr/src/uts/intel/ia32/os/sysi86.c b/usr/src/uts/intel/ia32/os/sysi86.c index cd1129ea1f..4573d62fad 100644 --- a/usr/src/uts/intel/ia32/os/sysi86.c +++ b/usr/src/uts/intel/ia32/os/sysi86.c @@ -284,9 +284,12 @@ ssd_to_usd(struct ssd *ssd, user_desc_t *usd) USEGD_SETLIMIT(usd, ssd->ls); /* - * set type, dpl and present bits. + * Set type, dpl and present bits. + * + * Force the "accessed" bit to on so that we don't run afoul of + * KPTI. */ - usd->usd_type = ssd->acc1; + usd->usd_type = ssd->acc1 | SDT_A; usd->usd_dpl = ssd->acc1 >> 5; usd->usd_p = ssd->acc1 >> (5 + 2); @@ -345,8 +348,7 @@ static void ldt_load(void) { #if defined(__xpv) - xen_set_ldt(get_ssd_base(&curproc->p_ldt_desc), - curproc->p_ldtlimit + 1); + xen_set_ldt(curproc->p_ldt, curproc->p_ldtlimit + 1); #else size_t len; system_desc_t desc; @@ -412,7 +414,7 @@ ldt_savectx(proc_t *p) #endif ldt_unload(); - cpu_fast_syscall_enable(NULL); + cpu_fast_syscall_enable(); } static void @@ -422,30 +424,34 @@ ldt_restorectx(proc_t *p) ASSERT(p == curproc); ldt_load(); - cpu_fast_syscall_disable(NULL); + cpu_fast_syscall_disable(); } /* - * When a process with a private LDT execs, fast syscalls must be enabled for - * the new process image. + * At exec time, we need to clear up our LDT context and re-enable fast syscalls + * for the new process image. + * + * The same is true for the other case, where we have: + * + * proc_exit() + * ->exitpctx()->ldt_savectx() + * ->freepctx()->ldt_freectx() + * + * Because pre-emption is not prevented between the two callbacks, we could have + * come off CPU, and brought back LDT context when coming back on CPU via + * ldt_restorectx(). */ /* ARGSUSED */ static void ldt_freectx(proc_t *p, int isexec) { - ASSERT(p->p_ldt); - - if (isexec) { - kpreempt_disable(); - cpu_fast_syscall_enable(NULL); - kpreempt_enable(); - } + ASSERT(p->p_ldt != NULL); + ASSERT(p == curproc); - /* - * ldt_free() will free the memory used by the private LDT, reset the - * process's descriptor, and re-program the LDTR. - */ + kpreempt_disable(); ldt_free(p); + cpu_fast_syscall_enable(); + kpreempt_enable(); } /* @@ -497,10 +503,10 @@ ldt_installctx(proc_t *p, proc_t *cp) int setdscr(struct ssd *ssd) { - ushort_t seli; /* selector index */ + ushort_t seli; /* selector index */ user_desc_t *ldp; /* descriptor pointer */ user_desc_t ndesc; /* new descriptor */ - proc_t *pp = ttoproc(curthread); + proc_t *pp = curproc; int rc = 0; /* @@ -541,11 +547,12 @@ setdscr(struct ssd *ssd) */ kpreempt_disable(); ldt_installctx(pp, NULL); - cpu_fast_syscall_disable(NULL); + cpu_fast_syscall_disable(); ASSERT(curthread->t_post_sys != 0); kpreempt_enable(); } else if (seli > pp->p_ldtlimit) { + ASSERT(pp->p_pctx != NULL); /* * Increase size of ldt to include seli. @@ -647,10 +654,14 @@ setdscr(struct ssd *ssd) } /* - * If acc1 is zero, clear the descriptor (including the 'present' bit) + * If acc1 is zero, clear the descriptor (including the 'present' bit). + * Make sure we update the CPU-private copy of the LDT. */ if (ssd->acc1 == 0) { rc = ldt_update_segd(ldp, &null_udesc); + kpreempt_disable(); + ldt_load(); + kpreempt_enable(); mutex_exit(&pp->p_ldtlock); return (rc); } @@ -664,7 +675,6 @@ setdscr(struct ssd *ssd) return (EINVAL); } -#if defined(__amd64) /* * Do not allow 32-bit applications to create 64-bit mode code * segments. @@ -674,50 +684,34 @@ setdscr(struct ssd *ssd) mutex_exit(&pp->p_ldtlock); return (EINVAL); } -#endif /* __amd64 */ /* - * Set up a code or data user segment descriptor. + * Set up a code or data user segment descriptor, making sure to update + * the CPU-private copy of the LDT. */ if (SI86SSD_ISUSEG(ssd)) { ssd_to_usd(ssd, &ndesc); rc = ldt_update_segd(ldp, &ndesc); + kpreempt_disable(); + ldt_load(); + kpreempt_enable(); mutex_exit(&pp->p_ldtlock); return (rc); } -#if defined(__i386) - /* - * Allow a call gate only if the destination is in the LDT - * and the system is running in 32-bit legacy mode. - * - * In long mode 32-bit call gates are redefined as 64-bit call - * gates and the hw enforces that the target code selector - * of the call gate must be 64-bit selector. A #gp fault is - * generated if otherwise. Since we do not allow 32-bit processes - * to switch themselves to 64-bits we never allow call gates - * on 64-bit system system. - */ - if (SI86SSD_TYPE(ssd) == SDT_SYSCGT && SELISLDT(ssd->ls)) { - - - ssd_to_sgd(ssd, (gate_desc_t *)&ndesc); - rc = ldt_update_segd(ldp, &ndesc); - mutex_exit(&pp->p_ldtlock); - return (rc); - } -#endif /* __i386 */ - mutex_exit(&pp->p_ldtlock); return (EINVAL); } /* - * Allocate new LDT for process just large enough to contain seli. - * Note we allocate and grow LDT in PAGESIZE chunks. We do this - * to simplify the implementation and because on the hypervisor it's - * required, since the LDT must live on pages that have PROT_WRITE - * removed and which are given to the hypervisor. + * Allocate new LDT for process just large enough to contain seli. Note we + * allocate and grow LDT in PAGESIZE chunks. We do this to simplify the + * implementation and because on the hypervisor it's required, since the LDT + * must live on pages that have PROT_WRITE removed and which are given to the + * hypervisor. + * + * Note that we don't actually load the LDT into the current CPU here: it's done + * later by our caller. */ static void ldt_alloc(proc_t *pp, uint_t seli) @@ -748,13 +742,6 @@ ldt_alloc(proc_t *pp, uint_t seli) pp->p_ldt = ldt; pp->p_ldtlimit = nsels - 1; - set_syssegd(&pp->p_ldt_desc, ldt, ldtsz - 1, SDT_SYSLDT, SEL_KPL); - - if (pp == curproc) { - kpreempt_disable(); - ldt_load(); - kpreempt_enable(); - } } static void @@ -773,7 +760,6 @@ ldt_free(proc_t *pp) pp->p_ldt = NULL; pp->p_ldtlimit = 0; - pp->p_ldt_desc = null_sdesc; mutex_exit(&pp->p_ldtlock); if (pp == curproc) { @@ -838,6 +824,14 @@ ldt_dup(proc_t *pp, proc_t *cp) } +/* + * Note that we don't actually load the LDT into the current CPU here: it's done + * later by our caller - unless we take an error. This works out because + * ldt_load() does a copy of ->p_ldt instead of directly loading it into the GDT + * (and therefore can't be using the freed old LDT), and by definition if the + * new entry didn't pass validation, then the proc shouldn't be referencing an + * entry in the extended region. + */ static void ldt_grow(proc_t *pp, uint_t seli) { @@ -888,17 +882,5 @@ ldt_grow(proc_t *pp, uint_t seli) pp->p_ldt = nldt; pp->p_ldtlimit = nsels - 1; - /* - * write new ldt segment descriptor. - */ - set_syssegd(&pp->p_ldt_desc, nldt, nldtsz - 1, SDT_SYSLDT, SEL_KPL); - - /* - * load the new ldt. - */ - kpreempt_disable(); - ldt_load(); - kpreempt_enable(); - kmem_free(oldt, oldtsz); } diff --git a/usr/src/uts/intel/sys/segments.h b/usr/src/uts/intel/sys/segments.h index 2240b781f0..fc2f1847cd 100644 --- a/usr/src/uts/intel/sys/segments.h +++ b/usr/src/uts/intel/sys/segments.h @@ -482,6 +482,10 @@ void init_boot_gdt(user_desc_t *); #define SDT_MEMERC 30 /* execute read conforming */ #define SDT_MEMERAC 31 /* execute read accessed conforming */ +/* These bits are within the "type" field, like the values above. */ +#define SDT_A 0x01 /* accessed bit */ +#define SDT_S 0x10 /* S-bit at the top of "type" for usegs */ + /* * Entries in the Interrupt Descriptor Table (IDT) */ diff --git a/usr/src/uts/intel/sys/x86_archext.h b/usr/src/uts/intel/sys/x86_archext.h index e4373821b7..33c4cba41f 100644 --- a/usr/src/uts/intel/sys/x86_archext.h +++ b/usr/src/uts/intel/sys/x86_archext.h @@ -751,8 +751,8 @@ extern void setcr4(ulong_t); extern void mtrr_sync(void); -extern void cpu_fast_syscall_enable(void *); -extern void cpu_fast_syscall_disable(void *); +extern void cpu_fast_syscall_enable(void); +extern void cpu_fast_syscall_disable(void); struct cpu; -- cgit v1.2.3