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