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 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * from: Utah $Hdr: mem.c 1.13 89/10/08$ 40 * from: @(#)mem.c 7.2 (Berkeley) 5/9/91 41 * $FreeBSD$ 42 */ 43 44 /* 45 * Memory special file 46 */ 47 48 #include <sys/param.h> 49 #include <sys/conf.h> 50 #include <sys/fcntl.h> 51 #include <sys/ioccom.h> 52 #include <sys/kernel.h> 53 #include <sys/malloc.h> 54 #include <sys/memrange.h> 55 #include <sys/proc.h> 56 #include <sys/signalvar.h> 57 #include <sys/systm.h> 58 #include <sys/uio.h> 59 60 #include <machine/db_machdep.h> 61 #include <machine/frame.h> 62 #include <machine/psl.h> 63 #include <machine/specialreg.h> 64 65 #include <vm/vm.h> 66 #include <vm/pmap.h> 67 #include <vm/vm_extern.h> 68 69 static dev_t memdev, kmemdev, iodev; 70 71 static d_open_t mmopen; 72 static d_close_t mmclose; 73 static d_read_t mmrw; 74 static d_ioctl_t mmioctl; 75 static d_mmap_t memmmap; 76 77 #define CDEV_MAJOR 2 78 static struct cdevsw mem_cdevsw = { 79 /* open */ mmopen, 80 /* close */ mmclose, 81 /* read */ mmrw, 82 /* write */ mmrw, 83 /* ioctl */ mmioctl, 84 /* poll */ (d_poll_t *)seltrue, 85 /* mmap */ memmmap, 86 /* strategy */ nostrategy, 87 /* name */ "mem", 88 /* maj */ CDEV_MAJOR, 89 /* dump */ nodump, 90 /* psize */ nopsize, 91 /* flags */ D_MEM, 92 }; 93 94 MALLOC_DEFINE(M_MEMDESC, "memdesc", "memory range descriptors"); 95 96 struct mem_range_softc mem_range_softc; 97 98 static int 99 mmclose(dev_t dev, int flags, int fmt, struct proc *p) 100 { 101 switch (minor(dev)) { 102 case 14: 103 p->p_md.md_regs->tf_eflags &= ~PSL_IOPL; 104 } 105 return (0); 106 } 107 108 static int 109 mmopen(dev_t dev, int flags, int fmt, struct proc *p) 110 { 111 int error; 112 113 switch (minor(dev)) { 114 case 0: 115 case 1: 116 if ((flags & FWRITE) && securelevel > 0) 117 return (EPERM); 118 break; 119 case 14: 120 error = suser(p); 121 if (error != 0) 122 return (error); 123 if (securelevel > 0) 124 return (EPERM); 125 p->p_md.md_regs->tf_eflags |= PSL_IOPL; 126 break; 127 } 128 return (0); 129 } 130 131 /*ARGSUSED*/ 132 static int 133 mmrw(dev_t dev, struct uio *uio, int flags) 134 { 135 int o; 136 u_int c = 0, v; 137 struct iovec *iov; 138 int error = 0; 139 vm_offset_t addr, eaddr; 140 141 while (uio->uio_resid > 0 && error == 0) { 142 iov = uio->uio_iov; 143 if (iov->iov_len == 0) { 144 uio->uio_iov++; 145 uio->uio_iovcnt--; 146 if (uio->uio_iovcnt < 0) 147 panic("mmrw"); 148 continue; 149 } 150 switch (minor(dev)) { 151 152 /* minor device 0 is physical memory */ 153 case 0: 154 v = uio->uio_offset; 155 v &= ~PAGE_MASK; 156 pmap_kenter((vm_offset_t)ptvmmap, v); 157 o = (int)uio->uio_offset & PAGE_MASK; 158 c = (u_int)(PAGE_SIZE - ((int)iov->iov_base & PAGE_MASK)); 159 c = min(c, (u_int)(PAGE_SIZE - o)); 160 c = min(c, (u_int)iov->iov_len); 161 error = uiomove((caddr_t)&ptvmmap[o], (int)c, uio); 162 pmap_kremove((vm_offset_t)ptvmmap); 163 continue; 164 165 /* minor device 1 is kernel memory */ 166 case 1: 167 c = iov->iov_len; 168 169 /* 170 * Make sure that all of the pages are currently resident so 171 * that we don't create any zero-fill pages. 172 */ 173 addr = trunc_page(uio->uio_offset); 174 eaddr = round_page(uio->uio_offset + c); 175 176 if (addr < (vm_offset_t)VADDR(PTDPTDI, 0)) 177 return EFAULT; 178 if (eaddr >= (vm_offset_t)VADDR(APTDPTDI, 0)) 179 return EFAULT; 180 for (; addr < eaddr; addr += PAGE_SIZE) 181 if (pmap_extract(kernel_pmap, addr) == 0) 182 return EFAULT; 183 184 if (!kernacc((caddr_t)(int)uio->uio_offset, c, 185 uio->uio_rw == UIO_READ ? 186 VM_PROT_READ : VM_PROT_WRITE)) 187 return (EFAULT); 188 error = uiomove((caddr_t)(int)uio->uio_offset, (int)c, uio); 189 continue; 190 } 191 192 if (error) 193 break; 194 iov->iov_base += c; 195 iov->iov_len -= c; 196 uio->uio_offset += c; 197 uio->uio_resid -= c; 198 } 199 return (error); 200 } 201 202 /*******************************************************\ 203 * allow user processes to MMAP some memory sections * 204 * instead of going through read/write * 205 \*******************************************************/ 206 static int 207 memmmap(dev_t dev, vm_offset_t offset, int prot) 208 { 209 switch (minor(dev)) 210 { 211 212 /* minor device 0 is physical memory */ 213 case 0: 214 return i386_btop(offset); 215 216 /* minor device 1 is kernel memory */ 217 case 1: 218 return i386_btop(vtophys(offset)); 219 220 default: 221 return -1; 222 } 223 } 224 225 /* 226 * Operations for changing memory attributes. 227 * 228 * This is basically just an ioctl shim for mem_range_attr_get 229 * and mem_range_attr_set. 230 */ 231 static int 232 mmioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p) 233 { 234 int nd, error = 0; 235 struct mem_range_op *mo = (struct mem_range_op *)data; 236 struct mem_range_desc *md; 237 238 /* is this for us? */ 239 if ((cmd != MEMRANGE_GET) && 240 (cmd != MEMRANGE_SET)) 241 return (ENOTTY); 242 243 /* any chance we can handle this? */ 244 if (mem_range_softc.mr_op == NULL) 245 return (EOPNOTSUPP); 246 247 /* do we have any descriptors? */ 248 if (mem_range_softc.mr_ndesc == 0) 249 return (ENXIO); 250 251 switch (cmd) { 252 case MEMRANGE_GET: 253 nd = imin(mo->mo_arg[0], mem_range_softc.mr_ndesc); 254 if (nd > 0) { 255 md = (struct mem_range_desc *) 256 malloc(nd * sizeof(struct mem_range_desc), 257 M_MEMDESC, M_WAITOK); 258 error = mem_range_attr_get(md, &nd); 259 if (!error) 260 error = copyout(md, mo->mo_desc, 261 nd * sizeof(struct mem_range_desc)); 262 free(md, M_MEMDESC); 263 } else { 264 nd = mem_range_softc.mr_ndesc; 265 } 266 mo->mo_arg[0] = nd; 267 break; 268 269 case MEMRANGE_SET: 270 md = (struct mem_range_desc *)malloc(sizeof(struct mem_range_desc), 271 M_MEMDESC, M_WAITOK); 272 error = copyin(mo->mo_desc, md, sizeof(struct mem_range_desc)); 273 /* clamp description string */ 274 md->mr_owner[sizeof(md->mr_owner) - 1] = 0; 275 if (error == 0) 276 error = mem_range_attr_set(md, &mo->mo_arg[0]); 277 free(md, M_MEMDESC); 278 break; 279 } 280 return (error); 281 } 282 283 /* 284 * Implementation-neutral, kernel-callable functions for manipulating 285 * memory range attributes. 286 */ 287 int 288 mem_range_attr_get(struct mem_range_desc *mrd, int *arg) 289 { 290 /* can we handle this? */ 291 if (mem_range_softc.mr_op == NULL) 292 return (EOPNOTSUPP); 293 294 if (*arg == 0) { 295 *arg = mem_range_softc.mr_ndesc; 296 } 297 else { 298 bcopy(mem_range_softc.mr_desc, mrd, 299 (*arg) * sizeof(struct mem_range_desc)); 300 } 301 return (0); 302 } 303 304 int 305 mem_range_attr_set(struct mem_range_desc *mrd, int *arg) 306 { 307 /* can we handle this? */ 308 if (mem_range_softc.mr_op == NULL) 309 return (EOPNOTSUPP); 310 311 return (mem_range_softc.mr_op->set(&mem_range_softc, mrd, arg)); 312 } 313 314 #ifdef SMP 315 void 316 mem_range_AP_init(void) 317 { 318 if (mem_range_softc.mr_op && mem_range_softc.mr_op->initAP) 319 return (mem_range_softc.mr_op->initAP(&mem_range_softc)); 320 } 321 #endif 322 323 static int 324 mem_modevent(module_t mod, int type, void *data) 325 { 326 switch(type) { 327 case MOD_LOAD: 328 if (bootverbose) 329 printf("mem: <memory & I/O>\n"); 330 /* Initialise memory range handling */ 331 if (mem_range_softc.mr_op != NULL) 332 mem_range_softc.mr_op->init(&mem_range_softc); 333 334 memdev = make_dev(&mem_cdevsw, 0, UID_ROOT, GID_KMEM, 335 0640, "mem"); 336 kmemdev = make_dev(&mem_cdevsw, 1, UID_ROOT, GID_KMEM, 337 0640, "kmem"); 338 iodev = make_dev(&mem_cdevsw, 14, UID_ROOT, GID_WHEEL, 339 0600, "io"); 340 return 0; 341 342 case MOD_UNLOAD: 343 destroy_dev(memdev); 344 destroy_dev(kmemdev); 345 destroy_dev(iodev); 346 return 0; 347 348 case MOD_SHUTDOWN: 349 return 0; 350 351 default: 352 return EOPNOTSUPP; 353 } 354 } 355 356 DEV_MODULE(mem, mem_modevent, NULL); 357