|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Copyright (c) 1992, 1993, 1994, 1995 NeXT Computer, Inc.
27: *
28: * Machine dependent clock and timer routines
29: * for i386 architecture.
30: *
31: * HISTORY
32: *
33: * 11 June 1995 ? at NeXT
34: * Major rewrite for new clock API - banished
35: * all occurrances of ns_time_t in favor of
36: * tvalspec_t.
37: *
38: * 24 March 1992 ? at NeXT
39: * Created from m68k version.
40: */
41:
42: #import <mach/mach_types.h>
43:
44: #import <bsd/sys/param.h>
45: #import <bsd/sys/time.h>
46:
47: #import <kern/clock.h>
48: #import <vm/vm_kern.h>
49:
50: #import <machdep/i386/timer.h>
51: #import <machdep/i386/timer_inline.h>
52: #import <machdep/i386/intr_exported.h>
53:
54: static tvalspec_t time_of_boot; /* rel to 1/1/70 (UNIX T[0]) */
55:
56: /*
57: * Nanosecond event counter ;-)
58: */
59:
60: static struct _system_clock {
61: tvalspec_t counter;
62: timer_cnt_val_t last_timer_count;
63: mapped_tvalspec_t *mapped_counter;
64: timer_cnt_val_t timer_const;
65: } system_clock;
66:
67: static tvalspec_t system_time_stamp(void);
68:
69: static struct _system_timer {
70: boolean_t is_set;
71: tvalspec_t expire_time;
72: timer_func_t expire_func;
73: } system_timer;
74:
75: struct _interrupt_location {
76: unsigned int eip;
77: int rpl;
78: int ipl;
79: };
80:
81: static void machine_hardclock(
82: struct _interrupt_location *loc);
83:
84: static boolean_t hardclock_enabled;
85:
86: void
87: system_timer_dispatch(
88: unsigned int irq,
89: void *_state,
90: int ipl
91: )
92: {
93: thread_saved_state_t *state = (thread_saved_state_t *)_state;
94: tvalspec_t now;
95: struct _interrupt_location loc;
96:
97: ADD_TVALSPEC_NSEC(&system_clock.counter, NSEC_PER_TICK);
98: system_clock.last_timer_count = system_clock.timer_const;
99:
100: if (state) {
101: loc.eip = state->frame.eip;
102:
103: if (!(state->frame.eflags & EFL_VM))
104: loc.rpl = state->frame.cs.rpl;
105: else
106: loc.rpl = USER_PRIV;
107:
108: loc.ipl = ipl;
109: }
110: else {
111: loc.eip = 0x00000000;
112: loc.rpl = KERN_PRIV;
113: loc.ipl = ipl;
114: }
115:
116: if (hardclock_enabled)
117: machine_hardclock(&loc);
118:
119: now = system_time_stamp();
120:
121: if (system_timer.is_set &&
122: CMP_TVALSPEC(&system_timer.expire_time, &now) <= 0) {
123: system_timer.is_set = FALSE;
124: (*system_timer.expire_func)(now);
125: }
126: }
127:
128: void
129: hardclock_init(void)
130: {
131: hardclock_enabled = TRUE;
132: }
133:
134: static void
135: machine_hardclock(
136: struct _interrupt_location *loc
137: )
138: {
139: clock_interrupt(tick, (loc->rpl == USER_PRIV), (loc->ipl == 0));
140:
141: hardclock(loc->eip, STATUS_WORD(loc->rpl, loc->ipl));
142: }
143:
144: static unsigned int us_spin_us_const = 0x2000;
145:
146: void
147: us_spin(
148: unsigned int us
149: )
150: {
151: unsigned int constant;
152:
153: while (us-- > 0) {
154: constant = us_spin_us_const;
155:
156: while (constant-- > 0)
157: continue;
158: }
159: }
160:
161: void
162: us_spin_calibrate(void)
163: {
164: timer_ctl_reg_t reg;
165: timer_cnt_val_t leftover;
166: int s;
167:
168: reg = (timer_ctl_reg_t) { 0 };
169:
170: reg.mode = TIMER_EVENTMODE;
171: reg.rw = TIMER_CTL_RW_BOTH;
172: timer_set_ctl(reg);
173:
174: s = splclock();
175: timer_write(TIMER_CNT0_SEL, TIMER_COUNT_MAX);
176:
177: us_spin(1);
178:
179: timer_latch(TIMER_CNT0_SEL); leftover = timer_read(TIMER_CNT0_SEL);
180: splx(s);
181:
182: /*
183: * Formula for spin constant is :
184: * (loopcount * timer clock speed)/ counter ticks
185: */
186: us_spin_us_const =
187: (us_spin_us_const *
188: (TIMER_CONSTANT / (TIMER_COUNT_MAX - leftover))) / 1000000;
189: }
190:
191: static timer_cnt_val_t
192: system_timer_constant(void)
193: {
194: unsigned int constant;
195:
196: constant = TIMER_CONSTANT / TICKS_PER_SEC;
197: if ((TIMER_CONSTANT % TICKS_PER_SEC) >= (TICKS_PER_SEC / 2))
198: constant++;
199:
200: return ((timer_cnt_val_t)constant);
201: }
202:
203: /*
204: * Initialize the clock and timer interface.
205: */
206: void
207: machine_clock_init(void)
208: {
209: timer_ctl_reg_t reg;
210: int s;
211: extern void readtodc(unsigned int *);
212:
213: (void) intr_register_irq(0, system_timer_dispatch, 0, INTR_IPL6);
214: (void) intr_enable_irq(0);
215:
216: /*
217: * Initialize the RTC, and set the system's idea of time.
218: */
219: readtodc(&time_of_boot.tv_sec);
220:
221: /*
222: * Set up the timer.
223: */
224: s = splclock();
225:
226: reg = (timer_ctl_reg_t){ 0 };
227:
228: reg.mode = TIMER_NDIVMODE;
229: reg.rw = TIMER_CTL_RW_BOTH;
230: timer_set_ctl(reg);
231:
232: // save constant for later use
233: system_clock.timer_const = system_timer_constant();
234:
235: timer_write(TIMER_CNT0_SEL, system_clock.timer_const);
236: system_clock.last_timer_count = system_clock.timer_const;
237:
238: splx(s);
239: }
240:
241: /*
242: * Clock functions
243: */
244: tvalspec_t
245: clock_get_counter(
246: clock_type_t which_clock
247: )
248: {
249: tvalspec_t result = system_time_stamp();
250:
251: switch (which_clock) {
252:
253: case System:
254: break;
255:
256: case Calendar: {
257: int s = splclock();
258:
259: ADD_TVALSPEC(&result, &time_of_boot);
260: splx(s);
261: break;
262: }
263:
264: default:
265: result = TVALSPEC_ZERO;
266: break;
267: }
268:
269: return (result);
270: }
271:
272: void
273: clock_set_counter(
274: clock_type_t which_clock,
275: tvalspec_t value
276: )
277: {
278: tvalspec_t counter = system_time_stamp();
279:
280: switch (which_clock) {
281:
282: case Calendar: {
283: int s = splclock();
284:
285: time_of_boot = value;
286: SUB_TVALSPEC(&time_of_boot, &counter);
287: splx(s);
288:
289: writetodc(&value.tv_sec);
290: break;
291: }
292:
293: default:
294: /* Can only set the calendar */
295: break;
296: }
297: }
298:
299: void
300: clock_adjust_counter(
301: clock_type_t which_clock,
302: clock_res_t nsec
303: )
304: {
305: switch (which_clock) {
306:
307: case Calendar: {
308: int s = splclock();
309:
310: ADD_TVALSPEC_NSEC(&time_of_boot, nsec);
311: splx(s);
312: break;
313: }
314:
315: default:
316: /* Can only adjust the calendar */
317: break;
318: }
319: }
320:
321: mapped_tvalspec_t *
322: clock_map_counter(
323: clock_type_t which_clock
324: )
325: {
326: mapped_tvalspec_t *mapped_clock;
327:
328: switch (which_clock) {
329:
330: case System:
331: if (!(mapped_clock = system_clock.mapped_counter)) {
332: int s;
333:
334: if (kmem_alloc_wired(kernel_map,
335: (vm_offset_t *)&mapped_clock,
336: PAGE_SIZE) != KERN_SUCCESS) {
337: mapped_clock = 0;
338: break;
339: }
340: s = splclock();
341: system_clock.mapped_counter = mapped_clock;
342: splx(s);
343: }
344: break;
345:
346: default:
347: mapped_clock = 0;
348: break;
349: }
350:
351: return (mapped_clock);
352: }
353:
354: void
355: timer_set_expire_func(
356: timer_type_t which_timer,
357: timer_func_t expire_func
358: )
359: {
360: switch (which_timer) {
361:
362: case SystemWide:
363: if (!expire_func || !system_timer.expire_func) {
364: int s = splclock();
365:
366: system_timer.expire_func = expire_func;
367: system_timer.is_set = FALSE;
368: splx(s);
369: }
370: break;
371:
372: default:
373: break;
374: }
375: }
376:
377: void
378: timer_set_deadline(
379: timer_type_t which_timer,
380: tvalspec_t deadline
381: )
382: {
383: switch (which_timer) {
384:
385: case SystemWide:
386: if (system_timer.expire_func) {
387: int s = splclock();
388:
389: system_timer.expire_time = deadline;
390: system_timer.is_set = TRUE;
391: splx(s);
392: }
393: break;
394:
395: default:
396: break;
397: }
398: }
399:
400: /*
401: * Get current clock value plus fraction of a tick.
402: */
403: static tvalspec_t
404: system_time_stamp(void)
405: {
406: timer_cnt_val_t current_timer_count, last_timer_count;
407: clock_res_t fraction;
408: tvalspec_t result;
409: int s = splclock();
410:
411: // take a snapshot of the whole counter state
412: result = system_clock.counter;
413: last_timer_count = system_clock.last_timer_count;
414: timer_latch(TIMER_CNT0_SEL);
415: current_timer_count = timer_read(TIMER_CNT0_SEL);
416: system_clock.last_timer_count = current_timer_count;
417: splx(s);
418:
419: // check for tick overflow
420: if (current_timer_count > last_timer_count) {
421: // we missed a tick
422: ADD_TVALSPEC_NSEC(&result, NSEC_PER_TICK);
423: }
424:
425: // convert fraction to ns
426: fraction = (system_clock.timer_const - current_timer_count);
427: fraction = fraction * (NSEC_PER_SEC / TIMER_CONSTANT);
428:
429: ADD_TVALSPEC_NSEC(&result, fraction);
430:
431: return (result);
432: }
433:
434: unsigned int
435: event_get(void)
436: {
437: return (system_time_stamp().tv_nsec);
438: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.