mem.c revision 277379
11590Srgrimes/*- 21590Srgrimes * Copyright (c) 1988 University of Utah. 31590Srgrimes * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 41590Srgrimes * All rights reserved. 51590Srgrimes * 61590Srgrimes * This code is derived from software contributed to Berkeley by 71590Srgrimes * the Systems Programming Group of the University of Utah Computer 81590Srgrimes * Science Department, and code derived from software contributed to 91590Srgrimes * Berkeley by William Jolitz. 101590Srgrimes * 111590Srgrimes * Redistribution and use in source and binary forms, with or without 121590Srgrimes * modification, are permitted provided that the following conditions 131590Srgrimes * are met: 141590Srgrimes * 1. Redistributions of source code must retain the above copyright 151590Srgrimes * notice, this list of conditions and the following disclaimer. 161590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 171590Srgrimes * notice, this list of conditions and the following disclaimer in the 181590Srgrimes * documentation and/or other materials provided with the distribution. 191590Srgrimes * 4. Neither the name of the University nor the names of its contributors 201590Srgrimes * may be used to endorse or promote products derived from this software 211590Srgrimes * without specific prior written permission. 221590Srgrimes * 231590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 241590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 251590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 261590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 271590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 281590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 291590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3087628Sdwmalone * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 311590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 321590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3328625Ssteve * SUCH DAMAGE. 3487628Sdwmalone * 351590Srgrimes * from: Utah $Hdr: mem.c 1.13 89/10/08$ 3687628Sdwmalone * from: @(#)mem.c 7.2 (Berkeley) 5/9/91 3787628Sdwmalone */ 3887628Sdwmalone 391590Srgrimes#include <sys/cdefs.h> 401590Srgrimes__FBSDID("$FreeBSD: stable/10/sys/amd64/amd64/mem.c 277379 2015-01-19 11:07:29Z kib $"); 4191382Sdwmalone 421590Srgrimes/* 431590Srgrimes * Memory special file 441590Srgrimes */ 4592920Simp 4692920Simp#include <sys/param.h> 4792920Simp#include <sys/conf.h> 4892920Simp#include <sys/fcntl.h> 491590Srgrimes#include <sys/ioccom.h> 501590Srgrimes#include <sys/kernel.h> 511590Srgrimes#include <sys/lock.h> 521590Srgrimes#include <sys/malloc.h> 531590Srgrimes#include <sys/memrange.h> 541590Srgrimes#include <sys/module.h> 55100822Sdwmalone#include <sys/mutex.h> 561590Srgrimes#include <sys/proc.h> 571590Srgrimes#include <sys/signalvar.h> 581590Srgrimes#include <sys/systm.h> 591590Srgrimes#include <sys/uio.h> 601590Srgrimes 611590Srgrimes#include <machine/md_var.h> 621590Srgrimes#include <machine/specialreg.h> 631590Srgrimes#include <machine/vmparam.h> 641590Srgrimes 651590Srgrimes#include <vm/vm.h> 661590Srgrimes#include <vm/pmap.h> 671590Srgrimes#include <vm/vm_extern.h> 681590Srgrimes 691590Srgrimes#include <machine/memdev.h> 701590Srgrimes 711590Srgrimes/* 721590Srgrimes * Used in /dev/mem drivers and elsewhere 731590Srgrimes */ 741590SrgrimesMALLOC_DEFINE(M_MEMDESC, "memdesc", "memory range descriptors"); 751590Srgrimes 761590Srgrimes/* ARGSUSED */ 771590Srgrimesint 781590Srgrimesmemrw(struct cdev *dev, struct uio *uio, int flags) 791590Srgrimes{ 801590Srgrimes struct iovec *iov; 811590Srgrimes void *p; 821590Srgrimes ssize_t orig_resid; 831590Srgrimes u_long v, vd; 841590Srgrimes u_int c; 851590Srgrimes int error; 861590Srgrimes 871590Srgrimes error = 0; 881590Srgrimes orig_resid = uio->uio_resid; 891590Srgrimes while (uio->uio_resid > 0 && error == 0) { 901590Srgrimes iov = uio->uio_iov; 911590Srgrimes if (iov->iov_len == 0) { 921590Srgrimes uio->uio_iov++; 931590Srgrimes uio->uio_iovcnt--; 941590Srgrimes if (uio->uio_iovcnt < 0) 951590Srgrimes panic("memrw"); 961590Srgrimes continue; 971590Srgrimes } 981590Srgrimes v = uio->uio_offset; 991590Srgrimes c = ulmin(iov->iov_len, PAGE_SIZE - (u_int)(v & PAGE_MASK)); 1001590Srgrimes 1011590Srgrimes switch (dev2unit(dev)) { 1021590Srgrimes case CDEV_MINOR_KMEM: 1031590Srgrimes /* 1041590Srgrimes * Since c is clamped to be less or equal than 1051590Srgrimes * PAGE_SIZE, the uiomove() call does not 1061590Srgrimes * access past the end of the direct map. 1071590Srgrimes */ 1081590Srgrimes if (v >= DMAP_MIN_ADDRESS && 1091590Srgrimes v < DMAP_MIN_ADDRESS + dmaplimit) { 1101590Srgrimes error = uiomove((void *)v, c, uio); 1111590Srgrimes break; 1121590Srgrimes } 113166503Srse 1141590Srgrimes if (!kernacc((void *)v, c, uio->uio_rw == UIO_READ ? 1151590Srgrimes VM_PROT_READ : VM_PROT_WRITE)) { 1161590Srgrimes error = EFAULT; 1171590Srgrimes break; 1181590Srgrimes } 1191590Srgrimes 1201590Srgrimes /* 1211590Srgrimes * If the extracted address is not accessible 12291189Sgshapiro * through the direct map, then we make a 12391189Sgshapiro * private (uncached) mapping because we can't 1241590Srgrimes * depend on the existing kernel mapping 1251590Srgrimes * remaining valid until the completion of 1261590Srgrimes * uiomove(). 1271590Srgrimes * 1281590Srgrimes * XXX We cannot provide access to the 1291590Srgrimes * physical page 0 mapped into KVA. 1301590Srgrimes */ 1311590Srgrimes v = pmap_extract(kernel_pmap, v); 1321590Srgrimes if (v == 0) { 1331590Srgrimes error = EFAULT; 1341590Srgrimes break; 1351590Srgrimes } 1361590Srgrimes /* FALLTHROUGH */ 1371590Srgrimes case CDEV_MINOR_MEM: 1381590Srgrimes if (v < dmaplimit) { 1391590Srgrimes vd = PHYS_TO_DMAP(v); 1401590Srgrimes error = uiomove((void *)vd, c, uio); 1411590Srgrimes break; 1421590Srgrimes } 1431590Srgrimes if (v >= (1ULL << cpu_maxphyaddr)) { 1441590Srgrimes error = EFAULT; 1451590Srgrimes break; 1461590Srgrimes } 1471590Srgrimes p = pmap_mapdev(v, PAGE_SIZE); 1481590Srgrimes error = uiomove(p, c, uio); 1491590Srgrimes pmap_unmapdev((vm_offset_t)p, PAGE_SIZE); 1501590Srgrimes break; 1511590Srgrimes } 1521590Srgrimes } 1531590Srgrimes /* 1541590Srgrimes * Don't return error if any byte was written. Read and write 1551590Srgrimes * can return error only if no i/o was performed. 1561590Srgrimes */ 1571590Srgrimes if (uio->uio_resid != orig_resid) 1581590Srgrimes error = 0; 1591590Srgrimes return (error); 1601590Srgrimes} 1611590Srgrimes 1621590Srgrimes/* 1631590Srgrimes * allow user processes to MMAP some memory sections 1641590Srgrimes * instead of going through read/write 1651590Srgrimes */ 1661590Srgrimes/* ARGSUSED */ 1671590Srgrimesint 1681590Srgrimesmemmmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, 1691590Srgrimes int prot __unused, vm_memattr_t *memattr __unused) 1701590Srgrimes{ 1711590Srgrimes if (dev2unit(dev) == CDEV_MINOR_MEM) 1721590Srgrimes *paddr = offset; 1731590Srgrimes else if (dev2unit(dev) == CDEV_MINOR_KMEM) 1741590Srgrimes *paddr = vtophys(offset); 1751590Srgrimes /* else panic! */ 1761590Srgrimes return (0); 1771590Srgrimes} 1781590Srgrimes 1791590Srgrimes/* 1801590Srgrimes * Operations for changing memory attributes. 1811590Srgrimes * 1821590Srgrimes * This is basically just an ioctl shim for mem_range_attr_get 1831590Srgrimes * and mem_range_attr_set. 1841590Srgrimes */ 1851590Srgrimes/* ARGSUSED */ 1861590Srgrimesint 1871590Srgrimesmemioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, int flags, 1881590Srgrimes struct thread *td) 1891590Srgrimes{ 1901590Srgrimes int nd, error = 0; 1911590Srgrimes struct mem_range_op *mo = (struct mem_range_op *)data; 1921590Srgrimes struct mem_range_desc *md; 1931590Srgrimes 1941590Srgrimes /* is this for us? */ 1951590Srgrimes if ((cmd != MEMRANGE_GET) && 1961590Srgrimes (cmd != MEMRANGE_SET)) 19728625Ssteve return (ENOTTY); 19828625Ssteve 19928625Ssteve /* any chance we can handle this? */ 20028625Ssteve if (mem_range_softc.mr_op == NULL) 20128625Ssteve return (EOPNOTSUPP); 20228625Ssteve 20328625Ssteve /* do we have any descriptors? */ 20428625Ssteve if (mem_range_softc.mr_ndesc == 0) 20528625Ssteve return (ENXIO); 20628625Ssteve 2071590Srgrimes switch (cmd) { 2081590Srgrimes case MEMRANGE_GET: 2091590Srgrimes nd = imin(mo->mo_arg[0], mem_range_softc.mr_ndesc); 2101590Srgrimes if (nd > 0) { 2111590Srgrimes md = (struct mem_range_desc *) 2121590Srgrimes malloc(nd * sizeof(struct mem_range_desc), 2131590Srgrimes M_MEMDESC, M_WAITOK); 2141590Srgrimes error = mem_range_attr_get(md, &nd); 2151590Srgrimes if (!error) 2161590Srgrimes error = copyout(md, mo->mo_desc, 2171590Srgrimes nd * sizeof(struct mem_range_desc)); 2181590Srgrimes free(md, M_MEMDESC); 2191590Srgrimes } 2201590Srgrimes else 2211590Srgrimes nd = mem_range_softc.mr_ndesc; 2221590Srgrimes mo->mo_arg[0] = nd; 2231590Srgrimes break; 2241590Srgrimes 2251590Srgrimes case MEMRANGE_SET: 2261590Srgrimes md = (struct mem_range_desc *)malloc(sizeof(struct mem_range_desc), 2271590Srgrimes M_MEMDESC, M_WAITOK); 2281590Srgrimes error = copyin(mo->mo_desc, md, sizeof(struct mem_range_desc)); 2291590Srgrimes /* clamp description string */ 2301590Srgrimes md->mr_owner[sizeof(md->mr_owner) - 1] = 0; 2311590Srgrimes if (error == 0) 2321590Srgrimes error = mem_range_attr_set(md, &mo->mo_arg[0]); 2331590Srgrimes free(md, M_MEMDESC); 2341590Srgrimes break; 2351590Srgrimes } 2361590Srgrimes return (error); 2371590Srgrimes} 23897574Stjr