Don't look up pid/tid on YAGL_LOG_FUNC_SET
[sdk/emulator/qemu.git] / tests / rtc-test.c
1 /*
2  * QTest testcase for the MC146818 real-time clock
3  *
4  * Copyright IBM, Corp. 2012
5  *
6  * Authors:
7  *  Anthony Liguori   <aliguori@us.ibm.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2 or later.
10  * See the COPYING file in the top-level directory.
11  *
12  */
13
14 #include "qemu/osdep.h"
15
16 #include "libqtest.h"
17 #include "hw/timer/mc146818rtc_regs.h"
18
19 static uint8_t base = 0x70;
20
21 static int bcd2dec(int value)
22 {
23     return (((value >> 4) & 0x0F) * 10) + (value & 0x0F);
24 }
25
26 static uint8_t cmos_read(uint8_t reg)
27 {
28     outb(base + 0, reg);
29     return inb(base + 1);
30 }
31
32 static void cmos_write(uint8_t reg, uint8_t val)
33 {
34     outb(base + 0, reg);
35     outb(base + 1, val);
36 }
37
38 static int tm_cmp(struct tm *lhs, struct tm *rhs)
39 {
40     time_t a, b;
41     struct tm d1, d2;
42
43     memcpy(&d1, lhs, sizeof(d1));
44     memcpy(&d2, rhs, sizeof(d2));
45
46     a = mktime(&d1);
47     b = mktime(&d2);
48
49     if (a < b) {
50         return -1;
51     } else if (a > b) {
52         return 1;
53     }
54
55     return 0;
56 }
57
58 #if 0
59 static void print_tm(struct tm *tm)
60 {
61     printf("%04d-%02d-%02d %02d:%02d:%02d\n",
62            tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
63            tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff);
64 }
65 #endif
66
67 static void cmos_get_date_time(struct tm *date)
68 {
69     int base_year = 2000, hour_offset;
70     int sec, min, hour, mday, mon, year;
71     time_t ts;
72     struct tm dummy;
73
74     sec = cmos_read(RTC_SECONDS);
75     min = cmos_read(RTC_MINUTES);
76     hour = cmos_read(RTC_HOURS);
77     mday = cmos_read(RTC_DAY_OF_MONTH);
78     mon = cmos_read(RTC_MONTH);
79     year = cmos_read(RTC_YEAR);
80
81     if ((cmos_read(RTC_REG_B) & REG_B_DM) == 0) {
82         sec = bcd2dec(sec);
83         min = bcd2dec(min);
84         hour = bcd2dec(hour);
85         mday = bcd2dec(mday);
86         mon = bcd2dec(mon);
87         year = bcd2dec(year);
88         hour_offset = 80;
89     } else {
90         hour_offset = 0x80;
91     }
92
93     if ((cmos_read(0x0B) & REG_B_24H) == 0) {
94         if (hour >= hour_offset) {
95             hour -= hour_offset;
96             hour += 12;
97         }
98     }
99
100     ts = time(NULL);
101     localtime_r(&ts, &dummy);
102
103     date->tm_isdst = dummy.tm_isdst;
104     date->tm_sec = sec;
105     date->tm_min = min;
106     date->tm_hour = hour;
107     date->tm_mday = mday;
108     date->tm_mon = mon - 1;
109     date->tm_year = base_year + year - 1900;
110 #ifndef __sun__
111     date->tm_gmtoff = 0;
112 #endif
113
114     ts = mktime(date);
115 }
116
117 static void check_time(int wiggle)
118 {
119     struct tm start, date[4], end;
120     struct tm *datep;
121     time_t ts;
122
123     /*
124      * This check assumes a few things.  First, we cannot guarantee that we get
125      * a consistent reading from the wall clock because we may hit an edge of
126      * the clock while reading.  To work around this, we read four clock readings
127      * such that at least two of them should match.  We need to assume that one
128      * reading is corrupt so we need four readings to ensure that we have at
129      * least two consecutive identical readings
130      *
131      * It's also possible that we'll cross an edge reading the host clock so
132      * simply check to make sure that the clock reading is within the period of
133      * when we expect it to be.
134      */
135
136     ts = time(NULL);
137     gmtime_r(&ts, &start);
138
139     cmos_get_date_time(&date[0]);
140     cmos_get_date_time(&date[1]);
141     cmos_get_date_time(&date[2]);
142     cmos_get_date_time(&date[3]);
143
144     ts = time(NULL);
145     gmtime_r(&ts, &end);
146
147     if (tm_cmp(&date[0], &date[1]) == 0) {
148         datep = &date[0];
149     } else if (tm_cmp(&date[1], &date[2]) == 0) {
150         datep = &date[1];
151     } else if (tm_cmp(&date[2], &date[3]) == 0) {
152         datep = &date[2];
153     } else {
154         g_assert_not_reached();
155     }
156
157     if (!(tm_cmp(&start, datep) <= 0 && tm_cmp(datep, &end) <= 0)) {
158         long t, s;
159
160         start.tm_isdst = datep->tm_isdst;
161
162         t = (long)mktime(datep);
163         s = (long)mktime(&start);
164         if (t < s) {
165             g_test_message("RTC is %ld second(s) behind wall-clock\n", (s - t));
166         } else {
167             g_test_message("RTC is %ld second(s) ahead of wall-clock\n", (t - s));
168         }
169
170         g_assert_cmpint(ABS(t - s), <=, wiggle);
171     }
172 }
173
174 static int wiggle = 2;
175
176 static void set_year_20xx(void)
177 {
178     /* Set BCD mode */
179     cmos_write(RTC_REG_B, REG_B_24H);
180     cmos_write(RTC_REG_A, 0x76);
181     cmos_write(RTC_YEAR, 0x11);
182     cmos_write(RTC_CENTURY, 0x20);
183     cmos_write(RTC_MONTH, 0x02);
184     cmos_write(RTC_DAY_OF_MONTH, 0x02);
185     cmos_write(RTC_HOURS, 0x02);
186     cmos_write(RTC_MINUTES, 0x04);
187     cmos_write(RTC_SECONDS, 0x58);
188     cmos_write(RTC_REG_A, 0x26);
189
190     g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02);
191     g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04);
192     g_assert_cmpint(cmos_read(RTC_SECONDS), >=, 0x58);
193     g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02);
194     g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02);
195     g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x11);
196     g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20);
197
198     if (sizeof(time_t) == 4) {
199         return;
200     }
201
202     /* Set a date in 2080 to ensure there is no year-2038 overflow.  */
203     cmos_write(RTC_REG_A, 0x76);
204     cmos_write(RTC_YEAR, 0x80);
205     cmos_write(RTC_REG_A, 0x26);
206
207     g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02);
208     g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04);
209     g_assert_cmpint(cmos_read(RTC_SECONDS), >=, 0x58);
210     g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02);
211     g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02);
212     g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x80);
213     g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20);
214
215     cmos_write(RTC_REG_A, 0x76);
216     cmos_write(RTC_YEAR, 0x11);
217     cmos_write(RTC_REG_A, 0x26);
218
219     g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02);
220     g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04);
221     g_assert_cmpint(cmos_read(RTC_SECONDS), >=, 0x58);
222     g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02);
223     g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02);
224     g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x11);
225     g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20);
226 }
227
228 static void set_year_1980(void)
229 {
230     /* Set BCD mode */
231     cmos_write(RTC_REG_B, REG_B_24H);
232     cmos_write(RTC_REG_A, 0x76);
233     cmos_write(RTC_YEAR, 0x80);
234     cmos_write(RTC_CENTURY, 0x19);
235     cmos_write(RTC_MONTH, 0x02);
236     cmos_write(RTC_DAY_OF_MONTH, 0x02);
237     cmos_write(RTC_HOURS, 0x02);
238     cmos_write(RTC_MINUTES, 0x04);
239     cmos_write(RTC_SECONDS, 0x58);
240     cmos_write(RTC_REG_A, 0x26);
241
242     g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02);
243     g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04);
244     g_assert_cmpint(cmos_read(RTC_SECONDS), >=, 0x58);
245     g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02);
246     g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02);
247     g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x80);
248     g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x19);
249 }
250
251 static void bcd_check_time(void)
252 {
253     /* Set BCD mode */
254     cmos_write(RTC_REG_B, REG_B_24H);
255     check_time(wiggle);
256 }
257
258 static void dec_check_time(void)
259 {
260     /* Set DEC mode */
261     cmos_write(RTC_REG_B, REG_B_24H | REG_B_DM);
262     check_time(wiggle);
263 }
264
265 static void alarm_time(void)
266 {
267     struct tm now;
268     time_t ts;
269     int i;
270
271     ts = time(NULL);
272     gmtime_r(&ts, &now);
273
274     /* set DEC mode */
275     cmos_write(RTC_REG_B, REG_B_24H | REG_B_DM);
276
277     g_assert(!get_irq(RTC_ISA_IRQ));
278     cmos_read(RTC_REG_C);
279
280     now.tm_sec = (now.tm_sec + 2) % 60;
281     cmos_write(RTC_SECONDS_ALARM, now.tm_sec);
282     cmos_write(RTC_MINUTES_ALARM, RTC_ALARM_DONT_CARE);
283     cmos_write(RTC_HOURS_ALARM, RTC_ALARM_DONT_CARE);
284     cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_AIE);
285
286     for (i = 0; i < 2 + wiggle; i++) {
287         if (get_irq(RTC_ISA_IRQ)) {
288             break;
289         }
290
291         clock_step(1000000000);
292     }
293
294     g_assert(get_irq(RTC_ISA_IRQ));
295     g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0);
296     g_assert(cmos_read(RTC_REG_C) == 0);
297 }
298
299 static void set_time(int mode, int h, int m, int s)
300 {
301     /* set BCD 12 hour mode */
302     cmos_write(RTC_REG_B, mode);
303
304     cmos_write(RTC_REG_A, 0x76);
305     cmos_write(RTC_HOURS, h);
306     cmos_write(RTC_MINUTES, m);
307     cmos_write(RTC_SECONDS, s);
308     cmos_write(RTC_REG_A, 0x26);
309 }
310
311 #define assert_time(h, m, s) \
312     do { \
313         g_assert_cmpint(cmos_read(RTC_HOURS), ==, h); \
314         g_assert_cmpint(cmos_read(RTC_MINUTES), ==, m); \
315         g_assert_cmpint(cmos_read(RTC_SECONDS), ==, s); \
316     } while(0)
317
318 static void basic_12h_bcd(void)
319 {
320     /* set BCD 12 hour mode */
321     set_time(0, 0x81, 0x59, 0x00);
322     clock_step(1000000000LL);
323     assert_time(0x81, 0x59, 0x01);
324     clock_step(59000000000LL);
325     assert_time(0x82, 0x00, 0x00);
326
327     /* test BCD wraparound */
328     set_time(0, 0x09, 0x59, 0x59);
329     clock_step(60000000000LL);
330     assert_time(0x10, 0x00, 0x59);
331
332     /* 12 AM -> 1 AM */
333     set_time(0, 0x12, 0x59, 0x59);
334     clock_step(1000000000LL);
335     assert_time(0x01, 0x00, 0x00);
336
337     /* 12 PM -> 1 PM */
338     set_time(0, 0x92, 0x59, 0x59);
339     clock_step(1000000000LL);
340     assert_time(0x81, 0x00, 0x00);
341
342     /* 11 AM -> 12 PM */
343     set_time(0, 0x11, 0x59, 0x59);
344     clock_step(1000000000LL);
345     assert_time(0x92, 0x00, 0x00);
346     /* TODO: test day wraparound */
347
348     /* 11 PM -> 12 AM */
349     set_time(0, 0x91, 0x59, 0x59);
350     clock_step(1000000000LL);
351     assert_time(0x12, 0x00, 0x00);
352     /* TODO: test day wraparound */
353 }
354
355 static void basic_12h_dec(void)
356 {
357     /* set decimal 12 hour mode */
358     set_time(REG_B_DM, 0x81, 59, 0);
359     clock_step(1000000000LL);
360     assert_time(0x81, 59, 1);
361     clock_step(59000000000LL);
362     assert_time(0x82, 0, 0);
363
364     /* 12 PM -> 1 PM */
365     set_time(REG_B_DM, 0x8c, 59, 59);
366     clock_step(1000000000LL);
367     assert_time(0x81, 0, 0);
368
369     /* 12 AM -> 1 AM */
370     set_time(REG_B_DM, 0x0c, 59, 59);
371     clock_step(1000000000LL);
372     assert_time(0x01, 0, 0);
373
374     /* 11 AM -> 12 PM */
375     set_time(REG_B_DM, 0x0b, 59, 59);
376     clock_step(1000000000LL);
377     assert_time(0x8c, 0, 0);
378
379     /* 11 PM -> 12 AM */
380     set_time(REG_B_DM, 0x8b, 59, 59);
381     clock_step(1000000000LL);
382     assert_time(0x0c, 0, 0);
383     /* TODO: test day wraparound */
384 }
385
386 static void basic_24h_bcd(void)
387 {
388     /* set BCD 24 hour mode */
389     set_time(REG_B_24H, 0x09, 0x59, 0x00);
390     clock_step(1000000000LL);
391     assert_time(0x09, 0x59, 0x01);
392     clock_step(59000000000LL);
393     assert_time(0x10, 0x00, 0x00);
394
395     /* test BCD wraparound */
396     set_time(REG_B_24H, 0x09, 0x59, 0x00);
397     clock_step(60000000000LL);
398     assert_time(0x10, 0x00, 0x00);
399
400     /* TODO: test day wraparound */
401     set_time(REG_B_24H, 0x23, 0x59, 0x00);
402     clock_step(60000000000LL);
403     assert_time(0x00, 0x00, 0x00);
404 }
405
406 static void basic_24h_dec(void)
407 {
408     /* set decimal 24 hour mode */
409     set_time(REG_B_24H | REG_B_DM, 9, 59, 0);
410     clock_step(1000000000LL);
411     assert_time(9, 59, 1);
412     clock_step(59000000000LL);
413     assert_time(10, 0, 0);
414
415     /* test BCD wraparound */
416     set_time(REG_B_24H | REG_B_DM, 9, 59, 0);
417     clock_step(60000000000LL);
418     assert_time(10, 0, 0);
419
420     /* TODO: test day wraparound */
421     set_time(REG_B_24H | REG_B_DM, 23, 59, 0);
422     clock_step(60000000000LL);
423     assert_time(0, 0, 0);
424 }
425
426 static void am_pm_alarm(void)
427 {
428     cmos_write(RTC_MINUTES_ALARM, 0xC0);
429     cmos_write(RTC_SECONDS_ALARM, 0xC0);
430
431     /* set BCD 12 hour mode */
432     cmos_write(RTC_REG_B, 0);
433
434     /* Set time and alarm hour.  */
435     cmos_write(RTC_REG_A, 0x76);
436     cmos_write(RTC_HOURS_ALARM, 0x82);
437     cmos_write(RTC_HOURS, 0x81);
438     cmos_write(RTC_MINUTES, 0x59);
439     cmos_write(RTC_SECONDS, 0x00);
440     cmos_read(RTC_REG_C);
441     cmos_write(RTC_REG_A, 0x26);
442
443     /* Check that alarm triggers when AM/PM is set.  */
444     clock_step(60000000000LL);
445     g_assert(cmos_read(RTC_HOURS) == 0x82);
446     g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0);
447
448     /*
449      * Each of the following two tests takes over 60 seconds due to the time
450      * needed to report the PIT interrupts.  Unfortunately, our PIT device
451      * model keeps counting even when GATE=0, so we cannot simply disable
452      * it in main().
453      */
454     if (g_test_quick()) {
455         return;
456     }
457
458     /* set DEC 12 hour mode */
459     cmos_write(RTC_REG_B, REG_B_DM);
460
461     /* Set time and alarm hour.  */
462     cmos_write(RTC_REG_A, 0x76);
463     cmos_write(RTC_HOURS_ALARM, 0x82);
464     cmos_write(RTC_HOURS, 3);
465     cmos_write(RTC_MINUTES, 0);
466     cmos_write(RTC_SECONDS, 0);
467     cmos_read(RTC_REG_C);
468     cmos_write(RTC_REG_A, 0x26);
469
470     /* Check that alarm triggers.  */
471     clock_step(3600 * 11 * 1000000000LL);
472     g_assert(cmos_read(RTC_HOURS) == 0x82);
473     g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0);
474
475     /* Same as above, with inverted HOURS and HOURS_ALARM.  */
476     cmos_write(RTC_REG_A, 0x76);
477     cmos_write(RTC_HOURS_ALARM, 2);
478     cmos_write(RTC_HOURS, 3);
479     cmos_write(RTC_MINUTES, 0);
480     cmos_write(RTC_SECONDS, 0);
481     cmos_read(RTC_REG_C);
482     cmos_write(RTC_REG_A, 0x26);
483
484     /* Check that alarm does not trigger if hours differ only by AM/PM.  */
485     clock_step(3600 * 11 * 1000000000LL);
486     g_assert(cmos_read(RTC_HOURS) == 0x82);
487     g_assert((cmos_read(RTC_REG_C) & REG_C_AF) == 0);
488 }
489
490 /* success if no crash or abort */
491 static void fuzz_registers(void)
492 {
493     unsigned int i;
494
495     for (i = 0; i < 1000; i++) {
496         uint8_t reg, val;
497
498         reg = (uint8_t)g_test_rand_int_range(0, 16);
499         val = (uint8_t)g_test_rand_int_range(0, 256);
500
501         cmos_write(reg, val);
502         cmos_read(reg);
503     }
504 }
505
506 static void register_b_set_flag(void)
507 {
508     /* Enable binary-coded decimal (BCD) mode and SET flag in Register B*/
509     cmos_write(RTC_REG_B, REG_B_24H | REG_B_SET);
510
511     cmos_write(RTC_REG_A, 0x76);
512     cmos_write(RTC_YEAR, 0x11);
513     cmos_write(RTC_CENTURY, 0x20);
514     cmos_write(RTC_MONTH, 0x02);
515     cmos_write(RTC_DAY_OF_MONTH, 0x02);
516     cmos_write(RTC_HOURS, 0x02);
517     cmos_write(RTC_MINUTES, 0x04);
518     cmos_write(RTC_SECONDS, 0x58);
519     cmos_write(RTC_REG_A, 0x26);
520
521     /* Since SET flag is still enabled, these are equality checks. */
522     g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02);
523     g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04);
524     g_assert_cmpint(cmos_read(RTC_SECONDS), ==, 0x58);
525     g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02);
526     g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02);
527     g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x11);
528     g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20);
529
530     /* Disable SET flag in Register B */
531     cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_SET);
532
533     g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02);
534     g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04);
535
536     /* Since SET flag is disabled, this is an inequality check.
537      * We (reasonably) assume that no (sexagesimal) overflow occurs. */
538     g_assert_cmpint(cmos_read(RTC_SECONDS), >=, 0x58);
539     g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02);
540     g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02);
541     g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x11);
542     g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20);
543 }
544
545 int main(int argc, char **argv)
546 {
547     QTestState *s = NULL;
548     int ret;
549
550     g_test_init(&argc, &argv, NULL);
551
552     s = qtest_start("-rtc clock=vm");
553     qtest_irq_intercept_in(s, "ioapic");
554
555     qtest_add_func("/rtc/check-time/bcd", bcd_check_time);
556     qtest_add_func("/rtc/check-time/dec", dec_check_time);
557     qtest_add_func("/rtc/alarm/interrupt", alarm_time);
558     qtest_add_func("/rtc/alarm/am-pm", am_pm_alarm);
559     qtest_add_func("/rtc/basic/dec-24h", basic_24h_dec);
560     qtest_add_func("/rtc/basic/bcd-24h", basic_24h_bcd);
561     qtest_add_func("/rtc/basic/dec-12h", basic_12h_dec);
562     qtest_add_func("/rtc/basic/bcd-12h", basic_12h_bcd);
563     qtest_add_func("/rtc/set-year/20xx", set_year_20xx);
564     qtest_add_func("/rtc/set-year/1980", set_year_1980);
565     qtest_add_func("/rtc/misc/register_b_set_flag", register_b_set_flag);
566     qtest_add_func("/rtc/misc/fuzz-registers", fuzz_registers);
567     ret = g_test_run();
568
569     if (s) {
570         qtest_quit(s);
571     }
572
573     return ret;
574 }