1206714Sjmallett/*-
2178172Simp * Copyright (c) 1988 University of Utah.
3206714Sjmallett * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
4206714Sjmallett * All rights reserved.
5178172Simp *
6178172Simp * This code is derived from software contributed to Berkeley by
7178172Simp * the Systems Programming Group of the University of Utah Computer
8206714Sjmallett * Science Department, and code derived from software contributed to
9206714Sjmallett * Berkeley by William Jolitz.
10178172Simp *
11178172Simp * Redistribution and use in source and binary forms, with or without
12178172Simp * modification, are permitted provided that the following conditions
13178172Simp * are met:
14178172Simp * 1. Redistributions of source code must retain the above copyright
15178172Simp *    notice, this list of conditions and the following disclaimer.
16178172Simp * 2. Redistributions in binary form must reproduce the above copyright
17178172Simp *    notice, this list of conditions and the following disclaimer in the
18178172Simp *    documentation and/or other materials provided with the distribution.
19178172Simp * 4. Neither the name of the University nor the names of its contributors
20178172Simp *    may be used to endorse or promote products derived from this software
21178172Simp *    without specific prior written permission.
22178172Simp *
23178172Simp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24178172Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25178172Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26178172Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27178172Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28178172Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29178172Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30178172Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31178172Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32178172Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33178172Simp * SUCH DAMAGE.
34178172Simp *
35206714Sjmallett *	from: Utah $Hdr: mem.c 1.13 89/10/08$
36206714Sjmallett *	from: @(#)mem.c	7.2 (Berkeley) 5/9/91
37178172Simp */
38178172Simp
39206714Sjmallett#include <sys/cdefs.h>
40206714Sjmallett__FBSDID("$FreeBSD$");
41206714Sjmallett
42178172Simp/*
43178172Simp * Memory special file
44178172Simp */
45178172Simp
46178172Simp#include <sys/param.h>
47206714Sjmallett#include <sys/conf.h>
48206714Sjmallett#include <sys/fcntl.h>
49178172Simp#include <sys/kernel.h>
50206714Sjmallett#include <sys/lock.h>
51206714Sjmallett#include <sys/malloc.h>
52206714Sjmallett#include <sys/memrange.h>
53206714Sjmallett#include <sys/module.h>
54206714Sjmallett#include <sys/mutex.h>
55178172Simp#include <sys/proc.h>
56178172Simp#include <sys/msgbuf.h>
57178172Simp#include <sys/systm.h>
58206714Sjmallett#include <sys/signalvar.h>
59178172Simp#include <sys/uio.h>
60206714Sjmallett
61178172Simp#include <machine/md_var.h>
62206714Sjmallett#include <machine/vmparam.h>
63206714Sjmallett
64206714Sjmallett#include <vm/vm.h>
65206714Sjmallett#include <vm/pmap.h>
66206714Sjmallett#include <vm/vm_extern.h>
67206714Sjmallett#include <vm/vm_page.h>
68206714Sjmallett
69178172Simp#include <machine/memdev.h>
70178172Simp
71206714Sjmallettstruct mem_range_softc mem_range_softc;
72178172Simp
73206714Sjmallett/* ARGSUSED */
74178172Simpint
75206714Sjmallettmemrw(struct cdev *dev, struct uio *uio, int flags)
76178172Simp{
77206714Sjmallett	struct iovec *iov;
78178172Simp	int error = 0;
79206714Sjmallett	vm_offset_t va, eva, off, v;
80206714Sjmallett	vm_prot_t prot;
81206714Sjmallett	struct vm_page m;
82206714Sjmallett	vm_page_t marr;
83206714Sjmallett	vm_size_t cnt;
84178172Simp
85206714Sjmallett	cnt = 0;
86206714Sjmallett	error = 0;
87206714Sjmallett
88206714Sjmallett	GIANT_REQUIRED;
89206714Sjmallett
90226459Sjchandra	pmap_page_init(&m);
91206714Sjmallett	while (uio->uio_resid > 0 && !error) {
92178172Simp		iov = uio->uio_iov;
93178172Simp		if (iov->iov_len == 0) {
94178172Simp			uio->uio_iov++;
95178172Simp			uio->uio_iovcnt--;
96178172Simp			if (uio->uio_iovcnt < 0)
97206714Sjmallett				panic("memrw");
98178172Simp			continue;
99178172Simp		}
100183397Sed		if (dev2unit(dev) == CDEV_MINOR_MEM) {
101178172Simp			v = uio->uio_offset;
102178172Simp
103206714Sjmallett			off = uio->uio_offset & PAGE_MASK;
104206714Sjmallett			cnt = PAGE_SIZE - ((vm_offset_t)iov->iov_base &
105206714Sjmallett			    PAGE_MASK);
106206714Sjmallett			cnt = min(cnt, PAGE_SIZE - off);
107206714Sjmallett			cnt = min(cnt, iov->iov_len);
108178172Simp
109206714Sjmallett			m.phys_addr = trunc_page(v);
110206714Sjmallett			marr = &m;
111206714Sjmallett			error = uiomove_fromphys(&marr, off, cnt, uio);
112178172Simp		}
113183397Sed		else if (dev2unit(dev) == CDEV_MINOR_KMEM) {
114206714Sjmallett			va = uio->uio_offset;
115202046Simp
116206714Sjmallett			va = trunc_page(uio->uio_offset);
117206714Sjmallett			eva = round_page(uio->uio_offset
118206714Sjmallett			    + iov->iov_len);
119178172Simp
120206714Sjmallett			/*
121206714Sjmallett			 * Make sure that all the pages are currently resident
122206714Sjmallett			 * so that we don't create any zero-fill pages.
123178172Simp			 */
124206718Sjmallett			if (va >= VM_MIN_KERNEL_ADDRESS &&
125206718Sjmallett			    eva <= VM_MAX_KERNEL_ADDRESS) {
126206718Sjmallett				for (; va < eva; va += PAGE_SIZE)
127206718Sjmallett					if (pmap_extract(kernel_pmap, va) == 0)
128206718Sjmallett						return (EFAULT);
129178172Simp
130206718Sjmallett				prot = (uio->uio_rw == UIO_READ)
131206718Sjmallett				    ? VM_PROT_READ : VM_PROT_WRITE;
132206718Sjmallett
133206718Sjmallett				va = uio->uio_offset;
134206718Sjmallett				if (kernacc((void *) va, iov->iov_len, prot)
135206718Sjmallett				    == FALSE)
136206714Sjmallett					return (EFAULT);
137206718Sjmallett			}
138178172Simp
139206714Sjmallett			va = uio->uio_offset;
140206714Sjmallett			error = uiomove((void *)va, iov->iov_len, uio);
141178172Simp			continue;
142178172Simp		}
143206714Sjmallett	}
144178172Simp
145178172Simp	return (error);
146178172Simp}
147178172Simp
148206714Sjmallett/*
149206714Sjmallett * allow user processes to MMAP some memory sections
150206714Sjmallett * instead of going through read/write
151206714Sjmallett */
152178172Simpint
153206714Sjmallettmemmmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
154201223Srnoland    int prot, vm_memattr_t *memattr)
155178172Simp{
156206714Sjmallett	/*
157206714Sjmallett	 * /dev/mem is the only one that makes sense through this
158206714Sjmallett	 * interface.  For /dev/kmem any physaddr we return here
159206714Sjmallett	 * could be transient and hence incorrect or invalid at
160206714Sjmallett	 * a later time.
161206714Sjmallett	 */
162206714Sjmallett	if (dev2unit(dev) != CDEV_MINOR_MEM)
163206714Sjmallett		return (-1);
164178172Simp
165206714Sjmallett	*paddr = offset;
166206714Sjmallett
167206714Sjmallett	return (0);
168178172Simp}
169