1
0
mirror of https://git.FreeBSD.org/src.git synced 2026-06-02 11:24:32 +00:00

linux_ntsync: linux compat shim for ntsync(9)

Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D57038
This commit is contained in:
Konstantin Belousov
2026-05-19 05:23:33 +03:00
parent d0ea3aff90
commit 510ee6698d
4 changed files with 371 additions and 0 deletions
+302
View File
@@ -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);
}
+62
View File
@@ -0,0 +1,62 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* Kernel support for NT synchronization primitive emulation
*
* Copyright (C) 2021-2022 Elizabeth Figura <zfigura@codeweavers.com>
*/
#ifndef __LINUX_NTSYNC_H
#define __LINUX_NTSYNC_H
#include <sys/types.h>
typedef uint32_t __u32;
typedef uint64_t __u64;
struct linux_ntsync_sem_args {
__u32 count;
__u32 max;
};
struct linux_ntsync_mutex_args {
__u32 owner;
__u32 count;
};
struct linux_ntsync_event_args {
__u32 manual;
__u32 signaled;
};
#define LINUX_NTSYNC_WAIT_REALTIME 0x1
struct linux_ntsync_wait_args {
__u64 timeout;
__u64 objs;
__u32 count;
__u32 index;
__u32 flags;
__u32 owner;
__u32 alert;
__u32 pad;
};
#define LNTSYNC_IOC_CREATE_SEM 0x40084e80
#define LNTSYNC_IOC_WAIT_ANY 0xc0284e82
#define LNTSYNC_IOC_WAIT_ALL 0xc0284e83
#define LNTSYNC_IOC_CREATE_MUTEX 0x40084e84
#define LNTSYNC_IOC_CREATE_EVENT 0x40084e87
#define LNTSYNC_IOC_SEM_RELEASE 0xc0044e81
#define LNTSYNC_IOC_MUTEX_UNLOCK 0xc0084e85
#define LNTSYNC_IOC_MUTEX_KILL 0x40044e86
#define LNTSYNC_IOC_EVENT_SET 0x80044e88
#define LNTSYNC_IOC_EVENT_RESET 0x80044e89
#define LNTSYNC_IOC_EVENT_PULSE 0x80044e8a
#define LNTSYNC_IOC_SEM_READ 0x80084e8b
#define LNTSYNC_IOC_MUTEX_READ 0x80084e8c
#define LNTSYNC_IOC_EVENT_READ 0x80084e8d
#define LNTSYNC_IOCTL_MIN 0x4e80
#define LNTSYNC_IOCTL_MAX 0x4eff
#endif
+1
View File
@@ -543,6 +543,7 @@ SUBDIR+= fdt
${MACHINE_CPUARCH} == "i386"
SUBDIR+= linprocfs
SUBDIR+= linsysfs
SUBDIR+= linux_ntsync
.endif
.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386"
SUBDIR+= linux
+6
View File
@@ -0,0 +1,6 @@
.PATH: ${SRCTOP}/sys/dev/ntsync
KMOD= linux_ntsync
SRCS= linux_ntsync.c
.include <bsd.kmod.mk>