aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/ntsync/linux_ntsync.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ntsync/linux_ntsync.c')
-rw-r--r--sys/dev/ntsync/linux_ntsync.c302
1 files changed, 302 insertions, 0 deletions
diff --git a/sys/dev/ntsync/linux_ntsync.c b/sys/dev/ntsync/linux_ntsync.c
new file mode 100644
index 000000000000..064e8c6aede9
--- /dev/null
+++ b/sys/dev/ntsync/linux_ntsync.c
@@ -0,0 +1,302 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright 2026 The FreeBSD Foundation
+ *
+ * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ */
+
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <dev/ntsync/ntsyncvar.h>
+
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#include <compat/linux/linux_common.h>
+#include <compat/linux/linux_ioctl.h>
+#include <dev/ntsync/linux_ntsync.h>
+
+MODULE_DEPEND(linux_ntsync, linux, 1, 1, 1);
+MODULE_DEPEND(linux_ntsync, ntsync, 1, 1, 1);
+
+static linux_ioctl_function_t linux_ntsync_ioctl;
+static struct linux_ioctl_handler linux_ntsync_handler = {linux_ntsync_ioctl,
+ LNTSYNC_IOCTL_MIN, LNTSYNC_IOCTL_MAX};
+
+static int
+linux_ntsync_modevent(module_t mod __unused, int type, void *data __unused)
+{
+ int error;
+
+ error = 0;
+ switch (type) {
+ case MOD_LOAD:
+ error = linux_ioctl_register_handler(&linux_ntsync_handler);
+ if (error != 0) {
+ printf("linux_ntsync: cannot register ioctl handler, "
+ "error %d\n", error);
+ } else if (bootverbose)
+ printf("linux_ntsync\n");
+ break;
+
+ case MOD_UNLOAD:
+ linux_ioctl_unregister_handler(&linux_ntsync_handler);
+ break;
+
+ case MOD_SHUTDOWN:
+ break;
+
+ default:
+ error = EOPNOTSUPP;
+ }
+
+ return (error);
+}
+
+DEV_MODULE(linux_ntsync, linux_ntsync_modevent, NULL);
+MODULE_VERSION(linux_ntsync, 1);
+
+/* XXXKIB no translation of structs */
+static void
+ntsync_lsa_to_sa(struct ntsync_sem_args *sa,
+ const struct linux_ntsync_sem_args *lsa)
+{
+ memcpy(sa, lsa, sizeof(*sa));
+}
+
+static void
+ntsync_sa_to_lsa(struct linux_ntsync_sem_args *lsa,
+ const struct ntsync_sem_args *sa)
+{
+ memcpy(lsa, sa, sizeof(*lsa));
+}
+
+static void
+ntsync_lma_to_ma(struct ntsync_mutex_args *ma,
+ const struct linux_ntsync_mutex_args *lma)
+{
+ memcpy(ma, lma, sizeof(*ma));
+}
+
+static void
+ntsync_ma_to_lma(struct linux_ntsync_mutex_args *ma,
+ const struct ntsync_mutex_args *lma)
+{
+ memcpy(ma, lma, sizeof(*ma));
+}
+
+static void
+ntsync_lea_to_ea(struct ntsync_event_args *ea,
+ const struct linux_ntsync_event_args *lea)
+{
+ memcpy(ea, lea, sizeof(*ea));
+}
+
+static void
+ntsync_ea_to_lea(struct linux_ntsync_event_args *lea,
+ const struct ntsync_event_args *ea)
+{
+ memcpy(lea, ea, sizeof(*lea));
+}
+
+static void
+ntsync_lwa_to_wa(struct ntsync_wait_args *wa,
+ const struct linux_ntsync_wait_args *lwa)
+{
+ memcpy(wa, lwa, sizeof(*wa));
+}
+
+static void
+ntsync_wa_to_lwa(struct linux_ntsync_wait_args *lwa,
+ const struct ntsync_wait_args *wa)
+{
+ memcpy(lwa, wa, sizeof(*lwa));
+}
+
+static int
+linux_ntsync_cdev_ioctl(struct thread *td, u_long cmd, void *data,
+ struct file *fp)
+{
+ struct cdev *dev;
+ struct cdevsw *dsw;
+ struct vnode *vp;
+ struct file *fpop;
+ int error, ref;
+
+ if (fp->f_type != DTYPE_VNODE)
+ return (error = ENOIOCTL);
+
+ vp = fp->f_vnode;
+ if (vp->v_type != VCHR)
+ return (ENOIOCTL);
+ dev = vp->v_rdev;
+ dsw = dev_refthread(dev, &ref);
+ if (dsw == NULL)
+ return (ENXIO);
+ if (dsw != &ntsync_cdevsw) {
+ error = ENOIOCTL;
+ } else {
+ fpop = td->td_fpop;
+ td->td_fpop = fp;
+ error = dsw->d_ioctl(dev, cmd, data, 0, td);
+ td->td_fpop = fpop;
+ }
+ dev_relthread(dev, ref);
+ return (error);
+}
+
+static int
+linux_ntsync_ioctl(struct thread *td, struct linux_ioctl_args *args)
+{
+ struct file *fp;
+ void *data;
+ struct linux_ntsync_sem_args lsa;
+ struct linux_ntsync_mutex_args lma;
+ struct linux_ntsync_event_args lea;
+ struct linux_ntsync_wait_args lwa;
+ struct ntsync_sem_args sa;
+ struct ntsync_mutex_args ma;
+ struct ntsync_event_args ea;
+ struct ntsync_wait_args wa;
+ uint32_t val;
+ int error, error1, lcmd;
+ bool doco;
+
+ lcmd = args->cmd;
+ data = (void *)args->arg;
+
+ error = fget_cap(td, args->fd, &cap_no_rights, NULL, &fp, NULL);
+ if (error != 0)
+ goto out;
+
+ doco = false;
+ switch (lcmd) {
+ case LNTSYNC_IOC_CREATE_SEM:
+ error = copyin(data, &lsa, sizeof(lsa));
+ ntsync_lsa_to_sa(&sa, &lsa);
+ if (error == 0) {
+ error = linux_ntsync_cdev_ioctl(td,
+ NTSYNC_IOC_CREATE_SEM, &sa, fp);
+ }
+ break;
+ case LNTSYNC_IOC_CREATE_MUTEX:
+ error = copyin(data, &lma, sizeof(lma));
+ ntsync_lma_to_ma(&ma, &lma);
+ if (error == 0) {
+ error = linux_ntsync_cdev_ioctl(td,
+ NTSYNC_IOC_CREATE_MUTEX, &ma, fp);
+ }
+ break;
+ case LNTSYNC_IOC_CREATE_EVENT:
+ error = copyin(data, &lea, sizeof(lea));
+ ntsync_lea_to_ea(&ea, &lea);
+ if (error == 0) {
+ error = linux_ntsync_cdev_ioctl(td,
+ NTSYNC_IOC_CREATE_EVENT, &ea, fp);
+ }
+ break;
+ case LNTSYNC_IOC_WAIT_ANY:
+ error = copyin(data, &lwa, sizeof(lwa));
+ ntsync_lwa_to_wa(&wa, &lwa);
+ if (error == 0) {
+ error = linux_ntsync_cdev_ioctl(td,
+ NTSYNC_IOC_WAIT_ANY, &wa, fp);
+ if (error == 0 || error == EOWNERDEAD) {
+ ntsync_wa_to_lwa(&lwa, &wa);
+ error1 = copyout(&lwa, data, sizeof(lwa));
+ if (error == 0)
+ error = error1;
+ }
+ }
+ break;
+ case LNTSYNC_IOC_WAIT_ALL:
+ error = copyin(data, &lwa, sizeof(lwa));
+ ntsync_lwa_to_wa(&wa, &lwa);
+ if (error == 0) {
+ error = linux_ntsync_cdev_ioctl(td,
+ NTSYNC_IOC_WAIT_ALL, &wa, fp);
+ if (error == 0 || error == EOWNERDEAD) {
+ ntsync_wa_to_lwa(&lwa, &wa);
+ error1 = copyout(&lwa, data, sizeof(lwa));
+ if (error == 0)
+ error = error1;
+ }
+ }
+ break;
+ case LNTSYNC_IOC_SEM_RELEASE:
+ error = copyin(data, &val, sizeof(val));
+ if (error == 0) {
+ error = ntsync_sem_release(td, fp, &val);
+ if (error == 0)
+ error = copyout(&val, data, sizeof(val));
+ }
+ break;
+ case LNTSYNC_IOC_SEM_READ:
+ error = ntsync_sem_read(td, fp, &sa);
+ if (error == 0) {
+ ntsync_sa_to_lsa(&lsa, &sa);
+ error = copyout(&lsa, data, sizeof(lsa));
+ }
+ break;
+ case LNTSYNC_IOC_MUTEX_UNLOCK:
+ error = copyin(data, &lma, sizeof(lma));
+ ntsync_lma_to_ma(&ma, &lma);
+ if (error == 0) {
+ error = ntsync_mutex_unlock(td, fp, &ma);
+ if (error == 0) {
+ ntsync_ma_to_lma(&lma, &ma);
+ error = copyout(&lma, data, sizeof(lma));
+ }
+ }
+ break;
+ case LNTSYNC_IOC_MUTEX_KILL:
+ error = copyin(data, &val, sizeof(val));
+ if (error == 0)
+ error = ntsync_mutex_kill(td, fp, val);
+ break;
+ case LNTSYNC_IOC_MUTEX_READ:
+ error = ntsync_mutex_read(td, fp, &ma, &doco);
+ if (doco) {
+ ntsync_ma_to_lma(&lma, &ma);
+ error1 = copyout(&lma, data, sizeof(lma));
+ if (error == 0)
+ error = error1;
+ }
+ break;
+ case LNTSYNC_IOC_EVENT_SET:
+ error = ntsync_event_set(td, fp, &val);
+ if (error == 0)
+ error = copyout(&val, data, sizeof(val));
+ break;
+ case LNTSYNC_IOC_EVENT_RESET:
+ error = ntsync_event_reset(td, fp, &val);
+ if (error == 0)
+ error = copyout(&val, data, sizeof(val));
+ break;
+ case LNTSYNC_IOC_EVENT_PULSE:
+ error = ntsync_event_pulse(td, fp, &val);
+ if (error == 0)
+ error = copyout(&val, data, sizeof(val));
+ break;
+ case LNTSYNC_IOC_EVENT_READ:
+ error = ntsync_event_read(td, fp, &ea);
+ if (error == 0) {
+ ntsync_ea_to_lea(&lea, &ea);
+ error = copyout(&lea, data, sizeof(lea));
+ }
+ break;
+ default:
+ error = ENOTTY;
+ break;
+ }
+ fdrop(fp, td);
+out:
+ return (error);
+}