xref: /freebsd/sys/dev/ntsync/linux_ntsync.c (revision f85e66e655c9293ea049814e21ed67ab246a7305)
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
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
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
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
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
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
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
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
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
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
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
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 		if (fp->f_type != DTYPE_NTSYNC) {
235 			error = ENOTTY;
236 			break;
237 		}
238 		error = copyin(data, &val, sizeof(val));
239 		if (error == 0) {
240 			error = ntsync_sem_release(td, fp, &val);
241 			if (error == 0)
242 				error = copyout(&val, data, sizeof(val));
243 		}
244 		break;
245 	case LNTSYNC_IOC_SEM_READ:
246 		if (fp->f_type != DTYPE_NTSYNC) {
247 			error = ENOTTY;
248 			break;
249 		}
250 		error = ntsync_sem_read(td, fp, &sa);
251 		if (error == 0) {
252 			ntsync_sa_to_lsa(&lsa, &sa);
253 			error = copyout(&lsa, data, sizeof(lsa));
254 		}
255 		break;
256 	case LNTSYNC_IOC_MUTEX_UNLOCK:
257 		if (fp->f_type != DTYPE_NTSYNC) {
258 			error = ENOTTY;
259 			break;
260 		}
261 		error = copyin(data, &lma, sizeof(lma));
262 		ntsync_lma_to_ma(&ma, &lma);
263 		if (error == 0) {
264 			error = ntsync_mutex_unlock(td, fp, &ma);
265 			if (error == 0) {
266 				ntsync_ma_to_lma(&lma, &ma);
267 				error = copyout(&lma, data, sizeof(lma));
268 			}
269 		}
270 		break;
271 	case LNTSYNC_IOC_MUTEX_KILL:
272 		if (fp->f_type != DTYPE_NTSYNC) {
273 			error = ENOTTY;
274 			break;
275 		}
276 		error = copyin(data, &val, sizeof(val));
277 		if (error == 0)
278 			error = ntsync_mutex_kill(td, fp, val);
279 		break;
280 	case LNTSYNC_IOC_MUTEX_READ:
281 		if (fp->f_type != DTYPE_NTSYNC) {
282 			error = ENOTTY;
283 			break;
284 		}
285 		error = ntsync_mutex_read(td, fp, &ma, &doco);
286 		if (doco) {
287 			ntsync_ma_to_lma(&lma, &ma);
288 			error1 = copyout(&lma, data, sizeof(lma));
289 			if (error == 0)
290 				error = error1;
291 		}
292 		break;
293 	case LNTSYNC_IOC_EVENT_SET:
294 		if (fp->f_type != DTYPE_NTSYNC) {
295 			error = ENOTTY;
296 			break;
297 		}
298 		error = ntsync_event_set(td, fp, &val);
299 		if (error == 0)
300 			error = copyout(&val, data, sizeof(val));
301 		break;
302 	case LNTSYNC_IOC_EVENT_RESET:
303 		if (fp->f_type != DTYPE_NTSYNC) {
304 			error = ENOTTY;
305 			break;
306 		}
307 		error = ntsync_event_reset(td, fp, &val);
308 		if (error == 0)
309 			error = copyout(&val, data, sizeof(val));
310 		break;
311 	case LNTSYNC_IOC_EVENT_PULSE:
312 		if (fp->f_type != DTYPE_NTSYNC) {
313 			error = ENOTTY;
314 			break;
315 		}
316 		error = ntsync_event_pulse(td, fp, &val);
317 		if (error == 0)
318 			error = copyout(&val, data, sizeof(val));
319 		break;
320 	case LNTSYNC_IOC_EVENT_READ:
321 		if (fp->f_type != DTYPE_NTSYNC) {
322 			error = ENOTTY;
323 			break;
324 		}
325 		error = ntsync_event_read(td, fp, &ea);
326 		if (error == 0) {
327 			ntsync_ea_to_lea(&lea, &ea);
328 			error = copyout(&lea, data, sizeof(lea));
329 		}
330 		break;
331 	default:
332 		error = ENOTTY;
333 		break;
334 	}
335 	fdrop(fp, td);
336 out:
337 	return (error);
338 }
339