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