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