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