From owner-svn-src-all@FreeBSD.ORG Mon Jan 19 11:02:24 2015 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 0D9009DC; Mon, 19 Jan 2015 11:02:24 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::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 ED7BBA6D; Mon, 19 Jan 2015 11:02:23 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t0JB2NUS053424; Mon, 19 Jan 2015 11:02:23 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t0JB2NV3053423; Mon, 19 Jan 2015 11:02:23 GMT (envelope-from kib@FreeBSD.org) Message-Id: <201501191102.t0JB2NV3053423@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Mon, 19 Jan 2015 11:02:23 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r277377 - stable/10/sys/amd64/amd64 X-SVN-Group: stable-10 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 19 Jan 2015 11:02:24 -0000 Author: kib Date: Mon Jan 19 11:02:23 2015 New Revision: 277377 URL: https://svnweb.freebsd.org/changeset/base/277377 Log: MFC r277051: Fix several issues with /dev/mem and /dev/kmem devices on amd64. Modified: stable/10/sys/amd64/amd64/mem.c Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/amd64/amd64/mem.c ============================================================================== --- stable/10/sys/amd64/amd64/mem.c Mon Jan 19 10:58:52 2015 (r277376) +++ stable/10/sys/amd64/amd64/mem.c Mon Jan 19 11:02:23 2015 (r277377) @@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include @@ -77,13 +78,15 @@ int memrw(struct cdev *dev, struct uio *uio, int flags) { struct iovec *iov; - u_long c, v, vd; - int error, o, sflags; - vm_offset_t addr, eaddr; + void *p; + ssize_t orig_resid; + u_long v, vd; + u_int c; + int error, sflags; error = 0; - c = 0; sflags = curthread_pflags_set(TDP_DEVMEMIO); + orig_resid = uio->uio_resid; while (uio->uio_resid > 0 && error == 0) { iov = uio->uio_iov; if (iov->iov_len == 0) { @@ -93,63 +96,68 @@ memrw(struct cdev *dev, struct uio *uio, panic("memrw"); continue; } - if (dev2unit(dev) == CDEV_MINOR_MEM) { - v = uio->uio_offset; -kmemphys: - o = v & PAGE_MASK; - c = min(uio->uio_resid, (u_int)(PAGE_SIZE - o)); - vd = PHYS_TO_DMAP(v); - if (vd < DMAP_MIN_ADDRESS || - (vd > DMAP_MIN_ADDRESS + dmaplimit && - vd <= DMAP_MAX_ADDRESS) || - (pmap_kextract(vd) == 0 && (v & PG_FRAME) != 0)) { - error = EFAULT; - goto ret; - } - error = uiomove((void *)vd, (int)c, uio); - continue; - } else if (dev2unit(dev) == CDEV_MINOR_KMEM) { - v = uio->uio_offset; + v = uio->uio_offset; + c = ulmin(iov->iov_len, PAGE_SIZE - (u_int)(v & PAGE_MASK)); - if (v >= DMAP_MIN_ADDRESS && v < DMAP_MAX_ADDRESS) { - v = DMAP_TO_PHYS(v); - goto kmemphys; + switch (dev2unit(dev)) { + case CDEV_MINOR_KMEM: + /* + * Since c is clamped to be less or equal than + * PAGE_SIZE, the uiomove() call does not + * access past the end of the direct map. + */ + if (v >= DMAP_MIN_ADDRESS && + v < DMAP_MIN_ADDRESS + dmaplimit) { + error = uiomove((void *)v, c, uio); + break; } - c = iov->iov_len; + if (!kernacc((void *)v, c, uio->uio_rw == UIO_READ ? + VM_PROT_READ : VM_PROT_WRITE)) { + error = EFAULT; + break; + } /* - * Make sure that all of the pages are currently - * resident so that we don't create any zero-fill - * pages. + * If the extracted address is not accessible + * through the direct map, then we make a + * private (uncached) mapping because we can't + * depend on the existing kernel mapping + * remaining valid until the completion of + * uiomove(). + * + * XXX We cannot provide access to the + * physical page 0 mapped into KVA. */ - addr = trunc_page(v); - eaddr = round_page(v + c); - - if (addr < VM_MIN_KERNEL_ADDRESS) { + v = pmap_extract(kernel_pmap, v); + if (v == 0) { error = EFAULT; - goto ret; + break; } - for (; addr < eaddr; addr += PAGE_SIZE) { - if (pmap_extract(kernel_pmap, addr) == 0) { - error = EFAULT; - goto ret; - } + /* FALLTHROUGH */ + case CDEV_MINOR_MEM: + if (v < dmaplimit) { + vd = PHYS_TO_DMAP(v); + error = uiomove((void *)vd, c, uio); + break; } - if (!kernacc((caddr_t)(long)v, c, - uio->uio_rw == UIO_READ ? - VM_PROT_READ : VM_PROT_WRITE)) { + if (v >= (1ULL << cpu_maxphyaddr)) { error = EFAULT; - goto ret; + break; } - - error = uiomove((caddr_t)(long)v, (int)c, uio); - continue; + p = pmap_mapdev(v, PAGE_SIZE); + error = uiomove(p, c, uio); + pmap_unmapdev((vm_offset_t)p, PAGE_SIZE); + break; } - /* else panic! */ } -ret: curthread_pflags_restore(sflags); + /* + * Don't return error if any byte was written. Read and write + * can return error only if no i/o was performed. + */ + if (uio->uio_resid != orig_resid) + error = 0; return (error); }