svn commit: r324855 - in stable/11/sys: amd64/amd64 amd64/include i386/i386 i386/include
Konstantin Belousov
kib at FreeBSD.org
Sun Oct 22 08:47:15 UTC 2017
Author: kib
Date: Sun Oct 22 08:47:13 2017
New Revision: 324855
URL: https://svnweb.freebsd.org/changeset/base/324855
Log:
MFC r323772, r324302-r324308, r324310, r324313, r324315, r324326, r324330,
r324334, r324354-r324355, r324366, r324432-r324433, r324437-r324439:
Fixes and improvements for x86 LDT handling.
Modified:
stable/11/sys/amd64/amd64/sys_machdep.c
stable/11/sys/amd64/include/proc.h
stable/11/sys/i386/i386/machdep.c
stable/11/sys/i386/i386/swtch.s
stable/11/sys/i386/i386/sys_machdep.c
stable/11/sys/i386/include/md_var.h
Directory Properties:
stable/11/ (props changed)
Modified: stable/11/sys/amd64/amd64/sys_machdep.c
==============================================================================
--- stable/11/sys/amd64/amd64/sys_machdep.c Sun Oct 22 08:42:01 2017 (r324854)
+++ stable/11/sys/amd64/amd64/sys_machdep.c Sun Oct 22 08:47:13 2017 (r324855)
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
#include <sys/mutex.h>
#include <sys/priv.h>
#include <sys/proc.h>
+#include <sys/smp.h>
#include <sys/sysproto.h>
#include <sys/uio.h>
@@ -64,7 +65,7 @@ __FBSDID("$FreeBSD$");
#define MAX_LD 8192
-int max_ldt_segment = 1024;
+int max_ldt_segment = 512;
SYSCTL_INT(_machdep, OID_AUTO, max_ldt_segment, CTLFLAG_RDTUN,
&max_ldt_segment, 0,
"Maximum number of allowed LDT segments in the single address space");
@@ -80,11 +81,6 @@ max_ldt_segment_init(void *arg __unused)
}
SYSINIT(maxldt, SI_SUB_VM_CONF, SI_ORDER_ANY, max_ldt_segment_init, NULL);
-#ifdef notyet
-#ifdef SMP
-static void set_user_ldt_rv(struct vmspace *vmsp);
-#endif
-#endif
static void user_ldt_derefl(struct proc_ldt *pldt);
#ifndef _SYS_SYSPROTO_H_
@@ -428,18 +424,14 @@ done:
* Update the GDT entry pointing to the LDT to point to the LDT of the
* current process.
*/
-void
+static void
set_user_ldt(struct mdproc *mdp)
{
- critical_enter();
*PCPU_GET(ldt) = mdp->md_ldt_sd;
lldt(GSEL(GUSERLDT_SEL, SEL_KPL));
- critical_exit();
}
-#ifdef notyet
-#ifdef SMP
static void
set_user_ldt_rv(struct vmspace *vmsp)
{
@@ -451,8 +443,6 @@ set_user_ldt_rv(struct vmspace *vmsp)
set_user_ldt(&td->td_proc->p_md);
}
-#endif
-#endif
struct proc_ldt *
user_ldt_alloc(struct proc *p, int force)
@@ -494,11 +484,13 @@ user_ldt_alloc(struct proc *p, int force)
sizeof(struct user_segment_descriptor));
user_ldt_derefl(pldt);
}
+ critical_enter();
ssdtosyssd(&sldt, &p->p_md.md_ldt_sd);
- atomic_store_rel_ptr((volatile uintptr_t *)&mdp->md_ldt,
- (uintptr_t)new_ldt);
- if (p == curproc)
- set_user_ldt(mdp);
+ atomic_thread_fence_rel();
+ mdp->md_ldt = new_ldt;
+ critical_exit();
+ smp_rendezvous(NULL, (void (*)(void *))set_user_ldt_rv, NULL,
+ p->p_vmspace);
return (mdp->md_ldt);
}
@@ -516,10 +508,13 @@ user_ldt_free(struct thread *td)
return;
}
+ critical_enter();
mdp->md_ldt = NULL;
+ atomic_thread_fence_rel();
bzero(&mdp->md_ldt_sd, sizeof(mdp->md_ldt_sd));
if (td == curthread)
lldt(GSEL(GNULL_SEL, SEL_KPL));
+ critical_exit();
user_ldt_deref(pldt);
}
@@ -550,57 +545,57 @@ user_ldt_deref(struct proc_ldt *pldt)
* the OS-specific one.
*/
int
-amd64_get_ldt(td, uap)
- struct thread *td;
- struct i386_ldt_args *uap;
+amd64_get_ldt(struct thread *td, struct i386_ldt_args *uap)
{
- int error = 0;
struct proc_ldt *pldt;
- int num;
struct user_segment_descriptor *lp;
+ uint64_t *data;
+ u_int i, num;
+ int error;
#ifdef DEBUG
- printf("amd64_get_ldt: start=%d num=%d descs=%p\n",
+ printf("amd64_get_ldt: start=%u num=%u descs=%p\n",
uap->start, uap->num, (void *)uap->descs);
#endif
- if ((pldt = td->td_proc->p_md.md_ldt) != NULL) {
- lp = &((struct user_segment_descriptor *)(pldt->ldt_base))
- [uap->start];
- num = min(uap->num, max_ldt_segment);
- } else
- return (EINVAL);
-
- if ((uap->start > (unsigned int)max_ldt_segment) ||
- ((unsigned int)num > (unsigned int)max_ldt_segment) ||
- ((unsigned int)(uap->start + num) > (unsigned int)max_ldt_segment))
- return(EINVAL);
-
- error = copyout(lp, uap->descs, num *
+ pldt = td->td_proc->p_md.md_ldt;
+ if (pldt == NULL || uap->start >= max_ldt_segment || uap->num == 0) {
+ td->td_retval[0] = 0;
+ return (0);
+ }
+ num = min(uap->num, max_ldt_segment - uap->start);
+ lp = &((struct user_segment_descriptor *)(pldt->ldt_base))[uap->start];
+ data = malloc(num * sizeof(struct user_segment_descriptor), M_TEMP,
+ M_WAITOK);
+ mtx_lock(&dt_lock);
+ for (i = 0; i < num; i++)
+ data[i] = ((volatile uint64_t *)lp)[i];
+ mtx_unlock(&dt_lock);
+ error = copyout(data, uap->descs, num *
sizeof(struct user_segment_descriptor));
- if (!error)
+ free(data, M_TEMP);
+ if (error == 0)
td->td_retval[0] = num;
-
- return(error);
+ return (error);
}
int
-amd64_set_ldt(td, uap, descs)
- struct thread *td;
- struct i386_ldt_args *uap;
- struct user_segment_descriptor *descs;
+amd64_set_ldt(struct thread *td, struct i386_ldt_args *uap,
+ struct user_segment_descriptor *descs)
{
- int error = 0;
- unsigned int largest_ld, i;
- struct mdproc *mdp = &td->td_proc->p_md;
+ struct mdproc *mdp;
struct proc_ldt *pldt;
struct user_segment_descriptor *dp;
struct proc *p;
+ u_int largest_ld, i;
+ int error;
#ifdef DEBUG
- printf("amd64_set_ldt: start=%d num=%d descs=%p\n",
+ printf("amd64_set_ldt: start=%u num=%u descs=%p\n",
uap->start, uap->num, (void *)uap->descs);
#endif
+ mdp = &td->td_proc->p_md;
+ error = 0;
set_pcb_flags(td->td_pcb, PCB_FULL_IRET);
p = td->td_proc;
@@ -618,10 +613,9 @@ amd64_set_ldt(td, uap, descs)
largest_ld = max_ldt_segment;
if (largest_ld < uap->start)
return (EINVAL);
- i = largest_ld - uap->start;
mtx_lock(&dt_lock);
- bzero(&((struct user_segment_descriptor *)(pldt->ldt_base))
- [uap->start], sizeof(struct user_segment_descriptor) * i);
+ for (i = uap->start; i < largest_ld; i++)
+ ((volatile uint64_t *)(pldt->ldt_base))[i] = 0;
mtx_unlock(&dt_lock);
return (0);
}
@@ -658,12 +652,7 @@ amd64_set_ldt(td, uap, descs)
case SDT_SYSNULL4:
case SDT_SYSIGT:
case SDT_SYSTGT:
- /* I can't think of any reason to allow a user proc
- * to create a segment of these types. They are
- * for OS use only.
- */
return (EACCES);
- /*NOTREACHED*/
/* memory segment types */
case SDT_MEMEC: /* memory execute only conforming */
@@ -689,7 +678,6 @@ amd64_set_ldt(td, uap, descs)
break;
default:
return(EINVAL);
- /*NOTREACHED*/
}
/* Only user (ring-3) descriptors may be present. */
@@ -743,14 +731,18 @@ int
amd64_set_ldt_data(struct thread *td, int start, int num,
struct user_segment_descriptor *descs)
{
- struct mdproc *mdp = &td->td_proc->p_md;
- struct proc_ldt *pldt = mdp->md_ldt;
+ struct mdproc *mdp;
+ struct proc_ldt *pldt;
+ volatile uint64_t *dst, *src;
+ int i;
mtx_assert(&dt_lock, MA_OWNED);
- /* Fill in range */
- bcopy(descs,
- &((struct user_segment_descriptor *)(pldt->ldt_base))[start],
- num * sizeof(struct user_segment_descriptor));
+ mdp = &td->td_proc->p_md;
+ pldt = mdp->md_ldt;
+ dst = (volatile uint64_t *)(pldt->ldt_base);
+ src = (volatile uint64_t *)descs;
+ for (i = 0; i < num; i++)
+ dst[start + i] = src[i];
return (0);
}
Modified: stable/11/sys/amd64/include/proc.h
==============================================================================
--- stable/11/sys/amd64/include/proc.h Sun Oct 22 08:42:01 2017 (r324854)
+++ stable/11/sys/amd64/include/proc.h Sun Oct 22 08:47:13 2017 (r324855)
@@ -88,7 +88,6 @@ struct syscall_args {
(char *)&td; \
} while (0)
-void set_user_ldt(struct mdproc *);
struct proc_ldt *user_ldt_alloc(struct proc *, int);
void user_ldt_free(struct thread *);
void user_ldt_deref(struct proc_ldt *);
Modified: stable/11/sys/i386/i386/machdep.c
==============================================================================
--- stable/11/sys/i386/i386/machdep.c Sun Oct 22 08:42:01 2017 (r324854)
+++ stable/11/sys/i386/i386/machdep.c Sun Oct 22 08:47:13 2017 (r324855)
@@ -1146,6 +1146,15 @@ exec_setregs(struct thread *td, struct image_params *i
else
mtx_unlock_spin(&dt_lock);
+ /*
+ * Reset the fs and gs bases. The values from the old address
+ * space do not make sense for the new program. In particular,
+ * gsbase might be the TLS base for the old program but the new
+ * program has no TLS now.
+ */
+ set_fsbase(td, 0);
+ set_gsbase(td, 0);
+
bzero((char *)regs, sizeof(struct trapframe));
regs->tf_eip = imgp->entry_addr;
regs->tf_esp = stack;
Modified: stable/11/sys/i386/i386/swtch.s
==============================================================================
--- stable/11/sys/i386/i386/swtch.s Sun Oct 22 08:42:01 2017 (r324854)
+++ stable/11/sys/i386/i386/swtch.s Sun Oct 22 08:47:13 2017 (r324855)
@@ -283,6 +283,10 @@ sw1:
pushl %edx /* Preserve pointer to pcb. */
addl $P_MD,%eax /* Pointer to mdproc is arg. */
pushl %eax
+ /*
+ * Holding dt_lock prevents context switches, so dt_lock cannot
+ * be held now and set_user_ldt() will not deadlock acquiring it.
+ */
call set_user_ldt
addl $4,%esp
popl %edx
Modified: stable/11/sys/i386/i386/sys_machdep.c
==============================================================================
--- stable/11/sys/i386/i386/sys_machdep.c Sun Oct 22 08:42:01 2017 (r324854)
+++ stable/11/sys/i386/i386/sys_machdep.c Sun Oct 22 08:47:13 2017 (r324855)
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <vm/vm_map.h>
#include <vm/vm_extern.h>
+#include <machine/atomic.h>
#include <machine/cpu.h>
#include <machine/pcb.h>
#include <machine/pcb_ext.h>
@@ -68,10 +69,10 @@ __FBSDID("$FreeBSD$");
#define NULL_LDT_BASE ((caddr_t)NULL)
#ifdef SMP
-static void set_user_ldt_rv(struct vmspace *vmsp);
+static void set_user_ldt_rv(void *arg);
#endif
static int i386_set_ldt_data(struct thread *, int start, int num,
- union descriptor *descs);
+ union descriptor *descs);
static int i386_ldt_grow(struct thread *td, int len);
void
@@ -90,6 +91,37 @@ fill_based_sd(struct segment_descriptor *sdp, uint32_t
sdp->sd_gran = 1;
}
+/*
+ * Construct special descriptors for "base" selectors. Store them in
+ * the PCB for later use by cpu_switch(). Store them in the GDT for
+ * more immediate use. The GDT entries are part of the current
+ * context. Callers must load related segment registers to complete
+ * setting up the current context.
+ */
+void
+set_fsbase(struct thread *td, uint32_t base)
+{
+ struct segment_descriptor sd;
+
+ fill_based_sd(&sd, base);
+ critical_enter();
+ td->td_pcb->pcb_fsd = sd;
+ PCPU_GET(fsgs_gdt)[0] = sd;
+ critical_exit();
+}
+
+void
+set_gsbase(struct thread *td, uint32_t base)
+{
+ struct segment_descriptor sd;
+
+ fill_based_sd(&sd, base);
+ critical_enter();
+ td->td_pcb->pcb_gsd = sd;
+ PCPU_GET(fsgs_gdt)[1] = sd;
+ critical_exit();
+}
+
#ifndef _SYS_SYSPROTO_H_
struct sysarch_args {
int op;
@@ -110,7 +142,7 @@ sysarch(td, uap)
struct i386_get_xfpustate xfpu;
} kargs;
uint32_t base;
- struct segment_descriptor sd, *sdp;
+ struct segment_descriptor *sdp;
AUDIT_ARG_CMD(uap->op);
@@ -155,8 +187,6 @@ sysarch(td, uap)
if ((error = copyin(uap->parms, &kargs.largs,
sizeof(struct i386_ldt_args))) != 0)
return (error);
- if (kargs.largs.num > MAX_LD || kargs.largs.num <= 0)
- return (EINVAL);
break;
case I386_GET_XFPUSTATE:
if ((error = copyin(uap->parms, &kargs.xfpu,
@@ -167,14 +197,15 @@ sysarch(td, uap)
break;
}
- switch(uap->op) {
+ switch (uap->op) {
case I386_GET_LDT:
error = i386_get_ldt(td, &kargs.largs);
break;
case I386_SET_LDT:
if (kargs.largs.descs != NULL) {
- lp = (union descriptor *)malloc(
- kargs.largs.num * sizeof(union descriptor),
+ if (kargs.largs.num > MAX_LD)
+ return (EINVAL);
+ lp = malloc(kargs.largs.num * sizeof(union descriptor),
M_TEMP, M_WAITOK);
error = copyin(kargs.largs.descs, lp,
kargs.largs.num * sizeof(union descriptor));
@@ -206,16 +237,11 @@ sysarch(td, uap)
error = copyin(uap->parms, &base, sizeof(base));
if (error == 0) {
/*
- * Construct a descriptor and store it in the pcb for
- * the next context switch. Also store it in the gdt
- * so that the load of tf_fs into %fs will activate it
- * at return to userland.
+ * Construct the special descriptor for fsbase
+ * and arrange for doreti to load its selector
+ * soon enough.
*/
- fill_based_sd(&sd, base);
- critical_enter();
- td->td_pcb->pcb_fsd = sd;
- PCPU_GET(fsgs_gdt)[0] = sd;
- critical_exit();
+ set_fsbase(td, base);
td->td_frame->tf_fs = GSEL(GUFS_SEL, SEL_UPL);
}
break;
@@ -228,15 +254,11 @@ sysarch(td, uap)
error = copyin(uap->parms, &base, sizeof(base));
if (error == 0) {
/*
- * Construct a descriptor and store it in the pcb for
- * the next context switch. Also store it in the gdt
- * because we have to do a load_gs() right now.
+ * Construct the special descriptor for gsbase.
+ * The selector is loaded immediately, since we
+ * normally only reload %gs on context switches.
*/
- fill_based_sd(&sd, base);
- critical_enter();
- td->td_pcb->pcb_gsd = sd;
- PCPU_GET(fsgs_gdt)[1] = sd;
- critical_exit();
+ set_gsbase(td, base);
load_gs(GSEL(GUGS_SEL, SEL_UPL));
}
break;
@@ -385,41 +407,40 @@ done:
* Update the GDT entry pointing to the LDT to point to the LDT of the
* current process. Manage dt_lock holding/unholding autonomously.
*/
-void
-set_user_ldt(struct mdproc *mdp)
+static void
+set_user_ldt_locked(struct mdproc *mdp)
{
struct proc_ldt *pldt;
- int dtlocked;
+ int gdt_idx;
- dtlocked = 0;
- if (!mtx_owned(&dt_lock)) {
- mtx_lock_spin(&dt_lock);
- dtlocked = 1;
- }
+ mtx_assert(&dt_lock, MA_OWNED);
pldt = mdp->md_ldt;
-#ifdef SMP
- gdt[PCPU_GET(cpuid) * NGDT + GUSERLDT_SEL].sd = pldt->ldt_sd;
-#else
- gdt[GUSERLDT_SEL].sd = pldt->ldt_sd;
-#endif
+ gdt_idx = GUSERLDT_SEL;
+ gdt_idx += PCPU_GET(cpuid) * NGDT; /* always 0 on UP */
+ gdt[gdt_idx].sd = pldt->ldt_sd;
lldt(GSEL(GUSERLDT_SEL, SEL_KPL));
PCPU_SET(currentldt, GSEL(GUSERLDT_SEL, SEL_KPL));
- if (dtlocked)
- mtx_unlock_spin(&dt_lock);
}
+void
+set_user_ldt(struct mdproc *mdp)
+{
+
+ mtx_lock_spin(&dt_lock);
+ set_user_ldt_locked(mdp);
+ mtx_unlock_spin(&dt_lock);
+}
+
#ifdef SMP
static void
-set_user_ldt_rv(struct vmspace *vmsp)
+set_user_ldt_rv(void *arg)
{
- struct thread *td;
+ struct proc *p;
- td = curthread;
- if (vmsp != td->td_proc->p_vmspace)
- return;
-
- set_user_ldt(&td->td_proc->p_md);
+ p = curproc;
+ if (arg == p->p_vmspace)
+ set_user_ldt(&p->p_md);
}
#endif
@@ -433,8 +454,7 @@ user_ldt_alloc(struct mdproc *mdp, int len)
mtx_assert(&dt_lock, MA_OWNED);
mtx_unlock_spin(&dt_lock);
- new_ldt = malloc(sizeof(struct proc_ldt),
- M_SUBPROC, M_WAITOK);
+ new_ldt = malloc(sizeof(struct proc_ldt), M_SUBPROC, M_WAITOK);
new_ldt->ldt_len = len = NEW_MAX_LD(len);
new_ldt->ldt_base = (caddr_t)kmem_malloc(kernel_arena,
@@ -464,10 +484,11 @@ user_ldt_alloc(struct mdproc *mdp, int len)
void
user_ldt_free(struct thread *td)
{
- struct mdproc *mdp = &td->td_proc->p_md;
+ struct mdproc *mdp;
struct proc_ldt *pldt;
mtx_assert(&dt_lock, MA_OWNED);
+ mdp = &td->td_proc->p_md;
if ((pldt = mdp->md_ldt) == NULL) {
mtx_unlock_spin(&dt_lock);
return;
@@ -503,61 +524,55 @@ user_ldt_deref(struct proc_ldt *pldt)
* the OS-specific one.
*/
int
-i386_get_ldt(td, uap)
- struct thread *td;
- struct i386_ldt_args *uap;
+i386_get_ldt(struct thread *td, struct i386_ldt_args *uap)
{
- int error = 0;
struct proc_ldt *pldt;
- int nldt, num;
- union descriptor *lp;
+ char *data;
+ u_int nldt, num;
+ int error;
-#ifdef DEBUG
- printf("i386_get_ldt: start=%d num=%d descs=%p\n",
+#ifdef DEBUG
+ printf("i386_get_ldt: start=%u num=%u descs=%p\n",
uap->start, uap->num, (void *)uap->descs);
#endif
+ num = min(uap->num, MAX_LD);
+ data = malloc(num * sizeof(union descriptor), M_TEMP, M_WAITOK);
mtx_lock_spin(&dt_lock);
- if ((pldt = td->td_proc->p_md.md_ldt) != NULL) {
- nldt = pldt->ldt_len;
- lp = &((union descriptor *)(pldt->ldt_base))[uap->start];
- mtx_unlock_spin(&dt_lock);
- num = min(uap->num, nldt);
+ pldt = td->td_proc->p_md.md_ldt;
+ nldt = pldt != NULL ? pldt->ldt_len : nitems(ldt);
+ if (uap->start >= nldt) {
+ num = 0;
} else {
- mtx_unlock_spin(&dt_lock);
- nldt = sizeof(ldt)/sizeof(ldt[0]);
- num = min(uap->num, nldt);
- lp = &ldt[uap->start];
+ num = min(num, nldt - uap->start);
+ bcopy(pldt != NULL ?
+ &((union descriptor *)(pldt->ldt_base))[uap->start] :
+ &ldt[uap->start], data, num * sizeof(union descriptor));
}
-
- if ((uap->start > (unsigned int)nldt) ||
- ((unsigned int)num > (unsigned int)nldt) ||
- ((unsigned int)(uap->start + num) > (unsigned int)nldt))
- return(EINVAL);
-
- error = copyout(lp, uap->descs, num * sizeof(union descriptor));
- if (!error)
+ mtx_unlock_spin(&dt_lock);
+ error = copyout(data, uap->descs, num * sizeof(union descriptor));
+ if (error == 0)
td->td_retval[0] = num;
-
- return(error);
+ free(data, M_TEMP);
+ return (error);
}
int
-i386_set_ldt(td, uap, descs)
- struct thread *td;
- struct i386_ldt_args *uap;
- union descriptor *descs;
+i386_set_ldt(struct thread *td, struct i386_ldt_args *uap,
+ union descriptor *descs)
{
- int error = 0, i;
- int largest_ld;
- struct mdproc *mdp = &td->td_proc->p_md;
+ struct mdproc *mdp;
struct proc_ldt *pldt;
union descriptor *dp;
+ u_int largest_ld, i;
+ int error;
-#ifdef DEBUG
- printf("i386_set_ldt: start=%d num=%d descs=%p\n",
+#ifdef DEBUG
+ printf("i386_set_ldt: start=%u num=%u descs=%p\n",
uap->start, uap->num, (void *)uap->descs);
#endif
+ error = 0;
+ mdp = &td->td_proc->p_md;
if (descs == NULL) {
/* Free descriptors */
@@ -569,8 +584,6 @@ i386_set_ldt(td, uap, descs)
uap->start = NLDT;
uap->num = MAX_LD - NLDT;
}
- if (uap->num == 0)
- return (EINVAL);
mtx_lock_spin(&dt_lock);
if ((pldt = mdp->md_ldt) == NULL ||
uap->start >= pldt->ldt_len) {
@@ -580,19 +593,18 @@ i386_set_ldt(td, uap, descs)
largest_ld = uap->start + uap->num;
if (largest_ld > pldt->ldt_len)
largest_ld = pldt->ldt_len;
- i = largest_ld - uap->start;
- bzero(&((union descriptor *)(pldt->ldt_base))[uap->start],
- sizeof(union descriptor) * i);
+ for (i = uap->start; i < largest_ld; i++)
+ atomic_store_rel_64(&((uint64_t *)(pldt->ldt_base))[i],
+ 0);
mtx_unlock_spin(&dt_lock);
return (0);
}
- if (!(uap->start == LDT_AUTO_ALLOC && uap->num == 1)) {
+ if (uap->start != LDT_AUTO_ALLOC || uap->num != 1) {
/* verify range of descriptors to modify */
largest_ld = uap->start + uap->num;
- if (uap->start >= MAX_LD || largest_ld > MAX_LD) {
+ if (uap->start >= MAX_LD || largest_ld > MAX_LD)
return (EINVAL);
- }
}
/* Check descriptors for access violations */
@@ -618,12 +630,7 @@ i386_set_ldt(td, uap, descs)
case SDT_SYS386TGT: /* system 386 trap gate */
case SDT_SYS286CGT: /* system 286 call gate */
case SDT_SYS386CGT: /* system 386 call gate */
- /* I can't think of any reason to allow a user proc
- * to create a segment of these types. They are
- * for OS use only.
- */
return (EACCES);
- /*NOTREACHED*/
/* memory segment types */
case SDT_MEMEC: /* memory execute only conforming */
@@ -648,12 +655,11 @@ i386_set_ldt(td, uap, descs)
case SDT_MEMERA: /* memory execute read accessed */
break;
default:
- return(EINVAL);
- /*NOTREACHED*/
+ return (EINVAL);
}
/* Only user (ring-3) descriptors may be present. */
- if ((dp->sd.sd_p != 0) && (dp->sd.sd_dpl != SEL_UPL))
+ if (dp->sd.sd_p != 0 && dp->sd.sd_dpl != SEL_UPL)
return (EACCES);
}
@@ -704,27 +710,37 @@ again:
static int
i386_set_ldt_data(struct thread *td, int start, int num,
- union descriptor *descs)
+ union descriptor *descs)
{
- struct mdproc *mdp = &td->td_proc->p_md;
- struct proc_ldt *pldt = mdp->md_ldt;
+ struct mdproc *mdp;
+ struct proc_ldt *pldt;
+ uint64_t *dst, *src;
+ int i;
mtx_assert(&dt_lock, MA_OWNED);
- /* Fill in range */
- bcopy(descs,
- &((union descriptor *)(pldt->ldt_base))[start],
- num * sizeof(union descriptor));
+ mdp = &td->td_proc->p_md;
+ pldt = mdp->md_ldt;
+ dst = (uint64_t *)(pldt->ldt_base);
+ src = (uint64_t *)descs;
+
+ /*
+ * Atomic(9) is used only to get 64bit atomic store with
+ * cmpxchg8b when available. There is no op without release
+ * semantic.
+ */
+ for (i = 0; i < num; i++)
+ atomic_store_rel_64(&dst[start + i], src[i]);
return (0);
}
static int
i386_ldt_grow(struct thread *td, int len)
{
- struct mdproc *mdp = &td->td_proc->p_md;
+ struct mdproc *mdp;
struct proc_ldt *new_ldt, *pldt;
- caddr_t old_ldt_base = NULL_LDT_BASE;
- int old_ldt_len = 0;
+ caddr_t old_ldt_base;
+ int old_ldt_len;
mtx_assert(&dt_lock, MA_OWNED);
@@ -733,6 +749,10 @@ i386_ldt_grow(struct thread *td, int len)
if (len < NLDT + 1)
len = NLDT + 1;
+ mdp = &td->td_proc->p_md;
+ old_ldt_base = NULL_LDT_BASE;
+ old_ldt_len = 0;
+
/* Allocate a user ldt. */
if ((pldt = mdp->md_ldt) == NULL || len > pldt->ldt_len) {
new_ldt = user_ldt_alloc(mdp, len);
@@ -774,10 +794,10 @@ i386_ldt_grow(struct thread *td, int len)
* to acquire it.
*/
mtx_unlock_spin(&dt_lock);
- smp_rendezvous(NULL, (void (*)(void *))set_user_ldt_rv,
- NULL, td->td_proc->p_vmspace);
+ smp_rendezvous(NULL, set_user_ldt_rv, NULL,
+ td->td_proc->p_vmspace);
#else
- set_user_ldt(&td->td_proc->p_md);
+ set_user_ldt_locked(&td->td_proc->p_md);
mtx_unlock_spin(&dt_lock);
#endif
if (old_ldt_base != NULL_LDT_BASE) {
Modified: stable/11/sys/i386/include/md_var.h
==============================================================================
--- stable/11/sys/i386/include/md_var.h Sun Oct 22 08:42:01 2017 (r324854)
+++ stable/11/sys/i386/include/md_var.h Sun Oct 22 08:47:13 2017 (r324855)
@@ -66,6 +66,8 @@ void init_AMD_Elan_sc520(void);
vm_paddr_t kvtop(void *addr);
void panicifcpuunsupported(void);
void ppro_reenable_apic(void);
+void set_fsbase(struct thread *td, uint32_t base);
+void set_gsbase(struct thread *td, uint32_t base);
void setidt(int idx, alias_for_inthand_t *func, int typ, int dpl, int selec);
union savefpu *get_pcb_user_save_td(struct thread *td);
union savefpu *get_pcb_user_save_pcb(struct pcb *pcb);
More information about the svn-src-stable-11
mailing list