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