1 /****************************************************************************** 2 * * 3 * Copyright (c) David L. Mills 1993, 1994 * 4 * * 5 * Permission to use, copy, modify, and distribute this software and its * 6 * documentation for any purpose and without fee is hereby granted, provided * 7 * that the above copyright notice appears in all copies and that both the * 8 * copyright notice and this permission notice appear in supporting * 9 * documentation, and that the name University of Delaware not be used in * 10 * advertising or publicity pertaining to distribution of the software * 11 * without specific, written prior permission. The University of Delaware * 12 * makes no representations about the suitability this software for any * 13 * purpose. It is provided "as is" without express or implied warranty. * 14 * * 15 ******************************************************************************/ 16 17 /* 18 * Modification history kern_ntptime.c 19 * 20 * 24 Mar 94 David L. Mills 21 * Revised syscall interface to include new variables for PPS 22 * time discipline. 23 * 24 * 14 Feb 94 David L. Mills 25 * Added code for external clock 26 * 27 * 28 Nov 93 David L. Mills 28 * Revised frequency scaling to conform with adjusted parameters 29 * 30 * 17 Sep 93 David L. Mills 31 * Created file 32 */ 33 /* 34 * ntp_gettime(), ntp_adjtime() - precision time interface for SunOS 35 * 4.1.1 and 4.1.3 36 * 37 * These routines consitute the Network Time Protocol (NTP) interfaces 38 * for user and daemon application programs. The ntp_gettime() routine 39 * provides the time, maximum error (synch distance) and estimated error 40 * (dispersion) to client user application programs. The ntp_adjtime() 41 * routine is used by the NTP daemon to adjust the system clock to an 42 * externally derived time. The time offset and related variables set by 43 * this routine are used by hardclock() to adjust the phase and 44 * frequency of the phase-lock loop which controls the system clock. 45 */ 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/sysproto.h> 49 #include <sys/kernel.h> 50 #include <sys/proc.h> 51 #include <sys/timex.h> 52 #include <sys/sysctl.h> 53 54 /* 55 * The following variables are used by the hardclock() routine in the 56 * kern_clock.c module and are described in that module. 57 */ 58 extern int time_state; /* clock state */ 59 extern int time_status; /* clock status bits */ 60 extern long time_offset; /* time adjustment (us) */ 61 extern long time_freq; /* frequency offset (scaled ppm) */ 62 extern long time_maxerror; /* maximum error (us) */ 63 extern long time_esterror; /* estimated error (us) */ 64 extern long time_constant; /* pll time constant */ 65 extern long time_precision; /* clock precision (us) */ 66 extern long time_tolerance; /* frequency tolerance (scaled ppm) */ 67 68 #ifdef PPS_SYNC 69 /* 70 * The following variables are used only if the PPS signal discipline 71 * is configured in the kernel. 72 */ 73 extern int pps_shift; /* interval duration (s) (shift) */ 74 extern long pps_freq; /* pps frequency offset (scaled ppm) */ 75 extern long pps_jitter; /* pps jitter (us) */ 76 extern long pps_stabil; /* pps stability (scaled ppm) */ 77 extern long pps_jitcnt; /* jitter limit exceeded */ 78 extern long pps_calcnt; /* calibration intervals */ 79 extern long pps_errcnt; /* calibration errors */ 80 extern long pps_stbcnt; /* stability limit exceeded */ 81 #endif /* PPS_SYNC */ 82 83 static int 84 ntp_sysctl SYSCTL_HANDLER_ARGS 85 { 86 struct timeval atv; 87 struct ntptimeval ntv; 88 int s; 89 90 s = splclock(); 91 #ifdef EXT_CLOCK 92 /* 93 * The microtime() external clock routine returns a 94 * status code. If less than zero, we declare an error 95 * in the clock status word and return the kernel 96 * (software) time variable. While there are other 97 * places that call microtime(), this is the only place 98 * that matters from an application point of view. 99 */ 100 if (microtime(&atv) < 0) { 101 time_status |= STA_CLOCKERR; 102 ntv.time = time; 103 } else { 104 time_status &= ~STA_CLOCKERR; 105 } 106 #else /* EXT_CLOCK */ 107 microtime(&atv); 108 #endif /* EXT_CLOCK */ 109 ntv.time = atv; 110 ntv.maxerror = time_maxerror; 111 ntv.esterror = time_esterror; 112 splx(s); 113 114 ntv.time_state = time_state; 115 116 /* 117 * Status word error decode. If any of these conditions 118 * occur, an error is returned, instead of the status 119 * word. Most applications will care only about the fact 120 * the system clock may not be trusted, not about the 121 * details. 122 * 123 * Hardware or software error 124 */ 125 if (time_status & (STA_UNSYNC | STA_CLOCKERR)) { 126 ntv.time_state = TIME_ERROR; 127 } 128 129 /* 130 * PPS signal lost when either time or frequency 131 * synchronization requested 132 */ 133 if (time_status & (STA_PPSFREQ | STA_PPSTIME) && 134 !(time_status & STA_PPSSIGNAL)) { 135 ntv.time_state = TIME_ERROR; 136 } 137 138 /* 139 * PPS jitter exceeded when time synchronization 140 * requested 141 */ 142 if (time_status & STA_PPSTIME && 143 time_status & STA_PPSJITTER) { 144 ntv.time_state = TIME_ERROR; 145 } 146 147 /* 148 * PPS wander exceeded or calibration error when 149 * frequency synchronization requested 150 */ 151 if (time_status & STA_PPSFREQ && 152 time_status & (STA_PPSWANDER | STA_PPSERROR)) { 153 ntv.time_state = TIME_ERROR; 154 } 155 return (sysctl_handle_opaque(oidp, &ntv, sizeof ntv, req)); 156 } 157 158 SYSCTL_NODE(_kern, KERN_NTP_PLL, ntp_pll, CTLFLAG_RW, 0, 159 "NTP kernel PLL related stuff"); 160 SYSCTL_PROC(_kern_ntp_pll, NTP_PLL_GETTIME, gettime, CTLTYPE_OPAQUE|CTLFLAG_RD, 161 0, sizeof(struct ntptimeval) , ntp_sysctl, "S,ntptimeval", ""); 162 163 /* 164 * ntp_adjtime() - NTP daemon application interface 165 */ 166 #ifndef _SYS_SYSPROTO_H_ 167 struct ntp_adjtime_args { 168 struct timex *tp; 169 }; 170 #endif 171 172 int 173 ntp_adjtime(struct proc *p, struct ntp_adjtime_args *uap, int *retval) 174 { 175 struct timex ntv; 176 int modes; 177 int s; 178 int error; 179 180 error = copyin((caddr_t)uap->tp, (caddr_t)&ntv, sizeof(ntv)); 181 if (error) 182 return error; 183 184 /* 185 * Update selected clock variables - only the superuser can 186 * change anything. Note that there is no error checking here on 187 * the assumption the superuser should know what it is doing. 188 */ 189 modes = ntv.modes; 190 if ((modes != 0) 191 && (error = suser(p->p_cred->pc_ucred, &p->p_acflag))) 192 return error; 193 194 s = splclock(); 195 if (modes & MOD_FREQUENCY) 196 #ifdef PPS_SYNC 197 time_freq = ntv.freq - pps_freq; 198 #else /* PPS_SYNC */ 199 time_freq = ntv.freq; 200 #endif /* PPS_SYNC */ 201 if (modes & MOD_MAXERROR) 202 time_maxerror = ntv.maxerror; 203 if (modes & MOD_ESTERROR) 204 time_esterror = ntv.esterror; 205 if (modes & MOD_STATUS) { 206 time_status &= STA_RONLY; 207 time_status |= ntv.status & ~STA_RONLY; 208 } 209 if (modes & MOD_TIMECONST) 210 time_constant = ntv.constant; 211 if (modes & MOD_OFFSET) 212 hardupdate(ntv.offset); 213 214 /* 215 * Retrieve all clock variables 216 */ 217 if (time_offset < 0) 218 ntv.offset = -(-time_offset >> SHIFT_UPDATE); 219 else 220 ntv.offset = time_offset >> SHIFT_UPDATE; 221 #ifdef PPS_SYNC 222 ntv.freq = time_freq + pps_freq; 223 #else /* PPS_SYNC */ 224 ntv.freq = time_freq; 225 #endif /* PPS_SYNC */ 226 ntv.maxerror = time_maxerror; 227 ntv.esterror = time_esterror; 228 ntv.status = time_status; 229 ntv.constant = time_constant; 230 ntv.precision = time_precision; 231 ntv.tolerance = time_tolerance; 232 #ifdef PPS_SYNC 233 ntv.shift = pps_shift; 234 ntv.ppsfreq = pps_freq; 235 ntv.jitter = pps_jitter >> PPS_AVG; 236 ntv.stabil = pps_stabil; 237 ntv.calcnt = pps_calcnt; 238 ntv.errcnt = pps_errcnt; 239 ntv.jitcnt = pps_jitcnt; 240 ntv.stbcnt = pps_stbcnt; 241 #endif /* PPS_SYNC */ 242 (void)splx(s); 243 244 error = copyout((caddr_t)&ntv, (caddr_t)uap->tp, sizeof(ntv)); 245 if (!error) { 246 /* 247 * Status word error decode. See comments in 248 * ntp_gettime() routine. 249 */ 250 retval[0] = time_state; 251 if (time_status & (STA_UNSYNC | STA_CLOCKERR)) 252 retval[0] = TIME_ERROR; 253 if (time_status & (STA_PPSFREQ | STA_PPSTIME) && 254 !(time_status & STA_PPSSIGNAL)) 255 retval[0] = TIME_ERROR; 256 if (time_status & STA_PPSTIME && 257 time_status & STA_PPSJITTER) 258 retval[0] = TIME_ERROR; 259 if (time_status & STA_PPSFREQ && 260 time_status & (STA_PPSWANDER | STA_PPSERROR)) 261 retval[0] = TIME_ERROR; 262 } 263 return error; 264 } 265 266 267