Annotation of kernel/machdep/i386/machine_clock.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.