Annotation of kernel/machdep/i386/machine_clock.c, revision 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.