/* * Copyright (c) 1982, 1986 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * * @(#)clock.c 7.1 (Berkeley) 6/5/86 */ #include "param.h" #include "time.h" #include "kernel.h" #include "mtpr.h" #include "clock.h" #include "cpu.h" /* * Machine-dependent clock routines. * * Startrtclock restarts the real-time clock, which provides * hardclock interrupts to kern_clock.c. * * Inittodr initializes the time of day hardware which provides * date functions. Its primary function is to use some file * system information in case the hardare clock lost state. * * Resettodr restores the time of day hardware after a time change. */ /* * Start the real-time clock. */ startrtclock() { #ifdef VAX630 if (cpu == VAX_630) { mtpr(ICCS, ICCS_IE); } else { #endif mtpr(NICR, -1000000/hz); mtpr(ICCS, ICCS_RUN+ICCS_IE+ICCS_TRANS+ICCS_INT+ICCS_ERR); #ifdef VAX630 } #endif } /* * Initialze the time of day register, based on the time base which is, e.g. * from a filesystem. Base provides the time to within six months, * and the time of year clock provides the rest. */ inittodr(base) time_t base; { register u_int todr = mfpr(TODR); long deltat; int year = YRREF; #if VAX630 /* * If this is a Ka630, call ka630tod to handle the funny tod clock. */ if (cpu == VAX_630) { ka630tod(base); return; } #endif if (base < 5*SECYR) { printf("WARNING: preposterous time in file system"); time.tv_sec = 6*SECYR + 186*SECDAY + SECDAY/2; resettodr(); goto check; } /* * TODRZERO is base used by VMS, which runs on local time. */ if (todr < TODRZERO) { printf("WARNING: todr too small"); time.tv_sec = base; /* * Believe the time in the file system for lack of * anything better, resetting the TODR. */ resettodr(); goto check; } /* * Sneak to within 6 month of the time in the filesystem, * by starting with the time of the year suggested by the TODR, * and advancing through succesive years. Adding the number of * seconds in the current year takes us to the end of the current year * and then around into the next year to the same position. */ time.tv_sec = (todr-TODRZERO)/100; while (time.tv_sec < base-SECYR/2) { if (LEAPYEAR(year)) time.tv_sec += SECDAY; year++; time.tv_sec += SECYR; } /* * See if we gained/lost two or more days; * if so, assume something is amiss. */ deltat = time.tv_sec - base; if (deltat < 0) deltat = -deltat; if (deltat < 2*SECDAY) return; printf("WARNING: clock %s %d days", time.tv_sec < base ? "lost" : "gained", deltat / SECDAY); check: printf(" -- CHECK AND RESET THE DATE!\n"); } /* * Reset the TODR based on the time value; used when the TODR * has a preposterous value and also when the time is reset * by the stime system call. Also called when the TODR goes past * TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight) * to wrap the TODR around. */ resettodr() { int year = YRREF; u_int secyr; u_int yrtime = time.tv_sec; #if VAX630 /* * If this is a ka630, call ka630stod to set the funny tod clock. */ if (cpu == VAX_630) { ka630stod(); return; } #endif /* * Whittle the time down to an offset in the current year, * by subtracting off whole years as long as possible. */ for (;;) { secyr = SECYR; if (LEAPYEAR(year)) secyr += SECDAY; if (yrtime < secyr) break; yrtime -= secyr; year++; } mtpr(TODR, TODRZERO + yrtime*100); }