xref: /netbsd-src/sys/compat/linux/common/linux_time.c (revision d48f14661dda8638fee055ba15d35bdfb29b9fa8)
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  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the NetBSD
21  *      Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $");
41 
42 #include <sys/param.h>
43 #include <sys/ucred.h>
44 #include <sys/mount.h>
45 #include <sys/signal.h>
46 #include <sys/stdint.h>
47 #include <sys/time.h>
48 #include <sys/systm.h>
49 #include <sys/sa.h>
50 #include <sys/syscallargs.h>
51 #include <sys/lwp.h>
52 #include <sys/proc.h>
53 
54 #include <compat/linux/common/linux_types.h>
55 #include <compat/linux/common/linux_signal.h>
56 #include <compat/linux/common/linux_machdep.h>
57 #include <compat/linux/common/linux_sched.h>
58 
59 #include <compat/linux/linux_syscallargs.h>
60 
61 #include <compat/common/compat_util.h>
62 
63 static void native_to_linux_timespec(struct linux_timespec *,
64 				     struct timespec *);
65 static void linux_to_native_timespec(struct timespec *,
66 				     struct linux_timespec *);
67 static int linux_to_native_clockid(clockid_t *, clockid_t);
68 
69 /*
70  * This is not implemented for alpha yet
71  */
72 #if defined (__i386__) || defined (__m68k__) || \
73     defined (__powerpc__) || defined (__mips__) || \
74     defined(__arm__) || defined(__amd64__)
75 
76 /*
77  * Linux keeps track of a system timezone in the kernel. It is readen
78  * by gettimeofday and set by settimeofday. This emulates this behavior
79  * See linux/kernel/time.c
80  */
81 struct timezone linux_sys_tz;
82 
83 int
84 linux_sys_gettimeofday(l, v, retval)
85 	struct lwp *l;
86 	void *v;
87 	register_t *retval;
88 {
89 	struct linux_sys_gettimeofday_args /* {
90 		syscallarg(struct timeval *) tz;
91 		syscallarg(struct timezone *) tzp;
92 	} */ *uap = v;
93 	int error = 0;
94 
95 	if (SCARG(uap, tp)) {
96 		error = sys_gettimeofday (l, v, retval);
97 		if (error)
98 			return (error);
99 	}
100 
101 	if (SCARG(uap, tzp)) {
102 		error = copyout(&linux_sys_tz, SCARG(uap, tzp), sizeof(linux_sys_tz));
103 		if (error)
104 			return (error);
105    }
106 
107 	return (0);
108 }
109 
110 int
111 linux_sys_settimeofday(l, v, retval)
112 	struct lwp *l;
113 	void *v;
114 	register_t *retval;
115 {
116 	struct linux_sys_settimeofday_args /* {
117 		syscallarg(struct timeval *) tz;
118 		syscallarg(struct timezone *) tzp;
119 	} */ *uap = v;
120 	int error = 0;
121 
122 	if (SCARG(uap, tp)) {
123 		error = sys_settimeofday(l, v, retval);
124 		if (error)
125 			return (error);
126 	}
127 
128 	/*
129 	 * If user is not the superuser, we returned
130 	 * after the sys_settimeofday() call.
131 	 */
132 	if (SCARG(uap, tzp)) {
133 		error = copyin(SCARG(uap, tzp), &linux_sys_tz, sizeof(linux_sys_tz));
134 		if (error)
135 			return (error);
136    }
137 
138 	return (0);
139 }
140 
141 #endif /* __i386__ || __m68k__ || __powerpc__ || __mips__ || __arm__ */
142 
143 static void
144 native_to_linux_timespec(struct linux_timespec *ltp, struct timespec *ntp)
145 {
146 	ltp->tv_sec = ntp->tv_sec;
147 	ltp->tv_nsec = ntp->tv_nsec;
148 }
149 
150 static void
151 linux_to_native_timespec(struct timespec *ntp, struct linux_timespec *ltp)
152 {
153 	ntp->tv_sec = ltp->tv_sec;
154 	ntp->tv_nsec = ltp->tv_nsec;
155 }
156 
157 static int
158 linux_to_native_clockid(clockid_t *n, clockid_t l)
159 {
160 	switch (l) {
161 	case LINUX_CLOCK_REALTIME:
162 		*n = CLOCK_REALTIME;
163 		break;
164 	case LINUX_CLOCK_MONOTONIC:
165 		*n = CLOCK_MONOTONIC;
166 		break;
167 	case LINUX_CLOCK_PROCESS_CPUTIME_ID:
168 	case LINUX_CLOCK_THREAD_CPUTIME_ID:
169 	case LINUX_CLOCK_REALTIME_HR:
170 	case LINUX_CLOCK_MONOTONIC_HR:
171 		return EINVAL;
172 	}
173 
174 	return 0;
175 }
176 
177 int
178 linux_sys_clock_gettime(l, v, retval)
179 	struct lwp *l;
180 	void *v;
181 	register_t *retval;
182 {
183 	struct linux_sys_clock_gettime_args /* {
184 		syscallarg(clockid_t) which;
185 		syscallarg(struct linux_timespec *)tp;
186 	} */ *uap = v;
187 	caddr_t sg;
188 	struct proc *p = l->l_proc;
189 	struct timespec *tp, ts;
190 	struct linux_timespec lts;
191 	int error;
192 	clockid_t nwhich = 0;	/* XXX: GCC */
193 	struct sys_clock_gettime_args sga;
194 
195 	error = linux_to_native_clockid(&nwhich, SCARG(uap, which));
196 	if (error != 0)
197 		return error;
198 	sg = stackgap_init(p, 0);
199 	tp = stackgap_alloc(p, &sg, sizeof *tp);
200 
201 	SCARG(&sga, clock_id) = nwhich;
202 	SCARG(&sga, tp) = tp;
203 
204 	error = sys_clock_gettime(l, &sga, retval);
205 	if (error != 0)
206 		return error;
207 
208 	error = copyin(tp, &ts, sizeof ts);
209 	if (error != 0)
210 		return error;
211 
212 	native_to_linux_timespec(&lts, &ts);
213 
214 	return copyout(&lts, SCARG(uap, tp), sizeof lts);
215 }
216 
217 int
218 linux_sys_clock_settime(l, v, retval)
219 	struct lwp *l;
220 	void *v;
221 	register_t *retval;
222 {
223 	struct linux_sys_clock_settime_args /* {
224 		syscallarg(clockid_t) which;
225 		syscallarg(struct linux_timespec *)tp;
226 	} */ *uap = v;
227 	caddr_t sg;
228 	struct proc *p = l->l_proc;
229 	struct timespec *tp, ts;
230 	struct linux_timespec lts;
231 	int error;
232 	clockid_t nwhich = 0;	/* XXX: GCC */
233 	struct sys_clock_settime_args sta;
234 
235 	error = linux_to_native_clockid(&nwhich, SCARG(uap, which));
236 	if (error != 0)
237 		return error;
238 
239 	error = copyin(SCARG(uap, tp), &lts, sizeof lts);
240 	if (error != 0)
241 		return error;
242 
243 	linux_to_native_timespec(&ts, &lts);
244 
245 	sg = stackgap_init(p, 0);
246 	tp = stackgap_alloc(p, &sg, sizeof *tp);
247 	error = copyout(&ts, tp, sizeof ts);
248 	if (error != 0)
249 		return error;
250 
251 	SCARG(&sta, clock_id) = nwhich;
252 	SCARG(&sta, tp) = tp;
253 
254 	return sys_clock_settime(l, &sta, retval);
255 }
256 
257 int
258 linux_sys_clock_getres(l, v, retval)
259 	struct lwp *l;
260 	void *v;
261 	register_t *retval;
262 {
263 	struct linux_sys_clock_gettime_args /* {
264 		syscallarg(clockid_t) which;
265 		syscallarg(struct linux_timespec *)tp;
266 	} */ *uap = v;
267 	caddr_t sg;
268 	struct proc *p = l->l_proc;
269 	struct timespec *tp, ts;
270 	struct linux_timespec lts;
271 	int error;
272 	clockid_t nwhich = 0;	/* XXX: GCC */
273 	struct sys_clock_gettime_args sga;
274 
275 	error = linux_to_native_clockid(&nwhich, SCARG(uap, which));
276 	if (error != 0)
277 		return error;
278 
279 	if (SCARG(uap, tp) != NULL) {
280 		sg = stackgap_init(p, 0);
281 		tp = stackgap_alloc(p, &sg, sizeof *tp);
282 	} else
283 		tp = NULL;
284 
285 	SCARG(&sga, clock_id) = nwhich;
286 	SCARG(&sga, tp) = tp;
287 
288 	error = sys_clock_getres(l, &sga, retval);
289 	if (error != 0)
290 		return error;
291 
292 	if (tp != NULL) {
293 		error = copyin(tp, &ts, sizeof ts);
294 		if (error != 0)
295 			return error;
296 		native_to_linux_timespec(&lts, &ts);
297 
298 		return copyout(&lts, SCARG(uap, tp), sizeof lts);
299 	}
300 
301 	return 0;
302 }
303 
304 int
305 linux_sys_clock_nanosleep(l, v, retval)
306 	struct lwp *l;
307 	void *v;
308 	register_t *retval;
309 {
310 	struct linux_sys_clock_nanosleep_args /* {
311 		syscallarg(clockid_t) which;
312 		syscallarg(int) flags;
313 		syscallarg(struct linux_timespec) *rqtp;
314 		syscallarg(struct linux_timespec) *rmtp;
315 	} */ *uap = v;
316 	caddr_t sg;
317 	struct proc *p = l->l_proc;
318 	struct timespec *rqtp, *rmtp;
319 	struct linux_timespec lrqts, lrmts;
320 	struct timespec rqts, rmts;
321 	int error;
322 	struct sys_nanosleep_args sna;
323 
324 	if (SCARG(uap, flags) != 0)
325 		return EINVAL;		/* XXX deal with TIMER_ABSTIME */
326 
327 	if (SCARG(uap, which) != LINUX_CLOCK_REALTIME)
328 		return EINVAL;
329 
330 	error = copyin(SCARG(uap, rqtp), &lrqts, sizeof lrqts);
331 	if (error != 0)
332 		return error;
333 
334 	linux_to_native_timespec(&rqts, &lrqts);
335 
336 	sg = stackgap_init(p, 0);
337 	rqtp = stackgap_alloc(p, &sg, sizeof *rqtp);
338 	error = copyout(&rqts, rqtp, sizeof rqts);
339 	if (error != 0)
340 		return error;
341 
342 	if (SCARG(uap, rmtp) != NULL)
343 		rmtp = stackgap_alloc(p, &sg, sizeof *rmtp);
344 	else
345 		rmtp = NULL;
346 
347 	SCARG(&sna, rqtp) = rqtp;
348 	SCARG(&sna, rmtp) = rmtp;
349 
350 	error = sys_nanosleep(l, &sna, retval);
351 	if (error != 0)
352 		return error;
353 
354 	if (rmtp != NULL) {
355 		error = copyin(rmtp, &rmts, sizeof rmts);
356 		if (error != 0)
357 			return error;
358 		native_to_linux_timespec(&lrmts, &rmts);
359 		error = copyout(&lrmts, SCARG(uap, rmtp), sizeof lrmts);
360 		if (error != 0)
361 			return error;
362 	}
363 
364 	return 0;
365 }
366