13f31c649SGarrett Wollman /****************************************************************************** 23f31c649SGarrett Wollman * * 33f31c649SGarrett Wollman * Copyright (c) David L. Mills 1993, 1994 * 43f31c649SGarrett Wollman * * 53f31c649SGarrett Wollman * Permission to use, copy, modify, and distribute this software and its * 63f31c649SGarrett Wollman * documentation for any purpose and without fee is hereby granted, provided * 73f31c649SGarrett Wollman * that the above copyright notice appears in all copies and that both the * 83f31c649SGarrett Wollman * copyright notice and this permission notice appear in supporting * 93f31c649SGarrett Wollman * documentation, and that the name University of Delaware not be used in * 103f31c649SGarrett Wollman * advertising or publicity pertaining to distribution of the software * 113f31c649SGarrett Wollman * without specific, written prior permission. The University of Delaware * 123f31c649SGarrett Wollman * makes no representations about the suitability this software for any * 133f31c649SGarrett Wollman * purpose. It is provided "as is" without express or implied warranty. * 143f31c649SGarrett Wollman * * 153f31c649SGarrett Wollman ******************************************************************************/ 163f31c649SGarrett Wollman 173f31c649SGarrett Wollman /* 183f31c649SGarrett Wollman * Modification history kern_ntptime.c 193f31c649SGarrett Wollman * 20885bd8e4SJohn Hay * 24 Sep 94 David L. Mills 21885bd8e4SJohn Hay * Tightened code at exits. 22885bd8e4SJohn Hay * 233f31c649SGarrett Wollman * 24 Mar 94 David L. Mills 243f31c649SGarrett Wollman * Revised syscall interface to include new variables for PPS 253f31c649SGarrett Wollman * time discipline. 263f31c649SGarrett Wollman * 273f31c649SGarrett Wollman * 14 Feb 94 David L. Mills 283f31c649SGarrett Wollman * Added code for external clock 293f31c649SGarrett Wollman * 303f31c649SGarrett Wollman * 28 Nov 93 David L. Mills 313f31c649SGarrett Wollman * Revised frequency scaling to conform with adjusted parameters 323f31c649SGarrett Wollman * 333f31c649SGarrett Wollman * 17 Sep 93 David L. Mills 343f31c649SGarrett Wollman * Created file 353f31c649SGarrett Wollman */ 363f31c649SGarrett Wollman /* 373f31c649SGarrett Wollman * ntp_gettime(), ntp_adjtime() - precision time interface for SunOS 38885bd8e4SJohn Hay * V4.1.1 and V4.1.3 393f31c649SGarrett Wollman * 403f31c649SGarrett Wollman * These routines consitute the Network Time Protocol (NTP) interfaces 413f31c649SGarrett Wollman * for user and daemon application programs. The ntp_gettime() routine 423f31c649SGarrett Wollman * provides the time, maximum error (synch distance) and estimated error 433f31c649SGarrett Wollman * (dispersion) to client user application programs. The ntp_adjtime() 443f31c649SGarrett Wollman * routine is used by the NTP daemon to adjust the system clock to an 453f31c649SGarrett Wollman * externally derived time. The time offset and related variables set by 463f31c649SGarrett Wollman * this routine are used by hardclock() to adjust the phase and 473f31c649SGarrett Wollman * frequency of the phase-lock loop which controls the system clock. 483f31c649SGarrett Wollman */ 493f31c649SGarrett Wollman #include <sys/param.h> 503f31c649SGarrett Wollman #include <sys/systm.h> 51d2d3e875SBruce Evans #include <sys/sysproto.h> 523f31c649SGarrett Wollman #include <sys/kernel.h> 533f31c649SGarrett Wollman #include <sys/proc.h> 543f31c649SGarrett Wollman #include <sys/timex.h> 553f31c649SGarrett Wollman #include <sys/sysctl.h> 563f31c649SGarrett Wollman 573f31c649SGarrett Wollman /* 583f31c649SGarrett Wollman * The following variables are used by the hardclock() routine in the 593f31c649SGarrett Wollman * kern_clock.c module and are described in that module. 603f31c649SGarrett Wollman */ 613f31c649SGarrett Wollman extern int time_state; /* clock state */ 623f31c649SGarrett Wollman extern int time_status; /* clock status bits */ 633f31c649SGarrett Wollman extern long time_offset; /* time adjustment (us) */ 643f31c649SGarrett Wollman extern long time_freq; /* frequency offset (scaled ppm) */ 653f31c649SGarrett Wollman extern long time_maxerror; /* maximum error (us) */ 663f31c649SGarrett Wollman extern long time_esterror; /* estimated error (us) */ 673f31c649SGarrett Wollman extern long time_constant; /* pll time constant */ 683f31c649SGarrett Wollman extern long time_precision; /* clock precision (us) */ 693f31c649SGarrett Wollman extern long time_tolerance; /* frequency tolerance (scaled ppm) */ 703f31c649SGarrett Wollman 713f31c649SGarrett Wollman #ifdef PPS_SYNC 723f31c649SGarrett Wollman /* 733f31c649SGarrett Wollman * The following variables are used only if the PPS signal discipline 743f31c649SGarrett Wollman * is configured in the kernel. 753f31c649SGarrett Wollman */ 763f31c649SGarrett Wollman extern int pps_shift; /* interval duration (s) (shift) */ 773f31c649SGarrett Wollman extern long pps_freq; /* pps frequency offset (scaled ppm) */ 783f31c649SGarrett Wollman extern long pps_jitter; /* pps jitter (us) */ 793f31c649SGarrett Wollman extern long pps_stabil; /* pps stability (scaled ppm) */ 803f31c649SGarrett Wollman extern long pps_jitcnt; /* jitter limit exceeded */ 813f31c649SGarrett Wollman extern long pps_calcnt; /* calibration intervals */ 823f31c649SGarrett Wollman extern long pps_errcnt; /* calibration errors */ 833f31c649SGarrett Wollman extern long pps_stbcnt; /* stability limit exceeded */ 843f31c649SGarrett Wollman #endif /* PPS_SYNC */ 853f31c649SGarrett Wollman 86a52752a4SPoul-Henning Kamp static int 87a52752a4SPoul-Henning Kamp ntp_sysctl SYSCTL_HANDLER_ARGS 883f31c649SGarrett Wollman { 893f31c649SGarrett Wollman struct timeval atv; 903f31c649SGarrett Wollman struct ntptimeval ntv; 913f31c649SGarrett Wollman int s; 923f31c649SGarrett Wollman 933f31c649SGarrett Wollman s = splclock(); 943f31c649SGarrett Wollman #ifdef EXT_CLOCK 953f31c649SGarrett Wollman /* 963f31c649SGarrett Wollman * The microtime() external clock routine returns a 973f31c649SGarrett Wollman * status code. If less than zero, we declare an error 983f31c649SGarrett Wollman * in the clock status word and return the kernel 993f31c649SGarrett Wollman * (software) time variable. While there are other 1003f31c649SGarrett Wollman * places that call microtime(), this is the only place 1013f31c649SGarrett Wollman * that matters from an application point of view. 1023f31c649SGarrett Wollman */ 1033f31c649SGarrett Wollman if (microtime(&atv) < 0) { 1043f31c649SGarrett Wollman time_status |= STA_CLOCKERR; 1053f31c649SGarrett Wollman ntv.time = time; 1063f31c649SGarrett Wollman } else { 1073f31c649SGarrett Wollman time_status &= ~STA_CLOCKERR; 1083f31c649SGarrett Wollman } 1093f31c649SGarrett Wollman #else /* EXT_CLOCK */ 1103f31c649SGarrett Wollman microtime(&atv); 1113f31c649SGarrett Wollman #endif /* EXT_CLOCK */ 1123f31c649SGarrett Wollman ntv.time = atv; 1133f31c649SGarrett Wollman ntv.maxerror = time_maxerror; 1143f31c649SGarrett Wollman ntv.esterror = time_esterror; 1153f31c649SGarrett Wollman splx(s); 1163f31c649SGarrett Wollman 1173f31c649SGarrett Wollman ntv.time_state = time_state; 1183f31c649SGarrett Wollman 1193f31c649SGarrett Wollman /* 1203f31c649SGarrett Wollman * Status word error decode. If any of these conditions 1213f31c649SGarrett Wollman * occur, an error is returned, instead of the status 1223f31c649SGarrett Wollman * word. Most applications will care only about the fact 1233f31c649SGarrett Wollman * the system clock may not be trusted, not about the 1243f31c649SGarrett Wollman * details. 1253f31c649SGarrett Wollman * 1263f31c649SGarrett Wollman * Hardware or software error 1273f31c649SGarrett Wollman */ 1283f31c649SGarrett Wollman if (time_status & (STA_UNSYNC | STA_CLOCKERR)) { 1293f31c649SGarrett Wollman ntv.time_state = TIME_ERROR; 1303f31c649SGarrett Wollman } 1313f31c649SGarrett Wollman 1323f31c649SGarrett Wollman /* 1333f31c649SGarrett Wollman * PPS signal lost when either time or frequency 1343f31c649SGarrett Wollman * synchronization requested 1353f31c649SGarrett Wollman */ 1363f31c649SGarrett Wollman if (time_status & (STA_PPSFREQ | STA_PPSTIME) && 1373f31c649SGarrett Wollman !(time_status & STA_PPSSIGNAL)) { 1383f31c649SGarrett Wollman ntv.time_state = TIME_ERROR; 1393f31c649SGarrett Wollman } 1403f31c649SGarrett Wollman 1413f31c649SGarrett Wollman /* 1423f31c649SGarrett Wollman * PPS jitter exceeded when time synchronization 1433f31c649SGarrett Wollman * requested 1443f31c649SGarrett Wollman */ 1453f31c649SGarrett Wollman if (time_status & STA_PPSTIME && 1463f31c649SGarrett Wollman time_status & STA_PPSJITTER) { 1473f31c649SGarrett Wollman ntv.time_state = TIME_ERROR; 1483f31c649SGarrett Wollman } 1493f31c649SGarrett Wollman 1503f31c649SGarrett Wollman /* 1513f31c649SGarrett Wollman * PPS wander exceeded or calibration error when 1523f31c649SGarrett Wollman * frequency synchronization requested 1533f31c649SGarrett Wollman */ 1543f31c649SGarrett Wollman if (time_status & STA_PPSFREQ && 1553f31c649SGarrett Wollman time_status & (STA_PPSWANDER | STA_PPSERROR)) { 1563f31c649SGarrett Wollman ntv.time_state = TIME_ERROR; 1573f31c649SGarrett Wollman } 158a52752a4SPoul-Henning Kamp return (sysctl_handle_opaque(oidp, &ntv, sizeof ntv, req)); 1593f31c649SGarrett Wollman } 1603f31c649SGarrett Wollman 161a52752a4SPoul-Henning Kamp SYSCTL_NODE(_kern, KERN_NTP_PLL, ntp_pll, CTLFLAG_RW, 0, 162a52752a4SPoul-Henning Kamp "NTP kernel PLL related stuff"); 163a52752a4SPoul-Henning Kamp SYSCTL_PROC(_kern_ntp_pll, NTP_PLL_GETTIME, gettime, CTLTYPE_OPAQUE|CTLFLAG_RD, 164946bb7a2SPoul-Henning Kamp 0, sizeof(struct ntptimeval) , ntp_sysctl, "S,ntptimeval", ""); 165a52752a4SPoul-Henning Kamp 1663f31c649SGarrett Wollman /* 1673f31c649SGarrett Wollman * ntp_adjtime() - NTP daemon application interface 1683f31c649SGarrett Wollman */ 169d2d3e875SBruce Evans #ifndef _SYS_SYSPROTO_H_ 1703f31c649SGarrett Wollman struct ntp_adjtime_args { 1713f31c649SGarrett Wollman struct timex *tp; 1723f31c649SGarrett Wollman }; 173d2d3e875SBruce Evans #endif 1743f31c649SGarrett Wollman 1753f31c649SGarrett Wollman int 1763f31c649SGarrett Wollman ntp_adjtime(struct proc *p, struct ntp_adjtime_args *uap, int *retval) 1773f31c649SGarrett Wollman { 1783f31c649SGarrett Wollman struct timex ntv; 1793f31c649SGarrett Wollman int modes; 1803f31c649SGarrett Wollman int s; 1813f31c649SGarrett Wollman int error; 1823f31c649SGarrett Wollman 1833f31c649SGarrett Wollman error = copyin((caddr_t)uap->tp, (caddr_t)&ntv, sizeof(ntv)); 1843f31c649SGarrett Wollman if (error) 1853f31c649SGarrett Wollman return error; 1863f31c649SGarrett Wollman 1873f31c649SGarrett Wollman /* 1883f31c649SGarrett Wollman * Update selected clock variables - only the superuser can 1893f31c649SGarrett Wollman * change anything. Note that there is no error checking here on 1903f31c649SGarrett Wollman * the assumption the superuser should know what it is doing. 1913f31c649SGarrett Wollman */ 1923f31c649SGarrett Wollman modes = ntv.modes; 1933f31c649SGarrett Wollman if ((modes != 0) 1943f31c649SGarrett Wollman && (error = suser(p->p_cred->pc_ucred, &p->p_acflag))) 1953f31c649SGarrett Wollman return error; 1963f31c649SGarrett Wollman 1973f31c649SGarrett Wollman s = splclock(); 1983f31c649SGarrett Wollman if (modes & MOD_FREQUENCY) 1993f31c649SGarrett Wollman #ifdef PPS_SYNC 2003f31c649SGarrett Wollman time_freq = ntv.freq - pps_freq; 2013f31c649SGarrett Wollman #else /* PPS_SYNC */ 2023f31c649SGarrett Wollman time_freq = ntv.freq; 2033f31c649SGarrett Wollman #endif /* PPS_SYNC */ 2043f31c649SGarrett Wollman if (modes & MOD_MAXERROR) 2053f31c649SGarrett Wollman time_maxerror = ntv.maxerror; 2063f31c649SGarrett Wollman if (modes & MOD_ESTERROR) 2073f31c649SGarrett Wollman time_esterror = ntv.esterror; 2083f31c649SGarrett Wollman if (modes & MOD_STATUS) { 2093f31c649SGarrett Wollman time_status &= STA_RONLY; 2103f31c649SGarrett Wollman time_status |= ntv.status & ~STA_RONLY; 2113f31c649SGarrett Wollman } 2123f31c649SGarrett Wollman if (modes & MOD_TIMECONST) 2133f31c649SGarrett Wollman time_constant = ntv.constant; 2143f31c649SGarrett Wollman if (modes & MOD_OFFSET) 2153f31c649SGarrett Wollman hardupdate(ntv.offset); 2163f31c649SGarrett Wollman 2173f31c649SGarrett Wollman /* 2183f31c649SGarrett Wollman * Retrieve all clock variables 2193f31c649SGarrett Wollman */ 2203f31c649SGarrett Wollman if (time_offset < 0) 2213f31c649SGarrett Wollman ntv.offset = -(-time_offset >> SHIFT_UPDATE); 2223f31c649SGarrett Wollman else 2233f31c649SGarrett Wollman ntv.offset = time_offset >> SHIFT_UPDATE; 2243f31c649SGarrett Wollman #ifdef PPS_SYNC 2253f31c649SGarrett Wollman ntv.freq = time_freq + pps_freq; 2263f31c649SGarrett Wollman #else /* PPS_SYNC */ 2273f31c649SGarrett Wollman ntv.freq = time_freq; 2283f31c649SGarrett Wollman #endif /* PPS_SYNC */ 2293f31c649SGarrett Wollman ntv.maxerror = time_maxerror; 2303f31c649SGarrett Wollman ntv.esterror = time_esterror; 2313f31c649SGarrett Wollman ntv.status = time_status; 2323f31c649SGarrett Wollman ntv.constant = time_constant; 2333f31c649SGarrett Wollman ntv.precision = time_precision; 2343f31c649SGarrett Wollman ntv.tolerance = time_tolerance; 2353f31c649SGarrett Wollman #ifdef PPS_SYNC 2363f31c649SGarrett Wollman ntv.shift = pps_shift; 2373f31c649SGarrett Wollman ntv.ppsfreq = pps_freq; 2383f31c649SGarrett Wollman ntv.jitter = pps_jitter >> PPS_AVG; 2393f31c649SGarrett Wollman ntv.stabil = pps_stabil; 2403f31c649SGarrett Wollman ntv.calcnt = pps_calcnt; 2413f31c649SGarrett Wollman ntv.errcnt = pps_errcnt; 2423f31c649SGarrett Wollman ntv.jitcnt = pps_jitcnt; 2433f31c649SGarrett Wollman ntv.stbcnt = pps_stbcnt; 2443f31c649SGarrett Wollman #endif /* PPS_SYNC */ 2453f31c649SGarrett Wollman (void)splx(s); 2463f31c649SGarrett Wollman 2473f31c649SGarrett Wollman error = copyout((caddr_t)&ntv, (caddr_t)uap->tp, sizeof(ntv)); 2483f31c649SGarrett Wollman if (!error) { 2493f31c649SGarrett Wollman /* 2503f31c649SGarrett Wollman * Status word error decode. See comments in 2513f31c649SGarrett Wollman * ntp_gettime() routine. 2523f31c649SGarrett Wollman */ 2533f31c649SGarrett Wollman retval[0] = time_state; 2543f31c649SGarrett Wollman if (time_status & (STA_UNSYNC | STA_CLOCKERR)) 2553f31c649SGarrett Wollman retval[0] = TIME_ERROR; 2563f31c649SGarrett Wollman if (time_status & (STA_PPSFREQ | STA_PPSTIME) && 2573f31c649SGarrett Wollman !(time_status & STA_PPSSIGNAL)) 2583f31c649SGarrett Wollman retval[0] = TIME_ERROR; 2593f31c649SGarrett Wollman if (time_status & STA_PPSTIME && 2603f31c649SGarrett Wollman time_status & STA_PPSJITTER) 2613f31c649SGarrett Wollman retval[0] = TIME_ERROR; 2623f31c649SGarrett Wollman if (time_status & STA_PPSFREQ && 2633f31c649SGarrett Wollman time_status & (STA_PPSWANDER | STA_PPSERROR)) 2643f31c649SGarrett Wollman retval[0] = TIME_ERROR; 2653f31c649SGarrett Wollman } 2663f31c649SGarrett Wollman return error; 2673f31c649SGarrett Wollman } 2683f31c649SGarrett Wollman 2693f31c649SGarrett Wollman 270