1 /*
2 * linux/kernel/time.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 *
6 * This file contains the interface functions for the various
7 * time related system calls: time, stime, gettimeofday, settimeofday,
8 * adjtime
9 */
10 /*
11 * Modification history kernel/time.c
12 *
13 * 1993-09-02 Philip Gladstone
14 * Created file with time related functions from sched.c and adjtimex()
15 * 1993-10-08 Torsten Duwe
16 * adjtime interface update and CMOS clock write code
17 * 1995-08-13 Torsten Duwe
18 * kernel PLL updated to 1994-12-13 specs (rfc-1489)
19 */
20
21 #include <linux/errno.h>
22 #include <linux/sched.h>
23 #include <linux/kernel.h>
24 #include <linux/param.h>
25 #include <linux/string.h>
26 #include <linux/mm.h>
27 #include <linux/timex.h>
28
29 #include <asm/segment.h>
30
31 /*
32 * The timezone where the local system is located. Used as a default by some
33 * programs who obtain this value by using gettimeofday.
34 */
35 struct timezone sys_tz = { 0, 0};
36
37 #ifndef __alpha__
38
39 /*
40 * sys_time() can be implemented in user-level using
41 * sys_gettimeofday(). Is this for backwards compatibility? If so,
42 * why not move it into the appropriate arch directory (for those
43 * architectures that need it).
44 */
45 asmlinkage int sys_time(int * tloc)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
46 {
47 int i;
48
49 i = CURRENT_TIME;
50 if (tloc) {
51 int error = verify_area(VERIFY_WRITE, tloc, sizeof(*tloc));
52 if (error)
53 return error;
54 put_user(i,tloc);
55 }
56 return i;
57 }
58
59 /*
60 * sys_stime() can be implemented in user-level using
61 * sys_settimeofday(). Is this for backwards compatibility? If so,
62 * why not move it into the appropriate arch directory (for those
63 * architectures that need it).
64 */
65 asmlinkage int sys_stime(int * tptr)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
66 {
67 int error, value;
68
69 if (!suser())
70 return -EPERM;
71 error = verify_area(VERIFY_READ, tptr, sizeof(*tptr));
72 if (error)
73 return error;
74 value = get_user(tptr);
75 cli();
76 xtime.tv_sec = value;
77 xtime.tv_usec = 0;
78 time_state = TIME_BAD;
79 time_maxerror = 0x70000000;
80 time_esterror = 0x70000000;
81 sti();
82 return 0;
83 }
84
85 #endif
86
87 asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
88 {
89 int error;
90
91 if (tv) {
92 struct timeval ktv;
93 error = verify_area(VERIFY_WRITE, tv, sizeof *tv);
94 if (error)
95 return error;
96 do_gettimeofday(&ktv);
97 memcpy_tofs(tv, &ktv, sizeof(ktv));
98 }
99 if (tz) {
100 error = verify_area(VERIFY_WRITE, tz, sizeof *tz);
101 if (error)
102 return error;
103 memcpy_tofs(tz, &sys_tz, sizeof(sys_tz));
104 }
105 return 0;
106 }
107
108 /*
109 * Adjust the time obtained from the CMOS to be UTC time instead of
110 * local time.
111 *
112 * This is ugly, but preferable to the alternatives. Otherwise we
113 * would either need to write a program to do it in /etc/rc (and risk
114 * confusion if the program gets run more than once; it would also be
115 * hard to make the program warp the clock precisely n hours) or
116 * compile in the timezone information into the kernel. Bad, bad....
117 *
118 * - TYT, 1992-01-01
119 *
120 * The best thing to do is to keep the CMOS clock in universal time (UTC)
121 * as real UNIX machines always do it. This avoids all headaches about
122 * daylight saving times and warping kernel clocks.
123 */
124 inline static void warp_clock(void)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
125 {
126 cli();
127 xtime.tv_sec += sys_tz.tz_minuteswest * 60;
128 sti();
129 }
130
131 /*
132 * In case for some reason the CMOS clock has not already been running
133 * in UTC, but in some local time: The first time we set the timezone,
134 * we will warp the clock so that it is ticking UTC time instead of
135 * local time. Presumably, if someone is setting the timezone then we
136 * are running in an environment where the programs understand about
137 * timezones. This should be done at boot time in the /etc/rc script,
138 * as soon as possible, so that the clock can be set right. Otherwise,
139 * various programs will get confused when the clock gets warped.
140 */
141 asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
142 {
143 static int firsttime = 1;
144 struct timeval new_tv;
145 struct timezone new_tz;
146
147 if (!suser())
148 return -EPERM;
149 if (tv) {
150 int error = verify_area(VERIFY_READ, tv, sizeof(*tv));
151 if (error)
152 return error;
153 memcpy_fromfs(&new_tv, tv, sizeof(*tv));
154 }
155 if (tz) {
156 int error = verify_area(VERIFY_READ, tz, sizeof(*tz));
157 if (error)
158 return error;
159 memcpy_fromfs(&new_tz, tz, sizeof(*tz));
160 }
161 if (tz) {
162 sys_tz = new_tz;
163 if (firsttime) {
164 firsttime = 0;
165 if (!tv)
166 warp_clock();
167 }
168 }
169 if (tv)
170 do_settimeofday(&new_tv);
171 return 0;
172 }
173
174 long pps_offset = 0; /* pps time offset (us) */
175 long pps_jitter = MAXTIME; /* time dispersion (jitter) (us) */
176
177 long pps_freq = 0; /* frequency offset (scaled ppm) */
178 long pps_stabil = MAXFREQ; /* frequency dispersion (scaled ppm) */
179
180 long pps_valid = PPS_VALID; /* pps signal watchdog counter */
181
182 int pps_shift = PPS_SHIFT; /* interval duration (s) (shift) */
183
184 long pps_jitcnt = 0; /* jitter limit exceeded */
185 long pps_calcnt = 0; /* calibration intervals */
186 long pps_errcnt = 0; /* calibration errors */
187 long pps_stbcnt = 0; /* stability limit exceeded */
188
189 /* hook for a loadable hardpps kernel module */
190 void (*hardpps_ptr)(struct timeval *) = (void (*)(struct timeval *))0;
191
192 /* adjtimex mainly allows reading (and writing, if superuser) of
193 * kernel time-keeping variables. used by xntpd.
194 */
195 asmlinkage int sys_adjtimex(struct timex *txc_p)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
196 {
197 long ltemp, mtemp, save_adjust;
198 int error;
199
200 /* Local copy of parameter */
201 struct timex txc;
202
203 error = verify_area(VERIFY_WRITE, txc_p, sizeof(struct timex));
204 if (error)
205 return error;
206
207 /* Copy the user data space into the kernel copy
208 * structure. But bear in mind that the structures
209 * may change
210 */
211 memcpy_fromfs(&txc, txc_p, sizeof(struct timex));
212
213 /* In order to modify anything, you gotta be super-user! */
214 if (txc.modes && !suser())
215 return -EPERM;
216
217 /* Now we validate the data before disabling interrupts
218 */
219
220 if (txc.modes != ADJ_OFFSET_SINGLESHOT && (txc.modes & ADJ_OFFSET))
221 /* adjustment Offset limited to +- .512 seconds */
222 if (txc.offset <= - MAXPHASE || txc.offset >= MAXPHASE )
223 return -EINVAL;
224
225 /* if the quartz is off by more than 10% something is VERY wrong ! */
226 if (txc.modes & ADJ_TICK)
227 if (txc.tick < 900000/HZ || txc.tick > 1100000/HZ)
228 return -EINVAL;
229
230 cli();
231
232 /* Save for later - semantics of adjtime is to return old value */
233 save_adjust = time_adjust;
234
235 /* If there are input parameters, then process them */
236 if (txc.modes)
237 {
238 if (time_state == TIME_BAD)
239 time_state = TIME_OK;
240
241 if (txc.modes & ADJ_STATUS)
242 time_status = txc.status;
243
244 if (txc.modes & ADJ_FREQUENCY)
245 time_freq = txc.freq;
246
247 if (txc.modes & ADJ_MAXERROR)
248 time_maxerror = txc.maxerror;
249
250 if (txc.modes & ADJ_ESTERROR)
251 time_esterror = txc.esterror;
252
253 if (txc.modes & ADJ_TIMECONST)
254 time_constant = txc.constant;
255
256 if (txc.modes & ADJ_OFFSET)
257 if ((txc.modes == ADJ_OFFSET_SINGLESHOT)
258 || !(time_status & STA_PLL))
259 {
260 time_adjust = txc.offset;
261 }
262 else if ((time_status & STA_PLL)||(time_status & STA_PPSTIME))
263 {
264 ltemp = (time_status & STA_PPSTIME &&
265 time_status & STA_PPSSIGNAL) ?
266 pps_offset : txc.offset;
267
268 /*
269 * Scale the phase adjustment and
270 * clamp to the operating range.
271 */
272 if (ltemp > MAXPHASE)
273 time_offset = MAXPHASE << SHIFT_UPDATE;
274 else if (ltemp < -MAXPHASE)
275 time_offset = -(MAXPHASE << SHIFT_UPDATE);
276 else
277 time_offset = ltemp << SHIFT_UPDATE;
278
279 /*
280 * Select whether the frequency is to be controlled and in which
281 * mode (PLL or FLL). Clamp to the operating range. Ugly
282 * multiply/divide should be replaced someday.
283 */
284
285 if (time_status & STA_FREQHOLD || time_reftime == 0)
286 time_reftime = xtime.tv_sec;
287 mtemp = xtime.tv_sec - time_reftime;
288 time_reftime = xtime.tv_sec;
289 if (time_status & STA_FLL)
290 {
291 if (mtemp >= MINSEC)
292 {
293 ltemp = ((time_offset / mtemp) << (SHIFT_USEC -
294 SHIFT_UPDATE));
295 if (ltemp < 0)
296 time_freq -= -ltemp >> SHIFT_KH;
297 else
298 time_freq += ltemp >> SHIFT_KH;
299 }
300 }
301 else
302 {
303 if (mtemp < MAXSEC)
304 {
305 ltemp *= mtemp;
306 if (ltemp < 0)
307 time_freq -= -ltemp >> (time_constant +
308 time_constant + SHIFT_KF -
309 SHIFT_USEC);
310 else
311 time_freq += ltemp >> (time_constant +
312 time_constant + SHIFT_KF -
313 SHIFT_USEC);
314 }
315 }
316 if (time_freq > time_tolerance)
317 time_freq = time_tolerance;
318 else if (time_freq < -time_tolerance)
319 time_freq = -time_tolerance;
320 }
321 if (txc.modes & ADJ_TICK)
322 tick = txc.tick;
323
324 }
325 txc.offset = save_adjust;
326 txc.freq = time_freq;
327 txc.maxerror = time_maxerror;
328 txc.esterror = time_esterror;
329 txc.status = time_status;
330 txc.constant = time_constant;
331 txc.precision = time_precision;
332 txc.tolerance = time_tolerance;
333 txc.time = xtime;
334 txc.tick = tick;
335 txc.ppsfreq = pps_freq;
336 txc.jitter = pps_jitter;
337 txc.shift = pps_shift;
338 txc.stabil = pps_stabil;
339 txc.jitcnt = pps_jitcnt;
340 txc.calcnt = pps_calcnt;
341 txc.errcnt = pps_errcnt;
342 txc.stbcnt = pps_stbcnt;
343
344 sti();
345
346 memcpy_tofs(txc_p, &txc, sizeof(struct timex));
347 return time_state;
348 }