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