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 * 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 __FBSDID("$FreeBSD$"); 34 #if 0 35 __KERNEL_RCSID(0, "$NetBSD: linux_time.c,v 1.14 2006/05/14 03:40:54 christos Exp $"); 36 #endif 37 38 #include "opt_compat.h" 39 #include "opt_kdtrace.h" 40 41 #include <sys/param.h> 42 #include <sys/kernel.h> 43 #include <sys/ucred.h> 44 #include <sys/mount.h> 45 #include <sys/sdt.h> 46 #include <sys/signal.h> 47 #include <sys/stdint.h> 48 #include <sys/syscallsubr.h> 49 #include <sys/sysproto.h> 50 #include <sys/time.h> 51 #include <sys/systm.h> 52 #include <sys/proc.h> 53 54 #ifdef COMPAT_LINUX32 55 #include <machine/../linux32/linux.h> 56 #include <machine/../linux32/linux32_proto.h> 57 #else 58 #include <machine/../linux/linux.h> 59 #include <machine/../linux/linux_proto.h> 60 #endif 61 62 #include <compat/linux/linux_dtrace.h> 63 #include <compat/linux/linux_misc.h> 64 65 /* DTrace init */ 66 LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); 67 68 /** 69 * DTrace probes in this module. 70 */ 71 LIN_SDT_PROBE_DEFINE2(time, native_to_linux_timespec, entry, 72 "struct l_timespec *", "struct timespec *"); 73 LIN_SDT_PROBE_DEFINE0(time, native_to_linux_timespec, return); 74 LIN_SDT_PROBE_DEFINE2(time, linux_to_native_timespec, entry, 75 "struct timespec *", "struct l_timespec *"); 76 LIN_SDT_PROBE_DEFINE1(time, linux_to_native_timespec, return, "int"); 77 LIN_SDT_PROBE_DEFINE2(time, linux_to_native_clockid, entry, "clockid_t *", 78 "clockid_t"); 79 LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unsupported_clockid, 80 "clockid_t"); 81 LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unknown_clockid, 82 "clockid_t"); 83 LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, return, "int"); 84 LIN_SDT_PROBE_DEFINE2(time, linux_clock_gettime, entry, "clockid_t", 85 "struct l_timespec *"); 86 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, conversion_error, "int"); 87 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, gettime_error, "int"); 88 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, copyout_error, "int"); 89 LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, return, "int"); 90 LIN_SDT_PROBE_DEFINE2(time, linux_clock_settime, entry, "clockid_t", 91 "struct l_timespec *"); 92 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, conversion_error, "int"); 93 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, settime_error, "int"); 94 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, copyin_error, "int"); 95 LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, return, "int"); 96 LIN_SDT_PROBE_DEFINE2(time, linux_clock_getres, entry, "clockid_t", 97 "struct l_timespec *"); 98 LIN_SDT_PROBE_DEFINE0(time, linux_clock_getres, nullcall); 99 LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, conversion_error, "int"); 100 LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, getres_error, "int"); 101 LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, copyout_error, "int"); 102 LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, return, "int"); 103 LIN_SDT_PROBE_DEFINE2(time, linux_nanosleep, entry, "const struct l_timespec *", 104 "struct l_timespec *"); 105 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, conversion_error, "int"); 106 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, nanosleep_error, "int"); 107 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyout_error, "int"); 108 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyin_error, "int"); 109 LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, return, "int"); 110 LIN_SDT_PROBE_DEFINE4(time, linux_clock_nanosleep, entry, "clockid_t", "int", 111 "struct l_timespec *", "struct l_timespec *"); 112 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, conversion_error, "int"); 113 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, nanosleep_error, "int"); 114 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyout_error, "int"); 115 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyin_error, "int"); 116 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, unsupported_flags, "int"); 117 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, unsupported_clockid, "int"); 118 LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, return, "int"); 119 120 static void native_to_linux_timespec(struct l_timespec *, 121 struct timespec *); 122 static int linux_to_native_timespec(struct timespec *, 123 struct l_timespec *); 124 static int linux_to_native_clockid(clockid_t *, clockid_t); 125 126 static void 127 native_to_linux_timespec(struct l_timespec *ltp, struct timespec *ntp) 128 { 129 130 LIN_SDT_PROBE2(time, native_to_linux_timespec, entry, ltp, ntp); 131 132 ltp->tv_sec = ntp->tv_sec; 133 ltp->tv_nsec = ntp->tv_nsec; 134 135 LIN_SDT_PROBE0(time, native_to_linux_timespec, return); 136 } 137 138 static int 139 linux_to_native_timespec(struct timespec *ntp, struct l_timespec *ltp) 140 { 141 142 LIN_SDT_PROBE2(time, linux_to_native_timespec, entry, ntp, ltp); 143 144 if (ltp->tv_sec < 0 || ltp->tv_nsec > (l_long)999999999L) { 145 LIN_SDT_PROBE1(time, linux_to_native_timespec, return, EINVAL); 146 return (EINVAL); 147 } 148 ntp->tv_sec = ltp->tv_sec; 149 ntp->tv_nsec = ltp->tv_nsec; 150 151 LIN_SDT_PROBE1(time, linux_to_native_timespec, return, 0); 152 return (0); 153 } 154 155 static int 156 linux_to_native_clockid(clockid_t *n, clockid_t l) 157 { 158 159 LIN_SDT_PROBE2(time, linux_to_native_clockid, entry, n, l); 160 161 switch (l) { 162 case LINUX_CLOCK_REALTIME: 163 *n = CLOCK_REALTIME; 164 break; 165 case LINUX_CLOCK_MONOTONIC: 166 *n = CLOCK_MONOTONIC; 167 break; 168 case LINUX_CLOCK_PROCESS_CPUTIME_ID: 169 case LINUX_CLOCK_THREAD_CPUTIME_ID: 170 case LINUX_CLOCK_REALTIME_HR: 171 case LINUX_CLOCK_MONOTONIC_HR: 172 LIN_SDT_PROBE1(time, linux_to_native_clockid, 173 unsupported_clockid, l); 174 LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL); 175 return (EINVAL); 176 break; 177 default: 178 LIN_SDT_PROBE1(time, linux_to_native_clockid, 179 unknown_clockid, l); 180 LIN_SDT_PROBE1(time, linux_to_native_clockid, return, EINVAL); 181 return (EINVAL); 182 break; 183 } 184 185 LIN_SDT_PROBE1(time, linux_to_native_clockid, return, 0); 186 return (0); 187 } 188 189 int 190 linux_clock_gettime(struct thread *td, struct linux_clock_gettime_args *args) 191 { 192 struct l_timespec lts; 193 int error; 194 clockid_t nwhich = 0; /* XXX: GCC */ 195 struct timespec tp; 196 197 LIN_SDT_PROBE2(time, linux_clock_gettime, entry, args->which, args->tp); 198 199 error = linux_to_native_clockid(&nwhich, args->which); 200 if (error != 0) { 201 LIN_SDT_PROBE1(time, linux_clock_gettime, conversion_error, 202 error); 203 LIN_SDT_PROBE1(time, linux_clock_gettime, return, error); 204 return (error); 205 } 206 error = kern_clock_gettime(td, nwhich, &tp); 207 if (error != 0) { 208 LIN_SDT_PROBE1(time, linux_clock_gettime, gettime_error, error); 209 LIN_SDT_PROBE1(time, linux_clock_gettime, return, error); 210 return (error); 211 } 212 native_to_linux_timespec(<s, &tp); 213 214 error = copyout(<s, args->tp, sizeof lts); 215 if (error != 0) 216 LIN_SDT_PROBE1(time, linux_clock_gettime, copyout_error, error); 217 218 LIN_SDT_PROBE1(time, linux_clock_gettime, return, error); 219 return (error); 220 } 221 222 int 223 linux_clock_settime(struct thread *td, struct linux_clock_settime_args *args) 224 { 225 struct timespec ts; 226 struct l_timespec lts; 227 int error; 228 clockid_t nwhich = 0; /* XXX: GCC */ 229 230 LIN_SDT_PROBE2(time, linux_clock_settime, entry, args->which, args->tp); 231 232 error = linux_to_native_clockid(&nwhich, args->which); 233 if (error != 0) { 234 LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error, 235 error); 236 LIN_SDT_PROBE1(time, linux_clock_settime, return, error); 237 return (error); 238 } 239 error = copyin(args->tp, <s, sizeof lts); 240 if (error != 0) { 241 LIN_SDT_PROBE1(time, linux_clock_settime, copyin_error, error); 242 LIN_SDT_PROBE1(time, linux_clock_settime, return, error); 243 return (error); 244 } 245 error = linux_to_native_timespec(&ts, <s); 246 if (error != 0) { 247 LIN_SDT_PROBE1(time, linux_clock_settime, conversion_error, 248 error); 249 LIN_SDT_PROBE1(time, linux_clock_settime, return, error); 250 return (error); 251 } 252 253 error = kern_clock_settime(td, nwhich, &ts); 254 if (error != 0) 255 LIN_SDT_PROBE1(time, linux_clock_settime, settime_error, error); 256 257 LIN_SDT_PROBE1(time, linux_clock_settime, return, error); 258 return (error); 259 } 260 261 int 262 linux_clock_getres(struct thread *td, struct linux_clock_getres_args *args) 263 { 264 struct timespec ts; 265 struct l_timespec lts; 266 int error; 267 clockid_t nwhich = 0; /* XXX: GCC */ 268 269 LIN_SDT_PROBE2(time, linux_clock_getres, entry, args->which, args->tp); 270 271 if (args->tp == NULL) { 272 LIN_SDT_PROBE0(time, linux_clock_getres, nullcall); 273 LIN_SDT_PROBE1(time, linux_clock_getres, return, 0); 274 return (0); 275 } 276 277 error = linux_to_native_clockid(&nwhich, args->which); 278 if (error != 0) { 279 LIN_SDT_PROBE1(time, linux_clock_getres, conversion_error, 280 error); 281 LIN_SDT_PROBE1(time, linux_clock_getres, return, error); 282 return (error); 283 } 284 error = kern_clock_getres(td, nwhich, &ts); 285 if (error != 0) { 286 LIN_SDT_PROBE1(time, linux_clock_getres, getres_error, error); 287 LIN_SDT_PROBE1(time, linux_clock_getres, return, error); 288 return (error); 289 } 290 native_to_linux_timespec(<s, &ts); 291 292 error = copyout(<s, args->tp, sizeof lts); 293 if (error != 0) 294 LIN_SDT_PROBE1(time, linux_clock_getres, copyout_error, error); 295 296 LIN_SDT_PROBE1(time, linux_clock_getres, return, error); 297 return (error); 298 } 299 300 int 301 linux_nanosleep(struct thread *td, struct linux_nanosleep_args *args) 302 { 303 struct timespec *rmtp; 304 struct l_timespec lrqts, lrmts; 305 struct timespec rqts, rmts; 306 int error; 307 308 LIN_SDT_PROBE2(time, linux_nanosleep, entry, args->rqtp, args->rmtp); 309 310 error = copyin(args->rqtp, &lrqts, sizeof lrqts); 311 if (error != 0) { 312 LIN_SDT_PROBE1(time, linux_nanosleep, copyin_error, error); 313 LIN_SDT_PROBE1(time, linux_nanosleep, return, error); 314 return (error); 315 } 316 317 if (args->rmtp != NULL) 318 rmtp = &rmts; 319 else 320 rmtp = NULL; 321 322 error = linux_to_native_timespec(&rqts, &lrqts); 323 if (error != 0) { 324 LIN_SDT_PROBE1(time, linux_nanosleep, conversion_error, error); 325 LIN_SDT_PROBE1(time, linux_nanosleep, return, error); 326 return (error); 327 } 328 error = kern_nanosleep(td, &rqts, rmtp); 329 if (error != 0) { 330 LIN_SDT_PROBE1(time, linux_nanosleep, nanosleep_error, error); 331 LIN_SDT_PROBE1(time, linux_nanosleep, return, error); 332 return (error); 333 } 334 335 if (args->rmtp != NULL) { 336 native_to_linux_timespec(&lrmts, rmtp); 337 error = copyout(&lrmts, args->rmtp, sizeof(lrmts)); 338 if (error != 0) { 339 LIN_SDT_PROBE1(time, linux_nanosleep, copyout_error, 340 error); 341 LIN_SDT_PROBE1(time, linux_nanosleep, return, error); 342 return (error); 343 } 344 } 345 346 LIN_SDT_PROBE1(time, linux_nanosleep, return, 0); 347 return (0); 348 } 349 350 int 351 linux_clock_nanosleep(struct thread *td, struct linux_clock_nanosleep_args *args) 352 { 353 struct timespec *rmtp; 354 struct l_timespec lrqts, lrmts; 355 struct timespec rqts, rmts; 356 int error; 357 358 LIN_SDT_PROBE4(time, linux_clock_nanosleep, entry, args->which, 359 args->flags, args->rqtp, args->rmtp); 360 361 if (args->flags != 0) { 362 /* XXX deal with TIMER_ABSTIME */ 363 LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_flags, 364 args->flags); 365 LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, EINVAL); 366 return (EINVAL); /* XXX deal with TIMER_ABSTIME */ 367 } 368 369 if (args->which != LINUX_CLOCK_REALTIME) { 370 LIN_SDT_PROBE1(time, linux_clock_nanosleep, unsupported_clockid, 371 args->which); 372 LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, EINVAL); 373 return (EINVAL); 374 } 375 376 error = copyin(args->rqtp, &lrqts, sizeof lrqts); 377 if (error != 0) { 378 LIN_SDT_PROBE1(time, linux_clock_nanosleep, copyin_error, 379 error); 380 LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error); 381 return (error); 382 } 383 384 if (args->rmtp != NULL) 385 rmtp = &rmts; 386 else 387 rmtp = NULL; 388 389 error = linux_to_native_timespec(&rqts, &lrqts); 390 if (error != 0) { 391 LIN_SDT_PROBE1(time, linux_clock_nanosleep, conversion_error, 392 error); 393 LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error); 394 return (error); 395 } 396 error = kern_nanosleep(td, &rqts, rmtp); 397 if (error != 0) { 398 LIN_SDT_PROBE1(time, linux_clock_nanosleep, nanosleep_error, 399 error); 400 LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, error); 401 return (error); 402 } 403 404 if (args->rmtp != NULL) { 405 native_to_linux_timespec(&lrmts, rmtp); 406 error = copyout(&lrmts, args->rmtp, sizeof lrmts ); 407 if (error != 0) { 408 LIN_SDT_PROBE1(time, linux_clock_nanosleep, 409 copyout_error, error); 410 LIN_SDT_PROBE1(time, linux_nanosleep, return, error); 411 return (error); 412 } 413 } 414 415 LIN_SDT_PROBE1(time, linux_clock_nanosleep, return, 0); 416 return (0); 417 } 418