1*510ee669SKonstantin Belousov /*
2*510ee669SKonstantin Belousov * SPDX-License-Identifier: BSD-2-Clause
3*510ee669SKonstantin Belousov *
4*510ee669SKonstantin Belousov * Copyright 2026 The FreeBSD Foundation
5*510ee669SKonstantin Belousov *
6*510ee669SKonstantin Belousov * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
7*510ee669SKonstantin Belousov * under sponsorship from the FreeBSD Foundation.
8*510ee669SKonstantin Belousov */
9*510ee669SKonstantin Belousov
10*510ee669SKonstantin Belousov #include <sys/systm.h>
11*510ee669SKonstantin Belousov #include <sys/conf.h>
12*510ee669SKonstantin Belousov #include <sys/file.h>
13*510ee669SKonstantin Belousov #include <sys/filedesc.h>
14*510ee669SKonstantin Belousov #include <sys/kernel.h>
15*510ee669SKonstantin Belousov #include <sys/module.h>
16*510ee669SKonstantin Belousov #include <sys/proc.h>
17*510ee669SKonstantin Belousov #include <sys/vnode.h>
18*510ee669SKonstantin Belousov #include <dev/ntsync/ntsyncvar.h>
19*510ee669SKonstantin Belousov
20*510ee669SKonstantin Belousov #include <machine/../linux/linux.h>
21*510ee669SKonstantin Belousov #include <machine/../linux/linux_proto.h>
22*510ee669SKonstantin Belousov #include <compat/linux/linux_common.h>
23*510ee669SKonstantin Belousov #include <compat/linux/linux_ioctl.h>
24*510ee669SKonstantin Belousov #include <dev/ntsync/linux_ntsync.h>
25*510ee669SKonstantin Belousov
26*510ee669SKonstantin Belousov MODULE_DEPEND(linux_ntsync, linux, 1, 1, 1);
27*510ee669SKonstantin Belousov MODULE_DEPEND(linux_ntsync, ntsync, 1, 1, 1);
28*510ee669SKonstantin Belousov
29*510ee669SKonstantin Belousov static linux_ioctl_function_t linux_ntsync_ioctl;
30*510ee669SKonstantin Belousov static struct linux_ioctl_handler linux_ntsync_handler = {linux_ntsync_ioctl,
31*510ee669SKonstantin Belousov LNTSYNC_IOCTL_MIN, LNTSYNC_IOCTL_MAX};
32*510ee669SKonstantin Belousov
33*510ee669SKonstantin Belousov static int
linux_ntsync_modevent(module_t mod __unused,int type,void * data __unused)34*510ee669SKonstantin Belousov linux_ntsync_modevent(module_t mod __unused, int type, void *data __unused)
35*510ee669SKonstantin Belousov {
36*510ee669SKonstantin Belousov int error;
37*510ee669SKonstantin Belousov
38*510ee669SKonstantin Belousov error = 0;
39*510ee669SKonstantin Belousov switch (type) {
40*510ee669SKonstantin Belousov case MOD_LOAD:
41*510ee669SKonstantin Belousov error = linux_ioctl_register_handler(&linux_ntsync_handler);
42*510ee669SKonstantin Belousov if (error != 0) {
43*510ee669SKonstantin Belousov printf("linux_ntsync: cannot register ioctl handler, "
44*510ee669SKonstantin Belousov "error %d\n", error);
45*510ee669SKonstantin Belousov } else if (bootverbose)
46*510ee669SKonstantin Belousov printf("linux_ntsync\n");
47*510ee669SKonstantin Belousov break;
48*510ee669SKonstantin Belousov
49*510ee669SKonstantin Belousov case MOD_UNLOAD:
50*510ee669SKonstantin Belousov linux_ioctl_unregister_handler(&linux_ntsync_handler);
51*510ee669SKonstantin Belousov break;
52*510ee669SKonstantin Belousov
53*510ee669SKonstantin Belousov case MOD_SHUTDOWN:
54*510ee669SKonstantin Belousov break;
55*510ee669SKonstantin Belousov
56*510ee669SKonstantin Belousov default:
57*510ee669SKonstantin Belousov error = EOPNOTSUPP;
58*510ee669SKonstantin Belousov }
59*510ee669SKonstantin Belousov
60*510ee669SKonstantin Belousov return (error);
61*510ee669SKonstantin Belousov }
62*510ee669SKonstantin Belousov
63*510ee669SKonstantin Belousov DEV_MODULE(linux_ntsync, linux_ntsync_modevent, NULL);
64*510ee669SKonstantin Belousov MODULE_VERSION(linux_ntsync, 1);
65*510ee669SKonstantin Belousov
66*510ee669SKonstantin Belousov /* XXXKIB no translation of structs */
67*510ee669SKonstantin Belousov static void
ntsync_lsa_to_sa(struct ntsync_sem_args * sa,const struct linux_ntsync_sem_args * lsa)68*510ee669SKonstantin Belousov ntsync_lsa_to_sa(struct ntsync_sem_args *sa,
69*510ee669SKonstantin Belousov const struct linux_ntsync_sem_args *lsa)
70*510ee669SKonstantin Belousov {
71*510ee669SKonstantin Belousov memcpy(sa, lsa, sizeof(*sa));
72*510ee669SKonstantin Belousov }
73*510ee669SKonstantin Belousov
74*510ee669SKonstantin Belousov static void
ntsync_sa_to_lsa(struct linux_ntsync_sem_args * lsa,const struct ntsync_sem_args * sa)75*510ee669SKonstantin Belousov ntsync_sa_to_lsa(struct linux_ntsync_sem_args *lsa,
76*510ee669SKonstantin Belousov const struct ntsync_sem_args *sa)
77*510ee669SKonstantin Belousov {
78*510ee669SKonstantin Belousov memcpy(lsa, sa, sizeof(*lsa));
79*510ee669SKonstantin Belousov }
80*510ee669SKonstantin Belousov
81*510ee669SKonstantin Belousov static void
ntsync_lma_to_ma(struct ntsync_mutex_args * ma,const struct linux_ntsync_mutex_args * lma)82*510ee669SKonstantin Belousov ntsync_lma_to_ma(struct ntsync_mutex_args *ma,
83*510ee669SKonstantin Belousov const struct linux_ntsync_mutex_args *lma)
84*510ee669SKonstantin Belousov {
85*510ee669SKonstantin Belousov memcpy(ma, lma, sizeof(*ma));
86*510ee669SKonstantin Belousov }
87*510ee669SKonstantin Belousov
88*510ee669SKonstantin Belousov static void
ntsync_ma_to_lma(struct linux_ntsync_mutex_args * ma,const struct ntsync_mutex_args * lma)89*510ee669SKonstantin Belousov ntsync_ma_to_lma(struct linux_ntsync_mutex_args *ma,
90*510ee669SKonstantin Belousov const struct ntsync_mutex_args *lma)
91*510ee669SKonstantin Belousov {
92*510ee669SKonstantin Belousov memcpy(ma, lma, sizeof(*ma));
93*510ee669SKonstantin Belousov }
94*510ee669SKonstantin Belousov
95*510ee669SKonstantin Belousov static void
ntsync_lea_to_ea(struct ntsync_event_args * ea,const struct linux_ntsync_event_args * lea)96*510ee669SKonstantin Belousov ntsync_lea_to_ea(struct ntsync_event_args *ea,
97*510ee669SKonstantin Belousov const struct linux_ntsync_event_args *lea)
98*510ee669SKonstantin Belousov {
99*510ee669SKonstantin Belousov memcpy(ea, lea, sizeof(*ea));
100*510ee669SKonstantin Belousov }
101*510ee669SKonstantin Belousov
102*510ee669SKonstantin Belousov static void
ntsync_ea_to_lea(struct linux_ntsync_event_args * lea,const struct ntsync_event_args * ea)103*510ee669SKonstantin Belousov ntsync_ea_to_lea(struct linux_ntsync_event_args *lea,
104*510ee669SKonstantin Belousov const struct ntsync_event_args *ea)
105*510ee669SKonstantin Belousov {
106*510ee669SKonstantin Belousov memcpy(lea, ea, sizeof(*lea));
107*510ee669SKonstantin Belousov }
108*510ee669SKonstantin Belousov
109*510ee669SKonstantin Belousov static void
ntsync_lwa_to_wa(struct ntsync_wait_args * wa,const struct linux_ntsync_wait_args * lwa)110*510ee669SKonstantin Belousov ntsync_lwa_to_wa(struct ntsync_wait_args *wa,
111*510ee669SKonstantin Belousov const struct linux_ntsync_wait_args *lwa)
112*510ee669SKonstantin Belousov {
113*510ee669SKonstantin Belousov memcpy(wa, lwa, sizeof(*wa));
114*510ee669SKonstantin Belousov }
115*510ee669SKonstantin Belousov
116*510ee669SKonstantin Belousov static void
ntsync_wa_to_lwa(struct linux_ntsync_wait_args * lwa,const struct ntsync_wait_args * wa)117*510ee669SKonstantin Belousov ntsync_wa_to_lwa(struct linux_ntsync_wait_args *lwa,
118*510ee669SKonstantin Belousov const struct ntsync_wait_args *wa)
119*510ee669SKonstantin Belousov {
120*510ee669SKonstantin Belousov memcpy(lwa, wa, sizeof(*lwa));
121*510ee669SKonstantin Belousov }
122*510ee669SKonstantin Belousov
123*510ee669SKonstantin Belousov static int
linux_ntsync_cdev_ioctl(struct thread * td,u_long cmd,void * data,struct file * fp)124*510ee669SKonstantin Belousov linux_ntsync_cdev_ioctl(struct thread *td, u_long cmd, void *data,
125*510ee669SKonstantin Belousov struct file *fp)
126*510ee669SKonstantin Belousov {
127*510ee669SKonstantin Belousov struct cdev *dev;
128*510ee669SKonstantin Belousov struct cdevsw *dsw;
129*510ee669SKonstantin Belousov struct vnode *vp;
130*510ee669SKonstantin Belousov struct file *fpop;
131*510ee669SKonstantin Belousov int error, ref;
132*510ee669SKonstantin Belousov
133*510ee669SKonstantin Belousov if (fp->f_type != DTYPE_VNODE)
134*510ee669SKonstantin Belousov return (error = ENOIOCTL);
135*510ee669SKonstantin Belousov
136*510ee669SKonstantin Belousov vp = fp->f_vnode;
137*510ee669SKonstantin Belousov if (vp->v_type != VCHR)
138*510ee669SKonstantin Belousov return (ENOIOCTL);
139*510ee669SKonstantin Belousov dev = vp->v_rdev;
140*510ee669SKonstantin Belousov dsw = dev_refthread(dev, &ref);
141*510ee669SKonstantin Belousov if (dsw == NULL)
142*510ee669SKonstantin Belousov return (ENXIO);
143*510ee669SKonstantin Belousov if (dsw != &ntsync_cdevsw) {
144*510ee669SKonstantin Belousov error = ENOIOCTL;
145*510ee669SKonstantin Belousov } else {
146*510ee669SKonstantin Belousov fpop = td->td_fpop;
147*510ee669SKonstantin Belousov td->td_fpop = fp;
148*510ee669SKonstantin Belousov error = dsw->d_ioctl(dev, cmd, data, 0, td);
149*510ee669SKonstantin Belousov td->td_fpop = fpop;
150*510ee669SKonstantin Belousov }
151*510ee669SKonstantin Belousov dev_relthread(dev, ref);
152*510ee669SKonstantin Belousov return (error);
153*510ee669SKonstantin Belousov }
154*510ee669SKonstantin Belousov
155*510ee669SKonstantin Belousov static int
linux_ntsync_ioctl(struct thread * td,struct linux_ioctl_args * args)156*510ee669SKonstantin Belousov linux_ntsync_ioctl(struct thread *td, struct linux_ioctl_args *args)
157*510ee669SKonstantin Belousov {
158*510ee669SKonstantin Belousov struct file *fp;
159*510ee669SKonstantin Belousov void *data;
160*510ee669SKonstantin Belousov struct linux_ntsync_sem_args lsa;
161*510ee669SKonstantin Belousov struct linux_ntsync_mutex_args lma;
162*510ee669SKonstantin Belousov struct linux_ntsync_event_args lea;
163*510ee669SKonstantin Belousov struct linux_ntsync_wait_args lwa;
164*510ee669SKonstantin Belousov struct ntsync_sem_args sa;
165*510ee669SKonstantin Belousov struct ntsync_mutex_args ma;
166*510ee669SKonstantin Belousov struct ntsync_event_args ea;
167*510ee669SKonstantin Belousov struct ntsync_wait_args wa;
168*510ee669SKonstantin Belousov uint32_t val;
169*510ee669SKonstantin Belousov int error, error1, lcmd;
170*510ee669SKonstantin Belousov bool doco;
171*510ee669SKonstantin Belousov
172*510ee669SKonstantin Belousov lcmd = args->cmd;
173*510ee669SKonstantin Belousov data = (void *)args->arg;
174*510ee669SKonstantin Belousov
175*510ee669SKonstantin Belousov error = fget_cap(td, args->fd, &cap_no_rights, NULL, &fp, NULL);
176*510ee669SKonstantin Belousov if (error != 0)
177*510ee669SKonstantin Belousov goto out;
178*510ee669SKonstantin Belousov
179*510ee669SKonstantin Belousov doco = false;
180*510ee669SKonstantin Belousov switch (lcmd) {
181*510ee669SKonstantin Belousov case LNTSYNC_IOC_CREATE_SEM:
182*510ee669SKonstantin Belousov error = copyin(data, &lsa, sizeof(lsa));
183*510ee669SKonstantin Belousov ntsync_lsa_to_sa(&sa, &lsa);
184*510ee669SKonstantin Belousov if (error == 0) {
185*510ee669SKonstantin Belousov error = linux_ntsync_cdev_ioctl(td,
186*510ee669SKonstantin Belousov NTSYNC_IOC_CREATE_SEM, &sa, fp);
187*510ee669SKonstantin Belousov }
188*510ee669SKonstantin Belousov break;
189*510ee669SKonstantin Belousov case LNTSYNC_IOC_CREATE_MUTEX:
190*510ee669SKonstantin Belousov error = copyin(data, &lma, sizeof(lma));
191*510ee669SKonstantin Belousov ntsync_lma_to_ma(&ma, &lma);
192*510ee669SKonstantin Belousov if (error == 0) {
193*510ee669SKonstantin Belousov error = linux_ntsync_cdev_ioctl(td,
194*510ee669SKonstantin Belousov NTSYNC_IOC_CREATE_MUTEX, &ma, fp);
195*510ee669SKonstantin Belousov }
196*510ee669SKonstantin Belousov break;
197*510ee669SKonstantin Belousov case LNTSYNC_IOC_CREATE_EVENT:
198*510ee669SKonstantin Belousov error = copyin(data, &lea, sizeof(lea));
199*510ee669SKonstantin Belousov ntsync_lea_to_ea(&ea, &lea);
200*510ee669SKonstantin Belousov if (error == 0) {
201*510ee669SKonstantin Belousov error = linux_ntsync_cdev_ioctl(td,
202*510ee669SKonstantin Belousov NTSYNC_IOC_CREATE_EVENT, &ea, fp);
203*510ee669SKonstantin Belousov }
204*510ee669SKonstantin Belousov break;
205*510ee669SKonstantin Belousov case LNTSYNC_IOC_WAIT_ANY:
206*510ee669SKonstantin Belousov error = copyin(data, &lwa, sizeof(lwa));
207*510ee669SKonstantin Belousov ntsync_lwa_to_wa(&wa, &lwa);
208*510ee669SKonstantin Belousov if (error == 0) {
209*510ee669SKonstantin Belousov error = linux_ntsync_cdev_ioctl(td,
210*510ee669SKonstantin Belousov NTSYNC_IOC_WAIT_ANY, &wa, fp);
211*510ee669SKonstantin Belousov if (error == 0 || error == EOWNERDEAD) {
212*510ee669SKonstantin Belousov ntsync_wa_to_lwa(&lwa, &wa);
213*510ee669SKonstantin Belousov error1 = copyout(&lwa, data, sizeof(lwa));
214*510ee669SKonstantin Belousov if (error == 0)
215*510ee669SKonstantin Belousov error = error1;
216*510ee669SKonstantin Belousov }
217*510ee669SKonstantin Belousov }
218*510ee669SKonstantin Belousov break;
219*510ee669SKonstantin Belousov case LNTSYNC_IOC_WAIT_ALL:
220*510ee669SKonstantin Belousov error = copyin(data, &lwa, sizeof(lwa));
221*510ee669SKonstantin Belousov ntsync_lwa_to_wa(&wa, &lwa);
222*510ee669SKonstantin Belousov if (error == 0) {
223*510ee669SKonstantin Belousov error = linux_ntsync_cdev_ioctl(td,
224*510ee669SKonstantin Belousov NTSYNC_IOC_WAIT_ALL, &wa, fp);
225*510ee669SKonstantin Belousov if (error == 0 || error == EOWNERDEAD) {
226*510ee669SKonstantin Belousov ntsync_wa_to_lwa(&lwa, &wa);
227*510ee669SKonstantin Belousov error1 = copyout(&lwa, data, sizeof(lwa));
228*510ee669SKonstantin Belousov if (error == 0)
229*510ee669SKonstantin Belousov error = error1;
230*510ee669SKonstantin Belousov }
231*510ee669SKonstantin Belousov }
232*510ee669SKonstantin Belousov break;
233*510ee669SKonstantin Belousov case LNTSYNC_IOC_SEM_RELEASE:
234*510ee669SKonstantin Belousov error = copyin(data, &val, sizeof(val));
235*510ee669SKonstantin Belousov if (error == 0) {
236*510ee669SKonstantin Belousov error = ntsync_sem_release(td, fp, &val);
237*510ee669SKonstantin Belousov if (error == 0)
238*510ee669SKonstantin Belousov error = copyout(&val, data, sizeof(val));
239*510ee669SKonstantin Belousov }
240*510ee669SKonstantin Belousov break;
241*510ee669SKonstantin Belousov case LNTSYNC_IOC_SEM_READ:
242*510ee669SKonstantin Belousov error = ntsync_sem_read(td, fp, &sa);
243*510ee669SKonstantin Belousov if (error == 0) {
244*510ee669SKonstantin Belousov ntsync_sa_to_lsa(&lsa, &sa);
245*510ee669SKonstantin Belousov error = copyout(&lsa, data, sizeof(lsa));
246*510ee669SKonstantin Belousov }
247*510ee669SKonstantin Belousov break;
248*510ee669SKonstantin Belousov case LNTSYNC_IOC_MUTEX_UNLOCK:
249*510ee669SKonstantin Belousov error = copyin(data, &lma, sizeof(lma));
250*510ee669SKonstantin Belousov ntsync_lma_to_ma(&ma, &lma);
251*510ee669SKonstantin Belousov if (error == 0) {
252*510ee669SKonstantin Belousov error = ntsync_mutex_unlock(td, fp, &ma);
253*510ee669SKonstantin Belousov if (error == 0) {
254*510ee669SKonstantin Belousov ntsync_ma_to_lma(&lma, &ma);
255*510ee669SKonstantin Belousov error = copyout(&lma, data, sizeof(lma));
256*510ee669SKonstantin Belousov }
257*510ee669SKonstantin Belousov }
258*510ee669SKonstantin Belousov break;
259*510ee669SKonstantin Belousov case LNTSYNC_IOC_MUTEX_KILL:
260*510ee669SKonstantin Belousov error = copyin(data, &val, sizeof(val));
261*510ee669SKonstantin Belousov if (error == 0)
262*510ee669SKonstantin Belousov error = ntsync_mutex_kill(td, fp, val);
263*510ee669SKonstantin Belousov break;
264*510ee669SKonstantin Belousov case LNTSYNC_IOC_MUTEX_READ:
265*510ee669SKonstantin Belousov error = ntsync_mutex_read(td, fp, &ma, &doco);
266*510ee669SKonstantin Belousov if (doco) {
267*510ee669SKonstantin Belousov ntsync_ma_to_lma(&lma, &ma);
268*510ee669SKonstantin Belousov error1 = copyout(&lma, data, sizeof(lma));
269*510ee669SKonstantin Belousov if (error == 0)
270*510ee669SKonstantin Belousov error = error1;
271*510ee669SKonstantin Belousov }
272*510ee669SKonstantin Belousov break;
273*510ee669SKonstantin Belousov case LNTSYNC_IOC_EVENT_SET:
274*510ee669SKonstantin Belousov error = ntsync_event_set(td, fp, &val);
275*510ee669SKonstantin Belousov if (error == 0)
276*510ee669SKonstantin Belousov error = copyout(&val, data, sizeof(val));
277*510ee669SKonstantin Belousov break;
278*510ee669SKonstantin Belousov case LNTSYNC_IOC_EVENT_RESET:
279*510ee669SKonstantin Belousov error = ntsync_event_reset(td, fp, &val);
280*510ee669SKonstantin Belousov if (error == 0)
281*510ee669SKonstantin Belousov error = copyout(&val, data, sizeof(val));
282*510ee669SKonstantin Belousov break;
283*510ee669SKonstantin Belousov case LNTSYNC_IOC_EVENT_PULSE:
284*510ee669SKonstantin Belousov error = ntsync_event_pulse(td, fp, &val);
285*510ee669SKonstantin Belousov if (error == 0)
286*510ee669SKonstantin Belousov error = copyout(&val, data, sizeof(val));
287*510ee669SKonstantin Belousov break;
288*510ee669SKonstantin Belousov case LNTSYNC_IOC_EVENT_READ:
289*510ee669SKonstantin Belousov error = ntsync_event_read(td, fp, &ea);
290*510ee669SKonstantin Belousov if (error == 0) {
291*510ee669SKonstantin Belousov ntsync_ea_to_lea(&lea, &ea);
292*510ee669SKonstantin Belousov error = copyout(&lea, data, sizeof(lea));
293*510ee669SKonstantin Belousov }
294*510ee669SKonstantin Belousov break;
295*510ee669SKonstantin Belousov default:
296*510ee669SKonstantin Belousov error = ENOTTY;
297*510ee669SKonstantin Belousov break;
298*510ee669SKonstantin Belousov }
299*510ee669SKonstantin Belousov fdrop(fp, td);
300*510ee669SKonstantin Belousov out:
301*510ee669SKonstantin Belousov return (error);
302*510ee669SKonstantin Belousov }
303