Annotation of XNU/osfmk/ppc/rtclock.c, revision 1.1.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.