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(<s, &ts); 213 214 return copyout(<s, 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), <s, sizeof lts); 240 if (error != 0) 241 return error; 242 243 linux_to_native_timespec(&ts, <s); 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(<s, &ts); 297 298 return copyout(<s, 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