166458Sdfr/*-
266458Sdfr * Copyright (c) 1988 University of Utah.
366458Sdfr * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
466458Sdfr * All rights reserved.
566458Sdfr *
666458Sdfr * This code is derived from software contributed to Berkeley by
766458Sdfr * the Systems Programming Group of the University of Utah Computer
866458Sdfr * Science Department, and code derived from software contributed to
966458Sdfr * Berkeley by William Jolitz.
1066458Sdfr *
1166458Sdfr * Redistribution and use in source and binary forms, with or without
1266458Sdfr * modification, are permitted provided that the following conditions
1366458Sdfr * are met:
1466458Sdfr * 1. Redistributions of source code must retain the above copyright
1566458Sdfr *    notice, this list of conditions and the following disclaimer.
1666458Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1766458Sdfr *    notice, this list of conditions and the following disclaimer in the
1866458Sdfr *    documentation and/or other materials provided with the distribution.
1966458Sdfr * 4. Neither the name of the University nor the names of its contributors
2066458Sdfr *    may be used to endorse or promote products derived from this software
2166458Sdfr *    without specific prior written permission.
2266458Sdfr *
2366458Sdfr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2466458Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2566458Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2666458Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2766458Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2866458Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2966458Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3066458Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3166458Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3266458Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3366458Sdfr * SUCH DAMAGE.
3466458Sdfr *
3566458Sdfr *	from: Utah $Hdr: mem.c 1.13 89/10/08$
3666458Sdfr *	from: @(#)mem.c	7.2 (Berkeley) 5/9/91
3766458Sdfr */
3866458Sdfr
39132956Smarkm#include <sys/cdefs.h>
40132956Smarkm__FBSDID("$FreeBSD$");
41132956Smarkm
4266458Sdfr/*
4366458Sdfr * Memory special file
4466458Sdfr */
4566458Sdfr
4666458Sdfr#include <sys/param.h>
4766458Sdfr#include <sys/conf.h>
48270296Semaste#include <sys/efi.h>
4966458Sdfr#include <sys/fcntl.h>
5066458Sdfr#include <sys/kernel.h>
5166458Sdfr#include <sys/malloc.h>
5266458Sdfr#include <sys/memrange.h>
5366458Sdfr#include <sys/systm.h>
5466458Sdfr#include <sys/uio.h>
5566458Sdfr
5666458Sdfr#include <vm/vm.h>
5766458Sdfr#include <vm/pmap.h>
5866458Sdfr#include <vm/vm_extern.h>
5966458Sdfr
60132956Smarkm#include <machine/memdev.h>
6166458Sdfr
6266458Sdfrstruct mem_range_softc mem_range_softc;
6366458Sdfr
64268194Smarcelstatic int
65268194Smarcelmem_phys2virt(vm_offset_t offset, int prot, void **ptr, u_long *limit)
66117993Smarcel{
67268194Smarcel	struct efi_md *md;
68268194Smarcel
69268194Smarcel	if (prot & ~(VM_PROT_READ | VM_PROT_WRITE))
70268194Smarcel		return (EPERM);
71268194Smarcel
72268194Smarcel	md = efi_md_find(offset);
73268194Smarcel	if (md == NULL)
74268194Smarcel		return (EFAULT);
75268194Smarcel
76268194Smarcel	if (md->md_type == EFI_MD_TYPE_BAD)
77268194Smarcel		return (EIO);
78268194Smarcel
79268194Smarcel	*ptr = (void *)((md->md_attr & EFI_MD_ATTR_WB)
80268194Smarcel	    ? IA64_PHYS_TO_RR7(offset) : IA64_PHYS_TO_RR6(offset));
81268194Smarcel	*limit = (md->md_pages * EFI_PAGE_SIZE) - (offset - md->md_phys);
82268194Smarcel	return (0);
83117993Smarcel}
84117993Smarcel
85132956Smarkm/* ARGSUSED */
86132956Smarkmint
87133023Smarcelmemrw(struct cdev *dev, struct uio *uio, int flags)
8866458Sdfr{
8966458Sdfr	struct iovec *iov;
90268194Smarcel	off_t ofs;
91268194Smarcel	vm_offset_t addr;
92268194Smarcel	void *ptr;
93268194Smarcel	u_long limit;
94268194Smarcel	int count, error, phys, rw;
9566458Sdfr
96115859Smarcel	error = 0;
97268194Smarcel	rw = (uio->uio_rw == UIO_READ) ? VM_PROT_READ : VM_PROT_WRITE;
98268194Smarcel
9966458Sdfr	while (uio->uio_resid > 0 && !error) {
10066458Sdfr		iov = uio->uio_iov;
10166458Sdfr		if (iov->iov_len == 0) {
10266458Sdfr			uio->uio_iov++;
10366458Sdfr			uio->uio_iovcnt--;
10466458Sdfr			if (uio->uio_iovcnt < 0)
105132956Smarkm				panic("memrw");
10666458Sdfr			continue;
10766458Sdfr		}
108115859Smarcel
109268194Smarcel		ofs = uio->uio_offset;
11066458Sdfr
111268194Smarcel		phys = (dev2unit(dev) == CDEV_MINOR_MEM) ? 1 : 0;
112268194Smarcel		if (phys == 0 && ofs >= IA64_RR_BASE(6)) {
113268194Smarcel			ofs = IA64_RR_MASK(ofs);
114268194Smarcel			phys++;
115132956Smarkm		}
11666458Sdfr
117268194Smarcel		if (phys) {
118268194Smarcel			error = mem_phys2virt(ofs, rw, &ptr, &limit);
119268194Smarcel			if (error)
120268194Smarcel				return (error);
12166458Sdfr
122268194Smarcel			count = min(uio->uio_resid, limit);
123268194Smarcel			error = uiomove(ptr, count, uio);
124268194Smarcel		} else {
125268194Smarcel			ptr = (void *)ofs;
126268194Smarcel			count = iov->iov_len;
127115859Smarcel
12866458Sdfr			/*
129115859Smarcel			 * Make sure that all of the pages are currently
130115859Smarcel			 * resident so that we don't create any zero-fill
131115859Smarcel			 * pages.
13266458Sdfr			 */
133268194Smarcel			limit = round_page(ofs + count);
134268194Smarcel			addr = trunc_page(ofs);
135246882Smarcel			if (addr < VM_MAXUSER_ADDRESS)
136268194Smarcel				return (EINVAL);
137268194Smarcel			for (; addr < limit; addr += PAGE_SIZE) {
138239379Smarcel				if (pmap_kextract(addr) == 0)
139115859Smarcel					return (EFAULT);
140115859Smarcel			}
141268194Smarcel			if (!kernacc(ptr, count, rw))
14266458Sdfr				return (EFAULT);
143268194Smarcel			error = uiomove(ptr, count, uio);
14466458Sdfr		}
145132956Smarkm		/* else panic! */
14666458Sdfr	}
14766458Sdfr	return (error);
14866458Sdfr}
14966458Sdfr
150132956Smarkm/*
151132956Smarkm * allow user processes to MMAP some memory sections
152132956Smarkm * instead of going through read/write
153132956Smarkm */
154132956Smarkmint
155201223Srnolandmemmmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr,
156201223Srnoland    int prot, vm_memattr_t *memattr)
15766458Sdfr{
158268194Smarcel	void *ptr;
159268194Smarcel	u_long limit;
160268194Smarcel	int error;
161268194Smarcel
16266458Sdfr	/*
16366458Sdfr	 * /dev/mem is the only one that makes sense through this
16466458Sdfr	 * interface.  For /dev/kmem any physaddr we return here
16566458Sdfr	 * could be transient and hence incorrect or invalid at
16666458Sdfr	 * a later time.
16766458Sdfr	 */
168183397Sed	if (dev2unit(dev) != CDEV_MINOR_MEM)
169268194Smarcel		return (ENXIO);
17066458Sdfr
171268194Smarcel	error = mem_phys2virt(offset, prot, &ptr, &limit);
172268194Smarcel	if (error)
173268194Smarcel		return (error);
174268194Smarcel
175268194Smarcel	*paddr = offset;
176268194Smarcel	*memattr = ((uintptr_t)ptr >= IA64_RR_BASE(7)) ?
177268194Smarcel	    VM_MEMATTR_WRITE_BACK : VM_MEMATTR_UNCACHEABLE;
178111462Smux	return (0);
17966458Sdfr}
180