#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: fopsmapper.c,v 1.3 2024/04/17 18:10:27 riastradh Exp $");
#include <sys/types.h>
#include <sys/conf.h>
#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/kernel.h>
#include <sys/kmem.h>
#include <sys/mman.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <uvm/uvm_extern.h>
dev_open_t fopsmapper_open;
const struct cdevsw fopsmapper_cdevsw = {
.d_open = fopsmapper_open,
.d_close = noclose,
.d_read = noread,
.d_write = nowrite,
.d_ioctl = noioctl,
.d_stop = nostop,
.d_tty = notty,
.d_poll = nopoll,
.d_mmap = nommap,
.d_kqfilter = nokqfilter,
.d_discard = nodiscard,
.d_flag = D_OTHER
};
static int fopsmapper_mmap(struct file *, off_t *, size_t, int, int *, int *,
struct uvm_object **, int *);
static int fopsmapper_close(struct file *);
const struct fileops mapper_fileops = {
.fo_read = fbadop_read,
.fo_write = fbadop_write,
.fo_ioctl = fbadop_ioctl,
.fo_fcntl = fnullop_fcntl,
.fo_poll = fnullop_poll,
.fo_stat = fbadop_stat,
.fo_close = fopsmapper_close,
.fo_kqfilter = fnullop_kqfilter,
.fo_restart = fnullop_restart,
.fo_mmap = fopsmapper_mmap,
};
struct fopsmapper_softc {
char *buf;
struct uvm_object *uobj;
size_t bufsize;
};
int
fopsmapper_open(dev_t dev, int flag, int mode, struct lwp *l)
{
struct fopsmapper_softc *fo;
struct file *fp;
int fd, error;
if ((error = fd_allocfile(&fp, &fd)) != 0)
return error;
fo = kmem_zalloc(sizeof(*fo), KM_SLEEP);
return fd_clone(fp, fd, flag, &mapper_fileops, fo);
}
int
fopsmapper_mmap(struct file *fp, off_t *offp, size_t size, int prot,
int *flagsp, int *advicep, struct uvm_object **uobjp, int *maxprotp)
{
struct fopsmapper_softc *fo;
vaddr_t va;
int error;
if (prot & PROT_EXEC)
return EACCES;
if (size != (size_t)PAGE_SIZE)
return EINVAL;
if ((fo = fp->f_data) == NULL)
return ENXIO;
fo->bufsize = size;
fo->uobj = uao_create(size, 0);
fo->buf = NULL;
error = uvm_map(kernel_map, &va, fo->bufsize, fo->uobj, 0, 0,
UVM_MAPFLAG(UVM_PROT_RW, UVM_PROT_RW,
UVM_INH_SHARE, UVM_ADV_RANDOM, 0));
if (error) {
uao_detach(fo->uobj);
goto out;
}
fo->buf = (char *)va;
snprintf(fo->buf, 13, "Hey There!");
uao_reference(fo->uobj);
*uobjp = fo->uobj;
*maxprotp = prot;
*advicep = UVM_ADV_RANDOM;
error = 0;
out: return error;
}
int
fopsmapper_close(struct file *fp)
{
struct fopsmapper_softc *fo;
fo = fp->f_data;
KASSERT(fo != NULL);
if (fo->buf != NULL)
uvm_deallocate(kernel_map, (vaddr_t)fo->buf, fo->bufsize);
kmem_free(fo, sizeof(*fo));
return 0;
}
MODULE(MODULE_CLASS_MISC, fopsmapper, NULL);
static int
fopsmapper_modcmd(modcmd_t cmd, void *arg __unused)
{
int cmajor = 351, bmajor = -1;
switch (cmd) {
case MODULE_CMD_INIT:
if (devsw_attach("fopsmapper", NULL, &bmajor,
&fopsmapper_cdevsw, &cmajor))
return ENXIO;
return 0;
case MODULE_CMD_FINI:
return EBUSY;
default:
return ENOTTY;
}
}