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.27 2008/01/20 18:09:12 joerg 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.27 2008/01/20 18:09:12 joerg 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 <sys/intr.h>
   87 
   88 #include <dev/clock_subr.h>     /* hmm.. this should probably move to sys */
   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         struct timespec ts;
  117         struct timeval tv;
  118 
  119         if (base < 5 * SECYR) {
  120                 struct clock_ymdhms basedate;
  121 
  122                 /*
  123                  * If base is 0, assume filesystem time is just unknown
  124                  * instead of preposterous. Don't bark.
  125                  */
  126                 if (base != 0)
  127                         printf("WARNING: preposterous time in file system\n");
  128                 /* not going to use it anyway, if the chip is readable */
  129                 basedate.dt_year = 2006;
  130                 basedate.dt_mon = 1;
  131                 basedate.dt_day = 1;
  132                 basedate.dt_hour = 12;
  133                 basedate.dt_min = 0;
  134                 basedate.dt_sec = 0;
  135                 base = clock_ymdhms_to_secs(&basedate);
  136                 badbase = 1;
  137         }
  138 
  139         /*
  140          * Some ports need to be supplied base in order to fabricate a time_t.
  141          */
  142         if (todr_handle)
  143                 todr_handle->base_time = base;
  144 
  145         if ((todr_handle == NULL) ||
  146             (todr_gettime(todr_handle, &tv) != 0) ||
  147             (tv.tv_sec < (25 * SECYR))) {
  148 
  149                 if (todr_handle != NULL)
  150                         printf("WARNING: preposterous TOD clock time\n");
  151                 else
  152                         printf("WARNING: no TOD clock present\n");
  153                 badrtc = 1;
  154         } else {
  155                 int deltat = tv.tv_sec - base;
  156 
  157                 if (deltat < 0)
  158                         deltat = -deltat;
  159 
  160                 if ((badbase == 0) && deltat >= 2 * SECDAY) {
  161                         
  162                         if (tv.tv_sec < base) {
  163                                 /*
  164                                  * The clock should never go backwards
  165                                  * relative to filesystem time.  If it
  166                                  * does by more than the threshold,
  167                                  * believe the filesystem.
  168                                  */
  169                                 printf("WARNING: clock lost %d days\n",
  170                                     deltat / SECDAY);
  171                                 badrtc = 1;
  172                         } else {
  173                                 printf("WARNING: clock gained %d days\n",
  174                                     deltat / SECDAY);
  175                         }
  176                 } else {
  177                         goodtime = 1;
  178                 }
  179         }
  180 
  181         /* if the rtc time is bad, use the filesystem time */
  182         if (badrtc) {
  183                 if (badbase) {
  184                         printf("WARNING: using default initial time\n");
  185                 } else {
  186                         printf("WARNING: using filesystem time\n");
  187                 }
  188                 tv.tv_sec = base;
  189                 tv.tv_usec = 0;
  190         }
  191 
  192         timeset = 1;
  193 
  194         ts.tv_sec = tv.tv_sec;
  195         ts.tv_nsec = tv.tv_usec * 1000;
  196         s = splclock();
  197         tc_setclock(&ts);
  198         splx(s);
  199 
  200         if (waszero || goodtime)
  201                 return;
  202 
  203         printf("WARNING: CHECK AND RESET THE DATE!\n");
  204 }
  205 
  206 /*
  207  * Reset the TODR based on the time value; used when the TODR
  208  * has a preposterous value and also when the time is reset
  209  * by the stime system call.  Also called when the TODR goes past
  210  * TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight)
  211  * to wrap the TODR around.
  212  */
  213 void
  214 resettodr(void)
  215 {
  216         struct timeval tv;
  217 
  218         /*
  219          * We might have been called by boot() due to a crash early
  220          * on.  Don't reset the clock chip if we don't know what time
  221          * it is.
  222          */
  223         if (!timeset)
  224                 return;
  225 
  226         getmicrotime(&tv);
  227 
  228         if (tv.tv_sec == 0)
  229                 return;
  230 
  231         if (todr_handle)
  232                 if (todr_settime(todr_handle, &tv) != 0)
  233                         printf("Cannot set TOD clock time\n");
  234 }
  235 
  236 #ifdef  TODR_DEBUG
  237 static void
  238 todr_debug(const char *prefix, int rv, struct clock_ymdhms *dt,
  239     volatile struct timeval *tvp)
  240 {
  241         struct timeval tv_val;
  242         struct clock_ymdhms dt_val;
  243 
  244         if (dt == NULL) {
  245                 clock_secs_to_ymdhms(tvp->tv_sec, &dt_val);
  246                 dt = &dt_val;
  247         }
  248         if (tvp == NULL) {
  249                 tvp = &tv_val;
  250                 tvp->tv_sec = clock_ymdhms_to_secs(dt);
  251                 tvp->tv_usec = 0;
  252         }
  253         printf("%s: rv = %d\n", prefix, rv);
  254         printf("%s: rtc_offset = %d\n", prefix, rtc_offset);
  255         printf("%s: %4u/%02u/%02u %02u:%02u:%02u, (wday %d) (epoch %u.%06u)\n",
  256             prefix,
  257             dt->dt_year, dt->dt_mon, dt->dt_day,
  258             dt->dt_hour, dt->dt_min, dt->dt_sec,
  259             dt->dt_wday, (unsigned)tvp->tv_sec, (unsigned)tvp->tv_usec);
  260 }
  261 #else   /* !TODR_DEBUG */
  262 #define todr_debug(prefix, rv, dt, tvp)
  263 #endif  /* TODR_DEBUG */
  264 
  265 
  266 int
  267 todr_gettime(todr_chip_handle_t tch, volatile struct timeval *tvp)
  268 {
  269         struct clock_ymdhms     dt;
  270         int                     rv;
  271 
  272         if (tch->todr_gettime) {
  273                 rv = tch->todr_gettime(tch, tvp);
  274                 /*
  275                  * Some unconverted ports have their own references to
  276                  * rtc_offset.   A converted port must not do that.
  277                  */
  278                 if (rv == 0)
  279                         tvp->tv_sec += rtc_offset * 60;
  280                 todr_debug("TODR-GET-SECS", rv, NULL, tvp);
  281                 return rv;
  282         } else if (tch->todr_gettime_ymdhms) {
  283                 rv = tch->todr_gettime_ymdhms(tch, &dt);
  284                 todr_debug("TODR-GET-YMDHMS", rv, &dt, NULL);
  285                 if (rv)
  286                         return rv;
  287 
  288                 /*
  289                  * Formerly we had code here that explicitly checked
  290                  * for 2038 year rollover.
  291                  *
  292                  * However, clock_ymdhms_to_secs performs the same
  293                  * check for us, so we need not worry about it.  Note
  294                  * that this assumes that the tvp->tv_sec member is
  295                  * a time_t.
  296                  */
  297 
  298                 /*
  299                  * Simple sanity checks.  Note that this includes a
  300                  * value for clocks that can return a leap second.
  301                  * Note that we don't support double leap seconds,
  302                  * since this was apparently an error/misunderstanding
  303                  * on the part of the ISO C committee, and can never
  304                  * actually occur.  If your clock issues us a double
  305                  * leap second, it must be broken.  Ultimately, you'd
  306                  * have to be trying to read time at precisely that
  307                  * instant to even notice, so even broken clocks will
  308                  * work the vast majority of the time.  In such a case
  309                  * it is recommended correction be applied in the
  310                  * clock driver.
  311                  */
  312                 if (dt.dt_mon < 1 || dt.dt_mon > 12 ||
  313                     dt.dt_day < 1 || dt.dt_day > 31 ||
  314                     dt.dt_hour > 23 || dt.dt_min > 59 || dt.dt_sec > 60) {
  315                         return EINVAL;
  316                 }
  317                 tvp->tv_sec = clock_ymdhms_to_secs(&dt) + rtc_offset * 60;
  318                 tvp->tv_usec = 0;
  319                 return tvp->tv_sec < 0 ? EINVAL : 0;
  320         }
  321 
  322         return ENXIO;
  323 }
  324 
  325 int
  326 todr_settime(todr_chip_handle_t tch, volatile struct timeval *tvp)
  327 {
  328         struct clock_ymdhms     dt;
  329         int                     rv;
  330 
  331         if (tch->todr_settime) {
  332                 /* See comments above in gettime why this is ifdef'd */
  333                 struct timeval  copy = *tvp;
  334                 copy.tv_sec -= rtc_offset * 60;
  335                 rv = tch->todr_settime(tch, &copy);
  336                 todr_debug("TODR-SET-SECS", rv, NULL, tvp);
  337                 return rv;
  338         } else if (tch->todr_settime_ymdhms) {
  339                 time_t  sec = tvp->tv_sec - rtc_offset * 60;
  340                 if (tvp->tv_usec >= 500000)
  341                         sec++;
  342                 clock_secs_to_ymdhms(sec, &dt);
  343                 rv = tch->todr_settime_ymdhms(tch, &dt);
  344                 todr_debug("TODR-SET-YMDHMS", rv, &dt, NULL);
  345                 return rv;
  346         } else {
  347                 return ENXIO;
  348         }
  349 }

Cache object: cdd84912f12b87e192c506cf16e5b993


[ 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.