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
hrtcntl(uap,rvp)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
hrtalarm(uap,rvp)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
hrt_bsd_cancel(int clock)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
hrt_checkres(ulong res)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
hrt_checkclock(register int clock)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
hrt_gettofd(hrtimes_t * td)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
hrtsys(uap,rvp)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