netlib.narod.ru< Назад | Оглавление | Далее >

kernel/time.c

31331 /*
31332  *  linux/kernel/time.c
31333  *
31334  *  Copyright (C) 1991, 1992  Linus Torvalds
31335  *
31336  *  This file contains the interface functions for the
31337  *  various time related system calls: time, stime,
31338  *  gettimeofday, settimeofday, adjtime */
31339 /*
31340  * Modification history kernel/time.c
31341  *
31342  * 1993-09-02    Philip Gladstone
31343  *      Created file with time related functions from
31344  *      sched.c and adjtimex()
31345  * 1993-10-08    Torsten Duwe
31346  *      adjtime interface update and CMOS clock write
31347  *      code
31348  * 1995-08-13    Torsten Duwe
31349  *      kernel PLL updated to 1994-12-13 specs (rfc-1589)
31350  * 1999-01-16    Ulrich Windl
31351  *      Introduced error checking for many cases in
31352  *      adjtimex().  Updated NTP code according to
31353  *      technical memorandum Jan '96 "A Kernel Model for
31354  *      Precision Timekeeping" by Dave Mills Allow
31355  *      time_constant larger than MAXTC(6) for NTP v4
31356  *      (MAXTC == 10) (Even though the technical
31357  *      memorandum forbids it) */
31358 
31359 #include <linux/mm.h>
31360 #include <linux/timex.h>
31361 #include <linux/smp_lock.h>
31362 
31363 #include <asm/uaccess.h>
31364 
31365 /* The timezone where the local system is located.  Used
31366  * as a default by some programs who obtain this value by
31367  * using gettimeofday.  */
31368 struct timezone sys_tz = { 0, 0};
31369 
31370 static void do_normal_gettime(struct timeval * tm)
31371 {
31372   *tm=xtime;
31373 }
31374 
31375 void (*do_get_fast_time)(struct timeval *) =
31376   do_normal_gettime;
31377 
31378 /* Generic way to access 'xtime' (the current time of
31379  * day).  This can be changed if the platform provides a
31380  * more accurate (and fast!)  version.  */
31381 
31382 void get_fast_time(struct timeval * t)
31383 {
31384   do_get_fast_time(t);
31385 }
31386 
31387 #ifndef __alpha__
31388 
31389 /* sys_time() can be implemented in user-level using
31390  * sys_gettimeofday().  Is this for backwards
31391  * compatibility?  If so, why not move it into the
31392  * appropriate arch directory (for those architectures
31393  * that need it).  */
 Комментарий
