The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/kern_todr.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: kern_todr.c,v 1.24 2006/09/24 18:24:55 peter Exp $     */
    2 
    3 /*
    4  * Copyright (c) 1992, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * This code is derived from software contributed to Berkeley by
    8  * the Systems Programming Group of the University of Utah Computer
    9  * Science Department and Ralph Campbell.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. Neither the name of the University nor the names of its contributors
   20  *    may be used to endorse or promote products derived from this software
   21  *    without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  *
   35  * from: Utah Hdr: clock.c 1.18 91/01/21
   36  *
   37  *      @(#)clock.c     8.1 (Berkeley) 6/10/93
   38  */
   39 /*
   40  * Copyright (c) 1988 University of Utah.
   41  *
   42  * This code is derived from software contributed to Berkeley by
   43  * the Systems Programming Group of the University of Utah Computer
   44  * Science Department and Ralph Campbell.
   45  *
   46  * Redistribution and use in source and binary forms, with or without
   47  * modification, are permitted provided that the following conditions
   48  * are met:
   49  * 1. Redistributions of source code must retain the above copyright
   50  *    notice, this list of conditions and the following disclaimer.
   51  * 2. Redistributions in binary form must reproduce the above copyright
   52  *    notice, this list of conditions and the following disclaimer in the
   53  *    documentation and/or other materials provided with the distribution.
   54  * 3. All advertising materials mentioning features or use of this software
   55  *    must display the following acknowledgement:
   56  *      This product includes software developed by the University of
   57  *      California, Berkeley and its contributors.
   58  * 4. Neither the name of the University nor the names of its contributors
   59  *    may be used to endorse or promote products derived from this software
   60  *    without specific prior written permission.
   61  *
   62  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   63  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   64  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   65  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   66  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   67  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   68  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   69  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   70  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   71  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   72  * SUCH DAMAGE.
   73  *
   74  * from: Utah Hdr: clock.c 1.18 91/01/21
   75  *
   76  *      @(#)clock.c     8.1 (Berkeley) 6/10/93
   77  */
   78 #include <sys/cdefs.h>
   79 __KERNEL_RCSID(0, "$NetBSD: kern_todr.c,v 1.24 2006/09/24 18:24:55 peter Exp $");
   80 
   81 #include <sys/param.h>
   82 #include <sys/kernel.h>
   83 #include <sys/systm.h>
   84 #include <sys/device.h>
   85 #include <sys/timetc.h>
   86 #include <dev/clock_subr.h>     /* hmm.. this should probably move to sys */
   87 
   88 #ifdef  __HAVE_GENERIC_TODR
   89 
   90 static todr_chip_handle_t todr_handle = NULL;
   91 
   92 /*
   93  * Attach the clock device to todr_handle.
   94  */
   95 void
   96 todr_attach(todr_chip_handle_t todr)
   97 {
   98 
   99         if (todr_handle) {
  100                 printf("todr_attach: TOD already configured\n");
  101                 return;
  102         }
  103         todr_handle = todr;
  104 }
  105 
  106 static int timeset = 0;
  107 
  108 /*
  109  * Set up the system's time, given a `reasonable' time value.
  110  */
  111 void
  112 inittodr(time_t base)
  113 {
  114         int badbase = 0, waszero = (base == 0), goodtime = 0, badrtc = 0;
  115         int s;
  116 #ifdef  __HAVE_TIMECOUNTER
  117         struct timespec ts;
  118 #endif
  119         struct timeval tv;
  120 
  121         if (base < 5 * SECYR) {
  122                 struct clock_ymdhms basedate;
  123 
  124                 /*
  125                  * If base is 0, assume filesystem time is just unknown
  126                  * instead of preposterous. Don't bark.
  127                  */
  128                 if (base != 0)
  129                         printf("WARNING: preposterous time in file system\n");
  130                 /* not going to use it anyway, if the chip is readable */
  131                 basedate.dt_year = 2006;
  132                 basedate.dt_mon = 1;
  133                 basedate.dt_day = 1;
  134                 basedate.dt_hour = 12;
  135                 basedate.dt_min = 0;
  136                 basedate.dt_sec = 0;
  137                 base = clock_ymdhms_to_secs(&basedate);
  138                 badbase = 1;
  139         }
  140 
  141         /*
  142          * Some ports need to be supplied base in order to fabricate a time_t.
  143          */
  144         if (todr_handle)
  145                 todr_handle->base_time = base;
  146 
  147         if ((todr_handle == NULL) ||
  148             (todr_gettime(todr_handle, &tv) != 0) ||
  149             (tv.tv_sec < (25 * SECYR))) {
  150 
  151                 if (todr_handle != NULL)
  152                         printf("WARNING: preposterous TOD clock time\n");
  153                 else
  154                         printf("WARNING: no TOD clock present\n");
  155                 badrtc = 1;
  156         } else {
  157                 int deltat = tv.tv_sec - base;
  158 
  159                 if (deltat < 0)
  160                         deltat = -deltat;
  161 
  162                 if ((badbase == 0) && deltat >= 2 * SECDAY) {
  163                         
  164                         if (tv.tv_sec < base) {
  165                                 /*
  166                                  * The clock should never go backwards
  167                                  * relative to filesystem time.  If it
  168                                  * does by more than the threshold,
  169                                  * believe the filesystem.
  170                                  */
  171                                 printf("WARNING: clock lost %d days\n",
  172                                     deltat / SECDAY);
  173                                 badrtc = 1;
  174                         } else {
  175                                 printf("WARNING: clock gained %d days\n",
  176                                     deltat / SECDAY);
  177                         }
  178                 } else {
  179                         goodtime = 1;
  180                 }
  181         }
  182 
  183         /* if the rtc time is bad, use the filesystem time */
  184         if (badrtc) {
  185                 if (badbase) {
  186                         printf("WARNING: using default initial time\n");
  187                 } else {
  188                         printf("WARNING: using filesystem time\n");
  189                 }
  190                 tv.tv_sec = base;
  191                 tv.tv_usec = 0;
  192         }
  193 
  194         timeset = 1;
  195 
  196         s = splclock();
  197 #ifdef  __HAVE_TIMECOUNTER
  198         ts.tv_sec = tv.tv_sec;
  199         ts.tv_nsec = tv.tv_usec * 1000;
  200         tc_setclock(&ts);
  201 #else
  202         time = tv;
  203 #endif
  204         splx(s);
  205 
  206         if (waszero || goodtime)
  207                 return;
  208 
  209         printf("WARNING: CHECK AND RESET THE DATE!\n");
  210 }
  211 
  212 /*
  213  * Reset the TODR based on the time value; used when the TODR
  214  * has a preposterous value and also when the time is reset
  215  * by the stime system call.  Also called when the TODR goes past
  216  * TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight)
  217  * to wrap the TODR around.
  218  */
  219 void
  220 resettodr(void)
  221 {
  222 #ifdef  __HAVE_TIMECOUNTER
  223         struct timeval  time;
  224 #endif
  225 
  226         /*
  227          * We might have been called by boot() due to a crash early
  228          * on.  Don't reset the clock chip if we don't know what time
  229          * it is.
  230          */
  231         if (!timeset)
  232                 return;
  233 
  234 #ifdef  __HAVE_TIMECOUNTER
  235         getmicrotime(&time);
  236 #endif
  237 
  238         if (time.tv_sec == 0)
  239                 return;
  240 
  241         if (todr_handle)
  242                 if (todr_settime(todr_handle, &time) != 0)
  243                         printf("Cannot set TOD clock time\n");
  244 }
  245 
  246 #endif  /* __HAVE_GENERIC_TODR */
  247 
  248 #ifdef  TODR_DEBUG
  249 static void
  250 todr_debug(const char *prefix, int rv, struct clock_ymdhms *dt,
  251     volatile struct timeval *tvp)
  252 {
  253         struct timeval tv_val;
  254         struct clock_ymdhms dt_val;
  255 
  256         if (dt == NULL) {
  257                 clock_secs_to_ymdhms(tvp->tv_sec, &dt_val);
  258                 dt = &dt_val;
  259         }
  260         if (tvp == NULL) {
  261                 tvp = &tv_val;
  262                 tvp->tv_sec = clock_ymdhms_to_secs(dt);
  263                 tvp->tv_usec = 0;
  264         }
  265         printf("%s: rv = %d\n", prefix, rv);
  266         printf("%s: rtc_offset = %d\n", prefix, rtc_offset);
  267         printf("%s: %4u/%02u/%02u %02u:%02u:%02u, (wday %d) (epoch %u.%06u)\n",
  268             prefix,
  269             dt->dt_year, dt->dt_mon, dt->dt_day,
  270             dt->dt_hour, dt->dt_min, dt->dt_sec,
  271             dt->dt_wday, (unsigned)tvp->tv_sec, (unsigned)tvp->tv_usec);
  272 }
  273 #else   /* !TODR_DEBUG */
  274 #define todr_debug(prefix, rv, dt, tvp)
  275 #endif  /* TODR_DEBUG */
  276 
  277 
  278 int
  279 todr_gettime(todr_chip_handle_t tch, volatile struct timeval *tvp)
  280 {
  281         struct clock_ymdhms     dt;
  282         int                     rv;
  283 
  284         if (tch->todr_gettime) {
  285                 rv = tch->todr_gettime(tch, tvp);
  286                 /*
  287                  * Some unconverted ports have their own references to
  288                  * rtc_offset.   A converted port must not do that.
  289                  */
  290 #ifdef  __HAVE_GENERIC_TODR
  291                 if (rv == 0)
  292                         tvp->tv_sec += rtc_offset * 60;
  293 #endif
  294                 todr_debug("TODR-GET-SECS", rv, NULL, tvp);
  295                 return rv;
  296         } else if (tch->todr_gettime_ymdhms) {
  297                 rv = tch->todr_gettime_ymdhms(tch, &dt);
  298                 todr_debug("TODR-GET-YMDHMS", rv, &dt, NULL);
  299                 if (rv)
  300                         return rv;
  301 
  302                 /*
  303                  * Formerly we had code here that explicitly checked
  304                  * for 2038 year rollover.
  305                  *
  306                  * However, clock_ymdhms_to_secs performs the same
  307                  * check for us, so we need not worry about it.  Note
  308                  * that this assumes that the tvp->tv_sec member is
  309                  * a time_t.
  310                  */
  311 
  312                 /*
  313                  * Simple sanity checks.  Note that this includes a
  314                  * value for clocks that can return a leap second.
  315                  * Note that we don't support double leap seconds,
  316                  * since this was apparently an error/misunderstanding
  317                  * on the part of the ISO C committee, and can never
  318                  * actually occur.  If your clock issues us a double
  319                  * leap second, it must be broken.  Ultimately, you'd
  320                  * have to be trying to read time at precisely that
  321                  * instant to even notice, so even broken clocks will
  322                  * work the vast majority of the time.  In such a case
  323                  * it is recommended correction be applied in the
  324                  * clock driver.
  325                  */
  326                 if (dt.dt_mon < 1 || dt.dt_mon > 12 ||
  327                     dt.dt_day < 1 || dt.dt_day > 31 ||
  328                     dt.dt_hour > 23 || dt.dt_min > 59 || dt.dt_sec > 60) {
  329                         return EINVAL;
  330                 }
  331                 tvp->tv_sec = clock_ymdhms_to_secs(&dt) + rtc_offset * 60;
  332                 tvp->tv_usec = 0;
  333                 return tvp->tv_sec < 0 ? EINVAL : 0;
  334         }
  335 
  336         return ENXIO;
  337 }
  338 
  339 int
  340 todr_settime(todr_chip_handle_t tch, volatile struct timeval *tvp)
  341 {
  342         struct clock_ymdhms     dt;
  343         int                     rv;
  344 
  345         if (tch->todr_settime) {
  346                 /* See comments above in gettime why this is ifdef'd */
  347 #ifdef  __HAVE_GENERIC_TODR
  348                 struct timeval  copy = *tvp;
  349                 copy.tv_sec -= rtc_offset * 60;
  350                 rv = tch->todr_settime(tch, &copy);
  351 #else
  352                 rv = tch->todr_settime(tch, tvp);
  353 #endif
  354                 todr_debug("TODR-SET-SECS", rv, NULL, tvp);
  355                 return rv;
  356         } else if (tch->todr_settime_ymdhms) {
  357                 time_t  sec = tvp->tv_sec - rtc_offset * 60;
  358                 if (tvp->tv_usec >= 500000)
  359                         sec++;
  360                 clock_secs_to_ymdhms(sec, &dt);
  361                 rv = tch->todr_settime_ymdhms(tch, &dt);
  362                 todr_debug("TODR-SET-YMDHMS", rv, &dt, NULL);
  363                 return rv;
  364         } else {
  365                 return ENXIO;
  366         }
  367 }

Cache object: df224a6a795b5d045bcf2194552eddd5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.