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