1*185d6cd7Sthorpej /* $NetBSD: linux_time.c,v 1.42 2021/09/19 23:51:37 thorpej Exp $ */
2d473f5bdSmanu
3d473f5bdSmanu /*-
4555b1851Sthorpej * Copyright (c) 2001, 2020 The NetBSD Foundation, Inc.
5d473f5bdSmanu * All rights reserved.
6d473f5bdSmanu *
7d473f5bdSmanu * This code is derived from software contributed to The NetBSD Foundation
8555b1851Sthorpej * by Emmanuel Dreyfus, and by Jason R. Thorpe.
9d473f5bdSmanu *
10d473f5bdSmanu * Redistribution and use in source and binary forms, with or without
11d473f5bdSmanu * modification, are permitted provided that the following conditions
12d473f5bdSmanu * are met:
13d473f5bdSmanu * 1. Redistributions of source code must retain the above copyright
14d473f5bdSmanu * notice, this list of conditions and the following disclaimer.
15d473f5bdSmanu * 2. Redistributions in binary form must reproduce the above copyright
16d473f5bdSmanu * notice, this list of conditions and the following disclaimer in the
17d473f5bdSmanu * documentation and/or other materials provided with the distribution.
18d473f5bdSmanu *
19d473f5bdSmanu * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20d473f5bdSmanu * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21d473f5bdSmanu * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22d473f5bdSmanu * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23d473f5bdSmanu * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24d473f5bdSmanu * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25d473f5bdSmanu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26d473f5bdSmanu * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27d473f5bdSmanu * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28d473f5bdSmanu * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29d473f5bdSmanu * POSSIBILITY OF SUCH DAMAGE.
30d473f5bdSmanu */
31d473f5bdSmanu
32dab6ef8bSlukem #include <sys/cdefs.h>
33*185d6cd7Sthorpej __KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.42 2021/09/19 23:51:37 thorpej Exp $");
34dab6ef8bSlukem
35d473f5bdSmanu #include <sys/param.h>
36d473f5bdSmanu #include <sys/ucred.h>
372cc0d0a9Sdsl #include <sys/kauth.h>
38d473f5bdSmanu #include <sys/mount.h>
39d473f5bdSmanu #include <sys/signal.h>
40d473f5bdSmanu #include <sys/stdint.h>
41d473f5bdSmanu #include <sys/time.h>
42*185d6cd7Sthorpej #include <sys/timerfd.h>
43d473f5bdSmanu #include <sys/systm.h>
444482e41eStsutsui #include <sys/sched.h>
45d473f5bdSmanu #include <sys/syscallargs.h>
46046b9a57Sfvdl #include <sys/lwp.h>
47046b9a57Sfvdl #include <sys/proc.h>
48d473f5bdSmanu
49d473f5bdSmanu #include <compat/linux/common/linux_types.h>
50*185d6cd7Sthorpej #include <compat/linux/common/linux_fcntl.h>
51*185d6cd7Sthorpej #include <compat/linux/common/linux_ioctl.h>
52d473f5bdSmanu #include <compat/linux/common/linux_signal.h>
53555b1851Sthorpej #include <compat/linux/common/linux_sigevent.h>
5488a5eb33Smanu #include <compat/linux/common/linux_machdep.h>
55046b9a57Sfvdl #include <compat/linux/common/linux_sched.h>
56a478f23bSnjoly #include <compat/linux/common/linux_ipc.h>
57a478f23bSnjoly #include <compat/linux/common/linux_sem.h>
58d473f5bdSmanu
59d473f5bdSmanu #include <compat/linux/linux_syscallargs.h>
60d473f5bdSmanu
61046b9a57Sfvdl #include <compat/common/compat_util.h>
62046b9a57Sfvdl
63555b1851Sthorpej CTASSERT(LINUX_TIMER_ABSTIME == TIMER_ABSTIME);
64555b1851Sthorpej
65d473f5bdSmanu /*
66d473f5bdSmanu * Linux keeps track of a system timezone in the kernel. It is readen
67d473f5bdSmanu * by gettimeofday and set by settimeofday. This emulates this behavior
68d473f5bdSmanu * See linux/kernel/time.c
69d473f5bdSmanu */
70d473f5bdSmanu struct timezone linux_sys_tz;
71d473f5bdSmanu
72046b9a57Sfvdl int
linux_sys_gettimeofday(struct lwp * l,const struct linux_sys_gettimeofday_args * uap,register_t * retval)737e2790cfSdsl linux_sys_gettimeofday(struct lwp *l, const struct linux_sys_gettimeofday_args *uap, register_t *retval)
74d473f5bdSmanu {
757e2790cfSdsl /* {
76461a86f9Schristos syscallarg(struct timeval50 *) tz;
77d473f5bdSmanu syscallarg(struct timezone *) tzp;
787e2790cfSdsl } */
79d473f5bdSmanu int error = 0;
80d473f5bdSmanu
81d473f5bdSmanu if (SCARG(uap, tp)) {
82461a86f9Schristos error = compat_50_sys_gettimeofday(l, (const void *)uap, retval);
83d473f5bdSmanu if (error)
84d473f5bdSmanu return (error);
85d473f5bdSmanu }
86d473f5bdSmanu
87d473f5bdSmanu if (SCARG(uap, tzp)) {
88d473f5bdSmanu error = copyout(&linux_sys_tz, SCARG(uap, tzp), sizeof(linux_sys_tz));
89d473f5bdSmanu if (error)
90d473f5bdSmanu return (error);
91d473f5bdSmanu }
92d473f5bdSmanu
93d473f5bdSmanu return (0);
94d473f5bdSmanu }
95d473f5bdSmanu
96046b9a57Sfvdl int
linux_sys_settimeofday(struct lwp * l,const struct linux_sys_settimeofday_args * uap,register_t * retval)977e2790cfSdsl linux_sys_settimeofday(struct lwp *l, const struct linux_sys_settimeofday_args *uap, register_t *retval)
98d473f5bdSmanu {
997e2790cfSdsl /* {
100461a86f9Schristos syscallarg(struct timeval50 *) tp;
101d473f5bdSmanu syscallarg(struct timezone *) tzp;
1027e2790cfSdsl } */
103d473f5bdSmanu int error = 0;
104d473f5bdSmanu
105d473f5bdSmanu if (SCARG(uap, tp)) {
106461a86f9Schristos error = compat_50_sys_settimeofday(l, (const void *)uap, retval);
107d473f5bdSmanu if (error)
108d473f5bdSmanu return (error);
109d473f5bdSmanu }
110d473f5bdSmanu
111d473f5bdSmanu if (SCARG(uap, tzp)) {
112d82060bcSriastradh if (kauth_authorize_generic(kauth_cred_get(),
113d82060bcSriastradh KAUTH_GENERIC_ISSUSER, NULL) != 0)
114d82060bcSriastradh return (EPERM);
115d473f5bdSmanu error = copyin(SCARG(uap, tzp), &linux_sys_tz, sizeof(linux_sys_tz));
116d473f5bdSmanu if (error)
117d473f5bdSmanu return (error);
118d473f5bdSmanu }
119d473f5bdSmanu
120d473f5bdSmanu return (0);
121d473f5bdSmanu }
12256839426Smanu
123377975c1Snjoly void
native_to_linux_timespec(struct linux_timespec * ltp,const struct timespec * ntp)124555b1851Sthorpej native_to_linux_timespec(struct linux_timespec *ltp, const struct timespec *ntp)
125046b9a57Sfvdl {
12641aa5859Sriastradh memset(ltp, 0, sizeof(*ltp));
127046b9a57Sfvdl ltp->tv_sec = ntp->tv_sec;
128046b9a57Sfvdl ltp->tv_nsec = ntp->tv_nsec;
129046b9a57Sfvdl }
130046b9a57Sfvdl
131377975c1Snjoly void
linux_to_native_timespec(struct timespec * ntp,const struct linux_timespec * ltp)132555b1851Sthorpej linux_to_native_timespec(struct timespec *ntp, const struct linux_timespec *ltp)
133046b9a57Sfvdl {
13441aa5859Sriastradh memset(ntp, 0, sizeof(*ntp));
135046b9a57Sfvdl ntp->tv_sec = ltp->tv_sec;
136046b9a57Sfvdl ntp->tv_nsec = ltp->tv_nsec;
137046b9a57Sfvdl }
138046b9a57Sfvdl
139555b1851Sthorpej void
native_to_linux_itimerspec(struct linux_itimerspec * litp,const struct itimerspec * nitp)140555b1851Sthorpej native_to_linux_itimerspec(struct linux_itimerspec *litp,
141555b1851Sthorpej const struct itimerspec *nitp)
142555b1851Sthorpej {
143555b1851Sthorpej memset(litp, 0, sizeof(*litp));
144555b1851Sthorpej native_to_linux_timespec(&litp->it_interval, &nitp->it_interval);
145555b1851Sthorpej native_to_linux_timespec(&litp->it_value, &nitp->it_value);
146555b1851Sthorpej }
147555b1851Sthorpej
148555b1851Sthorpej void
linux_to_native_itimerspec(struct itimerspec * nitp,const struct linux_itimerspec * litp)149555b1851Sthorpej linux_to_native_itimerspec(struct itimerspec *nitp,
150555b1851Sthorpej const struct linux_itimerspec *litp)
151555b1851Sthorpej {
152555b1851Sthorpej memset(nitp, 0, sizeof(*nitp));
153555b1851Sthorpej linux_to_native_timespec(&nitp->it_interval, &litp->it_interval);
154555b1851Sthorpej linux_to_native_timespec(&nitp->it_value, &litp->it_value);
155555b1851Sthorpej }
156555b1851Sthorpej
157c007e33aSnjoly int
linux_sys_nanosleep(struct lwp * l,const struct linux_sys_nanosleep_args * uap,register_t * retval)158cf192232Snjoly linux_sys_nanosleep(struct lwp *l, const struct linux_sys_nanosleep_args *uap,
159cf192232Snjoly register_t *retval)
160cf192232Snjoly {
161cf192232Snjoly /* {
162cf192232Snjoly syscallarg(struct linux_timespec *) rqtp;
163cf192232Snjoly syscallarg(struct linux_timespec *) rmtp;
164cf192232Snjoly } */
165cf192232Snjoly struct timespec rqts, rmts;
166cf192232Snjoly struct linux_timespec lrqts, lrmts;
167cf192232Snjoly int error, error1;
168cf192232Snjoly
169cf192232Snjoly error = copyin(SCARG(uap, rqtp), &lrqts, sizeof(lrqts));
170cf192232Snjoly if (error != 0)
171cf192232Snjoly return error;
172cf192232Snjoly linux_to_native_timespec(&rqts, &lrqts);
173cf192232Snjoly
1741ec74323Schristos error = nanosleep1(l, CLOCK_MONOTONIC, 0, &rqts,
1751ec74323Schristos SCARG(uap, rmtp) ? &rmts : NULL);
176cf192232Snjoly if (SCARG(uap, rmtp) == NULL || (error != 0 && error != EINTR))
177cf192232Snjoly return error;
178cf192232Snjoly
179cf192232Snjoly native_to_linux_timespec(&lrmts, &rmts);
180cf192232Snjoly error1 = copyout(&lrmts, SCARG(uap, rmtp), sizeof(lrmts));
181cf192232Snjoly return error1 ? error1 : error;
182cf192232Snjoly }
183cf192232Snjoly
184cf192232Snjoly int
linux_to_native_clockid(clockid_t * n,clockid_t l)185046b9a57Sfvdl linux_to_native_clockid(clockid_t *n, clockid_t l)
186046b9a57Sfvdl {
187046b9a57Sfvdl switch (l) {
188046b9a57Sfvdl case LINUX_CLOCK_REALTIME:
189046b9a57Sfvdl *n = CLOCK_REALTIME;
190046b9a57Sfvdl break;
191046b9a57Sfvdl case LINUX_CLOCK_MONOTONIC:
192046b9a57Sfvdl *n = CLOCK_MONOTONIC;
193046b9a57Sfvdl break;
194046b9a57Sfvdl case LINUX_CLOCK_PROCESS_CPUTIME_ID:
195555b1851Sthorpej *n = CLOCK_PROCESS_CPUTIME_ID /* self */;
196555b1851Sthorpej break;
197046b9a57Sfvdl case LINUX_CLOCK_THREAD_CPUTIME_ID:
198555b1851Sthorpej *n = CLOCK_THREAD_CPUTIME_ID /* self */;
199555b1851Sthorpej break;
200555b1851Sthorpej
201555b1851Sthorpej case LINUX_CLOCK_MONOTONIC_RAW:
202555b1851Sthorpej case LINUX_CLOCK_REALTIME_COARSE:
203555b1851Sthorpej case LINUX_CLOCK_MONOTONIC_COARSE:
204555b1851Sthorpej case LINUX_CLOCK_BOOTTIME:
205555b1851Sthorpej case LINUX_CLOCK_BOOTTIME_ALARM:
206555b1851Sthorpej case LINUX_CLOCK_REALTIME_ALARM:
207dd5f4082Snjoly default:
208555b1851Sthorpej return ENOTSUP;
209046b9a57Sfvdl }
210046b9a57Sfvdl
211046b9a57Sfvdl return 0;
212046b9a57Sfvdl }
213046b9a57Sfvdl
214046b9a57Sfvdl int
linux_sys_clock_gettime(struct lwp * l,const struct linux_sys_clock_gettime_args * uap,register_t * retval)2157e2790cfSdsl linux_sys_clock_gettime(struct lwp *l, const struct linux_sys_clock_gettime_args *uap, register_t *retval)
216046b9a57Sfvdl {
2177e2790cfSdsl /* {
218046b9a57Sfvdl syscallarg(clockid_t) which;
219046b9a57Sfvdl syscallarg(struct linux_timespec *)tp;
2207e2790cfSdsl } */
2214f2ea8f3Snjoly int error;
2224f2ea8f3Snjoly clockid_t id;
2232cc0d0a9Sdsl struct timespec ts;
224046b9a57Sfvdl struct linux_timespec lts;
225046b9a57Sfvdl
2264f2ea8f3Snjoly error = linux_to_native_clockid(&id, SCARG(uap, which));
2274f2ea8f3Snjoly if (error != 0)
2284f2ea8f3Snjoly return error;
2294f2ea8f3Snjoly
2304f2ea8f3Snjoly error = clock_gettime1(id, &ts);
2314f2ea8f3Snjoly if (error != 0)
2324f2ea8f3Snjoly return error;
233046b9a57Sfvdl
234046b9a57Sfvdl native_to_linux_timespec(<s, &ts);
235046b9a57Sfvdl return copyout(<s, SCARG(uap, tp), sizeof lts);
236046b9a57Sfvdl }
237046b9a57Sfvdl
238046b9a57Sfvdl int
linux_sys_clock_settime(struct lwp * l,const struct linux_sys_clock_settime_args * uap,register_t * retval)2397e2790cfSdsl linux_sys_clock_settime(struct lwp *l, const struct linux_sys_clock_settime_args *uap, register_t *retval)
240046b9a57Sfvdl {
2417e2790cfSdsl /* {
242046b9a57Sfvdl syscallarg(clockid_t) which;
243046b9a57Sfvdl syscallarg(struct linux_timespec *)tp;
2447e2790cfSdsl } */
2452cc0d0a9Sdsl struct timespec ts;
246046b9a57Sfvdl struct linux_timespec lts;
2476d63d669Snjoly clockid_t id;
248046b9a57Sfvdl int error;
249046b9a57Sfvdl
2506d63d669Snjoly error = linux_to_native_clockid(&id, SCARG(uap, which));
2516d63d669Snjoly if (error != 0)
2526d63d669Snjoly return error;
253046b9a57Sfvdl
254046b9a57Sfvdl error = copyin(SCARG(uap, tp), <s, sizeof lts);
255046b9a57Sfvdl if (error != 0)
256046b9a57Sfvdl return error;
257046b9a57Sfvdl
258046b9a57Sfvdl linux_to_native_timespec(&ts, <s);
259046b9a57Sfvdl
2606d63d669Snjoly return clock_settime1(l->l_proc, id, &ts, true);
261046b9a57Sfvdl }
262046b9a57Sfvdl
263046b9a57Sfvdl int
linux_sys_clock_getres(struct lwp * l,const struct linux_sys_clock_getres_args * uap,register_t * retval)2647e2790cfSdsl linux_sys_clock_getres(struct lwp *l, const struct linux_sys_clock_getres_args *uap, register_t *retval)
265046b9a57Sfvdl {
2667e2790cfSdsl /* {
267046b9a57Sfvdl syscallarg(clockid_t) which;
268046b9a57Sfvdl syscallarg(struct linux_timespec *)tp;
2697e2790cfSdsl } */
2702cc0d0a9Sdsl struct timespec ts;
271046b9a57Sfvdl struct linux_timespec lts;
272046b9a57Sfvdl int error;
273ca0ec852Schristos clockid_t nwhich = 0; /* XXX: GCC */
274046b9a57Sfvdl
275046b9a57Sfvdl error = linux_to_native_clockid(&nwhich, SCARG(uap, which));
2762cc0d0a9Sdsl if (error != 0 || SCARG(uap, tp) == NULL)
277046b9a57Sfvdl return error;
278046b9a57Sfvdl
2790876f873Snjoly error = clock_getres1(nwhich, &ts);
2800876f873Snjoly if (error != 0)
2810876f873Snjoly return error;
2820876f873Snjoly
283046b9a57Sfvdl native_to_linux_timespec(<s, &ts);
284046b9a57Sfvdl return copyout(<s, SCARG(uap, tp), sizeof lts);
285046b9a57Sfvdl }
286046b9a57Sfvdl
287046b9a57Sfvdl int
linux_sys_clock_nanosleep(struct lwp * l,const struct linux_sys_clock_nanosleep_args * uap,register_t * retval)2887e2790cfSdsl linux_sys_clock_nanosleep(struct lwp *l, const struct linux_sys_clock_nanosleep_args *uap, register_t *retval)
289046b9a57Sfvdl {
2907e2790cfSdsl /* {
291046b9a57Sfvdl syscallarg(clockid_t) which;
292046b9a57Sfvdl syscallarg(int) flags;
293046b9a57Sfvdl syscallarg(struct linux_timespec) *rqtp;
294046b9a57Sfvdl syscallarg(struct linux_timespec) *rmtp;
2957e2790cfSdsl } */
296046b9a57Sfvdl struct linux_timespec lrqts, lrmts;
297046b9a57Sfvdl struct timespec rqts, rmts;
2981ec74323Schristos int error, error1, flags;
299328f6885Snjoly clockid_t nwhich;
300046b9a57Sfvdl
301555b1851Sthorpej flags = SCARG(uap, flags);
302555b1851Sthorpej if (flags & ~TIMER_ABSTIME) {
303555b1851Sthorpej return EINVAL;
304555b1851Sthorpej }
305046b9a57Sfvdl
306328f6885Snjoly error = linux_to_native_clockid(&nwhich, SCARG(uap, which));
307328f6885Snjoly if (error != 0)
308328f6885Snjoly return error;
309046b9a57Sfvdl
310046b9a57Sfvdl error = copyin(SCARG(uap, rqtp), &lrqts, sizeof lrqts);
311046b9a57Sfvdl if (error != 0)
312046b9a57Sfvdl return error;
313046b9a57Sfvdl
314046b9a57Sfvdl linux_to_native_timespec(&rqts, &lrqts);
315046b9a57Sfvdl
3161ec74323Schristos error = nanosleep1(l, nwhich, flags, &rqts,
3171ec74323Schristos SCARG(uap, rmtp) ? &rmts : NULL);
3182cc0d0a9Sdsl if (SCARG(uap, rmtp) == NULL || (error != 0 && error != EINTR))
319046b9a57Sfvdl return error;
320046b9a57Sfvdl
321046b9a57Sfvdl native_to_linux_timespec(&lrmts, &rmts);
3222cc0d0a9Sdsl error1 = copyout(&lrmts, SCARG(uap, rmtp), sizeof lrmts);
3232cc0d0a9Sdsl return error1 ? error1 : error;
324046b9a57Sfvdl }
325555b1851Sthorpej
326555b1851Sthorpej int
linux_to_native_timer_create_clockid(clockid_t * nid,clockid_t lid)327555b1851Sthorpej linux_to_native_timer_create_clockid(clockid_t *nid, clockid_t lid)
328555b1851Sthorpej {
329555b1851Sthorpej clockid_t id;
330555b1851Sthorpej int error;
331555b1851Sthorpej
332555b1851Sthorpej error = linux_to_native_clockid(&id, lid);
333555b1851Sthorpej if (error == 0) {
334555b1851Sthorpej /*
335555b1851Sthorpej * We can't create a timer with every sort of clock ID
336555b1851Sthorpej * that the system understands, so filter them out.
337555b1851Sthorpej *
338555b1851Sthorpej * Map CLOCK_PROCESS_CPUTIME_ID to CLOCK_VIRTUAL.
339555b1851Sthorpej * We can't handle CLOCK_THREAD_CPUTIME_ID.
340555b1851Sthorpej */
341555b1851Sthorpej switch (id) {
342555b1851Sthorpej case CLOCK_REALTIME:
343555b1851Sthorpej case CLOCK_MONOTONIC:
344555b1851Sthorpej break;
345555b1851Sthorpej
346555b1851Sthorpej case CLOCK_PROCESS_CPUTIME_ID:
347555b1851Sthorpej id = CLOCK_VIRTUAL;
348555b1851Sthorpej break;
349555b1851Sthorpej
350555b1851Sthorpej default:
351555b1851Sthorpej return ENOTSUP;
352555b1851Sthorpej }
353555b1851Sthorpej *nid = id;
354555b1851Sthorpej }
355555b1851Sthorpej
356555b1851Sthorpej return error;
357555b1851Sthorpej }
358555b1851Sthorpej
359555b1851Sthorpej int
linux_sys_timer_create(struct lwp * l,const struct linux_sys_timer_create_args * uap,register_t * retval)360555b1851Sthorpej linux_sys_timer_create(struct lwp *l,
361555b1851Sthorpej const struct linux_sys_timer_create_args *uap, register_t *retval)
362555b1851Sthorpej {
363555b1851Sthorpej /* {
364555b1851Sthorpej syscallarg(clockid_t) clockid;
365555b1851Sthorpej syscallarg(struct linux_sigevent *) evp;
366555b1851Sthorpej syscallarg(timer_t *) timerid;
367555b1851Sthorpej } */
368555b1851Sthorpej clockid_t id;
369555b1851Sthorpej int error;
370555b1851Sthorpej
371555b1851Sthorpej error = linux_to_native_timer_create_clockid(&id, SCARG(uap, clockid));
372555b1851Sthorpej if (error == 0) {
373555b1851Sthorpej error = timer_create1(SCARG(uap, timerid), id,
374555b1851Sthorpej (void *)SCARG(uap, evp), linux_sigevent_copyin, l);
375555b1851Sthorpej }
376555b1851Sthorpej
377555b1851Sthorpej return error;
378555b1851Sthorpej }
379555b1851Sthorpej
380555b1851Sthorpej int
linux_sys_timer_settime(struct lwp * l,const struct linux_sys_timer_settime_args * uap,register_t * retval)381555b1851Sthorpej linux_sys_timer_settime(struct lwp *l,
382555b1851Sthorpej const struct linux_sys_timer_settime_args *uap, register_t *retval)
383555b1851Sthorpej {
384555b1851Sthorpej /* {
385555b1851Sthorpej syscallarg(timer_t) timerid;
386555b1851Sthorpej syscallarg(int) flags;
387555b1851Sthorpej syscallarg(const struct linux_itimerspec *) tim;
388555b1851Sthorpej syscallarg(struct linux_itimerspec *) otim;
389555b1851Sthorpej } */
390555b1851Sthorpej struct itimerspec value, ovalue, *ovp = NULL;
391555b1851Sthorpej struct linux_itimerspec tim, otim;
392555b1851Sthorpej int error;
393555b1851Sthorpej
394555b1851Sthorpej error = copyin(SCARG(uap, tim), &tim, sizeof(tim));
395555b1851Sthorpej if (error) {
396555b1851Sthorpej return error;
397555b1851Sthorpej }
398555b1851Sthorpej linux_to_native_itimerspec(&value, &tim);
399555b1851Sthorpej
400555b1851Sthorpej if (SCARG(uap, otim)) {
401555b1851Sthorpej ovp = &ovalue;
402555b1851Sthorpej }
403555b1851Sthorpej
404555b1851Sthorpej if (SCARG(uap, flags) & ~TIMER_ABSTIME) {
405555b1851Sthorpej return EINVAL;
406555b1851Sthorpej }
407555b1851Sthorpej
408555b1851Sthorpej error = dotimer_settime(SCARG(uap, timerid), &value, ovp,
409555b1851Sthorpej SCARG(uap, flags), l->l_proc);
410555b1851Sthorpej if (error) {
411555b1851Sthorpej return error;
412555b1851Sthorpej }
413555b1851Sthorpej
414555b1851Sthorpej if (ovp) {
415555b1851Sthorpej native_to_linux_itimerspec(&otim, ovp);
416555b1851Sthorpej error = copyout(&otim, SCARG(uap, otim), sizeof(otim));
417555b1851Sthorpej }
418555b1851Sthorpej
419555b1851Sthorpej return error;
420555b1851Sthorpej }
421555b1851Sthorpej
422555b1851Sthorpej int
linux_sys_timer_gettime(struct lwp * l,const struct linux_sys_timer_gettime_args * uap,register_t * retval)423555b1851Sthorpej linux_sys_timer_gettime(struct lwp *l,
424555b1851Sthorpej const struct linux_sys_timer_gettime_args *uap, register_t *retval)
425555b1851Sthorpej {
426555b1851Sthorpej /* {
427555b1851Sthorpej syscallarg(timer_t) timerid;
428555b1851Sthorpej syscallarg(struct linux_itimerspec *) tim;
429555b1851Sthorpej } */
430555b1851Sthorpej struct itimerspec its;
431555b1851Sthorpej struct linux_itimerspec lits;
432555b1851Sthorpej int error;
433555b1851Sthorpej
434555b1851Sthorpej error = dotimer_gettime(SCARG(uap, timerid), l->l_proc, &its);
435555b1851Sthorpej if (error == 0) {
436555b1851Sthorpej native_to_linux_itimerspec(&lits, &its);
437555b1851Sthorpej error = copyout(&lits, SCARG(uap, tim), sizeof(lits));
438555b1851Sthorpej }
439555b1851Sthorpej
440555b1851Sthorpej return error;
441555b1851Sthorpej }
442555b1851Sthorpej
443555b1851Sthorpej /*
444555b1851Sthorpej * timer_gettoverrun(2) and timer_delete(2) are handled directly
445555b1851Sthorpej * by the native calls.
446555b1851Sthorpej */
447*185d6cd7Sthorpej
448*185d6cd7Sthorpej #define LINUX_TFD_TIMER_ABSTIME 0x0001
449*185d6cd7Sthorpej #define LINUX_TFD_TIMER_CANCEL_ON_SET 0x0002
450*185d6cd7Sthorpej #define LINUX_TFD_CLOEXEC LINUX_O_CLOEXEC
451*185d6cd7Sthorpej #define LINUX_TFD_NONBLOCK LINUX_O_NONBLOCK
452*185d6cd7Sthorpej
453*185d6cd7Sthorpej int
linux_sys_timerfd_create(struct lwp * l,const struct linux_sys_timerfd_create_args * uap,register_t * retval)454*185d6cd7Sthorpej linux_sys_timerfd_create(struct lwp *l,
455*185d6cd7Sthorpej const struct linux_sys_timerfd_create_args *uap, register_t *retval)
456*185d6cd7Sthorpej {
457*185d6cd7Sthorpej /* {
458*185d6cd7Sthorpej syscallarg(clockid_t) clock_id;
459*185d6cd7Sthorpej syscallarg(int) flags;
460*185d6cd7Sthorpej } */
461*185d6cd7Sthorpej int nflags = 0;
462*185d6cd7Sthorpej clockid_t id;
463*185d6cd7Sthorpej int error;
464*185d6cd7Sthorpej
465*185d6cd7Sthorpej error = linux_to_native_clockid(&id, SCARG(uap, clock_id));
466*185d6cd7Sthorpej if (error) {
467*185d6cd7Sthorpej return error;
468*185d6cd7Sthorpej }
469*185d6cd7Sthorpej
470*185d6cd7Sthorpej if (SCARG(uap, flags) & ~(LINUX_TFD_CLOEXEC | LINUX_TFD_NONBLOCK)) {
471*185d6cd7Sthorpej return EINVAL;
472*185d6cd7Sthorpej }
473*185d6cd7Sthorpej if (SCARG(uap, flags) & LINUX_TFD_CLOEXEC) {
474*185d6cd7Sthorpej nflags |= TFD_CLOEXEC;
475*185d6cd7Sthorpej }
476*185d6cd7Sthorpej if (SCARG(uap, flags) & LINUX_TFD_NONBLOCK) {
477*185d6cd7Sthorpej nflags |= TFD_NONBLOCK;
478*185d6cd7Sthorpej }
479*185d6cd7Sthorpej
480*185d6cd7Sthorpej return do_timerfd_create(l, id, nflags, retval);
481*185d6cd7Sthorpej }
482*185d6cd7Sthorpej
483*185d6cd7Sthorpej int
linux_sys_timerfd_gettime(struct lwp * l,const struct linux_sys_timerfd_gettime_args * uap,register_t * retval)484*185d6cd7Sthorpej linux_sys_timerfd_gettime(struct lwp *l,
485*185d6cd7Sthorpej const struct linux_sys_timerfd_gettime_args *uap, register_t *retval)
486*185d6cd7Sthorpej {
487*185d6cd7Sthorpej /* {
488*185d6cd7Sthorpej syscallarg(int) fd;
489*185d6cd7Sthorpej syscallarg(struct linux_itimerspec *) tim;
490*185d6cd7Sthorpej } */
491*185d6cd7Sthorpej struct itimerspec its;
492*185d6cd7Sthorpej struct linux_itimerspec lits;
493*185d6cd7Sthorpej int error;
494*185d6cd7Sthorpej
495*185d6cd7Sthorpej error = do_timerfd_gettime(l, SCARG(uap, fd), &its, retval);
496*185d6cd7Sthorpej if (error == 0) {
497*185d6cd7Sthorpej native_to_linux_itimerspec(&lits, &its);
498*185d6cd7Sthorpej error = copyout(&lits, SCARG(uap, tim), sizeof(lits));
499*185d6cd7Sthorpej }
500*185d6cd7Sthorpej
501*185d6cd7Sthorpej return error;
502*185d6cd7Sthorpej }
503*185d6cd7Sthorpej
504*185d6cd7Sthorpej int
linux_to_native_timerfd_settime_flags(int * nflagsp,int lflags)505*185d6cd7Sthorpej linux_to_native_timerfd_settime_flags(int *nflagsp, int lflags)
506*185d6cd7Sthorpej {
507*185d6cd7Sthorpej int nflags = 0;
508*185d6cd7Sthorpej
509*185d6cd7Sthorpej if (lflags & ~(LINUX_TFD_TIMER_ABSTIME |
510*185d6cd7Sthorpej LINUX_TFD_TIMER_CANCEL_ON_SET)) {
511*185d6cd7Sthorpej return EINVAL;
512*185d6cd7Sthorpej }
513*185d6cd7Sthorpej if (lflags & LINUX_TFD_TIMER_ABSTIME) {
514*185d6cd7Sthorpej nflags |= TFD_TIMER_ABSTIME;
515*185d6cd7Sthorpej }
516*185d6cd7Sthorpej if (lflags & LINUX_TFD_TIMER_CANCEL_ON_SET) {
517*185d6cd7Sthorpej nflags |= TFD_TIMER_CANCEL_ON_SET;
518*185d6cd7Sthorpej }
519*185d6cd7Sthorpej
520*185d6cd7Sthorpej *nflagsp = nflags;
521*185d6cd7Sthorpej
522*185d6cd7Sthorpej return 0;
523*185d6cd7Sthorpej }
524*185d6cd7Sthorpej
525*185d6cd7Sthorpej int
linux_sys_timerfd_settime(struct lwp * l,const struct linux_sys_timerfd_settime_args * uap,register_t * retval)526*185d6cd7Sthorpej linux_sys_timerfd_settime(struct lwp *l,
527*185d6cd7Sthorpej const struct linux_sys_timerfd_settime_args *uap, register_t *retval)
528*185d6cd7Sthorpej {
529*185d6cd7Sthorpej /* {
530*185d6cd7Sthorpej syscallarg(int) fd;
531*185d6cd7Sthorpej syscallarg(int) flags;
532*185d6cd7Sthorpej syscallarg(const struct linux_itimerspec *) tim;
533*185d6cd7Sthorpej syscallarg(struct linux_itimerspec *) otim;
534*185d6cd7Sthorpej } */
535*185d6cd7Sthorpej struct itimerspec nits, oits, *oitsp = NULL;
536*185d6cd7Sthorpej struct linux_itimerspec lits;
537*185d6cd7Sthorpej int nflags;
538*185d6cd7Sthorpej int error;
539*185d6cd7Sthorpej
540*185d6cd7Sthorpej error = copyin(SCARG(uap, tim), &lits, sizeof(lits));
541*185d6cd7Sthorpej if (error) {
542*185d6cd7Sthorpej return error;
543*185d6cd7Sthorpej }
544*185d6cd7Sthorpej linux_to_native_itimerspec(&nits, &lits);
545*185d6cd7Sthorpej
546*185d6cd7Sthorpej error = linux_to_native_timerfd_settime_flags(&nflags,
547*185d6cd7Sthorpej SCARG(uap, flags));
548*185d6cd7Sthorpej if (error) {
549*185d6cd7Sthorpej return error;
550*185d6cd7Sthorpej }
551*185d6cd7Sthorpej
552*185d6cd7Sthorpej if (SCARG(uap, otim)) {
553*185d6cd7Sthorpej oitsp = &oits;
554*185d6cd7Sthorpej }
555*185d6cd7Sthorpej
556*185d6cd7Sthorpej error = do_timerfd_settime(l, SCARG(uap, fd), nflags,
557*185d6cd7Sthorpej &nits, oitsp, retval);
558*185d6cd7Sthorpej if (error == 0 && oitsp != NULL) {
559*185d6cd7Sthorpej native_to_linux_itimerspec(&lits, oitsp);
560*185d6cd7Sthorpej error = copyout(&lits, SCARG(uap, otim), sizeof(lits));
561*185d6cd7Sthorpej }
562*185d6cd7Sthorpej
563*185d6cd7Sthorpej return error;
564*185d6cd7Sthorpej }
565*185d6cd7Sthorpej
566*185d6cd7Sthorpej #define LINUX_TFD_IOC_SET_TICKS _LINUX_IOW('T', 0, uint64_t)
567*185d6cd7Sthorpej
568*185d6cd7Sthorpej int
linux_ioctl_timerfd(struct lwp * l,const struct linux_sys_ioctl_args * uap,register_t * retval)569*185d6cd7Sthorpej linux_ioctl_timerfd(struct lwp *l, const struct linux_sys_ioctl_args *uap,
570*185d6cd7Sthorpej register_t *retval)
571*185d6cd7Sthorpej {
572*185d6cd7Sthorpej /* {
573*185d6cd7Sthorpej syscallarg(int) fd;
574*185d6cd7Sthorpej syscallarg(u_long) com;
575*185d6cd7Sthorpej syscallarg(void *) data;
576*185d6cd7Sthorpej } */
577*185d6cd7Sthorpej struct sys_ioctl_args ua;
578*185d6cd7Sthorpej
579*185d6cd7Sthorpej SCARG(&ua, fd) = SCARG(uap, fd);
580*185d6cd7Sthorpej SCARG(&ua, data) = SCARG(uap, data);
581*185d6cd7Sthorpej
582*185d6cd7Sthorpej switch (SCARG(uap, com)) {
583*185d6cd7Sthorpej case LINUX_TFD_IOC_SET_TICKS:
584*185d6cd7Sthorpej SCARG(&ua, com) = TFD_IOC_SET_TICKS;
585*185d6cd7Sthorpej break;
586*185d6cd7Sthorpej
587*185d6cd7Sthorpej default:
588*185d6cd7Sthorpej return EINVAL;
589*185d6cd7Sthorpej }
590*185d6cd7Sthorpej
591*185d6cd7Sthorpej return sys_ioctl(l, (const void *)&ua, retval);
592*185d6cd7Sthorpej }
593