1 /* $NetBSD: linux32_time.c,v 1.28 2009/01/16 13:10:47 njoly Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Emmanuel Dreyfus, all rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Emmanuel Dreyfus 17 * 4. The name of the author may not be used to endorse or promote 18 * products derived from this software without specific prior written 19 * permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS'' 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 36 __KERNEL_RCSID(0, "$NetBSD: linux32_time.c,v 1.28 2009/01/16 13:10:47 njoly Exp $"); 37 38 #include <sys/types.h> 39 #include <sys/param.h> 40 #include <sys/fstypes.h> 41 #include <sys/signal.h> 42 #include <sys/dirent.h> 43 #include <sys/kauth.h> 44 #include <sys/kernel.h> 45 #include <sys/fcntl.h> 46 #include <sys/namei.h> 47 #include <sys/select.h> 48 #include <sys/proc.h> 49 #include <sys/resourcevar.h> 50 #include <sys/ucred.h> 51 #include <sys/swap.h> 52 #include <sys/vfs_syscalls.h> 53 #include <sys/timetc.h> 54 55 #include <machine/types.h> 56 57 #include <sys/syscallargs.h> 58 59 #include <compat/netbsd32/netbsd32.h> 60 #include <compat/netbsd32/netbsd32_conv.h> 61 #include <compat/netbsd32/netbsd32_syscallargs.h> 62 63 #include <compat/linux/common/linux_types.h> 64 #include <compat/linux/common/linux_signal.h> 65 #include <compat/linux/common/linux_machdep.h> 66 #include <compat/linux/common/linux_misc.h> 67 #include <compat/linux/common/linux_oldolduname.h> 68 #include <compat/linux/common/linux_sched.h> 69 #include <compat/linux/common/linux_ipc.h> 70 #include <compat/linux/common/linux_sem.h> 71 #include <compat/linux/linux_syscallargs.h> 72 73 #include <compat/linux32/common/linux32_types.h> 74 #include <compat/linux32/common/linux32_signal.h> 75 #include <compat/linux32/common/linux32_machdep.h> 76 #include <compat/linux32/common/linux32_sysctl.h> 77 #include <compat/linux32/common/linux32_socketcall.h> 78 #include <compat/linux32/linux32_syscallargs.h> 79 80 extern struct timezone linux_sys_tz; 81 82 static __inline void 83 native_to_linux32_timespec(struct linux32_timespec *, struct timespec *); 84 static __inline void 85 linux32_to_native_timespec(struct timespec *, struct linux32_timespec *); 86 87 int 88 linux32_sys_gettimeofday(struct lwp *l, const struct linux32_sys_gettimeofday_args *uap, register_t *retval) 89 { 90 /* { 91 syscallarg(netbsd32_timeval50p_t) tp; 92 syscallarg(netbsd32_timezonep_t) tzp; 93 } */ 94 struct timeval tv; 95 struct netbsd32_timeval50 tv32; 96 int error; 97 98 if (SCARG_P32(uap, tp) != NULL) { 99 microtime(&tv); 100 netbsd32_from_timeval50(&tv, &tv32); 101 if ((error = copyout(&tv32, SCARG_P32(uap, tp), 102 sizeof(tv32))) != 0) 103 return error; 104 } 105 106 /* timezone size does not change */ 107 if (SCARG_P32(uap, tzp) != NULL) { 108 if ((error = copyout(&linux_sys_tz, SCARG_P32(uap, tzp), 109 sizeof(linux_sys_tz))) != 0) 110 return error; 111 } 112 113 return 0; 114 } 115 116 int 117 linux32_sys_settimeofday(struct lwp *l, const struct linux32_sys_settimeofday_args *uap, register_t *retval) 118 { 119 /* { 120 syscallarg(netbsd32_timeval50p_t) tp; 121 syscallarg(netbsd32_timezonep_t) tzp; 122 } */ 123 struct linux_sys_settimeofday_args ua; 124 125 NETBSD32TOP_UAP(tp, struct timeval50); 126 NETBSD32TOP_UAP(tzp, struct timezone); 127 128 return linux_sys_settimeofday(l, &ua, retval); 129 } 130 131 int 132 linux32_sys_time(struct lwp *l, const struct linux32_sys_time_args *uap, register_t *retval) 133 { 134 /* { 135 syscallarg(linux32_timep_t) t; 136 } */ 137 struct timeval atv; 138 linux32_time_t tt; 139 int error; 140 141 microtime(&atv); 142 143 tt = (linux32_time_t)atv.tv_sec; 144 145 if (SCARG_P32(uap, t) && (error = copyout(&tt, 146 SCARG_P32(uap, t), sizeof(tt)))) 147 return error; 148 149 retval[0] = tt; 150 151 return 0; 152 } 153 154 155 #define CONVTCK(r) (r.tv_sec * hz + r.tv_usec / (1000000 / hz)) 156 157 int 158 linux32_sys_times(struct lwp *l, const struct linux32_sys_times_args *uap, register_t *retval) 159 { 160 /* { 161 syscallarg(linux32_tmsp_t) tms; 162 } */ 163 struct proc *p = l->l_proc; 164 struct timeval t; 165 int error; 166 167 if (SCARG_P32(uap, tms)) { 168 struct linux32_tms ltms32; 169 struct rusage ru; 170 171 mutex_enter(p->p_lock); 172 calcru(p, &ru.ru_utime, &ru.ru_stime, NULL, NULL); 173 ltms32.ltms32_utime = CONVTCK(ru.ru_utime); 174 ltms32.ltms32_stime = CONVTCK(ru.ru_stime); 175 ltms32.ltms32_cutime = CONVTCK(p->p_stats->p_cru.ru_utime); 176 ltms32.ltms32_cstime = CONVTCK(p->p_stats->p_cru.ru_stime); 177 mutex_exit(p->p_lock); 178 179 error = copyout(<ms32, SCARG_P32(uap, tms), sizeof(ltms32)); 180 if (error) 181 return error; 182 } 183 184 getmicrouptime(&t); 185 186 retval[0] = ((linux32_clock_t)(CONVTCK(t))); 187 return 0; 188 } 189 190 #undef CONVTCK 191 192 int 193 linux32_sys_stime(struct lwp *l, const struct linux32_sys_stime_args *uap, register_t *retval) 194 { 195 /* { 196 syscallarg(linux32_timep_t) t; 197 } */ 198 struct timespec ts; 199 linux32_time_t tt32; 200 int error; 201 202 if ((error = copyin(SCARG_P32(uap, t), &tt32, sizeof tt32)) != 0) 203 return error; 204 205 ts.tv_sec = (long)tt32; 206 ts.tv_nsec = 0; 207 208 return settime(l->l_proc, &ts); 209 } 210 211 int 212 linux32_sys_utime(struct lwp *l, const struct linux32_sys_utime_args *uap, register_t *retval) 213 { 214 /* { 215 syscallarg(const netbsd32_charp) path; 216 syscallarg(linux32_utimbufp_t) times; 217 } */ 218 struct timeval tv[2], *tvp; 219 struct linux32_utimbuf lut; 220 int error; 221 222 if (SCARG_P32(uap, times) != NULL) { 223 if ((error = copyin(SCARG_P32(uap, times), &lut, sizeof lut))) 224 return error; 225 226 tv[0].tv_sec = (long)lut.l_actime; 227 tv[0].tv_usec = 0; 228 tv[1].tv_sec = (long)lut.l_modtime; 229 tv[1].tv_usec = 0; 230 tvp = tv; 231 } else { 232 tvp = NULL; 233 } 234 235 return do_sys_utimes(l, NULL, SCARG_P32(uap, path), FOLLOW, 236 tvp, UIO_SYSSPACE); 237 } 238 239 static __inline void 240 native_to_linux32_timespec(struct linux32_timespec *ltp, struct timespec *ntp) 241 { 242 ltp->tv_sec = ntp->tv_sec; 243 ltp->tv_nsec = ntp->tv_nsec; 244 } 245 246 static __inline void 247 linux32_to_native_timespec(struct timespec *ntp, struct linux32_timespec *ltp) 248 { 249 ntp->tv_sec = ltp->tv_sec; 250 ntp->tv_nsec = ltp->tv_nsec; 251 } 252 253 int 254 linux32_sys_nanosleep(struct lwp *l, 255 const struct linux32_sys_nanosleep_args *uap, register_t *retval) 256 { 257 /* { 258 syscallarg(linux32_timespecp_t) rqtp; 259 syscallarg(linux32_timespecp_t) rmtp; 260 } */ 261 struct timespec rqts, rmts; 262 struct linux32_timespec lrqts, lrmts; 263 int error, error1; 264 265 error = copyin(SCARG_P32(uap, rqtp), &lrqts, sizeof(lrqts)); 266 if (error != 0) 267 return error; 268 linux32_to_native_timespec(&rqts, &lrqts); 269 270 error = nanosleep1(l, &rqts, SCARG_P32(uap, rmtp) ? &rmts : NULL); 271 if (SCARG_P32(uap, rmtp) == NULL || (error != 0 && error != EINTR)) 272 return error; 273 274 native_to_linux32_timespec(&lrmts, &rmts); 275 error1 = copyout(&lrmts, SCARG_P32(uap, rmtp), sizeof(lrmts)); 276 return error1 ? error1 : error; 277 } 278 279 int 280 linux32_sys_clock_settime(struct lwp *l, 281 const struct linux32_sys_clock_settime_args *uap, register_t *retval) 282 { 283 /* { 284 syscallarg(clockid_t) which; 285 syscallarg(linux32_timespecp_t) tp; 286 } */ 287 int error; 288 struct timespec ts; 289 struct linux32_timespec lts; 290 291 switch (SCARG(uap, which)) { 292 case LINUX_CLOCK_REALTIME: 293 break; 294 default: 295 return EINVAL; 296 } 297 298 if ((error = copyin(SCARG_P32(uap, tp), <s, sizeof lts))) 299 return error; 300 301 linux32_to_native_timespec(&ts, <s); 302 return settime(l->l_proc, &ts); 303 } 304 305 int 306 linux32_sys_clock_gettime(struct lwp *l, 307 const struct linux32_sys_clock_gettime_args *uap, register_t *retval) 308 { 309 /* { 310 syscallarg(clockid_t) which; 311 syscallarg(linux32_timespecp_t) tp; 312 } */ 313 struct timespec ts; 314 struct linux32_timespec lts; 315 316 switch (SCARG(uap, which)) { 317 case LINUX_CLOCK_REALTIME: 318 nanotime(&ts); 319 break; 320 case LINUX_CLOCK_MONOTONIC: 321 nanouptime(&ts); 322 break; 323 default: 324 return EINVAL; 325 } 326 327 native_to_linux32_timespec(<s, &ts); 328 return copyout(<s, SCARG_P32(uap, tp), sizeof lts); 329 } 330 331 int 332 linux32_sys_clock_getres(struct lwp *l, 333 const struct linux32_sys_clock_getres_args *uap, register_t *retval) 334 { 335 /* { 336 syscallarg(clockid_t) which; 337 syscallarg(linux32_timespecp_t) tp; 338 } */ 339 int error; 340 clockid_t id; 341 struct timespec ts; 342 struct linux32_timespec lts; 343 344 error = linux_to_native_clockid(&id, SCARG(uap, which)); 345 if (error != 0 || SCARG_P32(uap, tp) == NULL) 346 return error; 347 348 ts.tv_sec = 0; 349 ts.tv_nsec = 1000000000 / tc_getfrequency(); 350 native_to_linux32_timespec(<s, &ts); 351 return copyout(<s, SCARG_P32(uap, tp), sizeof lts); 352 353 return 0; 354 } 355 356 int 357 linux32_sys_clock_nanosleep(struct lwp *l, 358 const struct linux32_sys_clock_nanosleep_args *uap, register_t *retval) 359 { 360 /* { 361 syscallarg(clockid_t) which; 362 syscallarg(int) flags; 363 syscallarg(linux32_timespecp_t) rqtp; 364 syscallarg(linux32_timespecp_t) rmtp; 365 } */ 366 struct linux32_timespec lrqts, lrmts; 367 struct timespec rqts, rmts; 368 int error, error1; 369 370 if (SCARG(uap, flags) != 0) 371 return EINVAL; /* XXX deal with TIMER_ABSTIME */ 372 if (SCARG(uap, which) != LINUX_CLOCK_REALTIME) 373 return EINVAL; 374 375 error = copyin(SCARG_P32(uap, rqtp), &lrqts, sizeof lrqts); 376 if (error != 0) 377 return error; 378 linux32_to_native_timespec(&rqts, &lrqts); 379 380 error = nanosleep1(l, &rqts, SCARG_P32(uap, rmtp) ? &rmts : 0); 381 if (SCARG_P32(uap, rmtp) == NULL || (error != 0 && error != EINTR)) 382 return error; 383 384 native_to_linux32_timespec(&lrmts, &rmts); 385 error1 = copyout(&lrmts, SCARG_P32(uap, rmtp), sizeof lrmts); 386 return error1 ? error1 : error; 387 } 388