Don't look up pid/tid on YAGL_LOG_FUNC_SET
[sdk/emulator/qemu.git] / tests / m48t59-test.c
1 /*
2  * QTest testcase for the M48T59 and M48T08 real-time clocks
3  *
4  * Based on MC146818 RTC test:
5  * Copyright IBM, Corp. 2012
6  *
7  * Authors:
8  *  Anthony Liguori   <aliguori@us.ibm.com>
9  *
10  * This work is licensed under the terms of the GNU GPL, version 2 or later.
11  * See the COPYING file in the top-level directory.
12  *
13  */
14
15 #include "qemu/osdep.h"
16
17 #include "libqtest.h"
18
19 #define RTC_SECONDS             0x9
20 #define RTC_MINUTES             0xa
21 #define RTC_HOURS               0xb
22
23 #define RTC_DAY_OF_WEEK         0xc
24 #define RTC_DAY_OF_MONTH        0xd
25 #define RTC_MONTH               0xe
26 #define RTC_YEAR                0xf
27
28 static uint32_t base;
29 static uint16_t reg_base = 0x1ff0; /* 0x7f0 for m48t02 */
30 static int base_year;
31 static bool use_mmio;
32
33 static uint8_t cmos_read_mmio(uint8_t reg)
34 {
35     return readb(base + (uint32_t)reg_base + (uint32_t)reg);
36 }
37
38 static void cmos_write_mmio(uint8_t reg, uint8_t val)
39 {
40     uint8_t data = val;
41
42     writeb(base + (uint32_t)reg_base + (uint32_t)reg, data);
43 }
44
45 static uint8_t cmos_read_ioio(uint8_t reg)
46 {
47     outw(base + 0, reg_base + (uint16_t)reg);
48     return inb(base + 3);
49 }
50
51 static void cmos_write_ioio(uint8_t reg, uint8_t val)
52 {
53     outw(base + 0, reg_base + (uint16_t)reg);
54     outb(base + 3, val);
55 }
56
57 static uint8_t cmos_read(uint8_t reg)
58 {
59     if (use_mmio) {
60         return cmos_read_mmio(reg);
61     } else {
62         return cmos_read_ioio(reg);
63     }
64 }
65
66 static void cmos_write(uint8_t reg, uint8_t val)
67 {
68     if (use_mmio) {
69         cmos_write_mmio(reg, val);
70     } else {
71         cmos_write_ioio(reg, val);
72     }
73 }
74
75 static int bcd2dec(int value)
76 {
77     return (((value >> 4) & 0x0F) * 10) + (value & 0x0F);
78 }
79
80 static int tm_cmp(struct tm *lhs, struct tm *rhs)
81 {
82     time_t a, b;
83     struct tm d1, d2;
84
85     memcpy(&d1, lhs, sizeof(d1));
86     memcpy(&d2, rhs, sizeof(d2));
87
88     a = mktime(&d1);
89     b = mktime(&d2);
90
91     if (a < b) {
92         return -1;
93     } else if (a > b) {
94         return 1;
95     }
96
97     return 0;
98 }
99
100 #if 0
101 static void print_tm(struct tm *tm)
102 {
103     printf("%04d-%02d-%02d %02d:%02d:%02d %+02ld\n",
104            tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
105            tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff);
106 }
107 #endif
108
109 static void cmos_get_date_time(struct tm *date)
110 {
111     int sec, min, hour, mday, mon, year;
112     time_t ts;
113     struct tm dummy;
114
115     sec = cmos_read(RTC_SECONDS);
116     min = cmos_read(RTC_MINUTES);
117     hour = cmos_read(RTC_HOURS);
118     mday = cmos_read(RTC_DAY_OF_MONTH);
119     mon = cmos_read(RTC_MONTH);
120     year = cmos_read(RTC_YEAR);
121
122     sec = bcd2dec(sec);
123     min = bcd2dec(min);
124     hour = bcd2dec(hour);
125     mday = bcd2dec(mday);
126     mon = bcd2dec(mon);
127     year = bcd2dec(year);
128
129     ts = time(NULL);
130     localtime_r(&ts, &dummy);
131
132     date->tm_isdst = dummy.tm_isdst;
133     date->tm_sec = sec;
134     date->tm_min = min;
135     date->tm_hour = hour;
136     date->tm_mday = mday;
137     date->tm_mon = mon - 1;
138     date->tm_year = base_year + year - 1900;
139 #ifndef __sun__
140     date->tm_gmtoff = 0;
141 #endif
142
143     ts = mktime(date);
144 }
145
146 static void check_time(int wiggle)
147 {
148     struct tm start, date[4], end;
149     struct tm *datep;
150     time_t ts;
151
152     /*
153      * This check assumes a few things.  First, we cannot guarantee that we get
154      * a consistent reading from the wall clock because we may hit an edge of
155      * the clock while reading.  To work around this, we read four clock readings
156      * such that at least two of them should match.  We need to assume that one
157      * reading is corrupt so we need four readings to ensure that we have at
158      * least two consecutive identical readings
159      *
160      * It's also possible that we'll cross an edge reading the host clock so
161      * simply check to make sure that the clock reading is within the period of
162      * when we expect it to be.
163      */
164
165     ts = time(NULL);
166     gmtime_r(&ts, &start);
167
168     cmos_get_date_time(&date[0]);
169     cmos_get_date_time(&date[1]);
170     cmos_get_date_time(&date[2]);
171     cmos_get_date_time(&date[3]);
172
173     ts = time(NULL);
174     gmtime_r(&ts, &end);
175
176     if (tm_cmp(&date[0], &date[1]) == 0) {
177         datep = &date[0];
178     } else if (tm_cmp(&date[1], &date[2]) == 0) {
179         datep = &date[1];
180     } else if (tm_cmp(&date[2], &date[3]) == 0) {
181         datep = &date[2];
182     } else {
183         g_assert_not_reached();
184     }
185
186     if (!(tm_cmp(&start, datep) <= 0 && tm_cmp(datep, &end) <= 0)) {
187         long t, s;
188
189         start.tm_isdst = datep->tm_isdst;
190
191         t = (long)mktime(datep);
192         s = (long)mktime(&start);
193         if (t < s) {
194             g_test_message("RTC is %ld second(s) behind wall-clock\n", (s - t));
195         } else {
196             g_test_message("RTC is %ld second(s) ahead of wall-clock\n", (t - s));
197         }
198
199         g_assert_cmpint(ABS(t - s), <=, wiggle);
200     }
201 }
202
203 static int wiggle = 2;
204
205 static void bcd_check_time(void)
206 {
207     if (strcmp(qtest_get_arch(), "sparc64") == 0) {
208         base = 0x74;
209         base_year = 1900;
210         use_mmio = false;
211     } else if (strcmp(qtest_get_arch(), "sparc") == 0) {
212         base = 0x71200000;
213         base_year = 1968;
214         use_mmio = true;
215     } else { /* PPC: need to map macio in PCI */
216         g_assert_not_reached();
217     }
218     check_time(wiggle);
219 }
220
221 /* success if no crash or abort */
222 static void fuzz_registers(void)
223 {
224     unsigned int i;
225
226     for (i = 0; i < 1000; i++) {
227         uint8_t reg, val;
228
229         reg = (uint8_t)g_test_rand_int_range(0, 16);
230         val = (uint8_t)g_test_rand_int_range(0, 256);
231
232         if (reg == 7) {
233             /* watchdog setup register, may trigger system reset, skip */
234             continue;
235         }
236
237         cmos_write(reg, val);
238         cmos_read(reg);
239     }
240 }
241
242 int main(int argc, char **argv)
243 {
244     QTestState *s = NULL;
245     int ret;
246
247     g_test_init(&argc, &argv, NULL);
248
249     s = qtest_start("-rtc clock=vm");
250
251     qtest_add_func("/rtc/bcd/check-time", bcd_check_time);
252     qtest_add_func("/rtc/fuzz-registers", fuzz_registers);
253     ret = g_test_run();
254
255     if (s) {
256         qtest_quit(s);
257     }
258
259     return ret;
260 }