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.5 (Berkeley) 03/13/90 8 */ 9 10 #include "param.h" 11 #include "time.h" 12 #include "kernel.h" 13 14 #include "mtpr.h" 15 #include "clock.h" 16 #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 */ 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 */ 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 */ 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 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 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 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 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 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