mem.c revision 130585
1/*- 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department, and code derived from software contributed to 9 * Berkeley by William Jolitz. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * from: Utah $Hdr: mem.c 1.13 89/10/08$ 36 * from: @(#)mem.c 7.2 (Berkeley) 5/9/91 37 * from: FreeBSD: src/sys/i386/i386/mem.c,v 1.94 2001/09/26 38 * 39 * $FreeBSD: head/sys/sparc64/sparc64/mem.c 130585 2004-06-16 09:47:26Z phk $ 40 */ 41 42/* 43 * Memory special file 44 * 45 * NOTE: other architectures support mmap()'ing the mem and kmem devices; this 46 * might cause illegal aliases to be created for the locked kernel page(s), so 47 * it is not implemented. 48 */ 49 50#include <sys/param.h> 51#include <sys/conf.h> 52#include <sys/fcntl.h> 53#include <sys/kernel.h> 54#include <sys/lock.h> 55#include <sys/module.h> 56#include <sys/mutex.h> 57#include <sys/module.h> 58#include <sys/proc.h> 59#include <sys/signalvar.h> 60#include <sys/systm.h> 61#include <sys/uio.h> 62 63#include <vm/vm.h> 64#include <vm/vm_param.h> 65#include <vm/vm_page.h> 66#include <vm/vm_kern.h> 67#include <vm/pmap.h> 68#include <vm/vm_extern.h> 69 70#include <machine/cache.h> 71#include <machine/md_var.h> 72#include <machine/pmap.h> 73#include <machine/tlb.h> 74#include <machine/upa.h> 75 76static struct cdev *memdev, *kmemdev; 77 78static d_open_t mmopen; 79static d_close_t mmclose; 80static d_read_t mmrw; 81 82#define CDEV_MAJOR 2 83static struct cdevsw mem_cdevsw = { 84 .d_version = D_VERSION, 85 .d_open = mmopen, 86 .d_close = mmclose, 87 .d_read = mmrw, 88 .d_write = mmrw, 89 .d_name = "mem", 90 .d_maj = CDEV_MAJOR, 91 .d_flags = D_MEM | D_NEEDGIANT, 92}; 93 94static int 95mmclose(struct cdev *dev, int flags, int fmt, struct thread *td) 96{ 97 98 return (0); 99} 100 101static int 102mmopen(struct cdev *dev, int flags, int fmt, struct thread *td) 103{ 104 int error; 105 106 switch (minor(dev)) { 107 case 0: 108 case 1: 109 if (flags & FWRITE) { 110 error = securelevel_gt(td->td_ucred, 0); 111 if (error != 0) 112 return (error); 113 } 114 break; 115 default: 116 return (ENXIO); 117 } 118 return (0); 119} 120 121/*ARGSUSED*/ 122static int 123mmrw(struct cdev *dev, struct uio *uio, int flags) 124{ 125 struct iovec *iov; 126 vm_offset_t eva; 127 vm_offset_t off; 128 vm_offset_t ova; 129 vm_offset_t va; 130 vm_prot_t prot; 131 vm_paddr_t pa; 132 vm_size_t cnt; 133 vm_page_t m; 134 int color; 135 int error; 136 int i; 137 138 cnt = 0; 139 error = 0; 140 ova = 0; 141 142 GIANT_REQUIRED; 143 144 while (uio->uio_resid > 0 && error == 0) { 145 iov = uio->uio_iov; 146 if (iov->iov_len == 0) { 147 uio->uio_iov++; 148 uio->uio_iovcnt--; 149 if (uio->uio_iovcnt < 0) 150 panic("mmrw"); 151 continue; 152 } 153 switch (minor(dev)) { 154 case 0: 155 /* mem (physical memory) */ 156 pa = uio->uio_offset & ~PAGE_MASK; 157 if (!is_physical_memory(pa)) { 158 error = EFAULT; 159 break; 160 } 161 162 off = uio->uio_offset & PAGE_MASK; 163 cnt = PAGE_SIZE - ((vm_offset_t)iov->iov_base & 164 PAGE_MASK); 165 cnt = min(cnt, PAGE_SIZE - off); 166 cnt = min(cnt, iov->iov_len); 167 168 m = NULL; 169 for (i = 0; phys_avail[i] != 0; i += 2) { 170 if (pa >= phys_avail[i] && 171 pa < phys_avail[i + 1]) { 172 m = PHYS_TO_VM_PAGE(pa); 173 break; 174 } 175 } 176 177 if (m != NULL) { 178 if (ova == 0) { 179 ova = kmem_alloc_wait(kernel_map, 180 PAGE_SIZE * DCACHE_COLORS); 181 } 182 if ((color = m->md.color) == -1) 183 va = ova; 184 else 185 va = ova + color * PAGE_SIZE; 186 pmap_qenter(va, &m, 1); 187 error = uiomove((void *)(va + off), cnt, 188 uio); 189 pmap_qremove(va, 1); 190 } else { 191 va = TLB_PHYS_TO_DIRECT(pa); 192 error = uiomove((void *)(va + off), cnt, 193 uio); 194 } 195 break; 196 case 1: 197 /* kmem (kernel memory) */ 198 va = trunc_page(uio->uio_offset); 199 eva = round_page(uio->uio_offset + iov->iov_len); 200 201 /* 202 * Make sure that all of the pages are currently 203 * resident so we don't create any zero fill pages. 204 */ 205 for (; va < eva; va += PAGE_SIZE) 206 if (pmap_kextract(va) == 0) 207 return (EFAULT); 208 209 prot = (uio->uio_rw == UIO_READ) ? VM_PROT_READ : 210 VM_PROT_WRITE; 211 va = uio->uio_offset; 212 if (va < VM_MIN_DIRECT_ADDRESS && 213 kernacc((void *)va, iov->iov_len, prot) == FALSE) 214 return (EFAULT); 215 216 error = uiomove((void *)va, iov->iov_len, uio); 217 break; 218 default: 219 return (ENODEV); 220 } 221 } 222 if (ova != 0) 223 kmem_free_wakeup(kernel_map, ova, PAGE_SIZE * DCACHE_COLORS); 224 return (error); 225} 226 227static int 228mem_modevent(module_t mod, int type, void *data) 229{ 230 switch(type) { 231 case MOD_LOAD: 232 if (bootverbose) 233 printf("mem: <memory & I/O>\n"); 234 235 memdev = make_dev(&mem_cdevsw, 0, UID_ROOT, GID_KMEM, 236 0640, "mem"); 237 kmemdev = make_dev(&mem_cdevsw, 1, UID_ROOT, GID_KMEM, 238 0640, "kmem"); 239 return 0; 240 241 case MOD_UNLOAD: 242 destroy_dev(memdev); 243 destroy_dev(kmemdev); 244 return 0; 245 246 case MOD_SHUTDOWN: 247 return 0; 248 249 default: 250 return EOPNOTSUPP; 251 } 252} 253 254DEV_MODULE(mem, mem_modevent, NULL); 255