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 */ 66LIN_SDT_PROVIDER_DECLARE(LINUX_DTRACE); 67 68/** 69 * DTrace probes in this module. 70 */ 71LIN_SDT_PROBE_DEFINE2(time, native_to_linux_timespec, entry, 72 "struct l_timespec *", "struct timespec *"); 73LIN_SDT_PROBE_DEFINE0(time, native_to_linux_timespec, return); 74LIN_SDT_PROBE_DEFINE2(time, linux_to_native_timespec, entry, 75 "struct timespec *", "struct l_timespec *"); 76LIN_SDT_PROBE_DEFINE1(time, linux_to_native_timespec, return, "int"); 77LIN_SDT_PROBE_DEFINE2(time, linux_to_native_clockid, entry, "clockid_t *", 78 "clockid_t"); 79LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unsupported_clockid, 80 "clockid_t"); 81LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, unknown_clockid, 82 "clockid_t"); 83LIN_SDT_PROBE_DEFINE1(time, linux_to_native_clockid, return, "int"); 84LIN_SDT_PROBE_DEFINE2(time, linux_clock_gettime, entry, "clockid_t", 85 "struct l_timespec *"); 86LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, conversion_error, "int"); 87LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, gettime_error, "int"); 88LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, copyout_error, "int"); 89LIN_SDT_PROBE_DEFINE1(time, linux_clock_gettime, return, "int"); 90LIN_SDT_PROBE_DEFINE2(time, linux_clock_settime, entry, "clockid_t", 91 "struct l_timespec *"); 92LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, conversion_error, "int"); 93LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, settime_error, "int"); 94LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, copyin_error, "int"); 95LIN_SDT_PROBE_DEFINE1(time, linux_clock_settime, return, "int"); 96LIN_SDT_PROBE_DEFINE2(time, linux_clock_getres, entry, "clockid_t", 97 "struct l_timespec *"); 98LIN_SDT_PROBE_DEFINE0(time, linux_clock_getres, nullcall); 99LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, conversion_error, "int"); 100LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, getres_error, "int"); 101LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, copyout_error, "int"); 102LIN_SDT_PROBE_DEFINE1(time, linux_clock_getres, return, "int"); 103LIN_SDT_PROBE_DEFINE2(time, linux_nanosleep, entry, "const struct l_timespec *", 104 "struct l_timespec *"); 105LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, conversion_error, "int"); 106LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, nanosleep_error, "int"); 107LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyout_error, "int"); 108LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, copyin_error, "int"); 109LIN_SDT_PROBE_DEFINE1(time, linux_nanosleep, return, "int"); 110LIN_SDT_PROBE_DEFINE4(time, linux_clock_nanosleep, entry, "clockid_t", "int", 111 "struct l_timespec *", "struct l_timespec *"); 112LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, conversion_error, "int"); 113LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, nanosleep_error, "int"); 114LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyout_error, "int"); 115LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, copyin_error, "int"); 116LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, unsupported_flags, "int"); 117LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, unsupported_clockid, "int"); 118LIN_SDT_PROBE_DEFINE1(time, linux_clock_nanosleep, return, "int"); 119 120static void native_to_linux_timespec(struct l_timespec *, 121 struct timespec *); 122static int linux_to_native_timespec(struct timespec *, 123 struct l_timespec *); 124static int linux_to_native_clockid(clockid_t *, clockid_t); 125 126static void 127native_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 138static int 139linux_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 155static int 156linux_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 189int 190linux_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 222int 223linux_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 261int 262linux_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 300int 301linux_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 350int 351linux_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