diff options
-rw-r--r-- | sys/arch/i386/i386/machdep.c | 91 | ||||
-rw-r--r-- | sys/arch/i386/include/cpu.h | 4 | ||||
-rw-r--r-- | sys/arch/i386/isa/clock.c | 139 |
3 files changed, 146 insertions, 88 deletions
diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c index 765d8dd57ab..7600f40c446 100644 --- a/sys/arch/i386/i386/machdep.c +++ b/sys/arch/i386/i386/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.631 2019/06/14 18:13:55 kettenis Exp $ */ +/* $OpenBSD: machdep.c,v 1.632 2020/04/29 08:53:45 kettenis Exp $ */ /* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */ /*- @@ -378,6 +378,7 @@ cpu_startup(void) printf("%s", version); startclocks(); + rtcinit(); printf("real mem = %llu (%lluMB)\n", (unsigned long long)ptoa((psize_t)physmem), @@ -4037,3 +4038,91 @@ intr_barrier(void *ih) sched_barrier(NULL); } +#include <sys/timetc.h> +#include <dev/clock_subr.h> + +todr_chip_handle_t todr_handle; + +#define MINYEAR ((OpenBSD / 100) - 1) /* minimum plausible year */ + +/* + * inittodr: + * + * Initialize time from the time-of-day register. + */ +void +inittodr(time_t base) +{ + time_t deltat; + struct timeval rtctime; + struct timespec ts; + int badbase; + + if (base < (MINYEAR - 1970) * SECYR) { + printf("WARNING: preposterous time in file system\n"); + /* read the system clock anyway */ + base = (MINYEAR - 1970) * SECYR; + badbase = 1; + } else + badbase = 0; + + if (todr_handle == NULL || + todr_gettime(todr_handle, &rtctime) != 0 || + rtctime.tv_sec < (MINYEAR - 1970) * SECYR) { + /* + * Believe the time in the file system for lack of + * anything better, resetting the TODR. + */ + rtctime.tv_sec = base; + rtctime.tv_usec = 0; + if (todr_handle != NULL && !badbase) + printf("WARNING: bad clock chip time\n"); + ts.tv_sec = rtctime.tv_sec; + ts.tv_nsec = rtctime.tv_usec * 1000; + tc_setclock(&ts); + goto bad; + } else { + ts.tv_sec = rtctime.tv_sec; + ts.tv_nsec = rtctime.tv_usec * 1000; + tc_setclock(&ts); + } + + if (!badbase) { + /* + * See if we gained/lost two or more days; if + * so, assume something is amiss. + */ + deltat = rtctime.tv_sec - base; + if (deltat < 0) + deltat = -deltat; + if (deltat < 2 * SECDAY) + return; /* all is well */ +#ifndef SMALL_KERNEL + printf("WARNING: clock %s %lld days\n", + rtctime.tv_sec < base ? "lost" : "gained", + (long long)(deltat / SECDAY)); +#endif + } + bad: + printf("WARNING: CHECK AND RESET THE DATE!\n"); +} + +/* + * resettodr: + * + * Reset the time-of-day register with the current time. + */ +void +resettodr(void) +{ + struct timeval rtctime; + + if (time_second == 1) + return; + + microtime(&rtctime); + + if (todr_handle != NULL && + todr_settime(todr_handle, &rtctime) != 0) + printf("WARNING: can't update clock chip time\n"); +} diff --git a/sys/arch/i386/include/cpu.h b/sys/arch/i386/include/cpu.h index 8f8d0535687..63e5e840e96 100644 --- a/sys/arch/i386/include/cpu.h +++ b/sys/arch/i386/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.168 2019/12/20 07:55:30 jsg Exp $ */ +/* $OpenBSD: cpu.h,v 1.169 2020/04/29 08:53:45 kettenis Exp $ */ /* $NetBSD: cpu.h,v 1.35 1996/05/05 19:29:26 christos Exp $ */ /*- @@ -421,7 +421,7 @@ void proc_trampoline(void); /* clock.c */ extern void (*initclock_func)(void); void startclocks(void); -void rtcdrain(void *); +void rtcinit(void); void rtcstart(void); void rtcstop(void); void i8254_delay(int); diff --git a/sys/arch/i386/isa/clock.c b/sys/arch/i386/isa/clock.c index 2b3fe2e626f..836ac088662 100644 --- a/sys/arch/i386/isa/clock.c +++ b/sys/arch/i386/isa/clock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clock.c,v 1.56 2019/08/22 01:11:19 deraadt Exp $ */ +/* $OpenBSD: clock.c,v 1.57 2020/04/29 08:53:45 kettenis Exp $ */ /* $NetBSD: clock.c,v 1.39 1996/05/12 23:11:54 mycroft Exp $ */ /*- @@ -99,6 +99,7 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include <machine/pio.h> #include <machine/cpufunc.h> +#include <dev/clock_subr.h> #include <dev/isa/isareg.h> #include <dev/isa/isavar.h> #include <dev/ic/mc146818reg.h> @@ -110,8 +111,6 @@ int clockintr(void *); int gettick(void); int rtcget(mc_todregs *); void rtcput(mc_todregs *); -int hexdectodec(int); -int dectohexdec(int); int rtcintr(void *); void rtcdrain(void *); int calibrate_cyclecounter_ctr(void); @@ -481,21 +480,17 @@ rtcput(mc_todregs *regs) } int -hexdectodec(int n) +bcdtobin(int n) { - return (((n >> 4) & 0x0f) * 10 + (n & 0x0f)); } int -dectohexdec(int n) +bintobcd(int n) { - return ((u_char)(((n / 10) << 4) & 0xf0) | ((n % 10) & 0x0f)); } -static int timeset; - /* * check whether the CMOS layout is "standard"-like (ie, not PS/2-like), * to be called at splclock() @@ -551,7 +546,7 @@ clock_expandyear(int clockyear) #endif return (clockyear); } - cmoscentury = hexdectodec(cmoscentury); + cmoscentury = bcdtobin(cmoscentury); if (cmoscentury != clockcentury) { /* XXX note: saying "century is 20" might confuse the naive. */ @@ -566,7 +561,7 @@ clock_expandyear(int clockyear) clockcentury); s = splclock(); mc146818_write(NULL, NVRAM_CENTURY, - dectohexdec(clockcentury)); + bintobcd(clockcentury)); splx(s); } } else if (cmoscentury == 19 && rtc_update_century == 0) @@ -575,110 +570,84 @@ clock_expandyear(int clockyear) return (clockyear); } -/* - * Initialize the time of day register, based on the time base which is, e.g. - * from a filesystem. - */ -void -inittodr(time_t base) +int +rtcgettime(struct todr_chip_handle *handle, struct timeval *tv) { - struct timespec ts; mc_todregs rtclk; struct clock_ymdhms dt; int s; - - - ts.tv_nsec = 0; - - /* - * We mostly ignore the suggested time and go for the RTC clock time - * stored in the CMOS RAM. If the time can't be obtained from the - * CMOS, or if the time obtained from the CMOS is 5 or more years - * less than the suggested time, we used the suggested time. (In - * the latter case, it's likely that the CMOS battery has died.) - */ - - if (base < 15*SECYR) { /* if before 1985, something's odd... */ - printf("WARNING: preposterous time in file system\n"); - /* read the system clock anyway */ - base = 17*SECYR + 186*SECDAY + SECDAY/2; - } - + s = splclock(); if (rtcget(&rtclk)) { splx(s); - printf("WARNING: invalid time in clock chip\n"); - goto fstime; + return EINVAL; } splx(s); - dt.dt_sec = hexdectodec(rtclk[MC_SEC]); - dt.dt_min = hexdectodec(rtclk[MC_MIN]); - dt.dt_hour = hexdectodec(rtclk[MC_HOUR]); - dt.dt_day = hexdectodec(rtclk[MC_DOM]); - dt.dt_mon = hexdectodec(rtclk[MC_MONTH]); - dt.dt_year = clock_expandyear(hexdectodec(rtclk[MC_YEAR])); - - ts.tv_sec = clock_ymdhms_to_secs(&dt) - utc_offset; - - if (base < ts.tv_sec - 5*SECYR) - printf("WARNING: file system time much less than clock time\n"); - else if (base > ts.tv_sec + 5*SECYR) { - printf("WARNING: clock time much less than file system time\n"); - printf("WARNING: using file system time\n"); - goto fstime; - } +#ifdef CLOCK_DEBUG + printf("readclock: %x/%x/%x %x:%x:%x\n", rtclk[MC_YEAR], + rtclk[MC_MONTH], rtclk[MC_DOM], rtclk[MC_HOUR], rtclk[MC_MIN], + rtclk[MC_SEC]); +#endif - tc_setclock(&ts); - timeset = 1; - return; + dt.dt_sec = bcdtobin(rtclk[MC_SEC]); + dt.dt_min = bcdtobin(rtclk[MC_MIN]); + dt.dt_hour = bcdtobin(rtclk[MC_HOUR]); + dt.dt_day = bcdtobin(rtclk[MC_DOM]); + dt.dt_mon = bcdtobin(rtclk[MC_MONTH]); + dt.dt_year = clock_expandyear(bcdtobin(rtclk[MC_YEAR])); -fstime: - ts.tv_sec = base; - tc_setclock(&ts); - timeset = 1; - printf("WARNING: CHECK AND RESET THE DATE!\n"); + tv->tv_sec = clock_ymdhms_to_secs(&dt) - utc_offset; + tv->tv_usec = 0; + return 0; } -/* - * Reset the clock. - */ -void -resettodr(void) +int +rtcsettime(struct todr_chip_handle *handle, struct timeval *tv) { mc_todregs rtclk; struct clock_ymdhms dt; - int century; - int s; - - /* - * We might have been called by boot() due to a crash early - * on. Don't reset the clock chip in this case. - */ - if (!timeset) - return; + int century, s; s = splclock(); if (rtcget(&rtclk)) - bzero(&rtclk, sizeof(rtclk)); + memset(&rtclk, 0, sizeof(rtclk)); splx(s); clock_secs_to_ymdhms(time_second + utc_offset, &dt); - rtclk[MC_SEC] = dectohexdec(dt.dt_sec); - rtclk[MC_MIN] = dectohexdec(dt.dt_min); - rtclk[MC_HOUR] = dectohexdec(dt.dt_hour); - rtclk[MC_DOW] = dt.dt_wday; - rtclk[MC_YEAR] = dectohexdec(dt.dt_year % 100); - rtclk[MC_MONTH] = dectohexdec(dt.dt_mon); - rtclk[MC_DOM] = dectohexdec(dt.dt_day); + rtclk[MC_SEC] = bintobcd(dt.dt_sec); + rtclk[MC_MIN] = bintobcd(dt.dt_min); + rtclk[MC_HOUR] = bintobcd(dt.dt_hour); + rtclk[MC_DOW] = dt.dt_wday + 1; + rtclk[MC_YEAR] = bintobcd(dt.dt_year % 100); + rtclk[MC_MONTH] = bintobcd(dt.dt_mon); + rtclk[MC_DOM] = bintobcd(dt.dt_day); + +#ifdef CLOCK_DEBUG + printf("setclock: %x/%x/%x %x:%x:%x\n", rtclk[MC_YEAR], rtclk[MC_MONTH], + rtclk[MC_DOM], rtclk[MC_HOUR], rtclk[MC_MIN], rtclk[MC_SEC]); +#endif + s = splclock(); rtcput(&rtclk); if (rtc_update_century > 0) { - century = dectohexdec(dt.dt_year / 100); + century = bintobcd(dt.dt_year / 100); mc146818_write(NULL, NVRAM_CENTURY, century); /* XXX softc */ } splx(s); + return 0; +} + +extern todr_chip_handle_t todr_handle; +struct todr_chip_handle rtc_todr; + +void +rtcinit(void) +{ + rtc_todr.todr_gettime = rtcgettime; + rtc_todr.todr_settime = rtcsettime; + todr_handle = &rtc_todr; } void |