~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/kernel/time.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  linux/kernel/time.c
  3  *
  4  *  Copyright (C) 1991, 1992  Linus Torvalds
  5  *
  6  *  This file contains the interface functions for the various
  7  *  time related system calls: time, stime, gettimeofday, settimeofday,
  8  *                             adjtime
  9  */
 10 /*
 11  * Modification history kernel/time.c
 12  * 
 13  * 1993-09-02    Philip Gladstone
 14  *      Created file with time related functions from sched.c and adjtimex() 
 15  * 1993-10-08    Torsten Duwe
 16  *      adjtime interface update and CMOS clock write code
 17  * 1995-08-13    Torsten Duwe
 18  *      kernel PLL updated to 1994-12-13 specs (rfc-1589)
 19  * 1999-01-16    Ulrich Windl
 20  *      Introduced error checking for many cases in adjtimex().
 21  *      Updated NTP code according to technical memorandum Jan '96
 22  *      "A Kernel Model for Precision Timekeeping" by Dave Mills
 23  *      Allow time_constant larger than MAXTC(6) for NTP v4 (MAXTC == 10)
 24  *      (Even though the technical memorandum forbids it)
 25  */
 26 
 27 #include <linux/mm.h>
 28 #include <linux/timex.h>
 29 #include <linux/smp_lock.h>
 30 
 31 #include <asm/uaccess.h>
 32 
 33 /* 
 34  * The timezone where the local system is located.  Used as a default by some
 35  * programs who obtain this value by using gettimeofday.
 36  */
 37 struct timezone sys_tz;
 38 
 39 static void do_normal_gettime(struct timeval * tm)
 40 {
 41         *tm=xtime;
 42 }
 43 
 44 void (*do_get_fast_time)(struct timeval *) = do_normal_gettime;
 45 
 46 /*
 47  * Generic way to access 'xtime' (the current time of day).
 48  * This can be changed if the platform provides a more accurate (and fast!) 
 49  * version.
 50  */
 51 
 52 void get_fast_time(struct timeval * t)
 53 {
 54         do_get_fast_time(t);
 55 }
 56 
 57 /* The xtime_lock is not only serializing the xtime read/writes but it's also
 58    serializing all accesses to the global NTP variables now. */
 59 extern rwlock_t xtime_lock;
 60 
 61 #if !defined(__alpha__) && !defined(__ia64__)
 62 
 63 /*
 64  * sys_time() can be implemented in user-level using
 65  * sys_gettimeofday().  Is this for backwards compatibility?  If so,
 66  * why not move it into the appropriate arch directory (for those
 67  * architectures that need it).
 68  *
 69  * XXX This function is NOT 64-bit clean!
 70  */
 71 asmlinkage long sys_time(int * tloc)
 72 {
 73         int i;
 74 
 75         /* SMP: This is fairly trivial. We grab CURRENT_TIME and 
 76            stuff it to user space. No side effects */
 77         i = CURRENT_TIME;
 78         if (tloc) {
 79                 if (put_user(i,tloc))
 80                         i = -EFAULT;
 81         }
 82         return i;
 83 }
 84 
 85 /*
 86  * sys_stime() can be implemented in user-level using
 87  * sys_settimeofday().  Is this for backwards compatibility?  If so,
 88  * why not move it into the appropriate arch directory (for those
 89  * architectures that need it).
 90  */
 91  
 92 asmlinkage long sys_stime(int * tptr)
 93 {
 94         int value;
 95 
 96         if (!capable(CAP_SYS_TIME))
 97                 return -EPERM;
 98         if (get_user(value, tptr))
 99                 return -EFAULT;
100         write_lock_irq(&xtime_lock);
101         xtime.tv_sec = value;
102         xtime.tv_usec = 0;
103         time_adjust = 0;        /* stop active adjtime() */
104         time_status |= STA_UNSYNC;
105         time_maxerror = NTP_PHASE_LIMIT;
106         time_esterror = NTP_PHASE_LIMIT;
107         write_unlock_irq(&xtime_lock);
108         return 0;
109 }
110 
111 #endif
112 
113 asmlinkage long sys_gettimeofday(struct timeval *tv, struct timezone *tz)
114 {
115         if (tv) {
116                 struct timeval ktv;
117                 do_gettimeofday(&ktv);
118                 if (copy_to_user(tv, &ktv, sizeof(ktv)))
119                         return -EFAULT;
120         }
121         if (tz) {
122                 if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
123                         return -EFAULT;
124         }
125         return 0;
126 }
127 
128 /*
129  * Adjust the time obtained from the CMOS to be UTC time instead of
130  * local time.
131  * 
132  * This is ugly, but preferable to the alternatives.  Otherwise we
133  * would either need to write a program to do it in /etc/rc (and risk
134  * confusion if the program gets run more than once; it would also be 
135  * hard to make the program warp the clock precisely n hours)  or
136  * compile in the timezone information into the kernel.  Bad, bad....
137  *
138  *                                              - TYT, 1992-01-01
139  *
140  * The best thing to do is to keep the CMOS clock in universal time (UTC)
141  * as real UNIX machines always do it. This avoids all headaches about
142  * daylight saving times and warping kernel clocks.
143  */
144 inline static void warp_clock(void)
145 {
146         write_lock_irq(&xtime_lock);
147         xtime.tv_sec += sys_tz.tz_minuteswest * 60;
148         write_unlock_irq(&xtime_lock);
149 }
150 
151 /*
152  * In case for some reason the CMOS clock has not already been running
153  * in UTC, but in some local time: The first time we set the timezone,
154  * we will warp the clock so that it is ticking UTC time instead of
155  * local time. Presumably, if someone is setting the timezone then we
156  * are running in an environment where the programs understand about
157  * timezones. This should be done at boot time in the /etc/rc script,
158  * as soon as possible, so that the clock can be set right. Otherwise,
159  * various programs will get confused when the clock gets warped.
160  */
161 
162 int do_sys_settimeofday(struct timeval *tv, struct timezone *tz)
163 {
164         static int firsttime = 1;
165 
166         if (!capable(CAP_SYS_TIME))
167                 return -EPERM;
168                 
169         if (tz) {
170                 /* SMP safe, global irq locking makes it work. */
171                 sys_tz = *tz;
172                 if (firsttime) {
173                         firsttime = 0;
174                         if (!tv)
175                                 warp_clock();
176                 }
177         }
178         if (tv)
179         {
180                 /* SMP safe, again the code in arch/foo/time.c should
181                  * globally block out interrupts when it runs.
182                  */
183                 do_settimeofday(tv);
184         }
185         return 0;
186 }
187 
188 asmlinkage long sys_settimeofday(struct timeval *tv, struct timezone *tz)
189 {
190         struct timeval  new_tv;
191         struct timezone new_tz;
192 
193         if (tv) {
194                 if (copy_from_user(&new_tv, tv, sizeof(*tv)))
195                         return -EFAULT;
196         }
197         if (tz) {
198                 if (copy_from_user(&new_tz, tz, sizeof(*tz)))
199                         return -EFAULT;
200         }
201 
202         return do_sys_settimeofday(tv ? &new_tv : NULL, tz ? &new_tz : NULL);
203 }
204 
205 long pps_offset;                /* pps time offset (us) */
206 long pps_jitter = MAXTIME;      /* time dispersion (jitter) (us) */
207 
208 long pps_freq;                  /* frequency offset (scaled ppm) */
209 long pps_stabil = MAXFREQ;      /* frequency dispersion (scaled ppm) */
210 
211 long pps_valid = PPS_VALID;     /* pps signal watchdog counter */
212 
213 int pps_shift = PPS_SHIFT;      /* interval duration (s) (shift) */
214 
215 long pps_jitcnt;                /* jitter limit exceeded */
216 long pps_calcnt;                /* calibration intervals */
217 long pps_errcnt;                /* calibration errors */
218 long pps_stbcnt;                /* stability limit exceeded */
219 
220 /* hook for a loadable hardpps kernel module */
221 void (*hardpps_ptr)(struct timeval *);
222 
223 /* adjtimex mainly allows reading (and writing, if superuser) of
224  * kernel time-keeping variables. used by xntpd.
225  */
226 int do_adjtimex(struct timex *txc)
227 {
228         long ltemp, mtemp, save_adjust;
229         int result;
230 
231         /* In order to modify anything, you gotta be super-user! */
232         if (txc->modes && !capable(CAP_SYS_TIME))
233                 return -EPERM;
234                 
235         /* Now we validate the data before disabling interrupts */
236 
237         if (txc->modes != ADJ_OFFSET_SINGLESHOT && (txc->modes & ADJ_OFFSET))
238           /* adjustment Offset limited to +- .512 seconds */
239                 if (txc->offset <= - MAXPHASE || txc->offset >= MAXPHASE )
240                         return -EINVAL; 
241 
242         /* if the quartz is off by more than 10% something is VERY wrong ! */
243         if (txc->modes & ADJ_TICK)
244                 if (txc->tick < 900000/HZ || txc->tick > 1100000/HZ)
245                         return -EINVAL;
246 
247         write_lock_irq(&xtime_lock);
248         result = time_state;    /* mostly `TIME_OK' */
249 
250         /* Save for later - semantics of adjtime is to return old value */
251         save_adjust = time_adjust;
252 
253 #if 0   /* STA_CLOCKERR is never set yet */
254         time_status &= ~STA_CLOCKERR;           /* reset STA_CLOCKERR */
255 #endif
256         /* If there are input parameters, then process them */
257         if (txc->modes)
258         {
259             if (txc->modes & ADJ_STATUS)        /* only set allowed bits */
260                 time_status =  (txc->status & ~STA_RONLY) |
261                               (time_status & STA_RONLY);
262 
263             if (txc->modes & ADJ_FREQUENCY) {   /* p. 22 */
264                 if (txc->freq > MAXFREQ || txc->freq < -MAXFREQ) {
265                     result = -EINVAL;
266                     goto leave;
267                 }
268                 time_freq = txc->freq - pps_freq;
269             }
270 
271             if (txc->modes & ADJ_MAXERROR) {
272                 if (txc->maxerror < 0 || txc->maxerror >= NTP_PHASE_LIMIT) {
273                     result = -EINVAL;
274                     goto leave;
275                 }
276                 time_maxerror = txc->maxerror;
277             }
278 
279             if (txc->modes & ADJ_ESTERROR) {
280                 if (txc->esterror < 0 || txc->esterror >= NTP_PHASE_LIMIT) {
281                     result = -EINVAL;
282                     goto leave;
283                 }
284                 time_esterror = txc->esterror;
285             }
286 
287             if (txc->modes & ADJ_TIMECONST) {   /* p. 24 */
288                 if (txc->constant < 0) {        /* NTP v4 uses values > 6 */
289                     result = -EINVAL;
290                     goto leave;
291                 }
292                 time_constant = txc->constant;
293             }
294 
295             if (txc->modes & ADJ_OFFSET) {      /* values checked earlier */
296                 if (txc->modes == ADJ_OFFSET_SINGLESHOT) {
297                     /* adjtime() is independent from ntp_adjtime() */
298                     time_adjust = txc->offset;
299                 }
300                 else if ( time_status & (STA_PLL | STA_PPSTIME) ) {
301                     ltemp = (time_status & (STA_PPSTIME | STA_PPSSIGNAL)) ==
302                             (STA_PPSTIME | STA_PPSSIGNAL) ?
303                             pps_offset : txc->offset;
304 
305                     /*
306                      * Scale the phase adjustment and
307                      * clamp to the operating range.
308                      */
309                     if (ltemp > MAXPHASE)
310                         time_offset = MAXPHASE << SHIFT_UPDATE;
311                     else if (ltemp < -MAXPHASE)
312                         time_offset = -(MAXPHASE << SHIFT_UPDATE);
313                     else
314                         time_offset = ltemp << SHIFT_UPDATE;
315 
316                     /*
317                      * Select whether the frequency is to be controlled
318                      * and in which mode (PLL or FLL). Clamp to the operating
319                      * range. Ugly multiply/divide should be replaced someday.
320                      */
321 
322                     if (time_status & STA_FREQHOLD || time_reftime == 0)
323                         time_reftime = xtime.tv_sec;
324                     mtemp = xtime.tv_sec - time_reftime;
325                     time_reftime = xtime.tv_sec;
326                     if (time_status & STA_FLL) {
327                         if (mtemp >= MINSEC) {
328                             ltemp = (time_offset / mtemp) << (SHIFT_USEC -
329                                                               SHIFT_UPDATE);
330                             if (ltemp < 0)
331                                 time_freq -= -ltemp >> SHIFT_KH;
332                             else
333                                 time_freq += ltemp >> SHIFT_KH;
334                         } else /* calibration interval too short (p. 12) */
335                                 result = TIME_ERROR;
336                     } else {    /* PLL mode */
337                         if (mtemp < MAXSEC) {
338                             ltemp *= mtemp;
339                             if (ltemp < 0)
340                                 time_freq -= -ltemp >> (time_constant +
341                                                         time_constant +
342                                                         SHIFT_KF - SHIFT_USEC);
343                             else
344                                 time_freq += ltemp >> (time_constant +
345                                                        time_constant +
346                                                        SHIFT_KF - SHIFT_USEC);
347                         } else /* calibration interval too long (p. 12) */
348                                 result = TIME_ERROR;
349                     }
350                     if (time_freq > time_tolerance)
351                         time_freq = time_tolerance;
352                     else if (time_freq < -time_tolerance)
353                         time_freq = -time_tolerance;
354                 } /* STA_PLL || STA_PPSTIME */
355             } /* txc->modes & ADJ_OFFSET */
356             if (txc->modes & ADJ_TICK) {
357                 /* if the quartz is off by more than 10% something is
358                    VERY wrong ! */
359                 if (txc->tick < 900000/HZ || txc->tick > 1100000/HZ) {
360                     result = -EINVAL;
361                     goto leave;
362                 }
363                 tick = txc->tick;
364             }
365         } /* txc->modes */
366 leave:  if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0
367             || ((time_status & (STA_PPSFREQ|STA_PPSTIME)) != 0
368                 && (time_status & STA_PPSSIGNAL) == 0)
369             /* p. 24, (b) */
370             || ((time_status & (STA_PPSTIME|STA_PPSJITTER))
371                 == (STA_PPSTIME|STA_PPSJITTER))
372             /* p. 24, (c) */
373             || ((time_status & STA_PPSFREQ) != 0
374                 && (time_status & (STA_PPSWANDER|STA_PPSERROR)) != 0))
375             /* p. 24, (d) */
376                 result = TIME_ERROR;
377         
378         if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT)
379             txc->offset    = save_adjust;
380         else {
381             if (time_offset < 0)
382                 txc->offset = -(-time_offset >> SHIFT_UPDATE);
383             else
384                 txc->offset = time_offset >> SHIFT_UPDATE;
385         }
386         txc->freq          = time_freq + pps_freq;
387         txc->maxerror      = time_maxerror;
388         txc->esterror      = time_esterror;
389         txc->status        = time_status;
390         txc->constant      = time_constant;
391         txc->precision     = time_precision;
392         txc->tolerance     = time_tolerance;
393         txc->tick          = tick;
394         txc->ppsfreq       = pps_freq;
395         txc->jitter        = pps_jitter >> PPS_AVG;
396         txc->shift         = pps_shift;
397         txc->stabil        = pps_stabil;
398         txc->jitcnt        = pps_jitcnt;
399         txc->calcnt        = pps_calcnt;
400         txc->errcnt        = pps_errcnt;
401         txc->stbcnt        = pps_stbcnt;
402         write_unlock_irq(&xtime_lock);
403         do_gettimeofday(&txc->time);
404         return(result);
405 }
406 
407 asmlinkage long sys_adjtimex(struct timex *txc_p)
408 {
409         struct timex txc;               /* Local copy of parameter */
410         int ret;
411 
412         /* Copy the user data space into the kernel copy
413          * structure. But bear in mind that the structures
414          * may change
415          */
416         if(copy_from_user(&txc, txc_p, sizeof(struct timex)))
417                 return -EFAULT;
418         ret = do_adjtimex(&txc);
419         return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : ret;
420 }
421 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.