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 */ 38 39 #include <sys/cdefs.h> 40 __FBSDID("$FreeBSD$"); 41 42 /* 43 * Memory special file 44 */ 45 46 #include <sys/param.h> 47 #include <sys/conf.h> 48 #include <sys/fcntl.h> 49 #include <sys/ioccom.h> 50 #include <sys/kernel.h> 51 #include <sys/lock.h> 52 #include <sys/malloc.h> 53 #include <sys/memrange.h> 54 #include <sys/module.h> 55 #include <sys/mutex.h> 56 #include <sys/proc.h> 57 #include <sys/signalvar.h> 58 #include <sys/systm.h> 59 #include <sys/uio.h> 60 61 #include <machine/db_machdep.h> 62 #include <machine/frame.h> 63 #include <machine/psl.h> 64 #include <machine/specialreg.h> 65 #include <machine/vmparam.h> 66 67 #include <vm/vm.h> 68 #include <vm/pmap.h> 69 #include <vm/vm_extern.h> 70 71 static struct cdev *memdev, *kmemdev, *iodev; 72 73 static d_open_t mmopen; 74 static d_close_t mmclose; 75 static d_read_t mmrw; 76 static d_ioctl_t mmioctl; 77 static d_mmap_t memmmap; 78 79 #define CDEV_MAJOR 2 80 static struct cdevsw mem_cdevsw = { 81 .d_version = D_VERSION, 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 | D_NEEDGIANT, 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(struct cdev *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(struct cdev *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(struct cdev *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 kmemphys: 161 o = v & PAGE_MASK; 162 c = min(uio->uio_resid, (u_int)(PAGE_SIZE - o)); 163 error = uiomove((void *)PHYS_TO_DMAP(v), (int)c, uio); 164 continue; 165 166 /* minor device 1 is kernel memory */ 167 case 1: 168 v = uio->uio_offset; 169 170 if (v >= DMAP_MIN_ADDRESS && v < DMAP_MAX_ADDRESS) { 171 v = DMAP_TO_PHYS(v); 172 goto kmemphys; 173 } 174 175 c = iov->iov_len; 176 177 /* 178 * Make sure that all of the pages are currently resident so 179 * that we don't create any zero-fill pages. 180 */ 181 addr = trunc_page(v); 182 eaddr = round_page(v + c); 183 184 if (addr < (vm_offset_t)KERNBASE) 185 return (EFAULT); 186 for (; addr < eaddr; addr += PAGE_SIZE) 187 if (pmap_extract(kernel_pmap, addr) == 0) 188 return (EFAULT); 189 190 if (!kernacc((caddr_t)(long)v, c, 191 uio->uio_rw == UIO_READ ? 192 VM_PROT_READ : VM_PROT_WRITE)) 193 return (EFAULT); 194 195 error = uiomove((caddr_t)(long)v, (int)c, uio); 196 continue; 197 198 default: 199 return (ENODEV); 200 } 201 202 if (error) 203 break; 204 iov->iov_base = (char *)iov->iov_base + c; 205 iov->iov_len -= c; 206 uio->uio_offset += c; 207 uio->uio_resid -= c; 208 } 209 return (error); 210 } 211 212 /*******************************************************\ 213 * allow user processes to MMAP some memory sections * 214 * instead of going through read/write * 215 \*******************************************************/ 216 static int 217 memmmap(struct cdev *dev, vm_offset_t offset, vm_paddr_t *paddr, int prot) 218 { 219 switch (minor(dev)) 220 { 221 222 /* minor device 0 is physical memory */ 223 case 0: 224 *paddr = offset; 225 break; 226 227 /* minor device 1 is kernel memory */ 228 case 1: 229 *paddr = vtophys(offset); 230 break; 231 232 default: 233 return (-1); 234 } 235 return (0); 236 } 237 238 /* 239 * Operations for changing memory attributes. 240 * 241 * This is basically just an ioctl shim for mem_range_attr_get 242 * and mem_range_attr_set. 243 */ 244 static int 245 mmioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td) 246 { 247 int nd, error = 0; 248 struct mem_range_op *mo = (struct mem_range_op *)data; 249 struct mem_range_desc *md; 250 251 /* is this for us? */ 252 if ((cmd != MEMRANGE_GET) && 253 (cmd != MEMRANGE_SET)) 254 return (ENOTTY); 255 256 /* any chance we can handle this? */ 257 if (mem_range_softc.mr_op == NULL) 258 return (EOPNOTSUPP); 259 260 /* do we have any descriptors? */ 261 if (mem_range_softc.mr_ndesc == 0) 262 return (ENXIO); 263 264 switch (cmd) { 265 case MEMRANGE_GET: 266 nd = imin(mo->mo_arg[0], mem_range_softc.mr_ndesc); 267 if (nd > 0) { 268 md = (struct mem_range_desc *) 269 malloc(nd * sizeof(struct mem_range_desc), 270 M_MEMDESC, M_WAITOK); 271 error = mem_range_attr_get(md, &nd); 272 if (!error) 273 error = copyout(md, mo->mo_desc, 274 nd * sizeof(struct mem_range_desc)); 275 free(md, M_MEMDESC); 276 } 277 else 278 nd = mem_range_softc.mr_ndesc; 279 mo->mo_arg[0] = nd; 280 break; 281 282 case MEMRANGE_SET: 283 md = (struct mem_range_desc *)malloc(sizeof(struct mem_range_desc), 284 M_MEMDESC, M_WAITOK); 285 error = copyin(mo->mo_desc, md, sizeof(struct mem_range_desc)); 286 /* clamp description string */ 287 md->mr_owner[sizeof(md->mr_owner) - 1] = 0; 288 if (error == 0) 289 error = mem_range_attr_set(md, &mo->mo_arg[0]); 290 free(md, M_MEMDESC); 291 break; 292 } 293 return (error); 294 } 295 296 /* 297 * Implementation-neutral, kernel-callable functions for manipulating 298 * memory range attributes. 299 */ 300 int 301 mem_range_attr_get(struct mem_range_desc *mrd, int *arg) 302 { 303 /* can we handle this? */ 304 if (mem_range_softc.mr_op == NULL) 305 return (EOPNOTSUPP); 306 307 if (*arg == 0) 308 *arg = mem_range_softc.mr_ndesc; 309 else 310 bcopy(mem_range_softc.mr_desc, mrd, 311 (*arg) * sizeof(struct mem_range_desc)); 312 return (0); 313 } 314 315 int 316 mem_range_attr_set(struct mem_range_desc *mrd, int *arg) 317 { 318 /* can we handle this? */ 319 if (mem_range_softc.mr_op == NULL) 320 return (EOPNOTSUPP); 321 322 return (mem_range_softc.mr_op->set(&mem_range_softc, mrd, arg)); 323 } 324 325 #ifdef SMP 326 void 327 mem_range_AP_init(void) 328 { 329 if (mem_range_softc.mr_op && mem_range_softc.mr_op->initAP) 330 (mem_range_softc.mr_op->initAP(&mem_range_softc)); 331 } 332 #endif 333 334 static int 335 mem_modevent(module_t mod, int type, void *data) 336 { 337 switch(type) { 338 case MOD_LOAD: 339 if (bootverbose) 340 printf("mem: <memory & I/O>\n"); 341 /* Initialise memory range handling */ 342 if (mem_range_softc.mr_op != NULL) 343 mem_range_softc.mr_op->init(&mem_range_softc); 344 345 memdev = make_dev(&mem_cdevsw, 0, UID_ROOT, GID_KMEM, 346 0640, "mem"); 347 kmemdev = make_dev(&mem_cdevsw, 1, UID_ROOT, GID_KMEM, 348 0640, "kmem"); 349 iodev = make_dev(&mem_cdevsw, 14, UID_ROOT, GID_WHEEL, 350 0600, "io"); 351 return (0); 352 353 case MOD_UNLOAD: 354 destroy_dev(memdev); 355 destroy_dev(kmemdev); 356 destroy_dev(iodev); 357 return (0); 358 359 case MOD_SHUTDOWN: 360 return (0); 361 362 default: 363 return (EOPNOTSUPP); 364 } 365 } 366 367 DEV_MODULE(mem, mem_modevent, NULL); 368