|
|
|
@@ -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);
|
|
|
|
|
}
|