1 /* $NetBSD: linux_time.c,v 1.37 2014/01/13 10:33:03 njoly 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 __KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.37 2014/01/13 10:33:03 njoly Exp $");
34
35 #include <sys/param.h>
36 #include <sys/ucred.h>
37 #include <sys/kauth.h>
38 #include <sys/mount.h>
39 #include <sys/signal.h>
40 #include <sys/stdint.h>
41 #include <sys/time.h>
42 #include <sys/systm.h>
43 #include <sys/sched.h>
44 #include <sys/syscallargs.h>
45 #include <sys/lwp.h>
46 #include <sys/proc.h>
47
48 #include <compat/linux/common/linux_types.h>
49 #include <compat/linux/common/linux_signal.h>
50 #include <compat/linux/common/linux_machdep.h>
51 #include <compat/linux/common/linux_sched.h>
52 #include <compat/linux/common/linux_ipc.h>
53 #include <compat/linux/common/linux_sem.h>
54
55 #include <compat/linux/linux_syscallargs.h>
56
57 #include <compat/common/compat_util.h>
58
59 /*
60 * Linux keeps track of a system timezone in the kernel. It is readen
61 * by gettimeofday and set by settimeofday. This emulates this behavior
62 * See linux/kernel/time.c
63 */
64 struct timezone linux_sys_tz;
65
66 int
linux_sys_gettimeofday(struct lwp * l,const struct linux_sys_gettimeofday_args * uap,register_t * retval)67 linux_sys_gettimeofday(struct lwp *l, const struct linux_sys_gettimeofday_args *uap, register_t *retval)
68 {
69 /* {
70 syscallarg(struct timeval50 *) tz;
71 syscallarg(struct timezone *) tzp;
72 } */
73 int error = 0;
74
75 if (SCARG(uap, tp)) {
76 error = compat_50_sys_gettimeofday(l, (const void *)uap, retval);
77 if (error)
78 return (error);
79 }
80
81 if (SCARG(uap, tzp)) {
82 error = copyout(&linux_sys_tz, SCARG(uap, tzp), sizeof(linux_sys_tz));
83 if (error)
84 return (error);
85 }
86
87 return (0);
88 }
89
90 int
linux_sys_settimeofday(struct lwp * l,const struct linux_sys_settimeofday_args * uap,register_t * retval)91 linux_sys_settimeofday(struct lwp *l, const struct linux_sys_settimeofday_args *uap, register_t *retval)
92 {
93 /* {
94 syscallarg(struct timeval50 *) tp;
95 syscallarg(struct timezone *) tzp;
96 } */
97 int error = 0;
98
99 if (SCARG(uap, tp)) {
100 error = compat_50_sys_settimeofday(l, (const void *)uap, retval);
101 if (error)
102 return (error);
103 }
104
105 /*
106 * If user is not the superuser, we returned
107 * after the sys_settimeofday() call.
108 */
109 if (SCARG(uap, tzp)) {
110 error = copyin(SCARG(uap, tzp), &linux_sys_tz, sizeof(linux_sys_tz));
111 if (error)
112 return (error);
113 }
114
115 return (0);
116 }
117
118 void
native_to_linux_timespec(struct linux_timespec * ltp,struct timespec * ntp)119 native_to_linux_timespec(struct linux_timespec *ltp, struct timespec *ntp)
120 {
121 ltp->tv_sec = ntp->tv_sec;
122 ltp->tv_nsec = ntp->tv_nsec;
123 }
124
125 void
linux_to_native_timespec(struct timespec * ntp,struct linux_timespec * ltp)126 linux_to_native_timespec(struct timespec *ntp, struct linux_timespec *ltp)
127 {
128 ntp->tv_sec = ltp->tv_sec;
129 ntp->tv_nsec = ltp->tv_nsec;
130 }
131
132 int
linux_sys_nanosleep(struct lwp * l,const struct linux_sys_nanosleep_args * uap,register_t * retval)133 linux_sys_nanosleep(struct lwp *l, const struct linux_sys_nanosleep_args *uap,
134 register_t *retval)
135 {
136 /* {
137 syscallarg(struct linux_timespec *) rqtp;
138 syscallarg(struct linux_timespec *) rmtp;
139 } */
140 struct timespec rqts, rmts;
141 struct linux_timespec lrqts, lrmts;
142 int error, error1;
143
144 error = copyin(SCARG(uap, rqtp), &lrqts, sizeof(lrqts));
145 if (error != 0)
146 return error;
147 linux_to_native_timespec(&rqts, &lrqts);
148
149 error = nanosleep1(l, CLOCK_MONOTONIC, 0, &rqts,
150 SCARG(uap, rmtp) ? &rmts : NULL);
151 if (SCARG(uap, rmtp) == NULL || (error != 0 && error != EINTR))
152 return error;
153
154 native_to_linux_timespec(&lrmts, &rmts);
155 error1 = copyout(&lrmts, SCARG(uap, rmtp), sizeof(lrmts));
156 return error1 ? error1 : error;
157 }
158
159 int
linux_to_native_clockid(clockid_t * n,clockid_t l)160 linux_to_native_clockid(clockid_t *n, clockid_t l)
161 {
162 switch (l) {
163 case LINUX_CLOCK_REALTIME:
164 *n = CLOCK_REALTIME;
165 break;
166 case LINUX_CLOCK_MONOTONIC:
167 *n = CLOCK_MONOTONIC;
168 break;
169 case LINUX_CLOCK_PROCESS_CPUTIME_ID:
170 case LINUX_CLOCK_THREAD_CPUTIME_ID:
171 case LINUX_CLOCK_REALTIME_HR:
172 case LINUX_CLOCK_MONOTONIC_HR:
173 default:
174 return EINVAL;
175 }
176
177 return 0;
178 }
179
180 int
linux_sys_clock_gettime(struct lwp * l,const struct linux_sys_clock_gettime_args * uap,register_t * retval)181 linux_sys_clock_gettime(struct lwp *l, const struct linux_sys_clock_gettime_args *uap, register_t *retval)
182 {
183 /* {
184 syscallarg(clockid_t) which;
185 syscallarg(struct linux_timespec *)tp;
186 } */
187 int error;
188 clockid_t id;
189 struct timespec ts;
190 struct linux_timespec lts;
191
192 error = linux_to_native_clockid(&id, SCARG(uap, which));
193 if (error != 0)
194 return error;
195
196 error = clock_gettime1(id, &ts);
197 if (error != 0)
198 return error;
199
200 native_to_linux_timespec(<s, &ts);
201 return copyout(<s, SCARG(uap, tp), sizeof lts);
202 }
203
204 int
linux_sys_clock_settime(struct lwp * l,const struct linux_sys_clock_settime_args * uap,register_t * retval)205 linux_sys_clock_settime(struct lwp *l, const struct linux_sys_clock_settime_args *uap, register_t *retval)
206 {
207 /* {
208 syscallarg(clockid_t) which;
209 syscallarg(struct linux_timespec *)tp;
210 } */
211 struct timespec ts;
212 struct linux_timespec lts;
213 clockid_t id;
214 int error;
215
216 error = linux_to_native_clockid(&id, SCARG(uap, which));
217 if (error != 0)
218 return error;
219
220 error = copyin(SCARG(uap, tp), <s, sizeof lts);
221 if (error != 0)
222 return error;
223
224 linux_to_native_timespec(&ts, <s);
225
226 return clock_settime1(l->l_proc, id, &ts, true);
227 }
228
229 int
linux_sys_clock_getres(struct lwp * l,const struct linux_sys_clock_getres_args * uap,register_t * retval)230 linux_sys_clock_getres(struct lwp *l, const struct linux_sys_clock_getres_args *uap, register_t *retval)
231 {
232 /* {
233 syscallarg(clockid_t) which;
234 syscallarg(struct linux_timespec *)tp;
235 } */
236 struct timespec ts;
237 struct linux_timespec lts;
238 int error;
239 clockid_t nwhich = 0; /* XXX: GCC */
240
241 error = linux_to_native_clockid(&nwhich, SCARG(uap, which));
242 if (error != 0 || SCARG(uap, tp) == NULL)
243 return error;
244
245 error = clock_getres1(nwhich, &ts);
246 if (error != 0)
247 return error;
248
249 native_to_linux_timespec(<s, &ts);
250 return copyout(<s, SCARG(uap, tp), sizeof lts);
251 }
252
253 int
linux_sys_clock_nanosleep(struct lwp * l,const struct linux_sys_clock_nanosleep_args * uap,register_t * retval)254 linux_sys_clock_nanosleep(struct lwp *l, const struct linux_sys_clock_nanosleep_args *uap, register_t *retval)
255 {
256 /* {
257 syscallarg(clockid_t) which;
258 syscallarg(int) flags;
259 syscallarg(struct linux_timespec) *rqtp;
260 syscallarg(struct linux_timespec) *rmtp;
261 } */
262 struct linux_timespec lrqts, lrmts;
263 struct timespec rqts, rmts;
264 int error, error1, flags;
265 clockid_t nwhich;
266
267 flags = SCARG(uap, flags) != 0 ? TIMER_ABSTIME : 0;
268
269 error = linux_to_native_clockid(&nwhich, SCARG(uap, which));
270 if (error != 0)
271 return error;
272
273 error = copyin(SCARG(uap, rqtp), &lrqts, sizeof lrqts);
274 if (error != 0)
275 return error;
276
277 linux_to_native_timespec(&rqts, &lrqts);
278
279 error = nanosleep1(l, nwhich, flags, &rqts,
280 SCARG(uap, rmtp) ? &rmts : NULL);
281 if (SCARG(uap, rmtp) == NULL || (error != 0 && error != EINTR))
282 return error;
283
284 native_to_linux_timespec(&lrmts, &rmts);
285 error1 = copyout(&lrmts, SCARG(uap, rmtp), sizeof lrmts);
286 return error1 ? error1 : error;
287 }
288