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