1 /* $NetBSD: kern_ntptime.c,v 1.5 1996/12/22 06:23:40 cgd 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 #ifdef NTP 68 69 /* 70 * The following variables are used by the hardclock() routine in the 71 * kern_clock.c module and are described in that module. 72 */ 73 extern struct timeval time; /* kernel time variable */ 74 extern int time_state; /* clock state */ 75 extern int time_status; /* clock status bits */ 76 extern long time_offset; /* time adjustment (us) */ 77 extern long time_freq; /* frequency offset (scaled ppm) */ 78 extern long time_maxerror; /* maximum error (us) */ 79 extern long time_esterror; /* estimated error (us) */ 80 extern long time_constant; /* pll time constant */ 81 extern long time_precision; /* clock precision (us) */ 82 extern long time_tolerance; /* frequency tolerance (scaled ppm) */ 83 84 #ifdef PPS_SYNC 85 /* 86 * The following variables are used only if the PPS signal discipline 87 * is configured in the kernel. 88 */ 89 extern int pps_shift; /* interval duration (s) (shift) */ 90 extern long pps_freq; /* pps frequency offset (scaled ppm) */ 91 extern long pps_jitter; /* pps jitter (us) */ 92 extern long pps_stabil; /* pps stability (scaled ppm) */ 93 extern long pps_jitcnt; /* jitter limit exceeded */ 94 extern long pps_calcnt; /* calibration intervals */ 95 extern long pps_errcnt; /* calibration errors */ 96 extern long pps_stbcnt; /* stability limit exceeded */ 97 #endif /* PPS_SYNC */ 98 99 100 101 /*ARGSUSED*/ 102 /* 103 * ntp_gettime() - NTP user application interface 104 */ 105 int 106 sys_ntp_gettime(p, v, retval) 107 struct proc *p; 108 void *v; 109 register_t *retval; 110 111 { 112 struct sys_ntp_gettime_args /* { 113 syscallarg(struct ntptimeval *) ntvp; 114 } */ *uap = v; 115 struct timeval atv; 116 struct ntptimeval ntv; 117 int error = 0; 118 int s; 119 120 if (SCARG(uap, ntvp)) { 121 s = splclock(); 122 #ifdef EXT_CLOCK 123 /* 124 * The microtime() external clock routine returns a 125 * status code. If less than zero, we declare an error 126 * in the clock status word and return the kernel 127 * (software) time variable. While there are other 128 * places that call microtime(), this is the only place 129 * that matters from an application point of view. 130 */ 131 if (microtime(&atv) < 0) { 132 time_status |= STA_CLOCKERR; 133 ntv.time = time; 134 } else 135 time_status &= ~STA_CLOCKERR; 136 #else /* EXT_CLOCK */ 137 microtime(&atv); 138 #endif /* EXT_CLOCK */ 139 ntv.time = atv; 140 ntv.maxerror = time_maxerror; 141 ntv.esterror = time_esterror; 142 (void) splx(s); 143 144 error = copyout((caddr_t)&ntv, (caddr_t)SCARG(uap, ntvp), 145 sizeof (ntv)); 146 } 147 if (!error) { 148 149 /* 150 * Status word error decode. If any of these conditions 151 * occur, an error is returned, instead of the status 152 * word. Most applications will care only about the fact 153 * the system clock may not be trusted, not about the 154 * details. 155 * 156 * Hardware or software error 157 */ 158 if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) || 159 160 /* 161 * PPS signal lost when either time or frequency 162 * synchronization requested 163 */ 164 (time_status & (STA_PPSFREQ | STA_PPSTIME) && 165 !(time_status & STA_PPSSIGNAL)) || 166 167 /* 168 * PPS jitter exceeded when time synchronization 169 * requested 170 */ 171 (time_status & STA_PPSTIME && 172 time_status & STA_PPSJITTER) || 173 174 /* 175 * PPS wander exceeded or calibration error when 176 * frequency synchronization requested 177 */ 178 (time_status & STA_PPSFREQ && 179 time_status & (STA_PPSWANDER | STA_PPSERROR))) 180 *retval = TIME_ERROR; 181 else 182 *retval = (register_t)time_state; 183 } 184 return(error); 185 } 186 187 188 /* ARGSUSED */ 189 /* 190 * ntp_adjtime() - NTP daemon application interface 191 */ 192 int 193 sys_ntp_adjtime(p, v, retval) 194 struct proc *p; 195 void *v; 196 register_t *retval; 197 { 198 struct sys_ntp_adjtime_args /* { 199 syscallarg(struct timex *) tp; 200 } */ *uap = v; 201 struct timex ntv; 202 int error = 0; 203 int modes; 204 int s; 205 206 if ((error = copyin((caddr_t)SCARG(uap, tp), (caddr_t)&ntv, 207 sizeof(ntv)))) 208 return (error); 209 210 /* 211 * Update selected clock variables - only the superuser can 212 * change anything. Note that there is no error checking here on 213 * the assumption the superuser should know what it is doing. 214 */ 215 modes = ntv.modes; 216 if (modes != 0 && (error = suser(p->p_ucred, &p->p_acflag))) 217 return (error); 218 219 s = splclock(); 220 if (modes & MOD_FREQUENCY) 221 #ifdef PPS_SYNC 222 time_freq = ntv.freq - pps_freq; 223 #else /* PPS_SYNC */ 224 time_freq = ntv.freq; 225 #endif /* PPS_SYNC */ 226 if (modes & MOD_MAXERROR) 227 time_maxerror = ntv.maxerror; 228 if (modes & MOD_ESTERROR) 229 time_esterror = ntv.esterror; 230 if (modes & MOD_STATUS) { 231 time_status &= STA_RONLY; 232 time_status |= ntv.status & ~STA_RONLY; 233 } 234 if (modes & MOD_TIMECONST) 235 time_constant = ntv.constant; 236 if (modes & MOD_OFFSET) 237 hardupdate(ntv.offset); 238 239 /* 240 * Retrieve all clock variables 241 */ 242 if (time_offset < 0) 243 ntv.offset = -(-time_offset >> SHIFT_UPDATE); 244 else 245 ntv.offset = time_offset >> SHIFT_UPDATE; 246 #ifdef PPS_SYNC 247 ntv.freq = time_freq + pps_freq; 248 #else /* PPS_SYNC */ 249 ntv.freq = time_freq; 250 #endif /* PPS_SYNC */ 251 ntv.maxerror = time_maxerror; 252 ntv.esterror = time_esterror; 253 ntv.status = time_status; 254 ntv.constant = time_constant; 255 ntv.precision = time_precision; 256 ntv.tolerance = time_tolerance; 257 #ifdef PPS_SYNC 258 ntv.shift = pps_shift; 259 ntv.ppsfreq = pps_freq; 260 ntv.jitter = pps_jitter >> PPS_AVG; 261 ntv.stabil = pps_stabil; 262 ntv.calcnt = pps_calcnt; 263 ntv.errcnt = pps_errcnt; 264 ntv.jitcnt = pps_jitcnt; 265 ntv.stbcnt = pps_stbcnt; 266 #endif /* PPS_SYNC */ 267 (void)splx(s); 268 269 error = copyout((caddr_t)&ntv, (caddr_t)SCARG(uap, tp), sizeof(ntv)); 270 if (!error) { 271 272 /* 273 * Status word error decode. See comments in 274 * ntp_gettime() routine. 275 */ 276 if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) || 277 (time_status & (STA_PPSFREQ | STA_PPSTIME) && 278 !(time_status & STA_PPSSIGNAL)) || 279 (time_status & STA_PPSTIME && 280 time_status & STA_PPSJITTER) || 281 (time_status & STA_PPSFREQ && 282 time_status & (STA_PPSWANDER | STA_PPSERROR))) 283 *retval = TIME_ERROR; 284 else 285 *retval = (register_t)time_state; 286 } 287 return error; 288 } 289 290 291 292 /* 293 * return information about kernel precision timekeeping 294 */ 295 int 296 sysctl_ntptime(where, sizep) 297 register char *where; 298 size_t *sizep; 299 { 300 struct timeval atv; 301 struct ntptimeval ntv; 302 int s; 303 304 /* 305 * Construct ntp_timeval. 306 */ 307 308 s = splclock(); 309 #ifdef EXT_CLOCK 310 /* 311 * The microtime() external clock routine returns a 312 * status code. If less than zero, we declare an error 313 * in the clock status word and return the kernel 314 * (software) time variable. While there are other 315 * places that call microtime(), this is the only place 316 * that matters from an application point of view. 317 */ 318 if (microtime(&atv) < 0) { 319 time_status |= STA_CLOCKERR; 320 ntv.time = time; 321 } else { 322 time_status &= ~STA_CLOCKERR; 323 } 324 #else /* EXT_CLOCK */ 325 microtime(&atv); 326 #endif /* EXT_CLOCK */ 327 ntv.time = atv; 328 ntv.maxerror = time_maxerror; 329 ntv.esterror = time_esterror; 330 splx(s); 331 332 #ifdef notyet 333 /* 334 * Status word error decode. If any of these conditions 335 * occur, an error is returned, instead of the status 336 * word. Most applications will care only about the fact 337 * the system clock may not be trusted, not about the 338 * details. 339 * 340 * Hardware or software error 341 */ 342 if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) || 343 ntv.time_state = TIME_ERROR; 344 345 /* 346 * PPS signal lost when either time or frequency 347 * synchronization requested 348 */ 349 (time_status & (STA_PPSFREQ | STA_PPSTIME) && 350 !(time_status & STA_PPSSIGNAL)) || 351 352 /* 353 * PPS jitter exceeded when time synchronization 354 * requested 355 */ 356 (time_status & STA_PPSTIME && 357 time_status & STA_PPSJITTER) || 358 359 /* 360 * PPS wander exceeded or calibration error when 361 * frequency synchronization requested 362 */ 363 (time_status & STA_PPSFREQ && 364 time_status & (STA_PPSWANDER | STA_PPSERROR))) 365 ntv.time_state = TIME_ERROR; 366 else 367 ntv.time_state = time_state; 368 #endif /* notyet */ 369 return (sysctl_rdstruct(where, sizep, NULL, &ntv, sizeof(ntv))); 370 } 371 372 #else /* !NTP */ 373 374 /* 375 * For kernels configured without the NTP option, emulate the behavior 376 * of a kernel with no NTP support (i.e., sys_nosys()). On systems 377 * where kernel NTP support appears present when xntpd is compiled, 378 * (e.g., sys/timex.h is present), xntpd relies on getting a SIGSYS 379 * signal in response to an ntp_adjtime() syscal, to inform xntpd that 380 * NTP support is not really present, and xntpd should fall back to 381 * using a user-level phase-locked loop to discipline the clock. 382 */ 383 int 384 sys_ntp_gettime(p, v, retval) 385 struct proc *p; 386 void *v; 387 register_t *retval; 388 { 389 return(ENOSYS); 390 } 391 392 int 393 sys_ntp_adjtime(p, v, retval) 394 struct proc *p; 395 void *v; 396 register_t *retval; 397 { 398 return(sys_nosys(p, v, retval)); 399 } 400 401 int 402 sysctl_ntptime(where, sizep) 403 register char *where; 404 size_t *sizep; 405 { 406 return (ENOSYS); 407 } 408 #endif /* NTP */ 409