1295041Sbr/*- 2295041Sbr * Copyright (c) 2014 Andrew Turner 3295041Sbr * All rights reserved. 4295041Sbr * 5295041Sbr * Redistribution and use in source and binary forms, with or without 6295041Sbr * modification, are permitted provided that the following conditions 7295041Sbr * are met: 8295041Sbr * 1. Redistributions of source code must retain the above copyright 9295041Sbr * notice, this list of conditions and the following disclaimer. 10295041Sbr * 2. Redistributions in binary form must reproduce the above copyright 11295041Sbr * notice, this list of conditions and the following disclaimer in the 12295041Sbr * documentation and/or other materials provided with the distribution. 13295041Sbr * 14295041Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15295041Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16295041Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17295041Sbr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18295041Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19295041Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20295041Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21295041Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22295041Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23295041Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24295041Sbr * SUCH DAMAGE. 25295041Sbr * 26295041Sbr */ 27295041Sbr 28295041Sbr#include <sys/cdefs.h> 29295041Sbr__FBSDID("$FreeBSD$"); 30295041Sbr 31295041Sbr#include <sys/param.h> 32295041Sbr#include <sys/systm.h> 33295041Sbr#include <sys/conf.h> 34295041Sbr#include <sys/malloc.h> 35295041Sbr#include <sys/memrange.h> 36295041Sbr#include <sys/uio.h> 37295041Sbr 38295041Sbr#include <machine/memdev.h> 39295041Sbr#include <machine/vmparam.h> 40295041Sbr 41295041Sbr#include <vm/vm.h> 42295041Sbr#include <vm/pmap.h> 43295041Sbr#include <vm/vm_extern.h> 44295041Sbr#include <vm/vm_page.h> 45295041Sbr 46295041Sbrstruct mem_range_softc mem_range_softc; 47295041Sbr 48295041Sbrint 49295041Sbrmemrw(struct cdev *dev, struct uio *uio, int flags) 50295041Sbr{ 51295041Sbr ssize_t orig_resid; 52295041Sbr vm_offset_t off, v; 53295041Sbr struct iovec *iov; 54295041Sbr struct vm_page m; 55295041Sbr vm_page_t marr; 56295041Sbr u_int cnt; 57295041Sbr int error; 58295041Sbr 59295041Sbr error = 0; 60295041Sbr orig_resid = uio->uio_resid; 61295041Sbr while (uio->uio_resid > 0 && error == 0) { 62295041Sbr iov = uio->uio_iov; 63295041Sbr if (iov->iov_len == 0) { 64295041Sbr uio->uio_iov++; 65295041Sbr uio->uio_iovcnt--; 66295041Sbr if (uio->uio_iovcnt < 0) 67295041Sbr panic("memrw"); 68295041Sbr continue; 69295041Sbr } 70295041Sbr 71295041Sbr v = uio->uio_offset; 72295041Sbr off = v & PAGE_MASK; 73295041Sbr cnt = ulmin(iov->iov_len, PAGE_SIZE - (u_int)off); 74295041Sbr if (cnt == 0) 75295041Sbr continue; 76295041Sbr 77295041Sbr switch(dev2unit(dev)) { 78295041Sbr case CDEV_MINOR_KMEM: 79295041Sbr /* If the address is in the DMAP just copy it */ 80295041Sbr if (VIRT_IN_DMAP(v)) { 81295041Sbr error = uiomove((void *)v, cnt, uio); 82295041Sbr break; 83295041Sbr } 84295041Sbr 85295041Sbr if (!kernacc((void *)v, cnt, uio->uio_rw == UIO_READ ? 86295041Sbr VM_PROT_READ : VM_PROT_WRITE)) { 87295041Sbr error = EFAULT; 88295041Sbr break; 89295041Sbr } 90295041Sbr 91295041Sbr /* Get the physical address to read */ 92295041Sbr v = pmap_extract(kernel_pmap, v); 93295041Sbr if (v == 0) { 94295041Sbr error = EFAULT; 95295041Sbr break; 96295041Sbr } 97295041Sbr 98295041Sbr /* FALLTHROUGH */ 99295041Sbr case CDEV_MINOR_MEM: 100295041Sbr /* If within the DMAP use this to copy from */ 101295041Sbr if (PHYS_IN_DMAP(v)) { 102295041Sbr v = PHYS_TO_DMAP(v); 103295041Sbr error = uiomove((void *)v, cnt, uio); 104295041Sbr break; 105295041Sbr } 106295041Sbr 107295041Sbr /* Have uiomove_fromphys handle the data */ 108295041Sbr m.phys_addr = trunc_page(v); 109295041Sbr marr = &m; 110295041Sbr uiomove_fromphys(&marr, off, cnt, uio); 111295041Sbr break; 112295041Sbr } 113295041Sbr } 114295041Sbr 115295041Sbr /* 116295041Sbr * Don't return error if any byte was written. Read and write 117295041Sbr * can return error only if no i/o was performed. 118295041Sbr */ 119295041Sbr if (uio->uio_resid != orig_resid) 120295041Sbr error = 0; 121295041Sbr 122295041Sbr return (error); 123295041Sbr} 124295041Sbr 125