1 /* $NetBSD: fopsmapper.c,v 1.2 2020/04/01 11:45:53 kamil 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.2 2020/04/01 11:45:53 kamil Exp $"); 31 32 #include <sys/module.h> 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/kernel.h> 36 37 #include <sys/conf.h> 38 #include <sys/file.h> 39 #include <sys/filedesc.h> 40 #include <sys/kmem.h> 41 #include <sys/mman.h> 42 #include <sys/mutex.h> 43 #include <uvm/uvm_extern.h> 44 45 /* 46 * To use this module you need to: 47 * 48 * mknod /dev/fopsmapper c 351 0 49 * 50 */ 51 52 dev_type_open(fopsmapper_open); 53 54 const struct cdevsw fopsmapper_cdevsw = { 55 .d_open = fopsmapper_open, 56 .d_close = noclose, 57 .d_read = noread, 58 .d_write = nowrite, 59 .d_ioctl = noioctl, 60 .d_stop = nostop, 61 .d_tty = notty, 62 .d_poll = nopoll, 63 .d_mmap = nommap, 64 .d_kqfilter = nokqfilter, 65 .d_discard = nodiscard, 66 .d_flag = D_OTHER 67 }; 68 69 static int fopsmapper_mmap(file_t *, off_t *, size_t, 70 int, int *, int *,struct uvm_object **, int *); 71 static int fopsmapper_close(file_t *); 72 73 const struct fileops mapper_fileops = { 74 .fo_read = fbadop_read, 75 .fo_write = fbadop_write, 76 .fo_ioctl = fbadop_ioctl, 77 .fo_fcntl = fnullop_fcntl, 78 .fo_poll = fnullop_poll, 79 .fo_stat = fbadop_stat, 80 .fo_close = fopsmapper_close, 81 .fo_kqfilter = fnullop_kqfilter, 82 .fo_restart = fnullop_restart, 83 .fo_mmap = fopsmapper_mmap, 84 }; 85 86 typedef struct fopsmapper_softc { 87 char *buf; 88 struct uvm_object *uobj; 89 size_t bufsize; 90 } fops_t; 91 92 int 93 fopsmapper_open(dev_t dev, int flag, int mode, struct lwp *l) 94 { 95 fops_t *fo; 96 struct file *fp; 97 int fd, error; 98 99 if ((error = fd_allocfile(&fp, &fd)) != 0) 100 return error; 101 102 fo = kmem_zalloc(sizeof(*fo), KM_SLEEP); 103 104 return fd_clone(fp, fd, flag, &mapper_fileops, fo); 105 } 106 107 int 108 fopsmapper_mmap(file_t * fp, off_t * offp, size_t size, int prot, 109 int *flagsp, int *advicep, struct uvm_object **uobjp, 110 int *maxprotp) 111 { 112 fops_t *fo; 113 int error; 114 115 if (prot & PROT_EXEC) 116 return EACCES; 117 118 if (size != (size_t)PAGE_SIZE) 119 return EINVAL; 120 121 if ((fo = fp->f_data) == NULL) 122 return ENXIO; 123 124 fo->bufsize = size; 125 fo->uobj = uao_create(size, 0); 126 127 fo->buf = NULL; 128 /* Map the uvm object into kernel */ 129 error = uvm_map(kernel_map, (vaddr_t *) &fo->buf, fo->bufsize, 130 fo->uobj, 0, 0, 131 UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW, 132 UVM_INH_SHARE,UVM_ADV_RANDOM, 0)); 133 134 if (error) { 135 uao_detach(fo->uobj); 136 return error; 137 } 138 snprintf(fo->buf, 13, "Hey There!"); 139 140 /* Get the reference of uobj */ 141 uao_reference(fo->uobj); 142 143 *uobjp = fo->uobj; 144 *maxprotp = prot; 145 *advicep = UVM_ADV_RANDOM; 146 147 return 0; 148 } 149 150 int 151 fopsmapper_close(file_t * fp) 152 { 153 fops_t *fo; 154 155 fo = fp->f_data; 156 KASSERT(fo != NULL); 157 158 if (fo->buf != NULL) 159 uvm_deallocate(kernel_map, (vaddr_t)fo->buf, fo->bufsize); 160 161 kmem_free(fo, sizeof(*fo)); 162 163 return 0; 164 } 165 166 MODULE(MODULE_CLASS_MISC, fopsmapper, NULL); 167 168 static int 169 fopsmapper_modcmd(modcmd_t cmd, void *arg __unused) 170 { 171 int cmajor = 351, bmajor = -1; 172 173 switch (cmd) { 174 case MODULE_CMD_INIT: 175 if (devsw_attach("fopsmapper", NULL, &bmajor, 176 &fopsmapper_cdevsw, &cmajor)) 177 return ENXIO; 178 return 0; 179 case MODULE_CMD_FINI: 180 return EBUSY; 181 default: 182 return ENOTTY; 183 } 184 } 185