1
2 /*
3 * Copyright (c) 1982, 1986, 1988 Regents of the University of California.
4 * All rights reserved. The Berkeley software License Agreement
5 * specifies the terms and conditions for redistribution.
6 *
7 * @(#)clock.c 7.6 (Berkeley) 12/16/90
8 */
9
10 #include "sys/param.h"
11 #include "sys/time.h"
12 #include "sys/kernel.h"
13
14 #include "../include/mtpr.h"
15 #include "../include/clock.h"
16 #include "../include/cpu.h"
17
18 /*
19 * Machine-dependent clock routines.
20 *
21 * Startrtclock restarts the real-time clock, which provides
22 * hardclock interrupts to kern_clock.c.
23 *
24 * Inittodr initializes the time of day hardware which provides
25 * date functions. Its primary function is to use some file
26 * system information in case the hardare clock lost state.
27 *
28 * Resettodr restores the time of day hardware after a time change.
29 */
30
31 /*
32 * Start the real-time clock.
33 */
startrtclock()34 startrtclock()
35 {
36
37 (*cpuops->cpu_clock->clkstartrt)();
38 }
39
40 /*
41 * Initialze the time of day register, based on the time base which is, e.g.
42 * from a filesystem. Base provides the time to within six months,
43 * and the time of year clock (if any) provides the rest.
44 */
inittodr(base)45 inittodr(base)
46 time_t base;
47 {
48 long deltat, badbase = 0;
49
50 if (base < 5*SECYR) {
51 printf("WARNING: preposterous time in file system\n");
52 /* read the system clock anyway */
53 base = 6*SECYR + 186*SECDAY + SECDAY/2;
54 badbase = 1;
55 }
56 switch ((*cpuops->cpu_clock->clkread)(base)) {
57
58 case CLKREAD_BAD:
59 /*
60 * Believe the time in the file system for lack of
61 * anything better, resetting the TODR.
62 */
63 time.tv_sec = base;
64 if (!badbase)
65 resettodr();
66 break;
67
68 case CLKREAD_WARN:
69 break;
70
71 case CLKREAD_OK:
72 if (badbase)
73 break;
74 /*
75 * See if we gained/lost two or more days;
76 * if so, assume something is amiss.
77 */
78 deltat = time.tv_sec - base;
79 if (deltat < 0)
80 deltat = -deltat;
81 if (deltat < 2 * SECDAY)
82 return;
83 printf("WARNING: clock %s %d days",
84 time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
85 break;
86
87 default:
88 panic("inittodr");
89 /* NOTREACHED */
90 }
91 printf(" -- CHECK AND RESET THE DATE!\n");
92 }
93
94 /*
95 * Reset the TODR based on the time value; used when the TODR
96 * has a preposterous value, when the time is changed, and when rebooting.
97 * Also called when the TODR goes past TODRZERO + 100*(SECYEAR+2*SECDAY)
98 * (e.g. on Jan 2 just after midnight) to wrap the TODR around.
99 * Avoid doing this if we haven't figured out the time yet
100 * (e.g., when crashing during autoconfig).
101 */
resettodr()102 resettodr()
103 {
104
105 if (time.tv_sec)
106 (*cpuops->cpu_clock->clkwrite)();
107 }
108
109 /*
110 * ``Standard'' VAX clock routines.
111 */
112 #if VAX8600 || VAX8200 || VAX780 || VAX750 || VAX730
vaxstd_clkstartrt()113 vaxstd_clkstartrt()
114 {
115
116 mtpr(NICR, -1000000/hz);
117 mtpr(ICCS, ICCS_RUN+ICCS_IE+ICCS_TRANS+ICCS_INT+ICCS_ERR);
118 }
119 #endif
120
121 #if VAX8600 || VAX780 || VAX750 || VAX730 || VAX650
vaxstd_clkread(base)122 vaxstd_clkread(base)
123 time_t base;
124 {
125 register u_int todr = mfpr(TODR);
126 int year;
127
128 /*
129 * TODRZERO is base used by VMS, which runs on local time.
130 */
131 if (todr < TODRZERO) {
132 printf("WARNING: todr too small");
133 return (CLKREAD_BAD);
134 }
135
136 /*
137 * Sneak to within 6 months of the time in the filesystem,
138 * by starting with the time of the year suggested by the TODR,
139 * and advancing through succesive years. Adding the number of
140 * seconds in the current year takes us to the end of the current year
141 * and then around into the next year to the same position.
142 */
143 time.tv_sec = (todr - TODRZERO) / 100;
144 year = YRREF;
145 while (time.tv_sec < base - SECYR/2) {
146 if (LEAPYEAR(year))
147 time.tv_sec += SECDAY;
148 year++;
149 time.tv_sec += SECYR;
150 }
151
152 return (CLKREAD_OK);
153 }
154
vaxstd_clkwrite()155 vaxstd_clkwrite()
156 {
157 int year = YRREF;
158 u_int secyr;
159 u_int yrtime = time.tv_sec;
160
161 /*
162 * Whittle the time down to an offset in the current year,
163 * by subtracting off whole years as long as possible.
164 */
165 for (;;) {
166 secyr = SECYR;
167 if (LEAPYEAR(year))
168 secyr += SECDAY;
169 if (yrtime < secyr)
170 break;
171 yrtime -= secyr;
172 year++;
173 }
174 mtpr(TODR, TODRZERO + yrtime*100);
175 }
176 #endif
177
178 #if VAX8200 || VAX630
179 /*
180 * This code is defunct after 2099.
181 * Will Unix still be here then??
182 */
183 short dayyr[12] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
184
chiptotime(c)185 chiptotime(c)
186 register struct chiptime *c;
187 {
188 register int days, yr;
189
190 /* simple sanity checks */
191 if (c->year < 70 || c->mon < 1 || c->mon > 12 ||
192 c->day < 1 || c->day > 31) {
193 printf("WARNING: preposterous clock chip time");
194 return (0);
195 }
196 days = 0;
197 for (yr = 70; yr < c->year; yr++)
198 days += LEAPYEAR(yr) ? 366 : 365;
199 days += dayyr[c->mon - 1] + c->day - 1;
200 if (LEAPYEAR(yr) && c->mon > 2)
201 days++;
202 /* now have days since Jan 1, 1970; the rest is easy... */
203 return (days * SECDAY + c->hour * 3600 + c->min * 60 + c->sec);
204 }
205
timetochip(c)206 timetochip(c)
207 register struct chiptime *c;
208 {
209 register int t, t2, t3;
210
211 /* compute the year */
212 t2 = time.tv_sec / SECDAY;
213 t = 69;
214 while (t2 >= 0) { /* whittle off years */
215 t3 = t2;
216 t++;
217 t2 -= LEAPYEAR(t) ? 366 : 365;
218 }
219 c->year = t;
220
221 /* t3 = month + day; separate */
222 t = LEAPYEAR(t);
223 for (t2 = 1; t2 < 12; t2++)
224 if (t3 < dayyr[t2] + (t && t2 > 1))
225 break;
226
227 /* t2 is month */
228 c->mon = t2;
229 c->day = t3 - dayyr[t2 - 1] + 1;
230 if (t && t2 > 2)
231 c->day--;
232
233 /* the rest is easy */
234 t = time.tv_sec % SECDAY;
235 c->hour = t / 3600;
236 t %= 3600;
237 c->min = t / 60;
238 c->sec = t % 60;
239 }
240 #endif
241