Annotation of XNU/osfmk/ppc/rtclock.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:  * @OSF_COPYRIGHT@
        !            24:  */
        !            25: /*
        !            26:  * @APPLE_FREE_COPYRIGHT@
        !            27:  */
        !            28: /*
        !            29:  *     File:           rtclock.c
        !            30:  *     Purpose:        Routines for handling the machine dependent
        !            31:  *                             real-time clock.
        !            32:  */
        !            33: 
        !            34: #include <platforms.h>
        !            35: 
        !            36: #include <kern/cpu_number.h>
        !            37: #include <kern/clock.h>
        !            38: #include <kern/macro_help.h>
        !            39: #include <kern/misc_protos.h>
        !            40: #include <kern/spl.h>
        !            41: #include <machine/mach_param.h>        /* HZ */
        !            42: #include <mach/vm_prot.h>
        !            43: #include <vm/pmap.h>
        !            44: #include <vm/vm_kern.h>                /* for kernel_map */
        !            45: #include <ppc/misc_protos.h>
        !            46: #include <ppc/proc_reg.h>
        !            47: #include <ppc/spl.h>
        !            48: 
        !            49: #include <IOKit/IOPlatformExpert.h>
        !            50: 
        !            51: #include <sys/kdebug.h>
        !            52: 
        !            53: int            sysclk_config(void);
        !            54: 
        !            55: int            sysclk_init(void);
        !            56: 
        !            57: kern_return_t  sysclk_gettime(
        !            58:        mach_timespec_t                 *cur_time);
        !            59: 
        !            60: kern_return_t  sysclk_getattr(
        !            61:        clock_flavor_t                  flavor,
        !            62:        clock_attr_t                    attr,
        !            63:        mach_msg_type_number_t  *count);
        !            64: 
        !            65: void           sysclk_setalarm(
        !            66:        mach_timespec_t                 *deadline);
        !            67: 
        !            68: struct clock_ops sysclk_ops = {
        !            69:        sysclk_config,                  sysclk_init,
        !            70:        sysclk_gettime,                 0,
        !            71:        sysclk_getattr,                 0,
        !            72:        sysclk_setalarm,
        !            73: };
        !            74: 
        !            75: int            calend_config(void);
        !            76: 
        !            77: int            calend_init(void);
        !            78: 
        !            79: kern_return_t  calend_gettime(
        !            80:        mach_timespec_t                 *cur_time);
        !            81: 
        !            82: kern_return_t  calend_settime(
        !            83:        mach_timespec_t                 *cur_time);
        !            84: 
        !            85: kern_return_t  calend_getattr(
        !            86:        clock_flavor_t                  flavor,
        !            87:        clock_attr_t                    attr,
        !            88:        mach_msg_type_number_t  *count);
        !            89: 
        !            90: struct clock_ops calend_ops = {
        !            91:        calend_config,                  calend_init,
        !            92:        calend_gettime,                 calend_settime,
        !            93:        calend_getattr,                 0,
        !            94:        0,
        !            95: };
        !            96: 
        !            97: /* local data declarations */
        !            98: 
        !            99: static struct rtclock {
        !           100:        AbsoluteTime            alarm_deadline;
        !           101:        boolean_t                       alarm_is_set;
        !           102: 
        !           103:        mach_timespec_t         calend_offset;
        !           104:        boolean_t                       calend_is_set;
        !           105: 
        !           106:        struct {
        !           107:                natural_t       numer, denom;
        !           108:        }                                       timebase_const;
        !           109: 
        !           110:        AbsoluteTime            timer_deadline;
        !           111:        boolean_t                       timer_is_set;
        !           112:        clock_timer_func_t      timer_expire;
        !           113: 
        !           114:        /* debugging */
        !           115:        AbsoluteTime            last_abstime[NCPUS];
        !           116:        int                                     last_decr[NCPUS];
        !           117:        natural_t                       intr_entry;
        !           118:        natural_t                       intr_exit;
        !           119: 
        !           120:        decl_simple_lock_data(,lock)    /* real-time clock device lock */
        !           121: } rtclock;
        !           122: 
        !           123: static boolean_t               rtclock_initialized;
        !           124: 
        !           125: static AbsoluteTime            rtclock_tick_deadline[NCPUS];
        !           126: static AbsoluteTime            rtclock_tick_interval;
        !           127: 
        !           128: static void            absolutetime_to_timespec_internal(
        !           129:                                                        AbsoluteTime            abstime,
        !           130:                                                        mach_timespec_t         *result);
        !           131: 
        !           132: static void            timespec_to_absolutetime_internal(
        !           133:                                                        mach_timespec_t         timespec,
        !           134:                                                        AbsoluteTime            *result);
        !           135: 
        !           136: static int             deadline_to_decrementer(
        !           137:                                                        AbsoluteTime            deadline,
        !           138:                                                        AbsoluteTime            now);
        !           139: 
        !           140: /* global data declarations */
        !           141: 
        !           142: #define RTC_TICKPERIOD (NSEC_PER_SEC / HZ)
        !           143: 
        !           144: #define DECREMENTER_MAX                0x7FFFFFFFUL
        !           145: #define DECREMENTER_MIN                0xAUL
        !           146: 
        !           147: natural_t              rtclock_decrementer_min;
        !           148: 
        !           149: /*
        !           150:  *     Macros to lock/unlock real-time clock device.
        !           151:  */
        !           152: #define LOCK_RTC(s)                                    \
        !           153: MACRO_BEGIN                                                    \
        !           154:        (s) = splclock();                               \
        !           155:        simple_lock(&rtclock.lock);             \
        !           156: MACRO_END
        !           157: 
        !           158: #define UNLOCK_RTC(s)                          \
        !           159: MACRO_BEGIN                                                    \
        !           160:        simple_unlock(&rtclock.lock);   \
        !           161:        splx(s);                                                \
        !           162: MACRO_END
        !           163: 
        !           164: static void
        !           165: timebase_callback(
        !           166:        struct timebase_freq_t  *freq)
        !           167: {
        !           168:        natural_t       numer, denom;
        !           169:        int                     n;
        !           170:        spl_t           s;
        !           171: 
        !           172:        denom = freq->timebase_num;
        !           173:        n = 9;
        !           174:        while (!(denom % 10)) {
        !           175:                if (n < 1)
        !           176:                        break;
        !           177:                denom /= 10;
        !           178:                n--;
        !           179:        }
        !           180: 
        !           181:        numer = freq->timebase_den;
        !           182:        while (n-- > 0) {
        !           183:                numer *= 10;
        !           184:        }
        !           185: 
        !           186:        LOCK_RTC(s);
        !           187:        rtclock.timebase_const.numer = numer;
        !           188:        rtclock.timebase_const.denom = denom;
        !           189:        UNLOCK_RTC(s);
        !           190: }
        !           191: 
        !           192: /*
        !           193:  * Configure the real-time clock device.
        !           194:  */
        !           195: int
        !           196: sysclk_config(void)
        !           197: {
        !           198:        if (cpu_number() != master_cpu)
        !           199:                return(1);
        !           200: 
        !           201:        simple_lock_init(&rtclock.lock, ETAP_MISC_RT_CLOCK);
        !           202: 
        !           203:        PE_register_timebase_callback(timebase_callback);
        !           204: 
        !           205:        return (1);
        !           206: }
        !           207: 
        !           208: /*
        !           209:  * Initialize the system clock device.
        !           210:  */
        !           211: int
        !           212: sysclk_init(void)
        !           213: {
        !           214:        AbsoluteTime    abstime;
        !           215:        int                             decr, mycpu = cpu_number();
        !           216: 
        !           217:        if (mycpu != master_cpu) {
        !           218:                if (rtclock_initialized == FALSE) {
        !           219:                        panic("sysclk_init on cpu %d, rtc not initialized\n", mycpu);
        !           220:                }
        !           221:                /* Set decrementer and hence our next tick due */
        !           222:                clock_get_uptime(&abstime);
        !           223:                rtclock_tick_deadline[mycpu] = abstime;
        !           224:                ADD_ABSOLUTETIME(&rtclock_tick_deadline[mycpu],
        !           225:                                                                                        &rtclock_tick_interval);
        !           226:                decr = deadline_to_decrementer(rtclock_tick_deadline[mycpu], abstime);
        !           227:                mtdec(decr);
        !           228:                rtclock.last_decr[mycpu] = decr;
        !           229: 
        !           230:                return(1);
        !           231:        }
        !           232: 
        !           233:        /*
        !           234:         * Initialize non-zero clock structure values.
        !           235:         */
        !           236:        clock_interval_to_absolutetime_interval(RTC_TICKPERIOD, 1,
        !           237:                                                                                                &rtclock_tick_interval);
        !           238:        /* Set decrementer and our next tick due */
        !           239:        clock_get_uptime(&abstime);
        !           240:        rtclock_tick_deadline[mycpu] = abstime;
        !           241:        ADD_ABSOLUTETIME(&rtclock_tick_deadline[mycpu], &rtclock_tick_interval);
        !           242:        decr = deadline_to_decrementer(rtclock_tick_deadline[mycpu], abstime);
        !           243:        mtdec(decr);
        !           244:        rtclock.last_decr[mycpu] = decr;
        !           245: 
        !           246:        rtclock_initialized = TRUE;
        !           247: 
        !           248:        return (1);
        !           249: }
        !           250: 
        !           251: /*
        !           252:  * Perform a full 64 bit by 32 bit unsigned multiply,
        !           253:  * yielding a 96 bit product.  The most significant
        !           254:  * portion of the product is returned as a 64 bit
        !           255:  * quantity, with the lower portion as a 32 bit word.
        !           256:  */
        !           257: static void
        !           258: umul_64by32(
        !           259:        AbsoluteTime            now64,
        !           260:        natural_t                       mult32,
        !           261:        AbsoluteTime            *result64,
        !           262:        natural_t                       *result32)
        !           263: {
        !           264:        natural_t                       mid, mid2;
        !           265: 
        !           266:        asm volatile("  mullw %0,%1,%2" :
        !           267:                                                        "=r" (*result32) :
        !           268:                                                                "r" (now64.lo), "r" (mult32));
        !           269: 
        !           270:        asm volatile("  mullw %0,%1,%2" :
        !           271:                                                        "=r" (mid2) :
        !           272:                                                                "r" (now64.hi), "r" (mult32));
        !           273:        asm volatile("  mulhwu %0,%1,%2" :
        !           274:                                                        "=r" (mid) :
        !           275:                                                                "r" (now64.lo), "r" (mult32));
        !           276: 
        !           277:        asm volatile("  mulhwu %0,%1,%2" :
        !           278:                                                        "=r" (result64->hi) :
        !           279:                                                                "r" (now64.hi), "r" (mult32));
        !           280: 
        !           281:        asm volatile("  addc %0,%2,%3;
        !           282:                                        addze %1,%4" :
        !           283:                                                        "=r" (result64->lo), "=r" (result64->hi) :
        !           284:                                                                "r" (mid), "r" (mid2), "1" (result64->hi));
        !           285: }
        !           286: 
        !           287: /*
        !           288:  * Perform a partial 64 bit by 32 bit unsigned multiply,
        !           289:  * yielding a 64 bit product.  Only the least significant
        !           290:  * 64 bits of the product are calculated and returned.
        !           291:  */
        !           292: static void
        !           293: umul_64by32to64(
        !           294:        AbsoluteTime            now64,
        !           295:        natural_t                       mult32,
        !           296:        AbsoluteTime            *result64)
        !           297: {
        !           298:        natural_t                       mid, mid2;
        !           299: 
        !           300:        asm volatile("  mullw %0,%1,%2" :
        !           301:                                                        "=r" (result64->lo) :
        !           302:                                                                "r" (now64.lo), "r" (mult32));
        !           303: 
        !           304:        asm volatile("  mullw %0,%1,%2" :
        !           305:                                                        "=r" (mid2) :
        !           306:                                                                "r" (now64.hi), "r" (mult32));
        !           307:        asm volatile("  mulhwu %0,%1,%2" :
        !           308:                                                        "=r" (mid) :
        !           309:                                                                "r" (now64.lo), "r" (mult32));
        !           310: 
        !           311:        asm volatile("  add %0,%1,%2" :
        !           312:                                                        "=r" (result64->hi) :
        !           313:                                                                "r" (mid), "r" (mid2));
        !           314: }
        !           315: 
        !           316: /*
        !           317:  * Perform an unsigned division of a 96 bit value
        !           318:  * by a 32 bit value, yielding a 96 bit quotient.
        !           319:  * The most significant portion of the product is
        !           320:  * returned as a 64 bit quantity, with the lower
        !           321:  * portion as a 32 bit word.
        !           322:  */
        !           323: static __inline__
        !           324: void
        !           325: udiv_96by32(
        !           326:        AbsoluteTime    now64,
        !           327:        natural_t               now32,
        !           328:        natural_t               div32,
        !           329:        AbsoluteTime    *result64,
        !           330:        natural_t               *result32)
        !           331: {
        !           332:        AbsoluteTime    t64;
        !           333: 
        !           334:        if (now64.hi > 0 || now64.lo >= div32) {
        !           335:                AbsoluteTime_to_scalar(result64) =
        !           336:                                                        AbsoluteTime_to_scalar(&now64) / div32;
        !           337: 
        !           338:                umul_64by32to64(*result64, div32, &t64);
        !           339: 
        !           340:                AbsoluteTime_to_scalar(&t64) =
        !           341:                                AbsoluteTime_to_scalar(&now64) - AbsoluteTime_to_scalar(&t64);
        !           342: 
        !           343:                *result32 =     (((unsigned long long)t64.lo << 32) | now32) / div32;
        !           344:        }
        !           345:        else {
        !           346:                AbsoluteTime_to_scalar(result64) =
        !           347:                                        (((unsigned long long)now64.lo << 32) | now32) / div32;
        !           348: 
        !           349:                *result32 = result64->lo;
        !           350:                result64->lo = result64->hi;
        !           351:                result64->hi = 0;
        !           352:        }
        !           353: }
        !           354: 
        !           355: /*
        !           356:  * Perform an unsigned division of a 96 bit value
        !           357:  * by a 32 bit value, yielding a 64 bit quotient.
        !           358:  * Any higher order bits of the quotient are simply
        !           359:  * discarded.
        !           360:  */
        !           361: static __inline__
        !           362: void
        !           363: udiv_96by32to64(
        !           364:        AbsoluteTime    now64,
        !           365:        natural_t               now32,
        !           366:        natural_t               div32,
        !           367:        AbsoluteTime    *result64)
        !           368: {
        !           369:        AbsoluteTime    t64;
        !           370: 
        !           371:        if (now64.hi > 0 || now64.lo >= div32) {
        !           372:                AbsoluteTime_to_scalar(result64) =
        !           373:                                                AbsoluteTime_to_scalar(&now64) / div32;
        !           374: 
        !           375:                umul_64by32to64(*result64, div32, &t64);
        !           376: 
        !           377:                AbsoluteTime_to_scalar(&t64) =
        !           378:                                AbsoluteTime_to_scalar(&now64) - AbsoluteTime_to_scalar(&t64);
        !           379: 
        !           380:                result64->hi = result64->lo;
        !           381:                result64->lo = (((unsigned long long)t64.lo << 32) | now32) / div32;
        !           382:        }
        !           383:        else {
        !           384:                AbsoluteTime_to_scalar(result64) =
        !           385:                                        (((unsigned long long)now64.lo << 32) | now32) / div32;
        !           386:        }
        !           387: }
        !           388: 
        !           389: /*
        !           390:  * Perform an unsigned division of a 96 bit value
        !           391:  * by a 32 bit value, yielding a 32 bit quotient,
        !           392:  * and a 32 bit remainder.  Any higher order bits
        !           393:  * of the quotient are simply discarded.
        !           394:  */
        !           395: static __inline__
        !           396: void
        !           397: udiv_96by32to32and32(
        !           398:        AbsoluteTime    now64,
        !           399:        natural_t               now32,
        !           400:        natural_t               div32,
        !           401:        natural_t               *result32,
        !           402:        natural_t               *remain32)
        !           403: {
        !           404:        AbsoluteTime    t64, u64;
        !           405: 
        !           406:        if (now64.hi > 0 || now64.lo >= div32) {
        !           407:                AbsoluteTime_to_scalar(&t64) =
        !           408:                                                        AbsoluteTime_to_scalar(&now64) / div32;
        !           409: 
        !           410:                umul_64by32to64(t64, div32, &t64);
        !           411: 
        !           412:                AbsoluteTime_to_scalar(&t64) =
        !           413:                        AbsoluteTime_to_scalar(&now64) - AbsoluteTime_to_scalar(&t64);
        !           414: 
        !           415:                AbsoluteTime_to_scalar(&t64) =
        !           416:                                                ((unsigned long long)t64.lo << 32) | now32;
        !           417: 
        !           418:                AbsoluteTime_to_scalar(&u64) =
        !           419:                                                        AbsoluteTime_to_scalar(&t64) / div32;
        !           420: 
        !           421:                *result32 = u64.lo;
        !           422: 
        !           423:                umul_64by32to64(u64, div32, &u64);
        !           424: 
        !           425:                *remain32 = AbsoluteTime_to_scalar(&t64) -
        !           426:                                                                        AbsoluteTime_to_scalar(&u64);
        !           427:        }
        !           428:        else {
        !           429:                AbsoluteTime_to_scalar(&t64) =
        !           430:                                                ((unsigned long long)now64.lo << 32) | now32;
        !           431: 
        !           432:                AbsoluteTime_to_scalar(&u64) =
        !           433:                                                        AbsoluteTime_to_scalar(&t64) / div32;
        !           434: 
        !           435:                *result32 =      u64.lo;
        !           436: 
        !           437:                umul_64by32to64(u64, div32, &u64);
        !           438: 
        !           439:                *remain32 =     AbsoluteTime_to_scalar(&t64) -
        !           440:                                                                        AbsoluteTime_to_scalar(&u64);
        !           441:        }
        !           442: }
        !           443: 
        !           444: /*
        !           445:  * Get the clock device time. This routine is responsible
        !           446:  * for converting the device's machine dependent time value
        !           447:  * into a canonical mach_timespec_t value.
        !           448:  *
        !           449:  * SMP configurations - *this currently assumes that the processor
        !           450:  * clocks will be synchronised*
        !           451:  */
        !           452: kern_return_t
        !           453: sysclk_gettime_internal(
        !           454:        mach_timespec_t *time)  /* OUT */
        !           455: {
        !           456:        AbsoluteTime            now;
        !           457:        AbsoluteTime            t64;
        !           458:        natural_t                       t32;
        !           459:        natural_t                       numer, denom;
        !           460: 
        !           461:        numer = rtclock.timebase_const.numer;
        !           462:        denom = rtclock.timebase_const.denom;
        !           463: 
        !           464:        clock_get_uptime(&now);
        !           465: 
        !           466:        umul_64by32(now, numer, &t64, &t32);
        !           467: 
        !           468:        udiv_96by32(t64, t32, denom, &t64, &t32);
        !           469: 
        !           470:        udiv_96by32to32and32(t64, t32, NSEC_PER_SEC,
        !           471:                                                                &time->tv_sec, &time->tv_nsec);
        !           472: 
        !           473:        return (KERN_SUCCESS);
        !           474: }
        !           475: 
        !           476: kern_return_t
        !           477: sysclk_gettime(
        !           478:        mach_timespec_t *time)  /* OUT */
        !           479: {
        !           480:        AbsoluteTime            now;
        !           481:        AbsoluteTime            t64;
        !           482:        natural_t                       t32;
        !           483:        natural_t                       numer, denom;
        !           484:        spl_t                           s;
        !           485: 
        !           486:        LOCK_RTC(s);
        !           487:        numer = rtclock.timebase_const.numer;
        !           488:        denom = rtclock.timebase_const.denom;
        !           489:        UNLOCK_RTC(s);
        !           490: 
        !           491:        clock_get_uptime(&now);
        !           492: 
        !           493:        umul_64by32(now, numer, &t64, &t32);
        !           494: 
        !           495:        udiv_96by32(t64, t32, denom, &t64, &t32);
        !           496: 
        !           497:        udiv_96by32to32and32(t64, t32, NSEC_PER_SEC,
        !           498:                                                                &time->tv_sec, &time->tv_nsec);
        !           499: 
        !           500:        return (KERN_SUCCESS);
        !           501: }
        !           502: 
        !           503: /*
        !           504:  * Get clock device attributes.
        !           505:  */
        !           506: kern_return_t
        !           507: sysclk_getattr(
        !           508:        clock_flavor_t          flavor,
        !           509:        clock_attr_t            attr,           /* OUT */
        !           510:        mach_msg_type_number_t  *count)         /* IN/OUT */
        !           511: {
        !           512:        spl_t   s;
        !           513: 
        !           514:        if (*count != 1)
        !           515:                return (KERN_FAILURE);
        !           516:        switch (flavor) {
        !           517: 
        !           518:        case CLOCK_GET_TIME_RES:        /* >0 res */
        !           519:        case CLOCK_ALARM_CURRES:        /* =0 no alarm */
        !           520:        case CLOCK_ALARM_MINRES:
        !           521:        case CLOCK_ALARM_MAXRES:
        !           522:                LOCK_RTC(s);
        !           523:                *(clock_res_t *) attr = RTC_TICKPERIOD;
        !           524:                UNLOCK_RTC(s);
        !           525:                break;
        !           526: 
        !           527:        default:
        !           528:                return (KERN_INVALID_VALUE);
        !           529:        }
        !           530:        return (KERN_SUCCESS);
        !           531: }
        !           532: 
        !           533: /*
        !           534:  * Set deadline for the next alarm on the clock device. This call
        !           535:  * always resets the time to deliver an alarm for the clock.
        !           536:  */
        !           537: void
        !           538: sysclk_setalarm(
        !           539:        mach_timespec_t         *deadline)
        !           540: {
        !           541:        AbsoluteTime    abstime;
        !           542:        int                             decr, mycpu;
        !           543:        spl_t                   s;
        !           544: 
        !           545:        LOCK_RTC(s);
        !           546:        mycpu = cpu_number();
        !           547:        clock_get_uptime(&abstime);
        !           548:        rtclock.last_abstime[mycpu] = abstime;
        !           549:        timespec_to_absolutetime_internal(*deadline, &rtclock.alarm_deadline);
        !           550:        rtclock.alarm_is_set = TRUE;
        !           551:        if (    (!rtclock.timer_is_set ||
        !           552:                         CMP_ABSOLUTETIME(&rtclock.alarm_deadline,
        !           553:                                                                                &rtclock.timer_deadline) < 0) &&
        !           554:                        CMP_ABSOLUTETIME(&rtclock.alarm_deadline,
        !           555:                                                                                &rtclock_tick_deadline[mycpu]) < 0) {
        !           556:                decr = deadline_to_decrementer(rtclock.alarm_deadline, abstime);
        !           557:                if (    rtclock_decrementer_min != 0                            &&
        !           558:                                rtclock_decrementer_min < (natural_t)decr               )
        !           559:                        decr = rtclock_decrementer_min;
        !           560: 
        !           561:                KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 1)
        !           562:                                                          | DBG_FUNC_NONE, decr, 1, 0, 0, 0);
        !           563: 
        !           564:                mtdec(decr);
        !           565:                rtclock.last_decr[mycpu] = decr;
        !           566:        }
        !           567:        UNLOCK_RTC(s);
        !           568: }
        !           569: 
        !           570: /*
        !           571:  * Configure the calendar clock.
        !           572:  */
        !           573: int
        !           574: calend_config(void)
        !           575: {
        !           576:        return (1);
        !           577: }
        !           578: 
        !           579: /*
        !           580:  * Initialize the calendar clock.
        !           581:  */
        !           582: int
        !           583: calend_init(void)
        !           584: {
        !           585:        if (cpu_number() != master_cpu)
        !           586:                return(1);
        !           587: 
        !           588:        return (1);
        !           589: }
        !           590: 
        !           591: /*
        !           592:  * Get the current clock time.
        !           593:  */
        !           594: kern_return_t
        !           595: calend_gettime(
        !           596:        mach_timespec_t *curr_time)     /* OUT */
        !           597: {
        !           598:        spl_t           s;
        !           599: 
        !           600:        LOCK_RTC(s);
        !           601:        if (!rtclock.calend_is_set) {
        !           602:                UNLOCK_RTC(s);
        !           603:                return (KERN_FAILURE);
        !           604:        }
        !           605: 
        !           606:        (void) sysclk_gettime_internal(curr_time);
        !           607:        ADD_MACH_TIMESPEC(curr_time, &rtclock.calend_offset);
        !           608:        UNLOCK_RTC(s);
        !           609: 
        !           610:        return (KERN_SUCCESS);
        !           611: }
        !           612: 
        !           613: /*
        !           614:  * Set the current clock time.
        !           615:  */
        !           616: kern_return_t
        !           617: calend_settime(
        !           618:        mach_timespec_t *new_time)
        !           619: {
        !           620:        mach_timespec_t curr_time;
        !           621:        spl_t           s;
        !           622: 
        !           623:        LOCK_RTC(s);
        !           624:        (void) sysclk_gettime_internal(&curr_time);
        !           625:        rtclock.calend_offset = *new_time;
        !           626:        SUB_MACH_TIMESPEC(&rtclock.calend_offset, &curr_time);
        !           627:        rtclock.calend_is_set = TRUE;
        !           628:        UNLOCK_RTC(s);
        !           629: 
        !           630:        PESetGMTTimeOfDay(new_time->tv_sec);
        !           631: 
        !           632:        return (KERN_SUCCESS);
        !           633: }
        !           634: 
        !           635: /*
        !           636:  * Get clock device attributes.
        !           637:  */
        !           638: kern_return_t
        !           639: calend_getattr(
        !           640:        clock_flavor_t          flavor,
        !           641:        clock_attr_t            attr,           /* OUT */
        !           642:        mach_msg_type_number_t  *count)         /* IN/OUT */
        !           643: {
        !           644:        spl_t   s;
        !           645: 
        !           646:        if (*count != 1)
        !           647:                return (KERN_FAILURE);
        !           648:        switch (flavor) {
        !           649: 
        !           650:        case CLOCK_GET_TIME_RES:        /* >0 res */
        !           651:                LOCK_RTC(s);
        !           652:                *(clock_res_t *) attr = RTC_TICKPERIOD;
        !           653:                UNLOCK_RTC(s);
        !           654:                break;
        !           655: 
        !           656:        case CLOCK_ALARM_CURRES:        /* =0 no alarm */
        !           657:        case CLOCK_ALARM_MINRES:
        !           658:        case CLOCK_ALARM_MAXRES:
        !           659:                *(clock_res_t *) attr = 0;
        !           660:                break;
        !           661: 
        !           662:        default:
        !           663:                return (KERN_INVALID_VALUE);
        !           664:        }
        !           665:        return (KERN_SUCCESS);
        !           666: }
        !           667: 
        !           668: void
        !           669: clock_adjust_calendar(
        !           670:        clock_res_t     nsec)
        !           671: {
        !           672:        spl_t           s;
        !           673: 
        !           674:        LOCK_RTC(s);
        !           675:        if (rtclock.calend_is_set)
        !           676:                ADD_MACH_TIMESPEC_NSEC(&rtclock.calend_offset, nsec);
        !           677:        UNLOCK_RTC(s);
        !           678: }
        !           679: 
        !           680: void
        !           681: clock_initialize_calendar(void)
        !           682: {
        !           683:        mach_timespec_t curr_time;
        !           684:        long            seconds = PEGetGMTTimeOfDay();
        !           685:        spl_t           s;
        !           686: 
        !           687:        LOCK_RTC(s);
        !           688:        if (!rtclock.calend_is_set) {
        !           689:                (void) sysclk_gettime_internal(&curr_time);
        !           690:                rtclock.calend_offset.tv_sec = seconds;
        !           691:                rtclock.calend_offset.tv_nsec = 0;
        !           692:                SUB_MACH_TIMESPEC(&rtclock.calend_offset, &curr_time);
        !           693:                rtclock.calend_is_set = TRUE;
        !           694:        }
        !           695:        UNLOCK_RTC(s);
        !           696: }
        !           697: 
        !           698: mach_timespec_t
        !           699: clock_get_calendar_offset(void)
        !           700: {
        !           701:        mach_timespec_t result = MACH_TIMESPEC_ZERO;
        !           702:        spl_t           s;
        !           703: 
        !           704:        LOCK_RTC(s);
        !           705:        if (rtclock.calend_is_set)
        !           706:                result = rtclock.calend_offset;
        !           707:        UNLOCK_RTC(s);
        !           708: 
        !           709:        return (result);
        !           710: }
        !           711: 
        !           712: void
        !           713: clock_get_timebase_info(
        !           714:        natural_t               *delta,
        !           715:        natural_t               *abs_to_ns_num,
        !           716:        natural_t               *abs_to_ns_denom,
        !           717:        natural_t               *proc_to_abs_num,
        !           718:        natural_t               *proc_to_abs_denom)
        !           719: {
        !           720:        spl_t   s;
        !           721: 
        !           722:        LOCK_RTC(s);
        !           723:        *abs_to_ns_num =        rtclock.timebase_const.numer;
        !           724:        *abs_to_ns_denom =      rtclock.timebase_const.denom;
        !           725:        UNLOCK_RTC(s);
        !           726: 
        !           727:        /*
        !           728:         * Other values as returned by Mac OS 8.6.
        !           729:         */
        !           730:        *delta =        1;
        !           731:        *proc_to_abs_num = *proc_to_abs_denom = 1;
        !           732: }      
        !           733: 
        !           734: void
        !           735: clock_set_timer_deadline(
        !           736:        AbsoluteTime                    deadline)
        !           737: {
        !           738:        AbsoluteTime    abstime;
        !           739:        int                             decr, mycpu;
        !           740:        spl_t                   s;
        !           741: 
        !           742:        LOCK_RTC(s);
        !           743:        mycpu = cpu_number();
        !           744:        clock_get_uptime(&abstime);
        !           745:        rtclock.last_abstime[mycpu] = abstime;
        !           746:        rtclock.timer_deadline = deadline;
        !           747:        rtclock.timer_is_set = TRUE;
        !           748:        if (    (!rtclock.alarm_is_set ||
        !           749:                         CMP_ABSOLUTETIME(&rtclock.timer_deadline,
        !           750:                                                                                &rtclock.alarm_deadline) < 0) &&
        !           751:                        CMP_ABSOLUTETIME(&rtclock.timer_deadline,
        !           752:                                                                                &rtclock_tick_deadline[mycpu]) < 0) {
        !           753:                decr = deadline_to_decrementer(rtclock.timer_deadline, abstime);
        !           754:                if (    rtclock_decrementer_min != 0                            &&
        !           755:                                rtclock_decrementer_min < (natural_t)decr               )
        !           756:                        decr = rtclock_decrementer_min;
        !           757: 
        !           758:                KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 1)
        !           759:                                                          | DBG_FUNC_NONE, decr, 2, 0, 0, 0);
        !           760: 
        !           761:                mtdec(decr);
        !           762:                rtclock.last_decr[mycpu] = decr;
        !           763:        }
        !           764:        UNLOCK_RTC(s);
        !           765: }
        !           766: 
        !           767: void
        !           768: clock_set_timer_func(
        !           769:        clock_timer_func_t              func)
        !           770: {
        !           771:        spl_t           s;
        !           772: 
        !           773:        LOCK_RTC(s);
        !           774:        if (rtclock.timer_expire == NULL)
        !           775:                rtclock.timer_expire = func;
        !           776:        UNLOCK_RTC(s);
        !           777: }
        !           778: 
        !           779: /*
        !           780:  * Reset the clock device. This causes the realtime clock
        !           781:  * device to reload its mode and count value (frequency).
        !           782:  */
        !           783: void
        !           784: rtclock_reset(void)
        !           785: {
        !           786:        return;
        !           787: }
        !           788: 
        !           789: /*
        !           790:  * Real-time clock device interrupt.
        !           791:  */
        !           792: void
        !           793: rtclock_intr(
        !           794:        int                                             device,
        !           795:        struct ppc_saved_state  *ssp,
        !           796:        spl_t                                   old_spl)
        !           797: {
        !           798:        AbsoluteTime                    abstime;
        !           799:        mach_timespec_t                 timespec;
        !           800:        int                                             decr[4], mycpu = cpu_number();
        !           801:        spl_t                                   s;
        !           802: 
        !           803:        /*
        !           804:         * We may receive interrupts too early, we must reject them.
        !           805:         */
        !           806:        if (rtclock_initialized == FALSE) {
        !           807:                mtdec(DECREMENTER_MAX);         /* Max the decrementer if not init */
        !           808:                return;
        !           809:        }
        !           810: 
        !           811:        decr[1] = decr[2] = decr[3] = DECREMENTER_MAX;
        !           812: 
        !           813:        LOCK_RTC(s);
        !           814: 
        !           815:        rtclock.intr_entry++;
        !           816: 
        !           817:        clock_get_uptime(&abstime);
        !           818:        rtclock.last_abstime[mycpu] = abstime;
        !           819:        if (CMP_ABSOLUTETIME(&rtclock_tick_deadline[mycpu], &abstime) <= 0) {
        !           820:                clock_deadline_for_periodic_event(rtclock_tick_interval, abstime,
        !           821:                                                                                                &rtclock_tick_deadline[mycpu]);
        !           822:                UNLOCK_RTC(s);
        !           823: 
        !           824:                hertz_tick(USER_MODE(ssp->srr1), ssp->srr0);
        !           825: 
        !           826:                LOCK_RTC(s);
        !           827:        }
        !           828: 
        !           829:        if (rtclock.timer_is_set &&
        !           830:                        CMP_ABSOLUTETIME(&rtclock.timer_deadline, &abstime) <= 0) {
        !           831:                rtclock.timer_is_set = FALSE;
        !           832:                UNLOCK_RTC(s);
        !           833: 
        !           834:                (*rtclock.timer_expire)(abstime);
        !           835: 
        !           836:                LOCK_RTC(s);
        !           837:        }
        !           838: 
        !           839:        if (rtclock.alarm_is_set &&
        !           840:                        CMP_ABSOLUTETIME(&rtclock.alarm_deadline, &abstime) <= 0) {
        !           841:                absolutetime_to_timespec_internal(abstime, &timespec);
        !           842:                rtclock.alarm_is_set = FALSE;
        !           843:                UNLOCK_RTC(s);
        !           844: 
        !           845:                clock_alarm_intr(SYSTEM_CLOCK, &timespec);
        !           846: 
        !           847:                LOCK_RTC(s);
        !           848:        }
        !           849: 
        !           850:        clock_get_uptime(&abstime);
        !           851:        rtclock.last_abstime[mycpu] = abstime;
        !           852:        decr[1] = deadline_to_decrementer(rtclock_tick_deadline[mycpu], abstime);
        !           853: 
        !           854:        if (rtclock.timer_is_set)
        !           855:                decr[2] = deadline_to_decrementer(rtclock.timer_deadline, abstime);
        !           856: 
        !           857:        if (rtclock.alarm_is_set)
        !           858:                decr[3] = deadline_to_decrementer(rtclock.alarm_deadline, abstime);
        !           859: 
        !           860:        if (decr[1] > decr[2])
        !           861:                decr[1] = decr[2];
        !           862: 
        !           863:        if (decr[1] > decr[3])
        !           864:                decr[1] = decr[3];
        !           865: 
        !           866:        if (    rtclock_decrementer_min != 0                                    &&
        !           867:                        rtclock_decrementer_min < (natural_t)decr[1]            )
        !           868:                decr[1] = rtclock_decrementer_min;
        !           869: 
        !           870:        KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 1)
        !           871:                                                  | DBG_FUNC_NONE, decr[1], 3, 0, 0, 0);
        !           872: 
        !           873:        mtdec(decr[1]);
        !           874:        rtclock.last_decr[mycpu] = decr[1];
        !           875: 
        !           876:        rtclock.intr_exit++;
        !           877: 
        !           878:        UNLOCK_RTC(s);
        !           879: }
        !           880: 
        !           881: void
        !           882: clock_get_uptime(
        !           883:        AbsoluteTime    *result)
        !           884: {
        !           885:        natural_t       hi, lo, hic;
        !           886: 
        !           887:        do {
        !           888:                asm volatile("  mftbu %0" : "=r" (hi));
        !           889:                asm volatile("  mftb %0" : "=r" (lo));
        !           890:                asm volatile("  mftbu %0" : "=r" (hic));
        !           891:        } while (hic != hi);
        !           892: 
        !           893:        result->lo = lo;
        !           894:        result->hi = hi;
        !           895: }
        !           896: 
        !           897: static int
        !           898: deadline_to_decrementer(
        !           899:        AbsoluteTime            deadline,
        !           900:        AbsoluteTime            now)
        !           901: {
        !           902:        abstime_scalar_t        delt;
        !           903: 
        !           904:        if (CMP_ABSOLUTETIME(&deadline, &now) <= 0)
        !           905:                return DECREMENTER_MIN;
        !           906:        else {
        !           907:                delt = AbsoluteTime_to_scalar(&deadline) -
        !           908:                                                                        AbsoluteTime_to_scalar(&now);
        !           909:                return (delt >= (DECREMENTER_MAX + 1))? DECREMENTER_MAX:
        !           910:                                ((delt >= (DECREMENTER_MIN + 1))? (delt - 1): DECREMENTER_MIN);
        !           911:        }
        !           912: }
        !           913: 
        !           914: static void
        !           915: absolutetime_to_timespec_internal(
        !           916:        AbsoluteTime                    abstime,
        !           917:        mach_timespec_t                 *result)
        !           918: {
        !           919:        AbsoluteTime                    t64;
        !           920:        natural_t                               t32;
        !           921:        natural_t                               numer, denom;
        !           922: 
        !           923:        numer = rtclock.timebase_const.numer;
        !           924:        denom = rtclock.timebase_const.denom;
        !           925: 
        !           926:        umul_64by32(abstime, numer, &t64, &t32);
        !           927: 
        !           928:        udiv_96by32(t64, t32, denom, &t64, &t32);
        !           929: 
        !           930:        udiv_96by32to32and32(t64, t32, NSEC_PER_SEC,
        !           931:                                                                &result->tv_sec, &result->tv_nsec);
        !           932: }
        !           933: 
        !           934: static void
        !           935: timespec_to_absolutetime_internal(
        !           936:        mach_timespec_t                 timespec,
        !           937:        AbsoluteTime                    *result)
        !           938: {
        !           939:        AbsoluteTime                    t64;
        !           940:        natural_t                               t32;
        !           941:        natural_t                               numer, denom;
        !           942: 
        !           943:        numer = rtclock.timebase_const.numer;
        !           944:        denom = rtclock.timebase_const.denom;
        !           945: 
        !           946:        asm volatile("  mullw %0,%1,%2" :
        !           947:                                                        "=r" (t64.lo) :
        !           948:                                                                "r" (timespec.tv_sec), "r" (NSEC_PER_SEC));
        !           949: 
        !           950:        asm volatile("  mulhwu %0,%1,%2" :
        !           951:                                                        "=r" (t64.hi) :
        !           952:                                                                "r" (timespec.tv_sec), "r" (NSEC_PER_SEC));
        !           953: 
        !           954:        AbsoluteTime_to_scalar(&t64) += timespec.tv_nsec;
        !           955: 
        !           956:        umul_64by32(t64, denom, &t64, &t32);
        !           957: 
        !           958:        udiv_96by32(t64, t32, numer, &t64, &t32);
        !           959: 
        !           960:        result->hi = t64.lo;
        !           961:        result->lo = t32;
        !           962: }
        !           963: 
        !           964: void
        !           965: clock_interval_to_deadline(
        !           966:        natural_t                       interval,
        !           967:        natural_t                       scale_factor,
        !           968:        AbsoluteTime            *result)
        !           969: {
        !           970:        AbsoluteTime            abstime;
        !           971: 
        !           972:        clock_get_uptime(result);
        !           973: 
        !           974:        clock_interval_to_absolutetime_interval(interval, scale_factor, &abstime);
        !           975: 
        !           976:        ADD_ABSOLUTETIME(result, &abstime);
        !           977: }
        !           978: 
        !           979: void
        !           980: clock_interval_to_absolutetime_interval(
        !           981:        natural_t                       interval,
        !           982:        natural_t                       scale_factor,
        !           983:        AbsoluteTime            *result)
        !           984: {
        !           985:        AbsoluteTime            t64;
        !           986:        natural_t                       t32;
        !           987:        natural_t                       numer, denom;
        !           988:        spl_t                           s;
        !           989: 
        !           990:        LOCK_RTC(s);
        !           991:        numer = rtclock.timebase_const.numer;
        !           992:        denom = rtclock.timebase_const.denom;
        !           993:        UNLOCK_RTC(s);
        !           994: 
        !           995:        asm volatile("  mullw %0,%1,%2" :
        !           996:                                                        "=r" (t64.lo) :
        !           997:                                                                "r" (interval), "r" (scale_factor));
        !           998:        asm volatile("  mulhwu %0,%1,%2" :
        !           999:                                                        "=r" (t64.hi) :
        !          1000:                                                                "r" (interval), "r" (scale_factor));
        !          1001: 
        !          1002:        umul_64by32(t64, denom, &t64, &t32);
        !          1003: 
        !          1004:        udiv_96by32(t64, t32, numer, &t64, &t32);
        !          1005: 
        !          1006:        result->hi = t64.lo;
        !          1007:        result->lo = t32;
        !          1008: }
        !          1009: 
        !          1010: void
        !          1011: clock_absolutetime_interval_to_deadline(
        !          1012:        AbsoluteTime            abstime,
        !          1013:        AbsoluteTime            *result)
        !          1014: {
        !          1015:        clock_get_uptime(result);
        !          1016: 
        !          1017:        ADD_ABSOLUTETIME(result, &abstime);
        !          1018: }
        !          1019: 
        !          1020: void
        !          1021: absolutetime_to_nanoseconds(
        !          1022:        AbsoluteTime            abstime,
        !          1023:        UInt64                          *result)
        !          1024: {
        !          1025:        AbsoluteTime            t64;
        !          1026:        natural_t                       t32;
        !          1027:        natural_t                       numer, denom;
        !          1028:        spl_t                           s;
        !          1029: 
        !          1030:        LOCK_RTC(s);
        !          1031:        numer = rtclock.timebase_const.numer;
        !          1032:        denom = rtclock.timebase_const.denom;
        !          1033:        UNLOCK_RTC(s);
        !          1034: 
        !          1035:        umul_64by32(abstime, numer, &t64, &t32);
        !          1036: 
        !          1037:        udiv_96by32to64(t64, t32, denom, (void *)result);
        !          1038: }
        !          1039: 
        !          1040: void
        !          1041: nanoseconds_to_absolutetime(
        !          1042:        UInt64                          nanoseconds,
        !          1043:        AbsoluteTime            *result)
        !          1044: {
        !          1045:        AbsoluteTime            t64;
        !          1046:        natural_t                       t32;
        !          1047:        natural_t                       numer, denom;
        !          1048:        spl_t                           s;
        !          1049: 
        !          1050:        LOCK_RTC(s);
        !          1051:        numer = rtclock.timebase_const.numer;
        !          1052:        denom = rtclock.timebase_const.denom;
        !          1053:        UNLOCK_RTC(s);
        !          1054: 
        !          1055:        AbsoluteTime_to_scalar(&t64) = nanoseconds;
        !          1056: 
        !          1057:        umul_64by32(t64, denom, &t64, &t32);
        !          1058: 
        !          1059:        udiv_96by32to64(t64, t32, numer, result);
        !          1060: }
        !          1061: 
        !          1062: /*
        !          1063:  * Spin-loop delay primitives.
        !          1064:  */
        !          1065: void
        !          1066: delay_for_interval(
        !          1067:        natural_t                       interval,
        !          1068:        natural_t                       scale_factor)
        !          1069: {
        !          1070:        AbsoluteTime            now, end;
        !          1071: 
        !          1072:        clock_interval_to_deadline(interval, scale_factor, &end);
        !          1073: 
        !          1074:        do {
        !          1075:                clock_get_uptime(&now);
        !          1076:        } while (CMP_ABSOLUTETIME(&now, &end) < 0);
        !          1077: }
        !          1078: 
        !          1079: void
        !          1080: clock_delay_until(
        !          1081:        AbsoluteTime            deadline)
        !          1082: {
        !          1083:        AbsoluteTime            now;
        !          1084: 
        !          1085:        do {
        !          1086:                clock_get_uptime(&now);
        !          1087:        } while (CMP_ABSOLUTETIME(&now, &deadline) < 0);
        !          1088: }
        !          1089: 
        !          1090: void
        !          1091: delay(
        !          1092:        int                     usec)
        !          1093: {
        !          1094:        delay_for_interval((usec < 0)? -usec: usec, NSEC_PER_USEC);
        !          1095: }

unix.superglobalmegacorp.com

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