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 * 02 Sep 93 Philip Gladstone
14 * Created file with time related functions from sched.c and adjtimex()
15 * 08 Oct 93 Torsten Duwe
16 * adjtime interface update and CMOS clock write code
17 * 02 Jul 94 Alan Modra
18 * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
19 */
20
21 #include <linux/config.h>
22 #include <linux/errno.h>
23 #include <linux/sched.h>
24 #include <linux/kernel.h>
25 #include <linux/param.h>
26 #include <linux/string.h>
27
28 #include <asm/segment.h>
29 #include <asm/io.h>
30
31 #include <linux/mc146818rtc.h>
32 #define RTC_ALWAYS_BCD 1
33
34 #include <linux/timex.h>
35 extern struct timeval xtime;
36
37 /* converts date to days since 1/1/1970
38 * assumes year,mon,day in normal date format
39 * ie. 1/1/1970 => year=1970, mon=1, day=1
40 *
41 * For the Julian calendar (which was used in Russia before 1917,
42 * Britain & colonies before 1752, anywhere else before 1582,
43 * and is still in use by some communities) leave out the
44 * -year/100+year/400 terms, and add 10.
45 *
46 * This algorithm was first published by Gauss (I think).
47 */
48 static inline unsigned long mktime(unsigned int year, unsigned int mon,
/* ![[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)
*/
49 unsigned int day, unsigned int hour,
50 unsigned int min, unsigned int sec)
51 {
52 if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
53 mon += 12; /* Puts Feb last since it has leap day */
54 year -= 1;
55 }
56 return (((
57 (unsigned long)(year/4 - year/100 + year/400 + 367*mon/12 + day) +
58 year*365 - 719499
59 )*24 + hour /* now have hours */
60 )*60 + min /* now have minutes */
61 )*60 + sec; /* finally seconds */
62 }
63
64 void time_init(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)
*/
65 {
66 unsigned int year, mon, day, hour, min, sec;
67 int i;
68
69 /* checking for Update-In-Progress could be done more elegantly
70 * (using the "update finished"-interrupt for example), but that
71 * would require excessive testing. promise I'll do that when I find
72 * the time. - Torsten
73 */
74 /* read RTC exactly on falling edge of update flag */
75 for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
76 if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
77 break;
78 for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms*/
79 if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
80 break;
81 do { /* Isn't this overkill ? UIP above should guarantee consistency */
82 sec = CMOS_READ(RTC_SECONDS);
83 min = CMOS_READ(RTC_MINUTES);
84 hour = CMOS_READ(RTC_HOURS);
85 day = CMOS_READ(RTC_DAY_OF_MONTH);
86 mon = CMOS_READ(RTC_MONTH);
87 year = CMOS_READ(RTC_YEAR);
88 } while (sec != CMOS_READ(RTC_SECONDS));
89 if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
90 {
91 BCD_TO_BIN(sec);
92 BCD_TO_BIN(min);
93 BCD_TO_BIN(hour);
94 BCD_TO_BIN(day);
95 BCD_TO_BIN(mon);
96 BCD_TO_BIN(year);
97 }
98 if ((year += 1900) < 1970)
99 year += 100;
100 xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
101 }
102 /*
103 * The timezone where the local system is located. Used as a default by some
104 * programs who obtain this value by using gettimeofday.
105 */
106 struct timezone sys_tz = { 0, 0};
107
108 asmlinkage int sys_time(long * tloc)
/* ![[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 int i, error;
111
112 i = CURRENT_TIME;
113 if (tloc) {
114 error = verify_area(VERIFY_WRITE, tloc, 4);
115 if (error)
116 return error;
117 put_fs_long(i,(unsigned long *)tloc);
118 }
119 return i;
120 }
121
122 asmlinkage int sys_stime(long * 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)
*/
123 {
124 if (!suser())
125 return -EPERM;
126 cli();
127 xtime.tv_sec = get_fs_long((unsigned long *) tptr);
128 xtime.tv_usec = 0;
129 time_status = TIME_BAD;
130 time_maxerror = 0x70000000;
131 time_esterror = 0x70000000;
132 sti();
133 return 0;
134 }
135
136 /* This function must be called with interrupts disabled
137 * It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs
138 *
139 * However, the pc-audio speaker driver changes the divisor so that
140 * it gets interrupted rather more often - it loads 64 into the
141 * counter rather than 11932! This has an adverse impact on
142 * do_gettimeoffset() -- it stops working! What is also not
143 * good is that the interval that our timer function gets called
144 * is no longer 10.0002 msecs, but 9.9767 msec. To get around this
145 * would require using a different timing source. Maybe someone
146 * could use the RTC - I know that this can interrupt at frequencies
147 * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
148 * it so that at startup, the timer code in sched.c would select
149 * using either the RTC or the 8253 timer. The decision would be
150 * based on whether there was any other device around that needed
151 * to trample on the 8253. I'd set up the RTC to interrupt at 1024Hz,
152 * and then do some jiggery to have a version of do_timer that
153 * advanced the clock by 1/1024 sec. Every time that reached over 1/100
154 * of a second, then do all the old code. If the time was kept correct
155 * then do_gettimeoffset could just return 0 - there is no low order
156 * divider that can be accessed.
157 *
158 * Ideally, you would be able to use the RTC for the speaker driver,
159 * but it appears that the speaker driver really needs interrupt more
160 * often than every 120us or so.
161 *
162 * Anyway, this needs more thought.... pjsg (28 Aug 93)
163 *
164 * If you are really that interested, you should be reading
165 * comp.protocols.time.ntp!
166 */
167
168 #define TICK_SIZE tick
169
170 static inline unsigned long do_gettimeoffset(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)
*/
171 {
172 int count;
173 unsigned long offset = 0;
174
175 /* timer count may underflow right here */
176 outb_p(0x00, 0x43); /* latch the count ASAP */
177 count = inb_p(0x40); /* read the latched count */
178 count |= inb(0x40) << 8;
179 /* we know probability of underflow is always MUCH less than 1% */
180 if (count > (LATCH - LATCH/100)) {
181 /* check for pending timer interrupt */
182 outb_p(0x0a, 0x20);
183 if (inb(0x20) & 1)
184 offset = TICK_SIZE;
185 }
186 count = ((LATCH-1) - count) * TICK_SIZE;
187 count = (count + LATCH/2) / LATCH;
188 return offset + count;
189 }
190
191 /*
192 * This version of gettimeofday has near microsecond resolution.
193 */
194 static inline void do_gettimeofday(struct timeval *tv)
/* ![[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)
*/
195 {
196 #ifdef __i386__
197 cli();
198 *tv = xtime;
199 tv->tv_usec += do_gettimeoffset();
200 if (tv->tv_usec >= 1000000) {
201 tv->tv_usec -= 1000000;
202 tv->tv_sec++;
203 }
204 sti();
205 #else /* not __i386__ */
206 cli();
207 *tv = xtime;
208 sti();
209 #endif /* not __i386__ */
210 }
211
212 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)
*/
213 {
214 int error;
215
216 if (tv) {
217 struct timeval ktv;
218 error = verify_area(VERIFY_WRITE, tv, sizeof *tv);
219 if (error)
220 return error;
221 do_gettimeofday(&ktv);
222 put_fs_long(ktv.tv_sec, (unsigned long *) &tv->tv_sec);
223 put_fs_long(ktv.tv_usec, (unsigned long *) &tv->tv_usec);
224 }
225 if (tz) {
226 error = verify_area(VERIFY_WRITE, tz, sizeof *tz);
227 if (error)
228 return error;
229 put_fs_long(sys_tz.tz_minuteswest, (unsigned long *) tz);
230 put_fs_long(sys_tz.tz_dsttime, ((unsigned long *) tz)+1);
231 }
232 return 0;
233 }
234
235 /*
236 * Adjust the time obtained from the CMOS to be GMT time instead of
237 * local time.
238 *
239 * This is ugly, but preferable to the alternatives. Otherwise we
240 * would either need to write a program to do it in /etc/rc (and risk
241 * confusion if the program gets run more than once; it would also be
242 * hard to make the program warp the clock precisely n hours) or
243 * compile in the timezone information into the kernel. Bad, bad....
244 *
245 * XXX Currently does not adjust for daylight savings time. May not
246 * need to do anything, depending on how smart (dumb?) the BIOS
247 * is. Blast it all.... the best thing to do not depend on the CMOS
248 * clock at all, but get the time via NTP or timed if you're on a
249 * network.... - TYT, 1/1/92
250 */
251 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)
*/
252 {
253 cli();
254 xtime.tv_sec += sys_tz.tz_minuteswest * 60;
255 sti();
256 }
257
258 /*
259 * The first time we set the timezone, we will warp the clock so that
260 * it is ticking GMT time instead of local time. Presumably,
261 * if someone is setting the timezone then we are running in an
262 * environment where the programs understand about timezones.
263 * This should be done at boot time in the /etc/rc script, as
264 * soon as possible, so that the clock can be set right. Otherwise,
265 * various programs will get confused when the clock gets warped.
266 */
267 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)
*/
268 {
269 static int firsttime = 1;
270
271 if (!suser())
272 return -EPERM;
273 if (tz) {
274 sys_tz.tz_minuteswest = get_fs_long((unsigned long *) tz);
275 sys_tz.tz_dsttime = get_fs_long(((unsigned long *) tz)+1);
276 if (firsttime) {
277 firsttime = 0;
278 if (!tv)
279 warp_clock();
280 }
281 }
282 if (tv) {
283 int sec, usec;
284
285 sec = get_fs_long((unsigned long *)tv);
286 usec = get_fs_long(((unsigned long *)tv)+1);
287
288 cli();
289 /* This is revolting. We need to set the xtime.tv_usec
290 * correctly. However, the value in this location is
291 * is value at the last tick.
292 * Discover what correction gettimeofday
293 * would have done, and then undo it!
294 */
295 usec -= do_gettimeoffset();
296
297 if (usec < 0)
298 {
299 usec += 1000000;
300 sec--;
301 }
302 xtime.tv_sec = sec;
303 xtime.tv_usec = usec;
304 time_status = TIME_BAD;
305 time_maxerror = 0x70000000;
306 time_esterror = 0x70000000;
307 sti();
308 }
309 return 0;
310 }
311
312 /* adjtimex mainly allows reading (and writing, if superuser) of
313 * kernel time-keeping variables. used by xntpd.
314 */
315 asmlinkage int sys_adjtimex(struct timex *txc_p)
/* ![[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)
*/
316 {
317 long ltemp, mtemp, save_adjust;
318 int error;
319
320 /* Local copy of parameter */
321 struct timex txc;
322
323 error = verify_area(VERIFY_WRITE, txc_p, sizeof(struct timex));
324 if (error)
325 return error;
326
327 /* Copy the user data space into the kernel copy
328 * structure. But bear in mind that the structures
329 * may change
330 */
331 memcpy_fromfs(&txc, txc_p, sizeof(struct timex));
332
333 /* In order to modify anything, you gotta be super-user! */
334 if (txc.mode && !suser())
335 return -EPERM;
336
337 /* Now we validate the data before disabling interrupts
338 */
339
340 if (txc.mode & ADJ_OFFSET)
341 /* Microsec field limited to -131000 .. 131000 usecs */
342 if (txc.offset <= -(1 << (31 - SHIFT_UPDATE))
343 || txc.offset >= (1 << (31 - SHIFT_UPDATE)))
344 return -EINVAL;
345
346 /* time_status must be in a fairly small range */
347 if (txc.mode & ADJ_STATUS)
348 if (txc.status < TIME_OK || txc.status > TIME_BAD)
349 return -EINVAL;
350
351 /* if the quartz is off by more than 10% something is VERY wrong ! */
352 if (txc.mode & ADJ_TICK)
353 if (txc.tick < 900000/HZ || txc.tick > 1100000/HZ)
354 return -EINVAL;
355
356 cli();
357
358 /* Save for later - semantics of adjtime is to return old value */
359 save_adjust = time_adjust;
360
361 /* If there are input parameters, then process them */
362 if (txc.mode)
363 {
364 if (time_status == TIME_BAD)
365 time_status = TIME_OK;
366
367 if (txc.mode & ADJ_STATUS)
368 time_status = txc.status;
369
370 if (txc.mode & ADJ_FREQUENCY)
371 time_freq = txc.frequency << (SHIFT_KF - 16);
372
373 if (txc.mode & ADJ_MAXERROR)
374 time_maxerror = txc.maxerror;
375
376 if (txc.mode & ADJ_ESTERROR)
377 time_esterror = txc.esterror;
378
379 if (txc.mode & ADJ_TIMECONST)
380 time_constant = txc.time_constant;
381
382 if (txc.mode & ADJ_OFFSET)
383 if (txc.mode == ADJ_OFFSET_SINGLESHOT)
384 {
385 time_adjust = txc.offset;
386 }
387 else /* XXX should give an error if other bits set */
388 {
389 time_offset = txc.offset << SHIFT_UPDATE;
390 mtemp = xtime.tv_sec - time_reftime;
391 time_reftime = xtime.tv_sec;
392 if (mtemp > (MAXSEC+2) || mtemp < 0)
393 mtemp = 0;
394
395 if (txc.offset < 0)
396 time_freq -= (-txc.offset * mtemp) >>
397 (time_constant + time_constant);
398 else
399 time_freq += (txc.offset * mtemp) >>
400 (time_constant + time_constant);
401
402 ltemp = time_tolerance << SHIFT_KF;
403
404 if (time_freq > ltemp)
405 time_freq = ltemp;
406 else if (time_freq < -ltemp)
407 time_freq = -ltemp;
408 }
409 if (txc.mode & ADJ_TICK)
410 tick = txc.tick;
411
412 }
413 txc.offset = save_adjust;
414 txc.frequency = ((time_freq+1) >> (SHIFT_KF - 16));
415 txc.maxerror = time_maxerror;
416 txc.esterror = time_esterror;
417 txc.status = time_status;
418 txc.time_constant = time_constant;
419 txc.precision = time_precision;
420 txc.tolerance = time_tolerance;
421 txc.time = xtime;
422 txc.tick = tick;
423
424 sti();
425
426 memcpy_tofs(txc_p, &txc, sizeof(struct timex));
427 return time_status;
428 }
429
430 int set_rtc_mmss(unsigned long nowtime)
/* ![[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)
*/
431 {
432 int retval = 0;
433 int real_seconds, real_minutes, cmos_minutes;
434 unsigned char save_control, save_freq_select;
435
436 save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
437 CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
438
439 save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
440 CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
441
442 cmos_minutes = CMOS_READ(RTC_MINUTES);
443 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
444 BCD_TO_BIN(cmos_minutes);
445
446 /* since we're only adjusting minutes and seconds,
447 * don't interfere with hour overflow. This avoids
448 * messing with unknown time zones but requires your
449 * RTC not to be off by more than 15 minutes
450 */
451 real_seconds = nowtime % 60;
452 real_minutes = nowtime / 60;
453 if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
454 real_minutes += 30; /* correct for half hour time zone */
455 real_minutes %= 60;
456
457 if (abs(real_minutes - cmos_minutes) < 30)
458 {
459 if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
460 {
461 BIN_TO_BCD(real_seconds);
462 BIN_TO_BCD(real_minutes);
463 }
464 CMOS_WRITE(real_seconds,RTC_SECONDS);
465 CMOS_WRITE(real_minutes,RTC_MINUTES);
466 }
467 else
468 retval = -1;
469
470 CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
471 CMOS_WRITE(save_control, RTC_CONTROL);
472 return retval;
473 }