xref: /freebsd/sys/dev/ntsync/linux_ntsync.c (revision 510ee6698d377f4a9a4eeb08d9dc17bdc72ad5ab)
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