1 /* $NetBSD: linux_time.c,v 1.20 2007/11/25 00:35:27 elad 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.20 2007/11/25 00:35:27 elad Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/ucred.h> 44 #include <sys/kauth.h> 45 #include <sys/mount.h> 46 #include <sys/signal.h> 47 #include <sys/stdint.h> 48 #include <sys/time.h> 49 #include <sys/timetc.h> 50 #include <sys/systm.h> 51 #include <sys/syscallargs.h> 52 #include <sys/lwp.h> 53 #include <sys/proc.h> 54 55 #include <compat/linux/common/linux_types.h> 56 #include <compat/linux/common/linux_signal.h> 57 #include <compat/linux/common/linux_machdep.h> 58 #include <compat/linux/common/linux_sched.h> 59 #include <compat/linux/common/linux_ipc.h> 60 #include <compat/linux/common/linux_sem.h> 61 62 #include <compat/linux/linux_syscallargs.h> 63 64 #include <compat/common/compat_util.h> 65 66 static void native_to_linux_timespec(struct linux_timespec *, 67 struct timespec *); 68 static void linux_to_native_timespec(struct timespec *, 69 struct linux_timespec *); 70 static int linux_to_native_clockid(clockid_t *, clockid_t); 71 72 /* 73 * This is not implemented for alpha yet 74 */ 75 #if defined (__i386__) || defined (__m68k__) || \ 76 defined (__powerpc__) || defined (__mips__) || \ 77 defined(__arm__) || defined(__amd64__) 78 79 /* 80 * Linux keeps track of a system timezone in the kernel. It is readen 81 * by gettimeofday and set by settimeofday. This emulates this behavior 82 * See linux/kernel/time.c 83 */ 84 struct timezone linux_sys_tz; 85 86 int 87 linux_sys_gettimeofday(l, v, retval) 88 struct lwp *l; 89 void *v; 90 register_t *retval; 91 { 92 struct linux_sys_gettimeofday_args /* { 93 syscallarg(struct timeval *) tz; 94 syscallarg(struct timezone *) tzp; 95 } */ *uap = v; 96 int error = 0; 97 98 if (SCARG(uap, tp)) { 99 error = sys_gettimeofday (l, v, retval); 100 if (error) 101 return (error); 102 } 103 104 if (SCARG(uap, tzp)) { 105 error = copyout(&linux_sys_tz, SCARG(uap, tzp), sizeof(linux_sys_tz)); 106 if (error) 107 return (error); 108 } 109 110 return (0); 111 } 112 113 int 114 linux_sys_settimeofday(l, v, retval) 115 struct lwp *l; 116 void *v; 117 register_t *retval; 118 { 119 struct linux_sys_settimeofday_args /* { 120 syscallarg(struct timeval *) tp; 121 syscallarg(struct timezone *) tzp; 122 } */ *uap = v; 123 int error = 0; 124 125 if (SCARG(uap, tp)) { 126 error = sys_settimeofday(l, v, retval); 127 if (error) 128 return (error); 129 } 130 131 /* 132 * If user is not the superuser, we returned 133 * after the sys_settimeofday() call. 134 */ 135 if (SCARG(uap, tzp)) { 136 error = copyin(SCARG(uap, tzp), &linux_sys_tz, sizeof(linux_sys_tz)); 137 if (error) 138 return (error); 139 } 140 141 return (0); 142 } 143 144 #endif /* __i386__ || __m68k__ || __powerpc__ || __mips__ || __arm__ */ 145 146 static void 147 native_to_linux_timespec(struct linux_timespec *ltp, struct timespec *ntp) 148 { 149 ltp->tv_sec = ntp->tv_sec; 150 ltp->tv_nsec = ntp->tv_nsec; 151 } 152 153 static void 154 linux_to_native_timespec(struct timespec *ntp, struct linux_timespec *ltp) 155 { 156 ntp->tv_sec = ltp->tv_sec; 157 ntp->tv_nsec = ltp->tv_nsec; 158 } 159 160 static int 161 linux_to_native_clockid(clockid_t *n, clockid_t l) 162 { 163 switch (l) { 164 case LINUX_CLOCK_REALTIME: 165 *n = CLOCK_REALTIME; 166 break; 167 case LINUX_CLOCK_MONOTONIC: 168 *n = CLOCK_MONOTONIC; 169 break; 170 case LINUX_CLOCK_PROCESS_CPUTIME_ID: 171 case LINUX_CLOCK_THREAD_CPUTIME_ID: 172 case LINUX_CLOCK_REALTIME_HR: 173 case LINUX_CLOCK_MONOTONIC_HR: 174 return EINVAL; 175 } 176 177 return 0; 178 } 179 180 int 181 linux_sys_clock_gettime(l, v, retval) 182 struct lwp *l; 183 void *v; 184 register_t *retval; 185 { 186 struct linux_sys_clock_gettime_args /* { 187 syscallarg(clockid_t) which; 188 syscallarg(struct linux_timespec *)tp; 189 } */ *uap = v; 190 struct timespec ts; 191 struct linux_timespec lts; 192 193 switch (SCARG(uap, which)) { 194 case LINUX_CLOCK_REALTIME: 195 nanotime(&ts); 196 break; 197 case LINUX_CLOCK_MONOTONIC: 198 nanouptime(&ts); 199 break; 200 default: 201 return EINVAL; 202 } 203 204 native_to_linux_timespec(<s, &ts); 205 return copyout(<s, SCARG(uap, tp), sizeof lts); 206 } 207 208 int 209 linux_sys_clock_settime(l, v, retval) 210 struct lwp *l; 211 void *v; 212 register_t *retval; 213 { 214 struct linux_sys_clock_settime_args /* { 215 syscallarg(clockid_t) which; 216 syscallarg(struct linux_timespec *)tp; 217 } */ *uap = v; 218 struct timespec ts; 219 struct linux_timespec lts; 220 int error; 221 222 switch (SCARG(uap, which)) { 223 case LINUX_CLOCK_REALTIME: 224 break; 225 default: 226 return EINVAL; 227 } 228 229 error = copyin(SCARG(uap, tp), <s, sizeof lts); 230 if (error != 0) 231 return error; 232 233 linux_to_native_timespec(&ts, <s); 234 235 return settime(l->l_proc, &ts); 236 } 237 238 int 239 linux_sys_clock_getres(l, v, retval) 240 struct lwp *l; 241 void *v; 242 register_t *retval; 243 { 244 struct linux_sys_clock_gettime_args /* { 245 syscallarg(clockid_t) which; 246 syscallarg(struct linux_timespec *)tp; 247 } */ *uap = v; 248 struct timespec ts; 249 struct linux_timespec lts; 250 int error; 251 clockid_t nwhich = 0; /* XXX: GCC */ 252 253 error = linux_to_native_clockid(&nwhich, SCARG(uap, which)); 254 if (error != 0 || SCARG(uap, tp) == NULL) 255 return error; 256 257 ts.tv_sec = 0; 258 ts.tv_nsec = 1000000000 / tc_getfrequency(); 259 native_to_linux_timespec(<s, &ts); 260 return copyout(<s, SCARG(uap, tp), sizeof lts); 261 } 262 263 int 264 linux_sys_clock_nanosleep(l, v, retval) 265 struct lwp *l; 266 void *v; 267 register_t *retval; 268 { 269 struct linux_sys_clock_nanosleep_args /* { 270 syscallarg(clockid_t) which; 271 syscallarg(int) flags; 272 syscallarg(struct linux_timespec) *rqtp; 273 syscallarg(struct linux_timespec) *rmtp; 274 } */ *uap = v; 275 struct linux_timespec lrqts, lrmts; 276 struct timespec rqts, rmts; 277 int error, error1; 278 279 if (SCARG(uap, flags) != 0) 280 return EINVAL; /* XXX deal with TIMER_ABSTIME */ 281 282 if (SCARG(uap, which) != LINUX_CLOCK_REALTIME) 283 return EINVAL; 284 285 error = copyin(SCARG(uap, rqtp), &lrqts, sizeof lrqts); 286 if (error != 0) 287 return error; 288 289 linux_to_native_timespec(&rqts, &lrqts); 290 291 error = nanosleep1(l, &rqts, SCARG(uap, rmtp) ? &rmts : 0); 292 if (SCARG(uap, rmtp) == NULL || (error != 0 && error != EINTR)) 293 return error; 294 295 native_to_linux_timespec(&lrmts, &rmts); 296 error1 = copyout(&lrmts, SCARG(uap, rmtp), sizeof lrmts); 297 return error1 ? error1 : error; 298 } 299