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