1 /* $NetBSD: linux_time.c,v 1.11 2005/05/16 21:18:34 fvdl 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.11 2005/05/16 21:18:34 fvdl 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_sched.h> 57 58 #include <compat/linux/linux_syscallargs.h> 59 60 #include <compat/common/compat_util.h> 61 62 static void native_to_linux_timespec(struct linux_timespec *, 63 struct timespec *); 64 static void linux_to_native_timespec(struct timespec *, 65 struct linux_timespec *); 66 static int linux_to_native_clockid(clockid_t *, clockid_t); 67 68 /* 69 * This is not implemented for alpha yet 70 */ 71 #if defined (__i386__) || defined (__m68k__) || \ 72 defined (__powerpc__) || defined (__mips__) || \ 73 defined(__arm__) || defined(__amd64__) 74 75 /* 76 * Linux keeps track of a system timezone in the kernel. It is readen 77 * by gettimeofday and set by settimeofday. This emulates this behavior 78 * See linux/kernel/time.c 79 */ 80 struct timezone linux_sys_tz; 81 82 int 83 linux_sys_gettimeofday(l, v, retval) 84 struct lwp *l; 85 void *v; 86 register_t *retval; 87 { 88 struct linux_sys_gettimeofday_args /* { 89 syscallarg(struct timeval *) tz; 90 syscallarg(struct timezone *) tzp; 91 } */ *uap = v; 92 int error = 0; 93 94 if (SCARG(uap, tp)) { 95 error = sys_gettimeofday (l, v, retval); 96 if (error) 97 return (error); 98 } 99 100 if (SCARG(uap, tzp)) { 101 error = copyout(&linux_sys_tz, SCARG(uap, tzp), sizeof(linux_sys_tz)); 102 if (error) 103 return (error); 104 } 105 106 return (0); 107 } 108 109 int 110 linux_sys_settimeofday(l, v, retval) 111 struct lwp *l; 112 void *v; 113 register_t *retval; 114 { 115 struct linux_sys_settimeofday_args /* { 116 syscallarg(struct timeval *) tz; 117 syscallarg(struct timezone *) tzp; 118 } */ *uap = v; 119 int error = 0; 120 121 if (SCARG(uap, tp)) { 122 error = sys_settimeofday(l, v, retval); 123 if (error) 124 return (error); 125 } 126 127 /* 128 * If user is not the superuser, we returned 129 * after the sys_settimeofday() call. 130 */ 131 if (SCARG(uap, tzp)) { 132 error = copyin(SCARG(uap, tzp), &linux_sys_tz, sizeof(linux_sys_tz)); 133 if (error) 134 return (error); 135 } 136 137 return (0); 138 } 139 140 #endif /* __i386__ || __m68k__ || __powerpc__ || __mips__ || __arm__ */ 141 142 static void 143 native_to_linux_timespec(struct linux_timespec *ltp, struct timespec *ntp) 144 { 145 ltp->tv_sec = ntp->tv_sec; 146 ltp->tv_nsec = ntp->tv_nsec; 147 } 148 149 static void 150 linux_to_native_timespec(struct timespec *ntp, struct linux_timespec *ltp) 151 { 152 ntp->tv_sec = ltp->tv_sec; 153 ntp->tv_nsec = ltp->tv_nsec; 154 } 155 156 static int 157 linux_to_native_clockid(clockid_t *n, clockid_t l) 158 { 159 switch (l) { 160 case LINUX_CLOCK_REALTIME: 161 *n = CLOCK_REALTIME; 162 break; 163 case LINUX_CLOCK_MONOTONIC: 164 *n = CLOCK_MONOTONIC; 165 break; 166 case LINUX_CLOCK_PROCESS_CPUTIME_ID: 167 case LINUX_CLOCK_THREAD_CPUTIME_ID: 168 case LINUX_CLOCK_REALTIME_HR: 169 case LINUX_CLOCK_MONOTONIC_HR: 170 return EINVAL; 171 } 172 173 return 0; 174 } 175 176 int 177 linux_sys_clock_gettime(l, v, retval) 178 struct lwp *l; 179 void *v; 180 register_t *retval; 181 { 182 struct linux_sys_clock_gettime_args /* { 183 syscallarg(clockid_t) which; 184 syscallarg(struct linux_timespec *)tp; 185 } */ *uap = v; 186 caddr_t sg; 187 struct proc *p = l->l_proc; 188 struct timespec *tp, ts; 189 struct linux_timespec lts; 190 int error; 191 clockid_t nwhich; 192 struct sys_clock_gettime_args sga; 193 194 error = linux_to_native_clockid(&nwhich, SCARG(uap, which)); 195 if (error != 0) 196 return error; 197 sg = stackgap_init(p, 0); 198 tp = stackgap_alloc(p, &sg, sizeof *tp); 199 200 SCARG(&sga, clock_id) = nwhich; 201 SCARG(&sga, tp) = tp; 202 203 error = sys_clock_gettime(l, &sga, retval); 204 if (error != 0) 205 return error; 206 207 error = copyin(tp, &ts, sizeof ts); 208 if (error != 0) 209 return error; 210 211 native_to_linux_timespec(<s, &ts); 212 213 return copyout(<s, SCARG(uap, tp), sizeof lts); 214 } 215 216 int 217 linux_sys_clock_settime(l, v, retval) 218 struct lwp *l; 219 void *v; 220 register_t *retval; 221 { 222 struct linux_sys_clock_settime_args /* { 223 syscallarg(clockid_t) which; 224 syscallarg(struct linux_timespec *)tp; 225 } */ *uap = v; 226 caddr_t sg; 227 struct proc *p = l->l_proc; 228 struct timespec *tp, ts; 229 struct linux_timespec lts; 230 int error; 231 clockid_t nwhich; 232 struct sys_clock_settime_args sta; 233 234 error = linux_to_native_clockid(&nwhich, SCARG(uap, which)); 235 if (error != 0) 236 return error; 237 238 error = copyin(SCARG(uap, tp), <s, sizeof lts); 239 if (error != 0) 240 return error; 241 242 linux_to_native_timespec(&ts, <s); 243 244 sg = stackgap_init(p, 0); 245 tp = stackgap_alloc(p, &sg, sizeof *tp); 246 error = copyout(&ts, tp, sizeof ts); 247 if (error != 0) 248 return error; 249 250 SCARG(&sta, clock_id) = nwhich; 251 SCARG(&sta, tp) = tp; 252 253 return sys_clock_settime(l, &sta, retval); 254 } 255 256 int 257 linux_sys_clock_getres(l, v, retval) 258 struct lwp *l; 259 void *v; 260 register_t *retval; 261 { 262 struct linux_sys_clock_gettime_args /* { 263 syscallarg(clockid_t) which; 264 syscallarg(struct linux_timespec *)tp; 265 } */ *uap = v; 266 caddr_t sg; 267 struct proc *p = l->l_proc; 268 struct timespec *tp, ts; 269 struct linux_timespec lts; 270 int error; 271 clockid_t nwhich; 272 struct sys_clock_gettime_args sga; 273 274 error = linux_to_native_clockid(&nwhich, SCARG(uap, which)); 275 if (error != 0) 276 return error; 277 278 if (SCARG(uap, tp) != NULL) { 279 sg = stackgap_init(p, 0); 280 tp = stackgap_alloc(p, &sg, sizeof *tp); 281 } else 282 tp = NULL; 283 284 SCARG(&sga, clock_id) = nwhich; 285 SCARG(&sga, tp) = tp; 286 287 error = sys_clock_getres(l, &sga, retval); 288 if (error != 0) 289 return error; 290 291 if (tp != NULL) { 292 error = copyin(tp, &ts, sizeof ts); 293 if (error != 0) 294 return error; 295 native_to_linux_timespec(<s, &ts); 296 297 return copyout(<s, SCARG(uap, tp), sizeof lts); 298 } 299 300 return 0; 301 } 302 303 int 304 linux_sys_clock_nanosleep(l, v, retval) 305 struct lwp *l; 306 void *v; 307 register_t *retval; 308 { 309 struct linux_sys_clock_nanosleep_args /* { 310 syscallarg(clockid_t) which; 311 syscallarg(int) flags; 312 syscallarg(struct linux_timespec) *rqtp; 313 syscallarg(struct linux_timespec) *rmtp; 314 } */ *uap = v; 315 caddr_t sg; 316 struct proc *p = l->l_proc; 317 struct timespec *rqtp, *rmtp; 318 struct linux_timespec lrqts, lrmts; 319 struct timespec rqts, rmts; 320 int error; 321 struct sys_nanosleep_args sna; 322 323 if (SCARG(uap, flags) != 0) 324 return EINVAL; /* XXX deal with TIMER_ABSTIME */ 325 326 if (SCARG(uap, which) != LINUX_CLOCK_REALTIME) 327 return EINVAL; 328 329 error = copyin(SCARG(uap, rqtp), &lrqts, sizeof lrqts); 330 if (error != 0) 331 return error; 332 333 linux_to_native_timespec(&rqts, &lrqts); 334 335 sg = stackgap_init(p, 0); 336 rqtp = stackgap_alloc(p, &sg, sizeof *rqtp); 337 error = copyout(&rqts, rqtp, sizeof rqts); 338 if (error != 0) 339 return error; 340 341 if (SCARG(uap, rmtp) != NULL) 342 rmtp = stackgap_alloc(p, &sg, sizeof *rmtp); 343 else 344 rmtp = NULL; 345 346 SCARG(&sna, rqtp) = rqtp; 347 SCARG(&sna, rmtp) = rmtp; 348 349 error = sys_nanosleep(l, &sna, retval); 350 if (error != 0) 351 return error; 352 353 if (rmtp != NULL) { 354 error = copyin(rmtp, &rmts, sizeof rmts); 355 if (error != 0) 356 return error; 357 native_to_linux_timespec(&lrmts, &rmts); 358 error = copyout(&lrmts, SCARG(uap, rmtp), sizeof lrmts); 359 if (error != 0) 360 return error; 361 } 362 363 return 0; 364 } 365