Annotation of qemu/tests/rtc-test.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * QTest testcase for the MC146818 real-time clock
                      3:  *
                      4:  * Copyright IBM, Corp. 2012
                      5:  *
                      6:  * Authors:
                      7:  *  Anthony Liguori   <[email protected]>
                      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: #include "libqtest.h"
                     14: #include "hw/mc146818rtc_regs.h"
                     15: 
                     16: #include <glib.h>
                     17: #include <stdio.h>
                     18: #include <string.h>
                     19: #include <stdlib.h>
                     20: #include <unistd.h>
                     21: 
                     22: static uint8_t base = 0x70;
                     23: 
                     24: static int bcd2dec(int value)
                     25: {
                     26:     return (((value >> 4) & 0x0F) * 10) + (value & 0x0F);
                     27: }
                     28: 
                     29: static int dec2bcd(int value)
                     30: {
                     31:     return ((value / 10) << 4) | (value % 10);
                     32: }
                     33: 
                     34: static uint8_t cmos_read(uint8_t reg)
                     35: {
                     36:     outb(base + 0, reg);
                     37:     return inb(base + 1);
                     38: }
                     39: 
                     40: static void cmos_write(uint8_t reg, uint8_t val)
                     41: {
                     42:     outb(base + 0, reg);
                     43:     outb(base + 1, val);
                     44: }
                     45: 
                     46: static int tm_cmp(struct tm *lhs, struct tm *rhs)
                     47: {
                     48:     time_t a, b;
                     49:     struct tm d1, d2;
                     50: 
                     51:     memcpy(&d1, lhs, sizeof(d1));
                     52:     memcpy(&d2, rhs, sizeof(d2));
                     53: 
                     54:     a = mktime(&d1);
                     55:     b = mktime(&d2);
                     56: 
                     57:     if (a < b) {
                     58:         return -1;
                     59:     } else if (a > b) {
                     60:         return 1;
                     61:     }
                     62: 
                     63:     return 0;
                     64: }
                     65: 
                     66: #if 0
                     67: static void print_tm(struct tm *tm)
                     68: {
                     69:     printf("%04d-%02d-%02d %02d:%02d:%02d\n",
                     70:            tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
                     71:            tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff);
                     72: }
                     73: #endif
                     74: 
                     75: static void cmos_get_date_time(struct tm *date)
                     76: {
                     77:     int base_year = 2000, hour_offset;
                     78:     int sec, min, hour, mday, mon, year;
                     79:     time_t ts;
                     80:     struct tm dummy;
                     81: 
                     82:     sec = cmos_read(RTC_SECONDS);
                     83:     min = cmos_read(RTC_MINUTES);
                     84:     hour = cmos_read(RTC_HOURS);
                     85:     mday = cmos_read(RTC_DAY_OF_MONTH);
                     86:     mon = cmos_read(RTC_MONTH);
                     87:     year = cmos_read(RTC_YEAR);
                     88: 
                     89:     if ((cmos_read(RTC_REG_B) & REG_B_DM) == 0) {
                     90:         sec = bcd2dec(sec);
                     91:         min = bcd2dec(min);
                     92:         hour = bcd2dec(hour);
                     93:         mday = bcd2dec(mday);
                     94:         mon = bcd2dec(mon);
                     95:         year = bcd2dec(year);
                     96:         hour_offset = 80;
                     97:     } else {
                     98:         hour_offset = 0x80;
                     99:     }
                    100: 
                    101:     if ((cmos_read(0x0B) & REG_B_24H) == 0) {
                    102:         if (hour >= hour_offset) {
                    103:             hour -= hour_offset;
                    104:             hour += 12;
                    105:         }
                    106:     }
                    107: 
                    108:     ts = time(NULL);
                    109:     localtime_r(&ts, &dummy);
                    110: 
                    111:     date->tm_isdst = dummy.tm_isdst;
                    112:     date->tm_sec = sec;
                    113:     date->tm_min = min;
                    114:     date->tm_hour = hour;
                    115:     date->tm_mday = mday;
                    116:     date->tm_mon = mon - 1;
                    117:     date->tm_year = base_year + year - 1900;
                    118:     date->tm_gmtoff = 0;
                    119: 
                    120:     ts = mktime(date);
                    121: }
                    122: 
                    123: static void check_time(int wiggle)
                    124: {
                    125:     struct tm start, date[4], end;
                    126:     struct tm *datep;
                    127:     time_t ts;
                    128: 
                    129:     /*
                    130:      * This check assumes a few things.  First, we cannot guarantee that we get
                    131:      * a consistent reading from the wall clock because we may hit an edge of
                    132:      * the clock while reading.  To work around this, we read four clock readings
                    133:      * such that at least two of them should match.  We need to assume that one
                    134:      * reading is corrupt so we need four readings to ensure that we have at
                    135:      * least two consecutive identical readings
                    136:      *
                    137:      * It's also possible that we'll cross an edge reading the host clock so
                    138:      * simply check to make sure that the clock reading is within the period of
                    139:      * when we expect it to be.
                    140:      */
                    141: 
                    142:     ts = time(NULL);
                    143:     gmtime_r(&ts, &start);
                    144: 
                    145:     cmos_get_date_time(&date[0]);
                    146:     cmos_get_date_time(&date[1]);
                    147:     cmos_get_date_time(&date[2]);
                    148:     cmos_get_date_time(&date[3]);
                    149: 
                    150:     ts = time(NULL);
                    151:     gmtime_r(&ts, &end);
                    152: 
                    153:     if (tm_cmp(&date[0], &date[1]) == 0) {
                    154:         datep = &date[0];
                    155:     } else if (tm_cmp(&date[1], &date[2]) == 0) {
                    156:         datep = &date[1];
                    157:     } else if (tm_cmp(&date[2], &date[3]) == 0) {
                    158:         datep = &date[2];
                    159:     } else {
                    160:         g_assert_not_reached();
                    161:     }
                    162: 
                    163:     if (!(tm_cmp(&start, datep) <= 0 && tm_cmp(datep, &end) <= 0)) {
                    164:         long t, s;
                    165: 
                    166:         start.tm_isdst = datep->tm_isdst;
                    167: 
                    168:         t = (long)mktime(datep);
                    169:         s = (long)mktime(&start);
                    170:         if (t < s) {
                    171:             g_test_message("RTC is %ld second(s) behind wall-clock\n", (s - t));
                    172:         } else {
                    173:             g_test_message("RTC is %ld second(s) ahead of wall-clock\n", (t - s));
                    174:         }
                    175: 
                    176:         g_assert_cmpint(ABS(t - s), <=, wiggle);
                    177:     }
                    178: }
                    179: 
                    180: static int wiggle = 2;
                    181: 
                    182: static void bcd_check_time(void)
                    183: {
                    184:     /* Set BCD mode */
                    185:     cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_DM);
                    186:     check_time(wiggle);
                    187: }
                    188: 
                    189: static void dec_check_time(void)
                    190: {
                    191:     /* Set DEC mode */
                    192:     cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_DM);
                    193:     check_time(wiggle);
                    194: }
                    195: 
                    196: static void set_alarm_time(struct tm *tm)
                    197: {
                    198:     int sec;
                    199: 
                    200:     sec = tm->tm_sec;
                    201: 
                    202:     if ((cmos_read(RTC_REG_B) & REG_B_DM) == 0) {
                    203:         sec = dec2bcd(sec);
                    204:     }
                    205: 
                    206:     cmos_write(RTC_SECONDS_ALARM, sec);
                    207:     cmos_write(RTC_MINUTES_ALARM, RTC_ALARM_DONT_CARE);
                    208:     cmos_write(RTC_HOURS_ALARM, RTC_ALARM_DONT_CARE);
                    209: }
                    210: 
                    211: static void alarm_time(void)
                    212: {
                    213:     struct tm now;
                    214:     time_t ts;
                    215:     int i;
                    216: 
                    217:     ts = time(NULL);
                    218:     gmtime_r(&ts, &now);
                    219: 
                    220:     /* set DEC mode */
                    221:     cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_DM);
                    222: 
                    223:     g_assert(!get_irq(RTC_ISA_IRQ));
                    224:     cmos_read(RTC_REG_C);
                    225: 
                    226:     now.tm_sec = (now.tm_sec + 2) % 60;
                    227:     set_alarm_time(&now);
                    228:     cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_AIE);
                    229: 
                    230:     for (i = 0; i < 2 + wiggle; i++) {
                    231:         if (get_irq(RTC_ISA_IRQ)) {
                    232:             break;
                    233:         }
                    234: 
                    235:         clock_step(1000000000);
                    236:     }
                    237: 
                    238:     g_assert(get_irq(RTC_ISA_IRQ));
                    239:     g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0);
                    240:     g_assert(cmos_read(RTC_REG_C) == 0);
                    241: }
                    242: 
                    243: /* success if no crash or abort */
                    244: static void fuzz_registers(void)
                    245: {
                    246:     unsigned int i;
                    247: 
                    248:     for (i = 0; i < 1000; i++) {
                    249:         uint8_t reg, val;
                    250: 
                    251:         reg = (uint8_t)g_test_rand_int_range(0, 16);
                    252:         val = (uint8_t)g_test_rand_int_range(0, 256);
                    253: 
                    254:         cmos_write(reg, val);
                    255:         cmos_read(reg);
                    256:     }
                    257: }
                    258: 
                    259: int main(int argc, char **argv)
                    260: {
                    261:     QTestState *s = NULL;
                    262:     int ret;
                    263: 
                    264:     g_test_init(&argc, &argv, NULL);
                    265: 
                    266:     s = qtest_start("-display none -rtc clock=vm");
                    267:     qtest_irq_intercept_in(s, "ioapic");
                    268: 
                    269:     qtest_add_func("/rtc/bcd/check-time", bcd_check_time);
                    270:     qtest_add_func("/rtc/dec/check-time", dec_check_time);
                    271:     qtest_add_func("/rtc/alarm-time", alarm_time);
                    272:     qtest_add_func("/rtc/fuzz-registers", fuzz_registers);
                    273:     ret = g_test_run();
                    274: 
                    275:     if (s) {
                    276:         qtest_quit(s);
                    277:     }
                    278: 
                    279:     return ret;
                    280: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.