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