1 /* $NetBSD: fopsmapper.c,v 1.3 2024/04/17 18:10:27 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2020 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: fopsmapper.c,v 1.3 2024/04/17 18:10:27 riastradh Exp $"); 31 32 #include <sys/types.h> 33 34 #include <sys/conf.h> 35 #include <sys/file.h> 36 #include <sys/filedesc.h> 37 #include <sys/kernel.h> 38 #include <sys/kmem.h> 39 #include <sys/mman.h> 40 #include <sys/module.h> 41 #include <sys/mutex.h> 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 45 #include <uvm/uvm_extern.h> 46 47 /* 48 * To use this module you need to: 49 * 50 * mknod /dev/fopsmapper c 351 0 51 */ 52 53 dev_open_t fopsmapper_open; 54 55 const struct cdevsw fopsmapper_cdevsw = { 56 .d_open = fopsmapper_open, 57 .d_close = noclose, 58 .d_read = noread, 59 .d_write = nowrite, 60 .d_ioctl = noioctl, 61 .d_stop = nostop, 62 .d_tty = notty, 63 .d_poll = nopoll, 64 .d_mmap = nommap, 65 .d_kqfilter = nokqfilter, 66 .d_discard = nodiscard, 67 .d_flag = D_OTHER 68 }; 69 70 static int fopsmapper_mmap(struct file *, off_t *, size_t, int, int *, int *, 71 struct uvm_object **, int *); 72 static int fopsmapper_close(struct file *); 73 74 const struct fileops mapper_fileops = { 75 .fo_read = fbadop_read, 76 .fo_write = fbadop_write, 77 .fo_ioctl = fbadop_ioctl, 78 .fo_fcntl = fnullop_fcntl, 79 .fo_poll = fnullop_poll, 80 .fo_stat = fbadop_stat, 81 .fo_close = fopsmapper_close, 82 .fo_kqfilter = fnullop_kqfilter, 83 .fo_restart = fnullop_restart, 84 .fo_mmap = fopsmapper_mmap, 85 }; 86 87 struct fopsmapper_softc { 88 char *buf; 89 struct uvm_object *uobj; 90 size_t bufsize; 91 }; 92 93 int 94 fopsmapper_open(dev_t dev, int flag, int mode, struct lwp *l) 95 { 96 struct fopsmapper_softc *fo; 97 struct file *fp; 98 int fd, error; 99 100 if ((error = fd_allocfile(&fp, &fd)) != 0) 101 return error; 102 103 fo = kmem_zalloc(sizeof(*fo), KM_SLEEP); 104 105 return fd_clone(fp, fd, flag, &mapper_fileops, fo); 106 } 107 108 int 109 fopsmapper_mmap(struct file *fp, off_t *offp, size_t size, int prot, 110 int *flagsp, int *advicep, struct uvm_object **uobjp, int *maxprotp) 111 { 112 struct fopsmapper_softc *fo; 113 vaddr_t va; 114 int error; 115 116 if (prot & PROT_EXEC) 117 return EACCES; 118 119 if (size != (size_t)PAGE_SIZE) 120 return EINVAL; 121 122 if ((fo = fp->f_data) == NULL) 123 return ENXIO; 124 125 fo->bufsize = size; 126 fo->uobj = uao_create(size, 0); 127 128 fo->buf = NULL; 129 130 /* 131 * Map the uvm object into kernel. Consumes our reference to 132 * uobj on success. 133 */ 134 error = uvm_map(kernel_map, &va, fo->bufsize, fo->uobj, 0, 0, 135 UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, 136 UVM_INH_SHARE, UVM_ADV_RANDOM, 0)); 137 if (error) { 138 uao_detach(fo->uobj); 139 goto out; 140 } 141 fo->buf = (char *)va; 142 snprintf(fo->buf, 13, "Hey There!"); 143 144 /* Get the reference of uobj */ 145 uao_reference(fo->uobj); 146 *uobjp = fo->uobj; 147 *maxprotp = prot; 148 *advicep = UVM_ADV_RANDOM; 149 error = 0; 150 151 out: return error; 152 } 153 154 int 155 fopsmapper_close(struct file *fp) 156 { 157 struct fopsmapper_softc *fo; 158 159 fo = fp->f_data; 160 KASSERT(fo != NULL); 161 162 if (fo->buf != NULL) 163 uvm_deallocate(kernel_map, (vaddr_t)fo->buf, fo->bufsize); 164 165 kmem_free(fo, sizeof(*fo)); 166 167 return 0; 168 } 169 170 MODULE(MODULE_CLASS_MISC, fopsmapper, NULL); 171 172 static int 173 fopsmapper_modcmd(modcmd_t cmd, void *arg __unused) 174 { 175 int cmajor = 351, bmajor = -1; 176 177 switch (cmd) { 178 case MODULE_CMD_INIT: 179 if (devsw_attach("fopsmapper", NULL, &bmajor, 180 &fopsmapper_cdevsw, &cmajor)) 181 return ENXIO; 182 return 0; 183 case MODULE_CMD_FINI: 184 return EBUSY; 185 default: 186 return ENOTTY; 187 } 188 } 189