mem.c revision 221869
155714Skris/*-
2109998Smarkm * Copyright (c) 1988 University of Utah.
3109998Smarkm * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
4109998Smarkm * All rights reserved.
5109998Smarkm *
6109998Smarkm * This code is derived from software contributed to Berkeley by
7109998Smarkm * the Systems Programming Group of the University of Utah Computer
8109998Smarkm * Science Department, and code derived from software contributed to
9109998Smarkm * Berkeley by William Jolitz.
10109998Smarkm *
11109998Smarkm * Redistribution and use in source and binary forms, with or without
12109998Smarkm * modification, are permitted provided that the following conditions
13109998Smarkm * are met:
14109998Smarkm * 1. Redistributions of source code must retain the above copyright
15109998Smarkm *    notice, this list of conditions and the following disclaimer.
16109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright
17109998Smarkm *    notice, this list of conditions and the following disclaimer in the
18109998Smarkm *    documentation and/or other materials provided with the distribution.
19109998Smarkm * 4. Neither the name of the University nor the names of its contributors
20109998Smarkm *    may be used to endorse or promote products derived from this software
21109998Smarkm *    without specific prior written permission.
22109998Smarkm *
23109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24109998Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26109998Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27109998Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28109998Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29109998Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3155714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3255714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3355714Skris * SUCH DAMAGE.
3455714Skris *
3555714Skris *	from: Utah $Hdr: mem.c 1.13 89/10/08$
3655714Skris *	from: @(#)mem.c	7.2 (Berkeley) 5/9/91
37296341Sdelphij *	from: FreeBSD: src/sys/i386/i386/mem.c,v 1.94 2001/09/26
3855714Skris */
3955714Skris
4055714Skris#include <sys/cdefs.h>
4155714Skris__FBSDID("$FreeBSD: head/sys/sparc64/sparc64/mem.c 221869 2011-05-14 01:53:38Z attilio $");
4255714Skris
4355714Skris/*
44296341Sdelphij * Memory special file
4555714Skris *
4655714Skris * NOTE: other architectures support mmap()'ing the mem and kmem devices; this
4755714Skris * might cause illegal aliases to be created for the locked kernel page(s), so
4855714Skris * it is not implemented.
4955714Skris */
5055714Skris
51296341Sdelphij#include <sys/param.h>
5255714Skris#include <sys/conf.h>
5355714Skris#include <sys/fcntl.h>
5455714Skris#include <sys/kernel.h>
5555714Skris#include <sys/lock.h>
5655714Skris#include <sys/malloc.h>
5755714Skris#include <sys/memrange.h>
5855714Skris#include <sys/module.h>
5955714Skris#include <sys/mutex.h>
6055714Skris#include <sys/proc.h>
6155714Skris#include <sys/signalvar.h>
6255714Skris#include <sys/systm.h>
6355714Skris#include <sys/uio.h>
6455714Skris
6555714Skris#include <vm/vm.h>
66296341Sdelphij#include <vm/vm_param.h>
6755714Skris#include <vm/vm_page.h>
6855714Skris#include <vm/vm_kern.h>
69296341Sdelphij#include <vm/pmap.h>
7055714Skris#include <vm/vm_extern.h>
7155714Skris
7255714Skris#include <machine/cache.h>
7355714Skris#include <machine/md_var.h>
7455714Skris#include <machine/pmap.h>
7555714Skris#include <machine/tlb.h>
7655714Skris
7755714Skris#include <machine/memdev.h>
7855714Skris
7955714Skrisstruct mem_range_softc mem_range_softc;
8055714Skris
81296341Sdelphij/* ARGSUSED */
8255714Skrisint
8355714Skrismemrw(struct cdev *dev, struct uio *uio, int flags)
8455714Skris{
8555714Skris	struct iovec *iov;
8655714Skris	vm_offset_t eva;
87109998Smarkm	vm_offset_t off;
88109998Smarkm	vm_offset_t ova;
89109998Smarkm	vm_offset_t va;
90109998Smarkm	vm_prot_t prot;
91109998Smarkm	vm_paddr_t pa;
92109998Smarkm	vm_size_t cnt;
93109998Smarkm	vm_page_t m;
94109998Smarkm	int error;
95296341Sdelphij	int i;
96109998Smarkm	uint32_t colors;
97109998Smarkm
98109998Smarkm	cnt = 0;
99109998Smarkm	colors = 1;
100109998Smarkm	error = 0;
101109998Smarkm	ova = 0;
102109998Smarkm
103109998Smarkm	GIANT_REQUIRED;
104109998Smarkm
105109998Smarkm	while (uio->uio_resid > 0 && error == 0) {
106109998Smarkm		iov = uio->uio_iov;
107109998Smarkm		if (iov->iov_len == 0) {
108109998Smarkm			uio->uio_iov++;
109109998Smarkm			uio->uio_iovcnt--;
110109998Smarkm			if (uio->uio_iovcnt < 0)
111109998Smarkm				panic("memrw");
112109998Smarkm			continue;
113109998Smarkm		}
114109998Smarkm		if (dev2unit(dev) == CDEV_MINOR_MEM) {
115109998Smarkm			pa = uio->uio_offset & ~PAGE_MASK;
116109998Smarkm			if (!is_physical_memory(pa)) {
117109998Smarkm				error = EFAULT;
118109998Smarkm				break;
119109998Smarkm			}
120109998Smarkm
121109998Smarkm			off = uio->uio_offset & PAGE_MASK;
122109998Smarkm			cnt = PAGE_SIZE - ((vm_offset_t)iov->iov_base &
123109998Smarkm			    PAGE_MASK);
124109998Smarkm			cnt = ulmin(cnt, PAGE_SIZE - off);
125109998Smarkm			cnt = ulmin(cnt, iov->iov_len);
126109998Smarkm
127109998Smarkm			m = NULL;
128109998Smarkm			for (i = 0; phys_avail[i] != 0; i += 2) {
129109998Smarkm				if (pa >= phys_avail[i] &&
130109998Smarkm				    pa < phys_avail[i + 1]) {
131109998Smarkm					m = PHYS_TO_VM_PAGE(pa);
132109998Smarkm					break;
133109998Smarkm				}
134109998Smarkm			}
135109998Smarkm
136109998Smarkm			if (m != NULL) {
137109998Smarkm				if (ova == 0) {
138109998Smarkm					if (dcache_color_ignore == 0)
139109998Smarkm						colors = DCACHE_COLORS;
14055714Skris					ova = kmem_alloc_wait(kernel_map,
141160814Ssimon					    PAGE_SIZE * colors);
14255714Skris				}
14355714Skris				if (colors != 1 && m->md.color != -1)
144109998Smarkm					va = ova + m->md.color * PAGE_SIZE;
145296341Sdelphij				else
146296341Sdelphij					va = ova;
147296341Sdelphij				pmap_qenter(va, &m, 1);
148296341Sdelphij				error = uiomove((void *)(va + off), cnt,
149296341Sdelphij				    uio);
150296341Sdelphij				pmap_qremove(va, 1);
151296341Sdelphij			} else {
152296341Sdelphij				va = TLB_PHYS_TO_DIRECT(pa);
153296341Sdelphij				error = uiomove((void *)(va + off), cnt,
154296341Sdelphij				    uio);
155296341Sdelphij			}
156296341Sdelphij			break;
157296341Sdelphij		} else if (dev2unit(dev) == CDEV_MINOR_KMEM) {
158296341Sdelphij			va = trunc_page(uio->uio_offset);
159296341Sdelphij			eva = round_page(uio->uio_offset + iov->iov_len);
160296341Sdelphij
161296341Sdelphij			/*
162296341Sdelphij			 * Make sure that all of the pages are currently
163296341Sdelphij			 * resident so we don't create any zero fill pages.
164296341Sdelphij			 */
165296341Sdelphij			for (; va < eva; va += PAGE_SIZE)
16655714Skris				if (pmap_kextract(va) == 0)
167109998Smarkm					return (EFAULT);
168109998Smarkm
169109998Smarkm			prot = (uio->uio_rw == UIO_READ) ? VM_PROT_READ :
170296341Sdelphij			    VM_PROT_WRITE;
171296341Sdelphij			va = uio->uio_offset;
172296341Sdelphij			if (va < VM_MIN_DIRECT_ADDRESS &&
173296341Sdelphij			    kernacc((void *)va, iov->iov_len, prot) == FALSE)
174109998Smarkm				return (EFAULT);
175109998Smarkm
176109998Smarkm			error = uiomove((void *)va, iov->iov_len, uio);
177109998Smarkm			break;
178109998Smarkm		}
179109998Smarkm		/* else panic! */
180296341Sdelphij	}
181296341Sdelphij	if (ova != 0)
182296341Sdelphij		kmem_free_wakeup(kernel_map, ova, PAGE_SIZE * colors);
183109998Smarkm	return (error);
184296341Sdelphij}
185296341Sdelphij