1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ 23 /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */ 24 /* All Rights Reserved */ 25 26 /* 27 * Copyright (c) 1997, by Sun Microsystems, Inc. 28 * All rights reserved. 29 */ 30 31 #include <sys/param.h> 32 #include <sys/types.h> 33 #include <sys/sysmacros.h> 34 #include <sys/systm.h> 35 #include <sys/hrtcntl.h> 36 #include <sys/errno.h> 37 #include <sys/hrtsys.h> 38 #include <sys/time.h> 39 #include <sys/timer.h> 40 #include <sys/cmn_err.h> 41 42 /* 43 * This file contains the code that manages the hardware clocks and 44 * timers. We must provide UNIX with a HZ resolution clock and give 45 * the user an interface to the timers through system calls. 46 */ 47 48 static int hrt_checkres(ulong res); 49 static int hrt_bsd_cancel(int clock); 50 static int hrt_checkclock(register int clock); 51 52 /* 53 * Argument vectors for the various flavors of hrtsys(). 54 */ 55 56 #define HRTCNTL 0 57 #define HRTALARM 1 58 #define HRTSLEEP 2 59 #define HRTCANCEL 3 60 61 struct hrtsysa { 62 int opcode; 63 }; 64 65 struct hrtcntla { 66 int opcode; 67 int cmd; 68 int clk; 69 interval_t *intp; 70 hrtimes_t *hrtp; 71 }; 72 73 struct hrtalarma { 74 int opcode; 75 hrtcmd_t *cmdp; 76 int cmds; 77 }; 78 79 80 /* 81 * Hrtcntl (time control) system call. 82 */ 83 84 85 /*ARGSUSED1*/ 86 int 87 hrtcntl(uap, rvp) 88 register struct hrtcntla *uap; 89 rval_t *rvp; 90 { 91 register int error = 0; 92 hrtimes_t temptofd; 93 94 switch (uap->cmd) { 95 96 case HRT_TOFD: /* Get the time of day */ 97 98 if (uap->clk != CLK_STD) { 99 error = EINVAL; 100 break; 101 } 102 103 if (copyin((caddr_t)uap->hrtp, 104 (caddr_t)&temptofd, sizeof (hrtimes_t))) { 105 error = EFAULT; 106 break; 107 } 108 109 if ((error = hrt_checkres(temptofd.hrt_res))) 110 break; 111 112 hrt_gettofd(&temptofd); 113 114 if (copyout((caddr_t)&temptofd, 115 (caddr_t)uap->hrtp, sizeof (hrtimes_t))) 116 error = EFAULT; 117 118 break; 119 120 default: 121 error = EINVAL; 122 break; 123 } 124 return (error); 125 } 126 127 /* 128 * Hrtalarm (start one or more alarms) system call. 129 */ 130 131 int 132 hrtalarm(uap, rvp) 133 register struct hrtalarma *uap; 134 rval_t *rvp; 135 { 136 register hrtcmd_t *cp; 137 hrtcmd_t *hrcmdp; 138 uint alarm_cnt; 139 int cnt; 140 int error = 0; 141 int cmd; 142 hrtcmd_t timecmd; 143 hrtimes_t delay_ht; 144 145 146 /* 147 * Return EINVAL for negative and zero counts. 148 */ 149 150 if (uap->cmds <= 0) 151 return (EINVAL); 152 153 cp = &timecmd; 154 hrcmdp = uap->cmdp; 155 alarm_cnt = 0; 156 157 /* Loop through and process each command. */ 158 159 for (cnt = 0; cnt < uap->cmds; cnt++, hrcmdp++) { 160 161 if (copyin((caddr_t)hrcmdp, (caddr_t)cp, sizeof (hrtcmd_t))) 162 return (EFAULT); 163 164 cmd = cp->hrtc_cmd; 165 166 /* 167 * If we try to post a Berkley Timer remove 168 * previous timers. 169 */ 170 171 if (cmd == HRT_BSD || cmd == HRT_BSD_REP) 172 (void) hrt_bsd_cancel(cp->hrtc_clk); 173 174 /* See what kind of command we have. */ 175 176 switch (cmd) { 177 case HRT_BSD: /* one-shot timer */ 178 { 179 struct itimerval itv; 180 u_int which; 181 182 if ((error = hrt_checkclock(cp->hrtc_clk)) != 0) 183 break; 184 switch (cp->hrtc_clk) { 185 case CLK_STD: 186 which = ITIMER_REAL; 187 break; 188 case CLK_USERVIRT: 189 which = ITIMER_VIRTUAL; 190 break; 191 case CLK_PROCVIRT: 192 which = ITIMER_PROF; 193 break; 194 default: 195 error = EINVAL; 196 goto bad; 197 } 198 itv.it_value.tv_sec = cp->hrtc_int.hrt_secs; 199 itv.it_value.tv_usec = cp->hrtc_int.hrt_rem; 200 itv.it_interval.tv_sec = 0; 201 itv.it_interval.tv_usec = 0; 202 (void) xsetitimer(which, &itv, 1); 203 204 break; 205 } 206 207 case HRT_BSD_REP: 208 { 209 struct itimerval itv; 210 u_int which; 211 212 switch (cp->hrtc_clk) { 213 case CLK_STD: 214 which = ITIMER_REAL; 215 break; 216 case CLK_USERVIRT: 217 which = ITIMER_VIRTUAL; 218 break; 219 case CLK_PROCVIRT: 220 which = ITIMER_PROF; 221 break; 222 default: 223 error = EINVAL; 224 goto bad; 225 } 226 itv.it_value.tv_sec = cp->hrtc_tod.hrt_secs; 227 itv.it_value.tv_usec = cp->hrtc_tod.hrt_rem; 228 itv.it_interval.tv_sec = cp->hrtc_int.hrt_secs; 229 itv.it_interval.tv_usec = cp->hrtc_int.hrt_rem; 230 (void) xsetitimer(which, &itv, 1); 231 232 break; 233 } 234 235 case HRT_BSD_PEND: 236 { 237 struct itimerval itv; 238 u_int which; 239 240 switch (cp->hrtc_clk) { 241 case CLK_STD: 242 which = ITIMER_REAL; 243 break; 244 case CLK_USERVIRT: 245 which = ITIMER_VIRTUAL; 246 break; 247 case CLK_PROCVIRT: 248 which = ITIMER_PROF; 249 break; 250 default: 251 error = EINVAL; 252 goto bad; 253 } 254 (void) xgetitimer(which, &itv, 1); 255 delay_ht.hrt_secs = itv.it_value.tv_sec; 256 delay_ht.hrt_rem = itv.it_value.tv_usec; 257 } 258 259 if (copyout((caddr_t)&delay_ht, 260 (caddr_t)&hrcmdp->hrtc_int, sizeof (hrtimes_t))) 261 error = EFAULT; 262 263 break; 264 265 case HRT_BSD_CANCEL: 266 if ((error = hrt_checkclock(cp->hrtc_clk)) != 0) 267 break; 268 269 error = hrt_bsd_cancel(cp->hrtc_clk); 270 271 break; 272 273 default : 274 error = EINVAL; 275 break; 276 } 277 bad: 278 if (error) { 279 cp->hrtc_flags |= HRTF_ERROR; 280 cp->hrtc_error = error; 281 } else { 282 cp->hrtc_flags |= HRTF_DONE; 283 cp->hrtc_error = 0; 284 alarm_cnt++; 285 } 286 if (copyout((caddr_t)&cp->hrtc_flags, 287 (caddr_t)&hrcmdp->hrtc_flags, 288 sizeof (cp->hrtc_flags) + sizeof (cp->hrtc_error))) { 289 error = EFAULT; 290 return (error); 291 } 292 } 293 rvp->r_val1 = alarm_cnt; 294 return (0); 295 } 296 297 298 /* 299 * Cancel BSD timers 300 */ 301 302 static int 303 hrt_bsd_cancel(int clock) 304 { 305 struct itimerval itv; 306 u_int which; 307 308 switch (clock) { 309 case CLK_STD: 310 which = ITIMER_REAL; 311 break; 312 case CLK_USERVIRT: 313 which = ITIMER_VIRTUAL; 314 break; 315 case CLK_PROCVIRT: 316 which = ITIMER_PROF; 317 break; 318 default: 319 return (EINVAL); 320 } 321 itv.it_value.tv_sec = 0; 322 itv.it_value.tv_usec = 0; 323 (void) xsetitimer(which, &itv, 1); 324 return (0); 325 } 326 327 328 /* 329 * Return 0 if "res" is a legal resolution. Otherwise, 330 * return an error code, ERANGE. 331 */ 332 333 static int 334 hrt_checkres(ulong res) 335 { 336 if (res == 0 || res > NANOSEC) 337 return (ERANGE); 338 return (0); 339 } 340 341 /* 342 * Return 0 if "clock" is a valid clock. Otherwise, 343 * return an error code, EINVAL. 344 */ 345 346 static int 347 hrt_checkclock(register int clock) 348 { 349 switch (clock) 350 case CLK_STD: 351 case CLK_USERVIRT: 352 case CLK_PROCVIRT: 353 return (0); 354 355 return (EINVAL); 356 } 357 358 359 /* 360 * Set the current time of day in a specified resolution into 361 * a hrtimes_t structure. 362 */ 363 void 364 hrt_gettofd(hrtimes_t *td) 365 { 366 ulong new_res = td->hrt_res; 367 timestruc_t ts; 368 369 gethrestime(&ts); 370 td->hrt_secs = ts.tv_sec; 371 td->hrt_rem = ts.tv_nsec; 372 td->hrt_res = NANOSEC; 373 374 if (new_res != td->hrt_res) { 375 td->hrt_rem /= NANOSEC / new_res; 376 td->hrt_res = new_res; 377 } 378 } 379 380 381 /* 382 * System entry point for hrtcntl, hrtalarm 383 * system calls. 384 */ 385 386 int 387 hrtsys(uap, rvp) 388 register struct hrtsysa *uap; 389 rval_t *rvp; 390 { 391 register int error; 392 393 switch (uap->opcode) { 394 case HRTCNTL: 395 error = hrtcntl((struct hrtcntla *)uap, rvp); 396 break; 397 case HRTALARM: 398 error = hrtalarm((struct hrtalarma *)uap, rvp); 399 break; 400 default: 401 error = EINVAL; 402 break; 403 } 404 405 return (error); 406 } 407