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/lock.h> 54 #include <sys/malloc.h> 55 #include <sys/memrange.h> 56 #include <sys/mutex.h> 57 #include <sys/proc.h> 58 #include <sys/signalvar.h> 59 #include <sys/systm.h> 60 #include <sys/uio.h> 61 62 #include <machine/db_machdep.h> 63 #include <machine/frame.h> 64 #include <machine/psl.h> 65 #include <machine/specialreg.h> 66 #include <machine/vmparam.h> 67 68 #include <vm/vm.h> 69 #include <vm/pmap.h> 70 #include <vm/vm_extern.h> 71 72 static dev_t memdev, kmemdev, iodev; 73 74 static d_open_t mmopen; 75 static d_close_t mmclose; 76 static d_read_t mmrw; 77 static d_ioctl_t mmioctl; 78 static d_mmap_t memmmap; 79 80 #define CDEV_MAJOR 2 81 static struct cdevsw mem_cdevsw = { 82 .d_open = mmopen, 83 .d_close = mmclose, 84 .d_read = mmrw, 85 .d_write = mmrw, 86 .d_ioctl = mmioctl, 87 .d_mmap = memmmap, 88 .d_name = "mem", 89 .d_maj = CDEV_MAJOR, 90 .d_flags = D_MEM, 91 }; 92 93 MALLOC_DEFINE(M_MEMDESC, "memdesc", "memory range descriptors"); 94 95 struct mem_range_softc mem_range_softc; 96 97 static int 98 mmclose(dev_t dev, int flags, int fmt, struct thread *td) 99 { 100 switch (minor(dev)) { 101 case 14: 102 td->td_frame->tf_rflags &= ~PSL_IOPL; 103 } 104 return (0); 105 } 106 107 static int 108 mmopen(dev_t dev, int flags, int fmt, struct thread *td) 109 { 110 int error; 111 112 switch (minor(dev)) { 113 case 0: 114 case 1: 115 if (flags & FWRITE) { 116 error = securelevel_gt(td->td_ucred, 0); 117 if (error != 0) 118 return (error); 119 } 120 break; 121 case 14: 122 error = suser(td); 123 if (error != 0) 124 return (error); 125 error = securelevel_gt(td->td_ucred, 0); 126 if (error != 0) 127 return (error); 128 td->td_frame->tf_rflags |= PSL_IOPL; 129 break; 130 } 131 return (0); 132 } 133 134 /*ARGSUSED*/ 135 static int 136 mmrw(dev_t dev, struct uio *uio, int flags) 137 { 138 int o; 139 u_long c = 0, v; 140 struct iovec *iov; 141 int error = 0; 142 vm_offset_t addr, eaddr; 143 144 GIANT_REQUIRED; 145 146 while (uio->uio_resid > 0 && error == 0) { 147 iov = uio->uio_iov; 148 if (iov->iov_len == 0) { 149 uio->uio_iov++; 150 uio->uio_iovcnt--; 151 if (uio->uio_iovcnt < 0) 152 panic("mmrw"); 153 continue; 154 } 155 switch (minor(dev)) { 156 157 /* minor device 0 is physical memory */ 158 case 0: 159 v = uio->uio_offset; 160 v &= ~PAGE_MASK; 161 pmap_kenter((vm_offset_t)ptvmmap, v); 162 o = (int)uio->uio_offset & PAGE_MASK; 163 c = (u_long)(PAGE_SIZE - ((long)iov->iov_base & PAGE_MASK)); 164 c = min(c, (u_int)(PAGE_SIZE - o)); 165 c = min(c, (u_int)iov->iov_len); 166 error = uiomove((caddr_t)&ptvmmap[o], (int)c, uio); 167 pmap_qremove((vm_offset_t)ptvmmap, 1); 168 continue; 169 170 /* minor device 1 is kernel memory */ 171 case 1: 172 c = iov->iov_len; 173 174 /* 175 * Make sure that all of the pages are currently resident so 176 * that we don't create any zero-fill pages. 177 */ 178 addr = trunc_page(uio->uio_offset); 179 eaddr = round_page(uio->uio_offset + c); 180 181 if (addr < (vm_offset_t)KERNBASE) 182 return (EFAULT); 183 for (; addr < eaddr; addr += PAGE_SIZE) 184 if (pmap_extract(kernel_pmap, addr) == 0) 185 return (EFAULT); 186 187 if (!kernacc((caddr_t)(long)uio->uio_offset, c, 188 uio->uio_rw == UIO_READ ? 189 VM_PROT_READ : VM_PROT_WRITE)) 190 return (EFAULT); 191 error = uiomove((caddr_t)(long)uio->uio_offset, (int)c, uio); 192 continue; 193 194 default: 195 return (ENODEV); 196 } 197 198 if (error) 199 break; 200 iov->iov_base = (char *)iov->iov_base + c; 201 iov->iov_len -= c; 202 uio->uio_offset += c; 203 uio->uio_resid -= c; 204 } 205 return (error); 206 } 207 208 /*******************************************************\ 209 * allow user processes to MMAP some memory sections * 210 * instead of going through read/write * 211 \*******************************************************/ 212 static int 213 memmmap(dev_t dev, vm_offset_t offset, vm_paddr_t *paddr, int prot) 214 { 215 switch (minor(dev)) 216 { 217 218 /* minor device 0 is physical memory */ 219 case 0: 220 *paddr = offset; 221 break; 222 223 /* minor device 1 is kernel memory */ 224 case 1: 225 *paddr = vtophys(offset); 226 break; 227 228 default: 229 return (-1); 230 } 231 return (0); 232 } 233 234 /* 235 * Operations for changing memory attributes. 236 * 237 * This is basically just an ioctl shim for mem_range_attr_get 238 * and mem_range_attr_set. 239 */ 240 static int 241 mmioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct thread *td) 242 { 243 int nd, error = 0; 244 struct mem_range_op *mo = (struct mem_range_op *)data; 245 struct mem_range_desc *md; 246 247 /* is this for us? */ 248 if ((cmd != MEMRANGE_GET) && 249 (cmd != MEMRANGE_SET)) 250 return (ENOTTY); 251 252 /* any chance we can handle this? */ 253 if (mem_range_softc.mr_op == NULL) 254 return (EOPNOTSUPP); 255 256 /* do we have any descriptors? */ 257 if (mem_range_softc.mr_ndesc == 0) 258 return (ENXIO); 259 260 switch (cmd) { 261 case MEMRANGE_GET: 262 nd = imin(mo->mo_arg[0], mem_range_softc.mr_ndesc); 263 if (nd > 0) { 264 md = (struct mem_range_desc *) 265 malloc(nd * sizeof(struct mem_range_desc), 266 M_MEMDESC, M_WAITOK); 267 error = mem_range_attr_get(md, &nd); 268 if (!error) 269 error = copyout(md, mo->mo_desc, 270 nd * sizeof(struct mem_range_desc)); 271 free(md, M_MEMDESC); 272 } 273 else 274 nd = mem_range_softc.mr_ndesc; 275 mo->mo_arg[0] = nd; 276 break; 277 278 case MEMRANGE_SET: 279 md = (struct mem_range_desc *)malloc(sizeof(struct mem_range_desc), 280 M_MEMDESC, M_WAITOK); 281 error = copyin(mo->mo_desc, md, sizeof(struct mem_range_desc)); 282 /* clamp description string */ 283 md->mr_owner[sizeof(md->mr_owner) - 1] = 0; 284 if (error == 0) 285 error = mem_range_attr_set(md, &mo->mo_arg[0]); 286 free(md, M_MEMDESC); 287 break; 288 } 289 return (error); 290 } 291 292 /* 293 * Implementation-neutral, kernel-callable functions for manipulating 294 * memory range attributes. 295 */ 296 int 297 mem_range_attr_get(struct mem_range_desc *mrd, int *arg) 298 { 299 /* can we handle this? */ 300 if (mem_range_softc.mr_op == NULL) 301 return (EOPNOTSUPP); 302 303 if (*arg == 0) 304 *arg = mem_range_softc.mr_ndesc; 305 else 306 bcopy(mem_range_softc.mr_desc, mrd, 307 (*arg) * sizeof(struct mem_range_desc)); 308 return (0); 309 } 310 311 int 312 mem_range_attr_set(struct mem_range_desc *mrd, int *arg) 313 { 314 /* can we handle this? */ 315 if (mem_range_softc.mr_op == NULL) 316 return (EOPNOTSUPP); 317 318 return (mem_range_softc.mr_op->set(&mem_range_softc, mrd, arg)); 319 } 320 321 static int 322 mem_modevent(module_t mod, int type, void *data) 323 { 324 switch(type) { 325 case MOD_LOAD: 326 if (bootverbose) 327 printf("mem: <memory & I/O>\n"); 328 /* Initialise memory range handling */ 329 if (mem_range_softc.mr_op != NULL) 330 mem_range_softc.mr_op->init(&mem_range_softc); 331 332 memdev = make_dev(&mem_cdevsw, 0, UID_ROOT, GID_KMEM, 333 0640, "mem"); 334 kmemdev = make_dev(&mem_cdevsw, 1, UID_ROOT, GID_KMEM, 335 0640, "kmem"); 336 iodev = make_dev(&mem_cdevsw, 14, UID_ROOT, GID_WHEEL, 337 0600, "io"); 338 return (0); 339 340 case MOD_UNLOAD: 341 destroy_dev(memdev); 342 destroy_dev(kmemdev); 343 destroy_dev(iodev); 344 return (0); 345 346 case MOD_SHUTDOWN: 347 return (0); 348 349 default: 350 return (EOPNOTSUPP); 351 } 352 } 353 354 DEV_MODULE(mem, mem_modevent, NULL); 355