1 /* $NetBSD: kern_ntptime.c,v 1.3 1996/11/14 04:51:09 thorpej Exp $ */ 2 3 /****************************************************************************** 4 * * 5 * Copyright (c) David L. Mills 1993, 1994 * 6 * * 7 * Permission to use, copy, modify, and distribute this software and its * 8 * documentation for any purpose and without fee is hereby granted, provided * 9 * that the above copyright notice appears in all copies and that both the * 10 * copyright notice and this permission notice appear in supporting * 11 * documentation, and that the name University of Delaware not be used in * 12 * advertising or publicity pertaining to distribution of the software * 13 * without specific, written prior permission. The University of Delaware * 14 * makes no representations about the suitability this software for any * 15 * purpose. It is provided "as is" without express or implied warranty. * 16 * * 17 ******************************************************************************/ 18 19 /* 20 * Modification history kern_ntptime.c 21 * 22 * 24 Sep 94 David L. Mills 23 * Tightened code at exits. 24 * 25 * 24 Mar 94 David L. Mills 26 * Revised syscall interface to include new variables for PPS 27 * time discipline. 28 * 29 * 14 Feb 94 David L. Mills 30 * Added code for external clock 31 * 32 * 28 Nov 93 David L. Mills 33 * Revised frequency scaling to conform with adjusted parameters 34 * 35 * 17 Sep 93 David L. Mills 36 * Created file 37 */ 38 /* 39 * ntp_gettime(), ntp_adjtime() - precision time interface for SunOS 40 * V4.1.1 and V4.1.3 41 * 42 * These routines consitute the Network Time Protocol (NTP) interfaces 43 * for user and daemon application programs. The ntp_gettime() routine 44 * provides the time, maximum error (synch distance) and estimated error 45 * (dispersion) to client user application programs. The ntp_adjtime() 46 * routine is used by the NTP daemon to adjust the system clock to an 47 * externally derived time. The time offset and related variables set by 48 * this routine are used by hardclock() to adjust the phase and 49 * frequency of the phase-lock loop which controls the system clock. 50 */ 51 #include <sys/param.h> 52 #include <sys/resourcevar.h> 53 #include <sys/systm.h> 54 #include <sys/kernel.h> 55 #include <sys/proc.h> 56 #include <sys/timex.h> 57 #include <sys/vnode.h> 58 59 #include <sys/mount.h> 60 #include <sys/syscallargs.h> 61 62 #include <machine/cpu.h> 63 64 #include <vm/vm.h> 65 #include <sys/sysctl.h> 66 67 /* 68 * The following variables are used by the hardclock() routine in the 69 * kern_clock.c module and are described in that module. 70 */ 71 extern struct timeval time; /* kernel time variable */ 72 extern int time_state; /* clock state */ 73 extern int time_status; /* clock status bits */ 74 extern long time_offset; /* time adjustment (us) */ 75 extern long time_freq; /* frequency offset (scaled ppm) */ 76 extern long time_maxerror; /* maximum error (us) */ 77 extern long time_esterror; /* estimated error (us) */ 78 extern long time_constant; /* pll time constant */ 79 extern long time_precision; /* clock precision (us) */ 80 extern long time_tolerance; /* frequency tolerance (scaled ppm) */ 81 82 #ifdef PPS_SYNC 83 /* 84 * The following variables are used only if the PPS signal discipline 85 * is configured in the kernel. 86 */ 87 extern int pps_shift; /* interval duration (s) (shift) */ 88 extern long pps_freq; /* pps frequency offset (scaled ppm) */ 89 extern long pps_jitter; /* pps jitter (us) */ 90 extern long pps_stabil; /* pps stability (scaled ppm) */ 91 extern long pps_jitcnt; /* jitter limit exceeded */ 92 extern long pps_calcnt; /* calibration intervals */ 93 extern long pps_errcnt; /* calibration errors */ 94 extern long pps_stbcnt; /* stability limit exceeded */ 95 #endif /* PPS_SYNC */ 96 97 98 99 /*ARGSUSED*/ 100 /* 101 * ntp_gettime() - NTP user application interface 102 */ 103 int 104 sys_ntp_gettime(p, v, retval) 105 struct proc *p; 106 void *v; 107 register_t *retval; 108 109 { 110 struct sys_ntp_gettime_args /* { 111 syscallarg(struct timex *) tp; 112 } */ *uap = v; 113 struct timeval atv; 114 struct ntptimeval ntv; 115 int error = 0; 116 int s; 117 118 if (SCARG(uap, tp)) { 119 s = splclock(); 120 #ifdef EXT_CLOCK 121 /* 122 * The microtime() external clock routine returns a 123 * status code. If less than zero, we declare an error 124 * in the clock status word and return the kernel 125 * (software) time variable. While there are other 126 * places that call microtime(), this is the only place 127 * that matters from an application point of view. 128 */ 129 if (microtime(&atv) < 0) { 130 time_status |= STA_CLOCKERR; 131 ntv.time = time; 132 } else 133 time_status &= ~STA_CLOCKERR; 134 #else /* EXT_CLOCK */ 135 microtime(&atv); 136 #endif /* EXT_CLOCK */ 137 ntv.time = atv; 138 ntv.maxerror = time_maxerror; 139 ntv.esterror = time_esterror; 140 (void) splx(s); 141 142 error = copyout((caddr_t)&ntv, (caddr_t)SCARG(uap, tp), 143 sizeof (ntv)); 144 } 145 if (!error) { 146 147 /* 148 * Status word error decode. If any of these conditions 149 * occur, an error is returned, instead of the status 150 * word. Most applications will care only about the fact 151 * the system clock may not be trusted, not about the 152 * details. 153 * 154 * Hardware or software error 155 */ 156 if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) || 157 158 /* 159 * PPS signal lost when either time or frequency 160 * synchronization requested 161 */ 162 (time_status & (STA_PPSFREQ | STA_PPSTIME) && 163 !(time_status & STA_PPSSIGNAL)) || 164 165 /* 166 * PPS jitter exceeded when time synchronization 167 * requested 168 */ 169 (time_status & STA_PPSTIME && 170 time_status & STA_PPSJITTER) || 171 172 /* 173 * PPS wander exceeded or calibration error when 174 * frequency synchronization requested 175 */ 176 (time_status & STA_PPSFREQ && 177 time_status & (STA_PPSWANDER | STA_PPSERROR))) 178 *retval = TIME_ERROR; 179 else 180 *retval = (register_t)time_state; 181 } 182 return(error); 183 } 184 185 186 /* ARGSUSED */ 187 /* 188 * ntp_adjtime() - NTP daemon application interface 189 */ 190 int 191 sys_ntp_adjtime(p, v, retval) 192 struct proc *p; 193 void *v; 194 register_t *retval; 195 { 196 struct sys_ntp_adjtime_args /* { 197 syscallarg(struct timex *) tp; 198 } */ *uap = v; 199 struct timex ntv; 200 int error = 0; 201 int modes; 202 int s; 203 204 if ((error = copyin((caddr_t)SCARG(uap, tp), (caddr_t)&ntv, 205 sizeof(ntv)))) 206 return (error); 207 208 /* 209 * Update selected clock variables - only the superuser can 210 * change anything. Note that there is no error checking here on 211 * the assumption the superuser should know what it is doing. 212 */ 213 modes = ntv.modes; 214 if (modes != 0 && (error = suser(p->p_ucred, &p->p_acflag))) 215 return (error); 216 217 s = splclock(); 218 if (modes & MOD_FREQUENCY) 219 #ifdef PPS_SYNC 220 time_freq = ntv.freq - pps_freq; 221 #else /* PPS_SYNC */ 222 time_freq = ntv.freq; 223 #endif /* PPS_SYNC */ 224 if (modes & MOD_MAXERROR) 225 time_maxerror = ntv.maxerror; 226 if (modes & MOD_ESTERROR) 227 time_esterror = ntv.esterror; 228 if (modes & MOD_STATUS) { 229 time_status &= STA_RONLY; 230 time_status |= ntv.status & ~STA_RONLY; 231 } 232 if (modes & MOD_TIMECONST) 233 time_constant = ntv.constant; 234 if (modes & MOD_OFFSET) 235 hardupdate(ntv.offset); 236 237 /* 238 * Retrieve all clock variables 239 */ 240 if (time_offset < 0) 241 ntv.offset = -(-time_offset >> SHIFT_UPDATE); 242 else 243 ntv.offset = time_offset >> SHIFT_UPDATE; 244 #ifdef PPS_SYNC 245 ntv.freq = time_freq + pps_freq; 246 #else /* PPS_SYNC */ 247 ntv.freq = time_freq; 248 #endif /* PPS_SYNC */ 249 ntv.maxerror = time_maxerror; 250 ntv.esterror = time_esterror; 251 ntv.status = time_status; 252 ntv.constant = time_constant; 253 ntv.precision = time_precision; 254 ntv.tolerance = time_tolerance; 255 #ifdef PPS_SYNC 256 ntv.shift = pps_shift; 257 ntv.ppsfreq = pps_freq; 258 ntv.jitter = pps_jitter >> PPS_AVG; 259 ntv.stabil = pps_stabil; 260 ntv.calcnt = pps_calcnt; 261 ntv.errcnt = pps_errcnt; 262 ntv.jitcnt = pps_jitcnt; 263 ntv.stbcnt = pps_stbcnt; 264 #endif /* PPS_SYNC */ 265 (void)splx(s); 266 267 error = copyout((caddr_t)&ntv, (caddr_t)SCARG(uap, tp), sizeof(ntv)); 268 if (!error) { 269 270 /* 271 * Status word error decode. See comments in 272 * ntp_gettime() routine. 273 */ 274 if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) || 275 (time_status & (STA_PPSFREQ | STA_PPSTIME) && 276 !(time_status & STA_PPSSIGNAL)) || 277 (time_status & STA_PPSTIME && 278 time_status & STA_PPSJITTER) || 279 (time_status & STA_PPSFREQ && 280 time_status & (STA_PPSWANDER | STA_PPSERROR))) 281 *retval = TIME_ERROR; 282 else 283 *retval = (register_t)time_state; 284 } 285 return error; 286 } 287 288 289 290 /* 291 * return information about kernel precision timekeeping 292 */ 293 int 294 sysctl_ntptime(where, sizep) 295 register char *where; 296 size_t *sizep; 297 { 298 struct timeval atv; 299 struct ntptimeval ntv; 300 int s; 301 302 /* 303 * Construct ntp_timeval. 304 */ 305 306 s = splclock(); 307 #ifdef EXT_CLOCK 308 /* 309 * The microtime() external clock routine returns a 310 * status code. If less than zero, we declare an error 311 * in the clock status word and return the kernel 312 * (software) time variable. While there are other 313 * places that call microtime(), this is the only place 314 * that matters from an application point of view. 315 */ 316 if (microtime(&atv) < 0) { 317 time_status |= STA_CLOCKERR; 318 ntv.time = time; 319 } else { 320 time_status &= ~STA_CLOCKERR; 321 } 322 #else /* EXT_CLOCK */ 323 microtime(&atv); 324 #endif /* EXT_CLOCK */ 325 ntv.time = atv; 326 ntv.maxerror = time_maxerror; 327 ntv.esterror = time_esterror; 328 splx(s); 329 330 #ifdef notyet 331 /* 332 * Status word error decode. If any of these conditions 333 * occur, an error is returned, instead of the status 334 * word. Most applications will care only about the fact 335 * the system clock may not be trusted, not about the 336 * details. 337 * 338 * Hardware or software error 339 */ 340 if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) || 341 ntv.time_state = TIME_ERROR; 342 343 /* 344 * PPS signal lost when either time or frequency 345 * synchronization requested 346 */ 347 (time_status & (STA_PPSFREQ | STA_PPSTIME) && 348 !(time_status & STA_PPSSIGNAL)) || 349 350 /* 351 * PPS jitter exceeded when time synchronization 352 * requested 353 */ 354 (time_status & STA_PPSTIME && 355 time_status & STA_PPSJITTER) || 356 357 /* 358 * PPS wander exceeded or calibration error when 359 * frequency synchronization requested 360 */ 361 (time_status & STA_PPSFREQ && 362 time_status & (STA_PPSWANDER | STA_PPSERROR))) 363 ntv.time_state = TIME_ERROR; 364 else 365 ntv.time_state = time_state; 366 #endif /* notyet */ 367 return (sysctl_rdstruct(where, sizep, NULL, &ntv, sizeof(ntv))); 368 } 369