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