]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/compat/linux/linux_time.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / compat / linux / linux_time.c
1 /*      $NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $ */
2
3 /*-
4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Emmanuel Dreyfus.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 #if 0
35 __KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $");
36 #endif
37
38 #include "opt_compat.h"
39 #include "opt_kdtrace.h"
40
41 #include <sys/param.h>
42 #include <sys/kernel.h>
43 #include <sys/ucred.h>
44 #include <sys/mount.h>
45 #include <sys/sdt.h>
46 #include <sys/signal.h>
47 #include <sys/stdint.h>
48 #include <sys/syscallsubr.h>
49 #include <sys/sysproto.h>
50 #include <sys/time.h>
51 #include <sys/systm.h>
52 #include <sys/proc.h>
53
54 #ifdef COMPAT_LINUX32
55 #include <machine/../linux32/linux.h>
56 #include <machine/../linux32/linux32_proto.h>
57 #else
58 #include <machine/../linux/linux.h>
59 #include <machine/../linux/linux_proto.h>
60 #endif
61
62 #include <compat/linux/linux_dtrace.h>
63 #include <compat/linux/linux_misc.h>
64
65 /* DTrace init */
66 LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE);
67
68 /**
69  * DTrace probes in this module.
70  */
71 LIN_SDT_PROBE_DEFINE2(time, native_to_linux_timespec, entry,
72     "struct l_timespec *", "struct timespec *");
73 LIN_SDT_PROBE_DEFINE0(time, native_to_linux_timespec, return);
74 LIN_SDT_PROBE_DEFINE2(time, linux_to_native_timespec, entry,
75     "struct timespec *", "struct l_timespec *");
76 LIN_SDT_PROBE_DEFINE1(time, linux_to_native_timespec, return, "int");
77 LIN_SDT_PROBE_DEFINE2(time, linux_to_native_clockid, entry, "clockid_t *",
78     "clockid_t");
79 LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unsupported_clockid,
80     "clockid_t");
81 LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unknown_clockid,
82     "clockid_t");
83 LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, return, "int");
84 LIN_SDT_PROBE_DEFINE2(time, linux_clock_gettime, entry, "clockid_t",
85     "struct l_timespec *");
86 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, conversion_error, "int");
87 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, gettime_error, "int");
88 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, copyout_error, "int");
89 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, return, "int");
90 LIN_SDT_PROBE_DEFINE2(time, linux_clock_settime, entry, "clockid_t",
91     "struct l_timespec *");
92 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, conversion_error, "int");
93 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, settime_error, "int");
94 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, copyin_error, "int");
95 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, return, "int");
96 LIN_SDT_PROBE_DEFINE2(time, linux_clock_getres, entry, "clockid_t",
97     "struct l_timespec *");
98 LIN_SDT_PROBE_DEFINE0(time, linux_clock_getres, nullcall);
99 LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, conversion_error, "int");
100 LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, getres_error, "int");
101 LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, copyout_error, "int");
102 LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, return, "int");
103 LIN_SDT_PROBE_DEFINE2(time, linux_nanosleep, entry, "const struct l_timespec *",
104     "struct l_timespec *");
105 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, conversion_error, "int");
106 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, nanosleep_error, "int");
107 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyout_error, "int");
108 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyin_error, "int");
109 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, return, "int");
110 LIN_SDT_PROBE_DEFINE4(time, linux_clock_nanosleep, entry, "clockid_t", "int",
111     "struct l_timespec *", "struct l_timespec *");
112 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, conversion_error, "int");
113 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, nanosleep_error, "int");
114 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyout_error, "int");
115 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyin_error, "int");
116 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, unsupported_flags, "int");
117 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, unsupported_clockid, "int");
118 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, return, "int");
119
120 static void native_to_linux_timespec(struct l_timespec *,
121                                      struct timespec *);
122 static int linux_to_native_timespec(struct timespec *,
123                                      struct l_timespec *);
124 static int linux_to_native_clockid(clockid_t *, clockid_t);
125
126 static void
127 native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp)
128 {
129
130         LIN_SDT_PROBE2(time, native_to_linux_timespec, entry, ltp, ntp);
131
132         ltp->tv_sec = ntp->tv_sec;
133         ltp->tv_nsec = ntp->tv_nsec;
134
135         LIN_SDT_PROBE0(time, native_to_linux_timespec, return);
136 }
137
138 static int
139 linux_to_native_timespec(struct timespec *ntp, struct l_timespec *ltp)
140 {
141
142         LIN_SDT_PROBE2(time, linux_to_native_timespec, entry, ntp, ltp);
143
144         if (ltp->tv_sec < 0 || ltp->tv_nsec > (l_long)999999999L) {
145                 LIN_SDT_PROBE1(time, linux_to_native_timespec, return, EINVAL);
146                 return (EINVAL);
147         }
148         ntp->tv_sec = ltp->tv_sec;
149         ntp->tv_nsec = ltp->tv_nsec;
150
151         LIN_SDT_PROBE1(time, linux_to_native_timespec, return, 0);
152         return (0);
153 }
154
155 static int
156 linux_to_native_clockid(clockid_t *n, clockid_t l)
157 {
158
159         LIN_SDT_PROBE2(time, linux_to_native_clockid, entry, n, l);
160
161         switch (l) {
162         case LINUX_CLOCK_REALTIME:
163                 *n = CLOCK_REALTIME;
164                 break;
165         case LINUX_CLOCK_MONOTONIC:
166                 *n = CLOCK_MONOTONIC;
167                 break;
168         case LINUX_CLOCK_PROCESS_CPUTIME_ID:
169         case LINUX_CLOCK_THREAD_CPUTIME_ID:
170         case LINUX_CLOCK_REALTIME_HR:
171         case LINUX_CLOCK_MONOTONIC_HR:
172                 LIN_SDT_PROBE1(time, linux_to_native_clockid,
173                     unsupported_clockid, l);
174                 LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL);
175                 return (EINVAL);
176                 break;
177         default:
178                 LIN_SDT_PROBE1(time, linux_to_native_clockid,
179                     unknown_clockid, l);
180                 LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL);
181                 return (EINVAL);
182                 break;
183         }
184
185         LIN_SDT_PROBE1(time, linux_to_native_clockid, return, 0);
186         return (0);
187 }
188
189 int
190 linux_clock_gettime(struct thread *td, struct linux_clock_gettime_args *args)
191 {
192         struct l_timespec lts;
193         int error;
194         clockid_t nwhich = 0;   /* XXX: GCC */
195         struct timespec tp;
196
197         LIN_SDT_PROBE2(time, linux_clock_gettime, entry, args->which, args->tp);
198
199         error = linux_to_native_clockid(&nwhich, args->which);
200         if (error != 0) {
201                 LIN_SDT_PROBE1(time, linux_clock_gettime, conversion_error,
202                     error);
203                 LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
204                 return (error);
205         }
206         error = kern_clock_gettime(td, nwhich, &tp);
207         if (error != 0) {
208                 LIN_SDT_PROBE1(time, linux_clock_gettime, gettime_error, error);
209                 LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
210                 return (error);
211         }
212         native_to_linux_timespec(&lts, &tp);
213
214         error = copyout(&lts, args->tp, sizeof lts);
215         if (error != 0)
216                 LIN_SDT_PROBE1(time, linux_clock_gettime, copyout_error, error);
217
218         LIN_SDT_PROBE1(time, linux_clock_gettime, return, error);
219         return (error);
220 }
221
222 int
223 linux_clock_settime(struct thread *td, struct linux_clock_settime_args *args)
224 {
225         struct timespec ts;
226         struct l_timespec lts;
227         int error;
228         clockid_t nwhich = 0;   /* XXX: GCC */
229
230         LIN_SDT_PROBE2(time, linux_clock_settime, entry, args->which, args->tp);
231
232         error = linux_to_native_clockid(&nwhich, args->which);
233         if (error != 0) {
234                 LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error,
235                     error);
236                 LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
237                 return (error);
238         }
239         error = copyin(args->tp, &lts, sizeof lts);
240         if (error != 0) {
241                 LIN_SDT_PROBE1(time, linux_clock_settime, copyin_error, error);
242                 LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
243                 return (error);
244         }
245         error = linux_to_native_timespec(&ts, &lts);
246         if (error != 0) {
247                 LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error,
248                     error);
249                 LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
250                 return (error);
251         }
252
253         error = kern_clock_settime(td, nwhich, &ts);
254         if (error != 0)
255                 LIN_SDT_PROBE1(time, linux_clock_settime, settime_error, error);
256
257         LIN_SDT_PROBE1(time, linux_clock_settime, return, error);
258         return (error);
259 }
260
261 int
262 linux_clock_getres(struct thread *td, struct linux_clock_getres_args *args)
263 {
264         struct timespec ts;
265         struct l_timespec lts;
266         int error;
267         clockid_t nwhich = 0;   /* XXX: GCC */
268
269         LIN_SDT_PROBE2(time, linux_clock_getres, entry, args->which, args->tp);
270
271         if (args->tp == NULL) {
272                 LIN_SDT_PROBE0(time, linux_clock_getres, nullcall);
273                 LIN_SDT_PROBE1(time, linux_clock_getres, return, 0);
274                 return (0);
275         }
276
277         error = linux_to_native_clockid(&nwhich, args->which);
278         if (error != 0) {
279                 LIN_SDT_PROBE1(time, linux_clock_getres, conversion_error,
280                     error);
281                 LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
282                 return (error);
283         }
284         error = kern_clock_getres(td, nwhich, &ts);
285         if (error != 0) {
286                 LIN_SDT_PROBE1(time, linux_clock_getres, getres_error, error);
287                 LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
288                 return (error);
289         }
290         native_to_linux_timespec(&lts, &ts);
291
292         error = copyout(&lts, args->tp, sizeof lts);
293         if (error != 0)
294                 LIN_SDT_PROBE1(time, linux_clock_getres, copyout_error, error);
295
296         LIN_SDT_PROBE1(time, linux_clock_getres, return, error);
297         return (error);
298 }
299
300 int
301 linux_nanosleep(struct thread *td, struct linux_nanosleep_args *args)
302 {
303         struct timespec *rmtp;
304         struct l_timespec lrqts, lrmts;
305         struct timespec rqts, rmts;
306         int error;
307
308         LIN_SDT_PROBE2(time, linux_nanosleep, entry, args->rqtp, args->rmtp);
309
310         error = copyin(args->rqtp, &lrqts, sizeof lrqts);
311         if (error != 0) {
312                 LIN_SDT_PROBE1(time, linux_nanosleep, copyin_error, error);
313                 LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
314                 return (error);
315         }
316
317         if (args->rmtp != NULL)
318                 rmtp = &rmts;
319         else
320                 rmtp = NULL;
321
322         error = linux_to_native_timespec(&rqts, &lrqts);
323         if (error != 0) {
324                 LIN_SDT_PROBE1(time, linux_nanosleep, conversion_error, error);
325                 LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
326                 return (error);
327         }
328         error = kern_nanosleep(td, &rqts, rmtp);
329         if (error != 0) {
330                 LIN_SDT_PROBE1(time, linux_nanosleep, nanosleep_error, error);
331                 LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
332                 return (error);
333         }
334
335         if (args->rmtp != NULL) {
336                 native_to_linux_timespec(&lrmts, rmtp);
337                 error = copyout(&lrmts, args->rmtp, sizeof(lrmts));
338                 if (error != 0) {
339                         LIN_SDT_PROBE1(time, linux_nanosleep, copyout_error,
340                             error);
341                         LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
342                         return (error);
343                 }
344         }
345
346         LIN_SDT_PROBE1(time, linux_nanosleep, return, 0);
347         return (0);
348 }
349
350 int
351 linux_clock_nanosleep(struct thread *td, struct linux_clock_nanosleep_args *args)
352 {
353         struct timespec *rmtp;
354         struct l_timespec lrqts, lrmts;
355         struct timespec rqts, rmts;
356         int error;
357
358         LIN_SDT_PROBE4(time, linux_clock_nanosleep, entry, args->which,
359             args->flags, args->rqtp, args->rmtp);
360
361         if (args->flags != 0) {
362                 /* XXX deal with TIMER_ABSTIME */
363                 LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_flags,
364                     args->flags);
365                 LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, EINVAL);
366                 return (EINVAL);        /* XXX deal with TIMER_ABSTIME */
367         }
368
369         if (args->which != LINUX_CLOCK_REALTIME) {
370                 LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_clockid,
371                     args->which);
372                 LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, EINVAL);
373                 return (EINVAL);
374         }
375
376         error = copyin(args->rqtp, &lrqts, sizeof lrqts);
377         if (error != 0) {
378                 LIN_SDT_PROBE1(time, linux_clock_nanosleep, copyin_error,
379                     error);
380                 LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
381                 return (error);
382         }
383
384         if (args->rmtp != NULL)
385                 rmtp = &rmts;
386         else
387                 rmtp = NULL;
388
389         error = linux_to_native_timespec(&rqts, &lrqts);
390         if (error != 0) {
391                 LIN_SDT_PROBE1(time, linux_clock_nanosleep, conversion_error,
392                     error);
393                 LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
394                 return (error);
395         }
396         error = kern_nanosleep(td, &rqts, rmtp);
397         if (error != 0) {
398                 LIN_SDT_PROBE1(time, linux_clock_nanosleep, nanosleep_error,
399                     error);
400                 LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error);
401                 return (error);
402         }
403
404         if (args->rmtp != NULL) {
405                 native_to_linux_timespec(&lrmts, rmtp);
406                 error = copyout(&lrmts, args->rmtp, sizeof lrmts );
407                 if (error != 0) {
408                         LIN_SDT_PROBE1(time, linux_clock_nanosleep,
409                             copyout_error, error);
410                         LIN_SDT_PROBE1(time, linux_nanosleep, return, error);
411                         return (error);
412                 }
413         }
414
415         LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, 0);
416         return (0);
417 }