|
|
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.