mem.c revision 126080
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1988 University of Utah. 31556Srgrimes * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 41556Srgrimes * All rights reserved. 51556Srgrimes * 61556Srgrimes * This code is derived from software contributed to Berkeley by 71556Srgrimes * the Systems Programming Group of the University of Utah Computer 81556Srgrimes * Science Department, and code derived from software contributed to 91556Srgrimes * Berkeley by William Jolitz. 101556Srgrimes * 111556Srgrimes * Redistribution and use in source and binary forms, with or without 121556Srgrimes * modification, are permitted provided that the following conditions 131556Srgrimes * are met: 141556Srgrimes * 1. Redistributions of source code must retain the above copyright 151556Srgrimes * notice, this list of conditions and the following disclaimer. 161556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 171556Srgrimes * notice, this list of conditions and the following disclaimer in the 181556Srgrimes * documentation and/or other materials provided with the distribution. 191556Srgrimes * 3. All advertising materials mentioning features or use of this software 201556Srgrimes * must display the following acknowledgement: 211556Srgrimes * This product includes software developed by the University of 221556Srgrimes * California, Berkeley and its contributors. 231556Srgrimes * 4. Neither the name of the University nor the names of its contributors 241556Srgrimes * may be used to endorse or promote products derived from this software 251556Srgrimes * without specific prior written permission. 261556Srgrimes * 271556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 281556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 291556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 301556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 311556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 321556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 331556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 341556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 351556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 361556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 371556Srgrimes * SUCH DAMAGE. 381556Srgrimes * 3935773Scharnier * from: Utah $Hdr: mem.c 1.13 89/10/08$ 4036007Scharnier * from: @(#)mem.c 7.2 (Berkeley) 5/9/91 4135773Scharnier * from: FreeBSD: src/sys/i386/i386/mem.c,v 1.94 2001/09/26 4235773Scharnier * 4350471Speter * $FreeBSD: head/sys/sparc64/sparc64/mem.c 126080 2004-02-21 21:10:55Z phk $ 441556Srgrimes */ 451556Srgrimes 4636007Scharnier/* 471556Srgrimes * Memory special file 481556Srgrimes * 491556Srgrimes * NOTE: other architectures support mmap()'ing the mem and kmem devices; this 5051137Sgreen * might cause illegal aliases to be created for the locked kernel page(s), so 511556Srgrimes * it is not implemented. 521556Srgrimes */ 531556Srgrimes 541556Srgrimes#include <sys/param.h> 551556Srgrimes#include <sys/conf.h> 561556Srgrimes#include <sys/fcntl.h> 571556Srgrimes#include <sys/kernel.h> 581556Srgrimes#include <sys/lock.h> 591556Srgrimes#include <sys/mutex.h> 601556Srgrimes#include <sys/proc.h> 611556Srgrimes#include <sys/signalvar.h> 621556Srgrimes#include <sys/systm.h> 631556Srgrimes#include <sys/uio.h> 641556Srgrimes 6551208Sgreen#include <vm/vm.h> 6651208Sgreen#include <vm/vm_param.h> 6748026Sgreen#include <vm/vm_page.h> 6851208Sgreen#include <vm/vm_kern.h> 691556Srgrimes#include <vm/pmap.h> 701556Srgrimes#include <vm/vm_extern.h> 7148802Sgreen 7251137Sgreen#include <machine/cache.h> 7351208Sgreen#include <machine/md_var.h> 7451208Sgreen#include <machine/pmap.h> 751556Srgrimes#include <machine/tlb.h> 761556Srgrimes#include <machine/upa.h> 771556Srgrimes 781556Srgrimesstatic dev_t memdev, kmemdev; 791556Srgrimes 801556Srgrimesstatic d_open_t mmopen; 811556Srgrimesstatic d_close_t mmclose; 821556Srgrimesstatic d_read_t mmrw; 831556Srgrimes 841556Srgrimes#define CDEV_MAJOR 2 851556Srgrimesstatic struct cdevsw mem_cdevsw = { 861556Srgrimes .d_version = D_VERSION, 871556Srgrimes .d_open = mmopen, 881556Srgrimes .d_close = mmclose, 891556Srgrimes .d_read = mmrw, 901556Srgrimes .d_write = mmrw, 911556Srgrimes .d_name = "mem", 921556Srgrimes .d_maj = CDEV_MAJOR, 931556Srgrimes .d_flags = D_MEM | D_NEEDGIANT, 941556Srgrimes}; 951556Srgrimes 961556Srgrimesstatic int 971556Srgrimesmmclose(dev_t dev, int flags, int fmt, struct thread *td) 981556Srgrimes{ 991556Srgrimes 1001556Srgrimes return (0); 1011556Srgrimes} 1021556Srgrimes 1031556Srgrimesstatic int 1041556Srgrimesmmopen(dev_t dev, int flags, int fmt, struct thread *td) 1051556Srgrimes{ 1061556Srgrimes int error; 1071556Srgrimes 1081556Srgrimes switch (minor(dev)) { 1091556Srgrimes case 0: 1101556Srgrimes case 1: 1111556Srgrimes if (flags & FWRITE) { 1121556Srgrimes error = securelevel_gt(td->td_ucred, 0); 1131556Srgrimes if (error != 0) 1141556Srgrimes return (error); 1151556Srgrimes } 1161556Srgrimes break; 1171556Srgrimes default: 1181556Srgrimes return (ENXIO); 1191556Srgrimes } 1201556Srgrimes return (0); 1211556Srgrimes} 1221556Srgrimes 1231556Srgrimes/*ARGSUSED*/ 1241556Srgrimesstatic int 12548026Sgreenmmrw(dev_t dev, struct uio *uio, int flags) 12648026Sgreen{ 1271556Srgrimes struct iovec *iov; 12848802Sgreen vm_offset_t eva; 12948802Sgreen vm_offset_t off; 13051137Sgreen vm_offset_t ova; 13151137Sgreen vm_offset_t va; 13251208Sgreen vm_prot_t prot; 1331556Srgrimes vm_paddr_t pa; 1341556Srgrimes vm_size_t cnt; 1351556Srgrimes vm_page_t m; 1361556Srgrimes int color; 1371556Srgrimes int error; 1381556Srgrimes int i; 1391556Srgrimes 1401556Srgrimes cnt = 0; 1411556Srgrimes error = 0; 14248026Sgreen ova = 0; 1431556Srgrimes 1441556Srgrimes GIANT_REQUIRED; 1451556Srgrimes 1461556Srgrimes while (uio->uio_resid > 0 && error == 0) { 1471556Srgrimes iov = uio->uio_iov; 1481556Srgrimes if (iov->iov_len == 0) { 1491556Srgrimes uio->uio_iov++; 1501556Srgrimes uio->uio_iovcnt--; 1511556Srgrimes if (uio->uio_iovcnt < 0) 15248026Sgreen panic("mmrw"); 1531556Srgrimes continue; 1541556Srgrimes } 1551556Srgrimes switch (minor(dev)) { 1561556Srgrimes case 0: 1571556Srgrimes /* mem (physical memory) */ 1581556Srgrimes pa = uio->uio_offset & ~PAGE_MASK; 1591556Srgrimes if (!is_physical_memory(pa)) { 1601556Srgrimes error = EFAULT; 1611556Srgrimes break; 1621556Srgrimes } 1631556Srgrimes 1641556Srgrimes off = uio->uio_offset & PAGE_MASK; 1651556Srgrimes cnt = PAGE_SIZE - ((vm_offset_t)iov->iov_base & 1661556Srgrimes PAGE_MASK); 1671556Srgrimes cnt = min(cnt, PAGE_SIZE - off); 1681556Srgrimes cnt = min(cnt, iov->iov_len); 1691556Srgrimes 1701556Srgrimes m = NULL; 171 for (i = 0; phys_avail[i] != 0; i += 2) { 172 if (pa >= phys_avail[i] && 173 pa < phys_avail[i + 1]) { 174 m = PHYS_TO_VM_PAGE(pa); 175 break; 176 } 177 } 178 179 if (m != NULL) { 180 if (ova == 0) { 181 ova = kmem_alloc_wait(kernel_map, 182 PAGE_SIZE * DCACHE_COLORS); 183 } 184 if ((color = m->md.color) == -1) 185 va = ova; 186 else 187 va = ova + color * PAGE_SIZE; 188 pmap_qenter(va, &m, 1); 189 error = uiomove((void *)(va + off), cnt, 190 uio); 191 pmap_qremove(va, 1); 192 } else { 193 va = TLB_PHYS_TO_DIRECT(pa); 194 error = uiomove((void *)(va + off), cnt, 195 uio); 196 } 197 break; 198 case 1: 199 /* kmem (kernel memory) */ 200 va = trunc_page(uio->uio_offset); 201 eva = round_page(uio->uio_offset + iov->iov_len); 202 203 /* 204 * Make sure that all of the pages are currently 205 * resident so we don't create any zero fill pages. 206 */ 207 for (; va < eva; va += PAGE_SIZE) 208 if (pmap_kextract(va) == 0) 209 return (EFAULT); 210 211 prot = (uio->uio_rw == UIO_READ) ? VM_PROT_READ : 212 VM_PROT_WRITE; 213 va = uio->uio_offset; 214 if (va < VM_MIN_DIRECT_ADDRESS && 215 kernacc((void *)va, iov->iov_len, prot) == FALSE) 216 return (EFAULT); 217 218 error = uiomove((void *)va, iov->iov_len, uio); 219 break; 220 default: 221 return (ENODEV); 222 } 223 } 224 if (ova != 0) 225 kmem_free_wakeup(kernel_map, ova, PAGE_SIZE * DCACHE_COLORS); 226 return (error); 227} 228 229static int 230mem_modevent(module_t mod, int type, void *data) 231{ 232 switch(type) { 233 case MOD_LOAD: 234 if (bootverbose) 235 printf("mem: <memory & I/O>\n"); 236 237 memdev = make_dev(&mem_cdevsw, 0, UID_ROOT, GID_KMEM, 238 0640, "mem"); 239 kmemdev = make_dev(&mem_cdevsw, 1, UID_ROOT, GID_KMEM, 240 0640, "kmem"); 241 return 0; 242 243 case MOD_UNLOAD: 244 destroy_dev(memdev); 245 destroy_dev(kmemdev); 246 return 0; 247 248 case MOD_SHUTDOWN: 249 return 0; 250 251 default: 252 return EOPNOTSUPP; 253 } 254} 255 256DEV_MODULE(mem, mem_modevent, NULL); 257