diff options
-rw-r--r-- | sys/arch/i386/conf/files.i386 | 3 | ||||
-rw-r--r-- | sys/arch/i386/isa/clock.c | 202 |
2 files changed, 134 insertions, 71 deletions
diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386 index 0b946841edb..28c95489a36 100644 --- a/sys/arch/i386/conf/files.i386 +++ b/sys/arch/i386/conf/files.i386 @@ -1,4 +1,4 @@ -# $OpenBSD: files.i386,v 1.57 1999/09/13 13:08:13 deraadt Exp $ +# $OpenBSD: files.i386,v 1.58 1999/10/06 07:36:55 deraadt Exp $ # $NetBSD: files.i386,v 1.73 1996/05/07 00:58:36 thorpej Exp $ # # new style config file for i386 architecture @@ -111,6 +111,7 @@ file arch/i386/isa/isa_machdep.c isabus # PC clock file arch/i386/isa/clock.c isabus +file dev/clock_subr.c isabus # Numeric Processing Extension; Math Co-processor device npx diff --git a/sys/arch/i386/isa/clock.c b/sys/arch/i386/isa/clock.c index 12cc6bdf252..2bc4d6ce3a2 100644 --- a/sys/arch/i386/isa/clock.c +++ b/sys/arch/i386/isa/clock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clock.c,v 1.19 1999/01/31 14:56:01 espie Exp $ */ +/* $OpenBSD: clock.c,v 1.20 1999/10/06 07:36:55 deraadt Exp $ */ /* $NetBSD: clock.c,v 1.39 1996/05/12 23:11:54 mycroft Exp $ */ /*- @@ -100,6 +100,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> @@ -137,7 +138,6 @@ int gettick __P((void)); void sysbeep __P((int, int)); int rtcget __P((mc_todregs *)); void rtcput __P((mc_todregs *)); -static int yeartoday __P((int)); int hexdectodec __P((int)); int dectohexdec __P((int)); int rtcintr __P((void *)); @@ -151,8 +151,6 @@ int pentium_mhz; #define SECMIN ((unsigned)60) /* seconds per minute */ #define SECHOUR ((unsigned)(60*SECMIN)) /* seconds per hour */ -#define SECDAY ((unsigned)(24*SECHOUR)) /* seconds per day */ -#define SECYR ((unsigned)(365*SECDAY)) /* seconds per common year */ __inline u_int mc146818_read(sc, reg) @@ -410,17 +408,6 @@ rtcput(regs) MC146818_PUTTOD(NULL, regs); /* XXX softc */ } -static int month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - -static int -yeartoday(year) - int year; -{ - - return (((year % 4) == 0 && - ((year % 100) != 0 || (year % 400) == 0))? 366 : 365); -} - int hexdectodec(n) int n; @@ -440,6 +427,86 @@ dectohexdec(n) static int timeset; /* + * check whether the CMOS layout is "standard"-like (ie, not PS/2-like), + * to be called at splclock() + */ +static int cmoscheck __P((void)); +static int +cmoscheck() +{ + int i; + unsigned short cksum = 0; + + for (i = 0x10; i <= 0x2d; i++) + cksum += mc146818_read(NULL, i); /* XXX softc */ + + return (cksum == (mc146818_read(NULL, 0x2e) << 8) + + mc146818_read(NULL, 0x2f)); +} + +/* + * patchable to control century byte handling: + * 1: always update + * -1: never touch + * 0: try to figure out itself + */ +int rtc_update_century = 0; + +/* + * Expand a two-digit year as read from the clock chip + * into full width. + * Being here, deal with the CMOS century byte. + */ +static int clock_expandyear __P((int)); +static int +clock_expandyear(clockyear) + int clockyear; +{ + int s, clockcentury, cmoscentury; + + clockcentury = (clockyear < 70) ? 20 : 19; + clockyear += 100 * clockcentury; + + if (rtc_update_century < 0) + return (clockyear); + + s = splclock(); + if (cmoscheck()) + cmoscentury = mc146818_read(NULL, NVRAM_CENTURY); + else + cmoscentury = 0; + splx(s); + if (!cmoscentury) { +#ifdef DIAGNOSTIC + printf("clock: unknown CMOS layout\n"); +#endif + return (clockyear); + } + cmoscentury = hexdectodec(cmoscentury); + + if (cmoscentury != clockcentury) { + /* XXX note: saying "century is 20" might confuse the naive. */ + printf("WARNING: NVRAM century is %d but RTC year is %d\n", + cmoscentury, clockyear); + + /* Kludge to roll over century. */ + if ((rtc_update_century > 0) || + ((cmoscentury == 19) && (clockcentury == 20) && + (clockyear == 2000))) { + printf("WARNING: Setting NVRAM century to %d\n", + clockcentury); + s = splclock(); + mc146818_write(NULL, NVRAM_CENTURY, + dectohexdec(clockcentury)); + splx(s); + } + } else if (cmoscentury == 19 && rtc_update_century == 0) + rtc_update_century = 1; /* will update later in resettodr() */ + + return (clockyear); +} + +/* * Initialize the time of day register, based on the time base which is, e.g. * from a filesystem. */ @@ -448,9 +515,7 @@ inittodr(base) time_t base; { mc_todregs rtclk; - time_t n; - int sec, min, hr, dom, mon, yr; - int i, days = 0; + struct clock_ymdhms dt; int s; /* @@ -467,6 +532,8 @@ inittodr(base) base = 17*SECYR + 186*SECDAY + SECDAY/2; } + time.tv_usec = 0; + s = splclock(); if (rtcget(&rtclk)) { splx(s); @@ -475,47 +542,51 @@ inittodr(base) } splx(s); - sec = hexdectodec(rtclk[MC_SEC]); - min = hexdectodec(rtclk[MC_MIN]); - hr = hexdectodec(rtclk[MC_HOUR]); - dom = hexdectodec(rtclk[MC_DOM]); - mon = hexdectodec(rtclk[MC_MONTH]); - yr = hexdectodec(rtclk[MC_YEAR]); - yr = (yr < 70) ? yr+100 : yr; - - n = sec + 60 * min + 3600 * hr; - n += (dom - 1) * 3600 * 24; - - if (yeartoday(yr) == 366) - month[1] = 29; - for (i = mon - 2; i >= 0; i--) - days += month[i]; - month[1] = 28; - for (i = 70; i < yr; i++) - days += yeartoday(i); - n += days * 3600 * 24; - - n += tz.tz_minuteswest * 60; + 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])); + + + /* + * If time_t is 32 bits, then the "End of Time" is + * Mon Jan 18 22:14:07 2038 (US/Eastern) + * This code copes with RTC's past the end of time if time_t + * is an int32 or less. Needed because sometimes RTCs screw + * up or are badly set, and that would cause the time to go + * negative in the calculation below, which causes Very Bad + * Mojo. This at least lets the user boot and fix the problem. + * Note the code is self eliminating once time_t goes to 64 bits. + */ + if (sizeof(time_t) <= sizeof(int32_t)) { + if (dt.dt_year >= 2038) { + printf("WARNING: RTC time at or beyond 2038.\n"); + dt.dt_year = 2037; + printf("WARNING: year set back to 2037.\n"); + printf("WARNING: CHECK AND RESET THE DATE!\n"); + } + } + + time.tv_sec = clock_ymdhms_to_secs(&dt) + tz.tz_minuteswest * 60; if (tz.tz_dsttime) - n -= 3600; + time.tv_sec -= 3600; - if (base < n - 5*SECYR) + if (base < time.tv_sec - 5*SECYR) printf("WARNING: file system time much less than clock time\n"); - else if (base > n + 5*SECYR) { + else if (base > time.tv_sec + 5*SECYR) { printf("WARNING: clock time much less than file system time\n"); printf("WARNING: using file system time\n"); goto fstime; } timeset = 1; - time.tv_sec = n; - time.tv_usec = 0; return; fstime: timeset = 1; time.tv_sec = base; - time.tv_usec = 0; printf("WARNING: CHECK AND RESET THE DATE!\n"); } @@ -526,8 +597,9 @@ void resettodr() { mc_todregs rtclk; - time_t n; - int diff, i, j; + struct clock_ymdhms dt; + int diff; + int century; int s; /* @@ -545,31 +617,21 @@ resettodr() diff = tz.tz_minuteswest * 60; if (tz.tz_dsttime) diff -= 3600; - n = (time.tv_sec - diff) % (3600 * 24); /* hrs+mins+secs */ - rtclk[MC_SEC] = dectohexdec(n % 60); - n /= 60; - rtclk[MC_MIN] = dectohexdec(n % 60); - rtclk[MC_HOUR] = dectohexdec(n / 60); - - n = (time.tv_sec - diff) / (3600 * 24); /* days */ - rtclk[MC_DOW] = (n + 4) % 7; /* 1/1/70 is Thursday */ - - for (j = 1970, i = yeartoday(j); n >= i; j++, i = yeartoday(j)) - n -= i; - - rtclk[MC_YEAR] = dectohexdec(j - 1900); - - if (i == 366) - month[1] = 29; - for (i = 0; n >= month[i]; i++) - n -= month[i]; - month[1] = 28; - rtclk[MC_MONTH] = dectohexdec(++i); - - rtclk[MC_DOM] = dectohexdec(++n); - + clock_secs_to_ymdhms(time.tv_sec - diff, &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); s = splclock(); rtcput(&rtclk); + if (rtc_update_century > 0) { + century = dectohexdec(dt.dt_year / 100); + mc146818_write(NULL, NVRAM_CENTURY, century); /* XXX softc */ + } splx(s); } |