From owner-svn-src-head@freebsd.org Tue Sep 19 17:57:05 2017 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id B3934E21334; Tue, 19 Sep 2017 17:57:05 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 81763657E0; Tue, 19 Sep 2017 17:57:05 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v8JHv4sk073677; Tue, 19 Sep 2017 17:57:04 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v8JHv4aD073675; Tue, 19 Sep 2017 17:57:04 GMT (envelope-from kib@FreeBSD.org) Message-Id: <201709191757.v8JHv4aD073675@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Tue, 19 Sep 2017 17:57:04 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r323772 - in head/sys: amd64/amd64 i386/i386 X-SVN-Group: head X-SVN-Commit-Author: kib X-SVN-Commit-Paths: in head/sys: amd64/amd64 i386/i386 X-SVN-Commit-Revision: 323772 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 19 Sep 2017 17:57:05 -0000 Author: kib Date: Tue Sep 19 17:57:04 2017 New Revision: 323772 URL: https://svnweb.freebsd.org/changeset/base/323772 Log: Do not do torn writes to active LDTs. Care must be taken when updating the active LDT, since parallel threads might try to load a segment descriptor which is currently updated. Since the results are undefined, this cannot be ignored by claiming to be an application race. Reviewed by: jhb Sponsored by: The FreeBSD Foundation MFC after: 2 weeks Differential revision: https://reviews.freebsd.org/D12413 Modified: head/sys/amd64/amd64/sys_machdep.c head/sys/i386/i386/sys_machdep.c Modified: head/sys/amd64/amd64/sys_machdep.c ============================================================================== --- head/sys/amd64/amd64/sys_machdep.c Tue Sep 19 17:12:18 2017 (r323771) +++ head/sys/amd64/amd64/sys_machdep.c Tue Sep 19 17:57:04 2017 (r323772) @@ -583,22 +583,22 @@ amd64_get_ldt(td, uap) } 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; + int error; + unsigned int largest_ld, i; #ifdef DEBUG printf("amd64_set_ldt: start=%d num=%d 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; @@ -616,10 +616,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++) + ((uint64_t *)(pldt->ldt_base))[i] = 0; mtx_unlock(&dt_lock); return (0); } @@ -741,14 +740,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; + 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 = (uint64_t *)(pldt->ldt_base); + src = (uint64_t *)descs; + for (i = 0; i < num; i++) + dst[start + i] = src[i]; return (0); } Modified: head/sys/i386/i386/sys_machdep.c ============================================================================== --- head/sys/i386/i386/sys_machdep.c Tue Sep 19 17:12:18 2017 (r323771) +++ head/sys/i386/i386/sys_machdep.c Tue Sep 19 17:57:04 2017 (r323772) @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include #include @@ -546,7 +547,7 @@ i386_set_ldt(td, uap, descs) struct i386_ldt_args *uap; union descriptor *descs; { - int error = 0, i; + int error, i; int largest_ld; struct mdproc *mdp = &td->td_proc->p_md; struct proc_ldt *pldt; @@ -556,6 +557,7 @@ i386_set_ldt(td, uap, descs) printf("i386_set_ldt: start=%d num=%d descs=%p\n", uap->start, uap->num, (void *)uap->descs); #endif + error = 0; if (descs == NULL) { /* Free descriptors */ @@ -578,9 +580,9 @@ 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); } @@ -702,17 +704,27 @@ 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); }