31394 asmlinkage int sys_time(int * tloc)
31395 {
31396   int i;
31397 
31398   /* SMP: This is fairly trivial. We grab CURRENT_TIME
31399    * and stuff it to user space. No side effects */
31400   i = CURRENT_TIME;
31401   if (tloc) {
31402     if (put_user(i,tloc))
31403       i = -EFAULT;
31404   }
31405   return i;
31406 }
31407 
31408 /* sys_stime() can be implemented in user-level using
31409  * sys_settimeofday().  Is this for backwards
31410  * compatibility?  If so, why not move it into the
31411  * appropriate arch directory (for those architectures
31412  * that need it).  */
31413 asmlinkage int sys_stime(int * tptr)
31414 {
31415   int value;
31416 
31417   if (!capable(CAP_SYS_TIME))
31418     return -EPERM;
31419   if (get_user(value, tptr))
31420     return -EFAULT;
31421   cli();
31422   xtime.tv_sec = value;
31423   xtime.tv_usec = 0;
31424   time_adjust = 0;        /* stop active adjtime() */
31425   time_status |= STA_UNSYNC;
31426   time_maxerror = NTP_PHASE_LIMIT;
31427   time_esterror = NTP_PHASE_LIMIT;
31428   sti();
31429   return 0;
31430 }
31431 
31432 #endif
31433 
31434 asmlinkage int sys_gettimeofday(struct timeval *tv,
31435                                 struct timezone *tz)
31436 {
31437   if (tv) {
31438     struct timeval ktv;
31439     do_gettimeofday(&ktv);
31440     if (copy_to_user(tv, &ktv, sizeof(ktv)))
31441       return -EFAULT;
31442   }
31443   if (tz) {
31444     if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
31445       return -EFAULT;
31446   }
31447   return 0;
31448 }
31449 
31450 /* Adjust the time obtained from the CMOS to be UTC time
31451  * instead of local time.
31452  *
31453  * This is ugly, but preferable to the alternatives.
31454  * Otherwise we would either need to write a program to
31455  * do it in /etc/rc (and risk confusion if the program
31456  * gets run more than once; it would also be hard to make
31457  * the program warp the clock precisely n hours) or
31458  * compile in the timezone information into the kernel.
31459  * Bad, bad....
31460  *
31461  *  - TYT, 1992-01-01
31462  *
31463  * The best thing to do is to keep the CMOS clock in
31464  * universal time (UTC) as real UNIX machines always do
31465  * it. This avoids all headaches about daylight saving
31466  * times and warping kernel clocks.  */
31467 inline static void warp_clock(void)
31468 {
31469   cli();
31470   xtime.tv_sec += sys_tz.tz_minuteswest * 60;
31471   sti();
31472 }
31473 
31474 /* In case for some reason the CMOS clock has not already
31475  * been running in UTC, but in some local time: The first
31476  * time we set the timezone, we will warp the clock so
31477  * that it is ticking UTC time instead of local
31478  * time. Presumably, if someone is setting the timezone
31479  * then we are running in an environment where the
31480  * programs understand about timezones. This should be
31481  * done at boot time in the /etc/rc script, as soon as
31482  * possible, so that the clock can be set
31483  * right. Otherwise, various programs will get confused
31484  * when the clock gets warped.  */
31485 int do_sys_settimeofday(struct timeval *tv,
31486                         struct timezone *tz)
31487 {
31488   static int firsttime = 1;
31489 
31490   if (!capable(CAP_SYS_TIME))
31491     return -EPERM;
31492 
31493   if (tz) {
31494     /* SMP safe, global irq locking makes it work. */
31495     sys_tz = *tz;
31496     if (firsttime) {
31497       firsttime = 0;
31498       if (!tv)
31499         warp_clock();
31500     }
31501   }
31502   if (tv)
31503   {
31504     /* SMP safe, again the code in arch/foo/time.c should
31505      * globally block out interrupts when it runs.
31506      */
31507     do_settimeofday(tv);
31508   }
31509   return 0;
31510 }
31511 
31512 asmlinkage int sys_settimeofday(struct timeval *tv,
31513                                 struct timezone *tz)
31514 {
31515   struct timeval  new_tv;
31516   struct timezone new_tz;
31517 
31518   if (tv) {
31519     if (copy_from_user(&new_tv, tv, sizeof(*tv)))
31520       return -EFAULT;
31521   }
31522   if (tz) {
31523     if (copy_from_user(&new_tz, tz, sizeof(*tz)))
31524       return -EFAULT;
31525   }
31526 
31527   return do_sys_settimeofday(tv ? &new_tv : NULL,
31528                              tz ? &new_tz : NULL);
31529 }
31530 
31531 long pps_offset = 0;        /* pps time offset (us) */
31532 long pps_jitter = MAXTIME;  /* time dispersion (jitter)
31533                                (us) */
31534 long pps_freq = 0;          /* frequency offset (scaled
31535                                ppm) */
31536 long pps_stabil = MAXFREQ;  /* frequency dispersion
31537                                (scaled ppm) */
31538 long pps_valid = PPS_VALID; /* pps signal watchdog
31539                                counter */
31540 int pps_shift = PPS_SHIFT;  /* interval duration (s)
31541                                (shift) */
31542 long pps_jitcnt = 0;        /* jitter limit exceeded */
31543 long pps_calcnt = 0;        /* calibration intervals */
31544 long pps_errcnt = 0;        /* calibration errors */
31545 long pps_stbcnt = 0;        /* stability limit exceeded*/
31546 
31547 /* hook for a loadable hardpps kernel module */
31548 void (*hardpps_ptr)(struct timeval *) =
31549   (void (*)(struct timeval *))0;
31550 
31551 /* adjtimex mainly allows reading (and writing, if
31552  * superuser) of kernel time-keeping variables. used by
31553  * xntpd.  */
31554 int do_adjtimex(struct timex *txc)
31555 {
31556   long ltemp, mtemp, save_adjust;
31557   int result = time_state;        /* mostly `TIME_OK' */
31558 
31559   /* In order to modify anything, you gotta be
31560    * super-user! */
31561   if (txc->modes && !capable(CAP_SYS_TIME))
31562     return -EPERM;
31563 
31564   /* Now we validate the data before disabling interrupts
31565    */
31566   if (txc->modes != ADJ_OFFSET_SINGLESHOT &&
31567       (txc->modes & ADJ_OFFSET))
31568     /* adjustment Offset limited to +- .512 seconds */
31569     if (txc->offset <= - MAXPHASE ||
31570         txc->offset >= MAXPHASE)
31571       return -EINVAL;
31572 
31573   /* if the quartz is off by more than 10% something is
31574    * VERY wrong ! */
31575   if (txc->modes & ADJ_TICK)
31576     if (txc->tick < 900000/HZ || txc->tick > 1100000/HZ)
31577       return -EINVAL;
31578 
31579   cli(); /* SMP: global cli() is enough protection. */
31580 
31581   /* Save for later - semantics of adjtime is to return
31582    * old value */
31583   save_adjust = time_adjust;
31584 
31585 #if 0   /* STA_CLOCKERR is never set yet */
31586   time_status &= ~STA_CLOCKERR; /* reset STA_CLOCKERR */
31587 #endif
31588   /* If there are input parameters, then process them */
31589   if (txc->modes)
31590   {
31591     if (txc->modes & ADJ_STATUS)
31592       /* only set allowed bits */
31593       time_status =  (txc->status & ~STA_RONLY) |
31594         (time_status & STA_RONLY);
31595 
31596     if (txc->modes & ADJ_FREQUENCY) {   /* p. 22 */
31597       if (txc->freq > MAXFREQ || txc->freq < -MAXFREQ){
31598         result = -EINVAL;
31599         goto leave;
31600       }
31601       time_freq = txc->freq - pps_freq;
31602     }
31603 
31604     if (txc->modes & ADJ_MAXERROR) {
31605       if (txc->maxerror < 0 ||
31606           txc->maxerror >= NTP_PHASE_LIMIT) {
31607         result = -EINVAL;
31608         goto leave;
31609       }
31610       time_maxerror = txc->maxerror;
31611     }
31612 
31613     if (txc->modes & ADJ_ESTERROR) {
31614       if (txc->esterror < 0 ||
31615           txc->esterror >= NTP_PHASE_LIMIT) {
31616         result = -EINVAL;
31617         goto leave;
31618       }
31619       time_esterror = txc->esterror;
31620     }
31621 
31622     if (txc->modes & ADJ_TIMECONST) {   /* p. 24 */
31623       if (txc->constant < 0) { /*NTP v4 uses values > 6*/
31624         result = -EINVAL;
31625         goto leave;
31626       }
31627       time_constant = txc->constant;
31628     }
31629 
31630     /* values checked earlier */
31631     if (txc->modes & ADJ_OFFSET) {
31632       if (txc->modes == ADJ_OFFSET_SINGLESHOT) {
31633         /* adjtime() is independent from ntp_adjtime() */
31634         time_adjust = txc->offset;
31635       }
31636       else if ( time_status & (STA_PLL | STA_PPSTIME) ) {
31637         ltemp =
31638           (time_status & (STA_PPSTIME | STA_PPSSIGNAL))
31639           == (STA_PPSTIME | STA_PPSSIGNAL)
31640           ? pps_offset : txc->offset;
31641 
31642         /* Scale the phase adjustment and clamp to the
31643          * operating range.  */
31644         if (ltemp > MAXPHASE)
31645           time_offset = MAXPHASE << SHIFT_UPDATE;
31646         else if (ltemp < -MAXPHASE)
31647           time_offset = -(MAXPHASE << SHIFT_UPDATE);
31648         else
31649           time_offset = ltemp << SHIFT_UPDATE;
31650 
31651         /* Select whether the frequency is to be
31652          * controlled and in which mode (PLL or
31653          * FLL). Clamp to the operating range. Ugly
31654          * multiply/divide should be replaced someday.
31655          */
31656 
31657         if (time_status & STA_FREQHOLD ||
31658             time_reftime == 0)
31659           time_reftime = xtime.tv_sec;
31660         mtemp = xtime.tv_sec - time_reftime;
31661         time_reftime = xtime.tv_sec;
31662         if (time_status & STA_FLL) {
31663           if (mtemp >= MINSEC) {
31664             ltemp = (time_offset / mtemp) <<
31665                              (SHIFT_USEC - SHIFT_UPDATE);
31666             if (ltemp < 0)
31667               time_freq -= -ltemp >> SHIFT_KH;
31668             else
31669               time_freq += ltemp >> SHIFT_KH;
31670           } else
31671             /* calibration interval too short (p. 12) */
31672             result = TIME_ERROR;
31673         } else {                /* PLL mode */
31674           if (mtemp < MAXSEC) {
31675             ltemp *= mtemp;
31676             if (ltemp < 0)
31677               time_freq -= -ltemp >>
31678                 (time_constant +
31679                  time_constant +
31680                  SHIFT_KF - SHIFT_USEC);
31681             else
31682               time_freq += ltemp >>
31683                 (time_constant +
31684                  time_constant +
31685                  SHIFT_KF - SHIFT_USEC);
31686           } else
31687             /* calibration interval too long (p. 12) */
31688             result = TIME_ERROR;
31689         }
31690         if (time_freq > time_tolerance)
31691           time_freq = time_tolerance;
31692         else if (time_freq < -time_tolerance)
31693           time_freq = -time_tolerance;
31694       } /* STA_PLL || STA_PPSTIME */
31695     } /* txc->modes & ADJ_OFFSET */
31696     if (txc->modes & ADJ_TICK) {
31697       /* if the quartz is off by more than 10% something
31698          is VERY wrong ! */
31699       if (txc->tick < 900000/HZ ||
31700           txc->tick > 1100000/HZ) {
31701         result = -EINVAL;
31702         goto leave;
31703       }
31704       tick = txc->tick;
31705     }
31706   } /* txc->modes */
31707  leave:
31708   if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0
31709       || ((time_status & (STA_PPSFREQ|STA_PPSTIME)) != 0
31710           && (time_status & STA_PPSSIGNAL) == 0)
31711       /* p. 24, (b) */
31712       || ((time_status & (STA_PPSTIME|STA_PPSJITTER))
31713           == (STA_PPSTIME|STA_PPSJITTER))
31714       /* p. 24, (c) */
31715       || ((time_status & STA_PPSFREQ) != 0
31716           && (time_status &
31717               (STA_PPSWANDER|STA_PPSERROR)) != 0))
31718     /* p. 24, (d) */
31719     result = TIME_ERROR;
31720 
31721   if ((txc->modes & ADJ_OFFSET_SINGLESHOT) ==
31722       ADJ_OFFSET_SINGLESHOT)
31723     txc->offset    = save_adjust;
31724   else {
31725     if (time_offset < 0)
31726       txc->offset = -(-time_offset >> SHIFT_UPDATE);
31727     else
31728       txc->offset = time_offset >> SHIFT_UPDATE;
31729   }
31730   txc->freq          = time_freq + pps_freq;
31731   txc->maxerror      = time_maxerror;
31732   txc->esterror      = time_esterror;
31733   txc->status        = time_status;
31734   txc->constant      = time_constant;
31735   txc->precision     = time_precision;
31736   txc->tolerance     = time_tolerance;
31737   do_gettimeofday(&txc->time);
31738   txc->tick          = tick;
31739   txc->ppsfreq       = pps_freq;
31740   txc->jitter        = pps_jitter >> PPS_AVG;
31741   txc->shift         = pps_shift;
31742   txc->stabil        = pps_stabil;
31743   txc->jitcnt        = pps_jitcnt;
31744   txc->calcnt        = pps_calcnt;
31745   txc->errcnt        = pps_errcnt;
31746   txc->stbcnt        = pps_stbcnt;
31747 
31748   sti();
31749   return(result);
31750 }
31751 
31752 asmlinkage int sys_adjtimex(struct timex *txc_p)
31753 {
31754   struct timex txc;  /* Local copy of parameter */
31755   int ret;
31756 
31757   /* Copy the user data space into the kernel copy
31758    * structure. But bear in mind that the structures may
31759    * change */
31760   if(copy_from_user(&txc, txc_p, sizeof(struct timex)))
31761     return -EFAULT;
31762   ret = do_adjtimex(&txc);
31763   return copy_to_user(txc_p, &txc, sizeof(struct timex))
31764     ? -EFAULT : ret;
31765 }

netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz