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