kern_ntptime.c revision 12221
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 <vm/vm.h> 53#include <sys/sysctl.h> 54 55/* 56 * The following variables are used by the hardclock() routine in the 57 * kern_clock.c module and are described in that module. 58 */ 59extern int time_state; /* clock state */ 60extern int time_status; /* clock status bits */ 61extern long time_offset; /* time adjustment (us) */ 62extern long time_freq; /* frequency offset (scaled ppm) */ 63extern long time_maxerror; /* maximum error (us) */ 64extern long time_esterror; /* estimated error (us) */ 65extern long time_constant; /* pll time constant */ 66extern long time_precision; /* clock precision (us) */ 67extern long time_tolerance; /* frequency tolerance (scaled ppm) */ 68 69#ifdef PPS_SYNC 70/* 71 * The following variables are used only if the PPS signal discipline 72 * is configured in the kernel. 73 */ 74extern int pps_shift; /* interval duration (s) (shift) */ 75extern long pps_freq; /* pps frequency offset (scaled ppm) */ 76extern long pps_jitter; /* pps jitter (us) */ 77extern long pps_stabil; /* pps stability (scaled ppm) */ 78extern long pps_jitcnt; /* jitter limit exceeded */ 79extern long pps_calcnt; /* calibration intervals */ 80extern long pps_errcnt; /* calibration errors */ 81extern long pps_stbcnt; /* stability limit exceeded */ 82#endif /* PPS_SYNC */ 83 84int 85ntp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, 86 void *newp, size_t newlen, struct proc *p) 87{ 88 struct timeval atv; 89 struct ntptimeval ntv; 90 int s; 91 92 /* All names at this level are terminal. */ 93 if (namelen != 1) { 94 return ENOTDIR; 95 } 96 97 if (name[0] != NTP_PLL_GETTIME) { 98 return EOPNOTSUPP; 99 } 100 101 s = splclock(); 102#ifdef EXT_CLOCK 103 /* 104 * The microtime() external clock routine returns a 105 * status code. If less than zero, we declare an error 106 * in the clock status word and return the kernel 107 * (software) time variable. While there are other 108 * places that call microtime(), this is the only place 109 * that matters from an application point of view. 110 */ 111 if (microtime(&atv) < 0) { 112 time_status |= STA_CLOCKERR; 113 ntv.time = time; 114 } else { 115 time_status &= ~STA_CLOCKERR; 116 } 117#else /* EXT_CLOCK */ 118 microtime(&atv); 119#endif /* EXT_CLOCK */ 120 ntv.time = atv; 121 ntv.maxerror = time_maxerror; 122 ntv.esterror = time_esterror; 123 splx(s); 124 125 ntv.time_state = time_state; 126 127 /* 128 * Status word error decode. If any of these conditions 129 * occur, an error is returned, instead of the status 130 * word. Most applications will care only about the fact 131 * the system clock may not be trusted, not about the 132 * details. 133 * 134 * Hardware or software error 135 */ 136 if (time_status & (STA_UNSYNC | STA_CLOCKERR)) { 137 ntv.time_state = TIME_ERROR; 138 } 139 140 /* 141 * PPS signal lost when either time or frequency 142 * synchronization requested 143 */ 144 if (time_status & (STA_PPSFREQ | STA_PPSTIME) && 145 !(time_status & STA_PPSSIGNAL)) { 146 ntv.time_state = TIME_ERROR; 147 } 148 149 /* 150 * PPS jitter exceeded when time synchronization 151 * requested 152 */ 153 if (time_status & STA_PPSTIME && 154 time_status & STA_PPSJITTER) { 155 ntv.time_state = TIME_ERROR; 156 } 157 158 /* 159 * PPS wander exceeded or calibration error when 160 * frequency synchronization requested 161 */ 162 if (time_status & STA_PPSFREQ && 163 time_status & (STA_PPSWANDER | STA_PPSERROR)) { 164 ntv.time_state = TIME_ERROR; 165 } 166 return(sysctl_rdstruct(oldp, oldlenp, newp, &ntv, sizeof ntv)); 167} 168 169/* 170 * ntp_adjtime() - NTP daemon application interface 171 */ 172#ifndef _SYS_SYSPROTO_H_ 173struct ntp_adjtime_args { 174 struct timex *tp; 175}; 176#endif 177 178int 179ntp_adjtime(struct proc *p, struct ntp_adjtime_args *uap, int *retval) 180{ 181 struct timex ntv; 182 int modes; 183 int s; 184 int error; 185 186 error = copyin((caddr_t)uap->tp, (caddr_t)&ntv, sizeof(ntv)); 187 if (error) 188 return error; 189 190 /* 191 * Update selected clock variables - only the superuser can 192 * change anything. Note that there is no error checking here on 193 * the assumption the superuser should know what it is doing. 194 */ 195 modes = ntv.modes; 196 if ((modes != 0) 197 && (error = suser(p->p_cred->pc_ucred, &p->p_acflag))) 198 return error; 199 200 s = splclock(); 201 if (modes & MOD_FREQUENCY) 202#ifdef PPS_SYNC 203 time_freq = ntv.freq - pps_freq; 204#else /* PPS_SYNC */ 205 time_freq = ntv.freq; 206#endif /* PPS_SYNC */ 207 if (modes & MOD_MAXERROR) 208 time_maxerror = ntv.maxerror; 209 if (modes & MOD_ESTERROR) 210 time_esterror = ntv.esterror; 211 if (modes & MOD_STATUS) { 212 time_status &= STA_RONLY; 213 time_status |= ntv.status & ~STA_RONLY; 214 } 215 if (modes & MOD_TIMECONST) 216 time_constant = ntv.constant; 217 if (modes & MOD_OFFSET) 218 hardupdate(ntv.offset); 219 220 /* 221 * Retrieve all clock variables 222 */ 223 if (time_offset < 0) 224 ntv.offset = -(-time_offset >> SHIFT_UPDATE); 225 else 226 ntv.offset = time_offset >> SHIFT_UPDATE; 227#ifdef PPS_SYNC 228 ntv.freq = time_freq + pps_freq; 229#else /* PPS_SYNC */ 230 ntv.freq = time_freq; 231#endif /* PPS_SYNC */ 232 ntv.maxerror = time_maxerror; 233 ntv.esterror = time_esterror; 234 ntv.status = time_status; 235 ntv.constant = time_constant; 236 ntv.precision = time_precision; 237 ntv.tolerance = time_tolerance; 238#ifdef PPS_SYNC 239 ntv.shift = pps_shift; 240 ntv.ppsfreq = pps_freq; 241 ntv.jitter = pps_jitter >> PPS_AVG; 242 ntv.stabil = pps_stabil; 243 ntv.calcnt = pps_calcnt; 244 ntv.errcnt = pps_errcnt; 245 ntv.jitcnt = pps_jitcnt; 246 ntv.stbcnt = pps_stbcnt; 247#endif /* PPS_SYNC */ 248 (void)splx(s); 249 250 error = copyout((caddr_t)&ntv, (caddr_t)uap->tp, sizeof(ntv)); 251 if (!error) { 252 /* 253 * Status word error decode. See comments in 254 * ntp_gettime() routine. 255 */ 256 retval[0] = time_state; 257 if (time_status & (STA_UNSYNC | STA_CLOCKERR)) 258 retval[0] = TIME_ERROR; 259 if (time_status & (STA_PPSFREQ | STA_PPSTIME) && 260 !(time_status & STA_PPSSIGNAL)) 261 retval[0] = TIME_ERROR; 262 if (time_status & STA_PPSTIME && 263 time_status & STA_PPSJITTER) 264 retval[0] = TIME_ERROR; 265 if (time_status & STA_PPSFREQ && 266 time_status & (STA_PPSWANDER | STA_PPSERROR)) 267 retval[0] = TIME_ERROR; 268 } 269 return error; 270} 271 272 273