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