rtc-test.c (20536B)
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-single.h" 17#include "qemu/timer.h" 18#include "hw/rtc/mc146818rtc.h" 19#include "hw/rtc/mc146818rtc_regs.h" 20 21#define UIP_HOLD_LENGTH (8 * NANOSECONDS_PER_SECOND / 32768) 22 23static uint8_t base = 0x70; 24 25static int bcd2dec(int value) 26{ 27 return (((value >> 4) & 0x0F) * 10) + (value & 0x0F); 28} 29 30static uint8_t cmos_read(uint8_t reg) 31{ 32 outb(base + 0, reg); 33 return inb(base + 1); 34} 35 36static void cmos_write(uint8_t reg, uint8_t val) 37{ 38 outb(base + 0, reg); 39 outb(base + 1, val); 40} 41 42static int tm_cmp(struct tm *lhs, struct tm *rhs) 43{ 44 time_t a, b; 45 struct tm d1, d2; 46 47 memcpy(&d1, lhs, sizeof(d1)); 48 memcpy(&d2, rhs, sizeof(d2)); 49 50 a = mktime(&d1); 51 b = mktime(&d2); 52 53 if (a < b) { 54 return -1; 55 } else if (a > b) { 56 return 1; 57 } 58 59 return 0; 60} 61 62#if 0 63static void print_tm(struct tm *tm) 64{ 65 printf("%04d-%02d-%02d %02d:%02d:%02d\n", 66 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, 67 tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff); 68} 69#endif 70 71static void cmos_get_date_time(struct tm *date) 72{ 73 int base_year = 2000, hour_offset; 74 int sec, min, hour, mday, mon, year; 75 time_t ts; 76 struct tm dummy; 77 78 sec = cmos_read(RTC_SECONDS); 79 min = cmos_read(RTC_MINUTES); 80 hour = cmos_read(RTC_HOURS); 81 mday = cmos_read(RTC_DAY_OF_MONTH); 82 mon = cmos_read(RTC_MONTH); 83 year = cmos_read(RTC_YEAR); 84 85 if ((cmos_read(RTC_REG_B) & REG_B_DM) == 0) { 86 sec = bcd2dec(sec); 87 min = bcd2dec(min); 88 hour = bcd2dec(hour); 89 mday = bcd2dec(mday); 90 mon = bcd2dec(mon); 91 year = bcd2dec(year); 92 hour_offset = 80; 93 } else { 94 hour_offset = 0x80; 95 } 96 97 if ((cmos_read(0x0B) & REG_B_24H) == 0) { 98 if (hour >= hour_offset) { 99 hour -= hour_offset; 100 hour += 12; 101 } 102 } 103 104 ts = time(NULL); 105 localtime_r(&ts, &dummy); 106 107 date->tm_isdst = dummy.tm_isdst; 108 date->tm_sec = sec; 109 date->tm_min = min; 110 date->tm_hour = hour; 111 date->tm_mday = mday; 112 date->tm_mon = mon - 1; 113 date->tm_year = base_year + year - 1900; 114#ifndef __sun__ 115 date->tm_gmtoff = 0; 116#endif 117 118 ts = mktime(date); 119} 120 121static void check_time(int wiggle) 122{ 123 struct tm start, date[4], end; 124 struct tm *datep; 125 time_t ts; 126 127 /* 128 * This check assumes a few things. First, we cannot guarantee that we get 129 * a consistent reading from the wall clock because we may hit an edge of 130 * the clock while reading. To work around this, we read four clock readings 131 * such that at least two of them should match. We need to assume that one 132 * reading is corrupt so we need four readings to ensure that we have at 133 * least two consecutive identical readings 134 * 135 * It's also possible that we'll cross an edge reading the host clock so 136 * simply check to make sure that the clock reading is within the period of 137 * when we expect it to be. 138 */ 139 140 ts = time(NULL); 141 gmtime_r(&ts, &start); 142 143 cmos_get_date_time(&date[0]); 144 cmos_get_date_time(&date[1]); 145 cmos_get_date_time(&date[2]); 146 cmos_get_date_time(&date[3]); 147 148 ts = time(NULL); 149 gmtime_r(&ts, &end); 150 151 if (tm_cmp(&date[0], &date[1]) == 0) { 152 datep = &date[0]; 153 } else if (tm_cmp(&date[1], &date[2]) == 0) { 154 datep = &date[1]; 155 } else if (tm_cmp(&date[2], &date[3]) == 0) { 156 datep = &date[2]; 157 } else { 158 g_assert_not_reached(); 159 } 160 161 if (!(tm_cmp(&start, datep) <= 0 && tm_cmp(datep, &end) <= 0)) { 162 long t, s; 163 164 start.tm_isdst = datep->tm_isdst; 165 166 t = (long)mktime(datep); 167 s = (long)mktime(&start); 168 if (t < s) { 169 g_test_message("RTC is %ld second(s) behind wall-clock", (s - t)); 170 } else { 171 g_test_message("RTC is %ld second(s) ahead of wall-clock", (t - s)); 172 } 173 174 g_assert_cmpint(ABS(t - s), <=, wiggle); 175 } 176} 177 178static int wiggle = 2; 179 180static void set_year_20xx(void) 181{ 182 /* Set BCD mode */ 183 cmos_write(RTC_REG_B, REG_B_24H); 184 cmos_write(RTC_REG_A, 0x76); 185 cmos_write(RTC_YEAR, 0x11); 186 cmos_write(RTC_CENTURY, 0x20); 187 cmos_write(RTC_MONTH, 0x02); 188 cmos_write(RTC_DAY_OF_MONTH, 0x02); 189 cmos_write(RTC_HOURS, 0x02); 190 cmos_write(RTC_MINUTES, 0x04); 191 cmos_write(RTC_SECONDS, 0x58); 192 cmos_write(RTC_REG_A, 0x26); 193 194 g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02); 195 g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04); 196 g_assert_cmpint(cmos_read(RTC_SECONDS), >=, 0x58); 197 g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02); 198 g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02); 199 g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x11); 200 g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20); 201 202 if (sizeof(time_t) == 4) { 203 return; 204 } 205 206 /* Set a date in 2080 to ensure there is no year-2038 overflow. */ 207 cmos_write(RTC_REG_A, 0x76); 208 cmos_write(RTC_YEAR, 0x80); 209 cmos_write(RTC_REG_A, 0x26); 210 211 g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02); 212 g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04); 213 g_assert_cmpint(cmos_read(RTC_SECONDS), >=, 0x58); 214 g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02); 215 g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02); 216 g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x80); 217 g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20); 218 219 cmos_write(RTC_REG_A, 0x76); 220 cmos_write(RTC_YEAR, 0x11); 221 cmos_write(RTC_REG_A, 0x26); 222 223 g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02); 224 g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04); 225 g_assert_cmpint(cmos_read(RTC_SECONDS), >=, 0x58); 226 g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02); 227 g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02); 228 g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x11); 229 g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20); 230} 231 232static void set_year_1980(void) 233{ 234 /* Set BCD mode */ 235 cmos_write(RTC_REG_B, REG_B_24H); 236 cmos_write(RTC_REG_A, 0x76); 237 cmos_write(RTC_YEAR, 0x80); 238 cmos_write(RTC_CENTURY, 0x19); 239 cmos_write(RTC_MONTH, 0x02); 240 cmos_write(RTC_DAY_OF_MONTH, 0x02); 241 cmos_write(RTC_HOURS, 0x02); 242 cmos_write(RTC_MINUTES, 0x04); 243 cmos_write(RTC_SECONDS, 0x58); 244 cmos_write(RTC_REG_A, 0x26); 245 246 g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02); 247 g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04); 248 g_assert_cmpint(cmos_read(RTC_SECONDS), >=, 0x58); 249 g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02); 250 g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02); 251 g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x80); 252 g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x19); 253} 254 255static void bcd_check_time(void) 256{ 257 /* Set BCD mode */ 258 cmos_write(RTC_REG_B, REG_B_24H); 259 check_time(wiggle); 260} 261 262static void dec_check_time(void) 263{ 264 /* Set DEC mode */ 265 cmos_write(RTC_REG_B, REG_B_24H | REG_B_DM); 266 check_time(wiggle); 267} 268 269static void alarm_time(void) 270{ 271 struct tm now; 272 time_t ts; 273 int i; 274 275 ts = time(NULL); 276 gmtime_r(&ts, &now); 277 278 /* set DEC mode */ 279 cmos_write(RTC_REG_B, REG_B_24H | REG_B_DM); 280 281 g_assert(!get_irq(RTC_ISA_IRQ)); 282 cmos_read(RTC_REG_C); 283 284 now.tm_sec = (now.tm_sec + 2) % 60; 285 cmos_write(RTC_SECONDS_ALARM, now.tm_sec); 286 cmos_write(RTC_MINUTES_ALARM, RTC_ALARM_DONT_CARE); 287 cmos_write(RTC_HOURS_ALARM, RTC_ALARM_DONT_CARE); 288 cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_AIE); 289 290 for (i = 0; i < 2 + wiggle; i++) { 291 if (get_irq(RTC_ISA_IRQ)) { 292 break; 293 } 294 295 clock_step(NANOSECONDS_PER_SECOND); 296 } 297 298 g_assert(get_irq(RTC_ISA_IRQ)); 299 g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0); 300 g_assert(cmos_read(RTC_REG_C) == 0); 301} 302 303static void set_time_regs(int h, int m, int s) 304{ 305 cmos_write(RTC_HOURS, h); 306 cmos_write(RTC_MINUTES, m); 307 cmos_write(RTC_SECONDS, s); 308} 309 310static void set_time(int mode, int h, int m, int s) 311{ 312 cmos_write(RTC_REG_B, mode); 313 cmos_write(RTC_REG_A, 0x76); 314 set_time_regs(h, m, s); 315 cmos_write(RTC_REG_A, 0x26); 316} 317 318static void set_datetime_bcd(int h, int min, int s, int d, int m, int y) 319{ 320 cmos_write(RTC_HOURS, h); 321 cmos_write(RTC_MINUTES, min); 322 cmos_write(RTC_SECONDS, s); 323 cmos_write(RTC_YEAR, y & 0xFF); 324 cmos_write(RTC_CENTURY, y >> 8); 325 cmos_write(RTC_MONTH, m); 326 cmos_write(RTC_DAY_OF_MONTH, d); 327} 328 329static void set_datetime_dec(int h, int min, int s, int d, int m, int y) 330{ 331 cmos_write(RTC_HOURS, h); 332 cmos_write(RTC_MINUTES, min); 333 cmos_write(RTC_SECONDS, s); 334 cmos_write(RTC_YEAR, y % 100); 335 cmos_write(RTC_CENTURY, y / 100); 336 cmos_write(RTC_MONTH, m); 337 cmos_write(RTC_DAY_OF_MONTH, d); 338} 339 340static void set_datetime(int mode, int h, int min, int s, int d, int m, int y) 341{ 342 cmos_write(RTC_REG_B, mode); 343 344 cmos_write(RTC_REG_A, 0x76); 345 if (mode & REG_B_DM) { 346 set_datetime_dec(h, min, s, d, m, y); 347 } else { 348 set_datetime_bcd(h, min, s, d, m, y); 349 } 350 cmos_write(RTC_REG_A, 0x26); 351} 352 353#define assert_time(h, m, s) \ 354 do { \ 355 g_assert_cmpint(cmos_read(RTC_HOURS), ==, h); \ 356 g_assert_cmpint(cmos_read(RTC_MINUTES), ==, m); \ 357 g_assert_cmpint(cmos_read(RTC_SECONDS), ==, s); \ 358 } while(0) 359 360#define assert_datetime_bcd(h, min, s, d, m, y) \ 361 do { \ 362 g_assert_cmpint(cmos_read(RTC_HOURS), ==, h); \ 363 g_assert_cmpint(cmos_read(RTC_MINUTES), ==, min); \ 364 g_assert_cmpint(cmos_read(RTC_SECONDS), ==, s); \ 365 g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, d); \ 366 g_assert_cmpint(cmos_read(RTC_MONTH), ==, m); \ 367 g_assert_cmpint(cmos_read(RTC_YEAR), ==, (y & 0xFF)); \ 368 g_assert_cmpint(cmos_read(RTC_CENTURY), ==, (y >> 8)); \ 369 } while(0) 370 371static void basic_12h_bcd(void) 372{ 373 /* set BCD 12 hour mode */ 374 set_time(0, 0x81, 0x59, 0x00); 375 clock_step(1000000000LL); 376 assert_time(0x81, 0x59, 0x01); 377 clock_step(59000000000LL); 378 assert_time(0x82, 0x00, 0x00); 379 380 /* test BCD wraparound */ 381 set_time(0, 0x09, 0x59, 0x59); 382 clock_step(60000000000LL); 383 assert_time(0x10, 0x00, 0x59); 384 385 /* 12 AM -> 1 AM */ 386 set_time(0, 0x12, 0x59, 0x59); 387 clock_step(1000000000LL); 388 assert_time(0x01, 0x00, 0x00); 389 390 /* 12 PM -> 1 PM */ 391 set_time(0, 0x92, 0x59, 0x59); 392 clock_step(1000000000LL); 393 assert_time(0x81, 0x00, 0x00); 394 395 /* 11 AM -> 12 PM */ 396 set_time(0, 0x11, 0x59, 0x59); 397 clock_step(1000000000LL); 398 assert_time(0x92, 0x00, 0x00); 399 /* TODO: test day wraparound */ 400 401 /* 11 PM -> 12 AM */ 402 set_time(0, 0x91, 0x59, 0x59); 403 clock_step(1000000000LL); 404 assert_time(0x12, 0x00, 0x00); 405 /* TODO: test day wraparound */ 406} 407 408static void basic_12h_dec(void) 409{ 410 /* set decimal 12 hour mode */ 411 set_time(REG_B_DM, 0x81, 59, 0); 412 clock_step(1000000000LL); 413 assert_time(0x81, 59, 1); 414 clock_step(59000000000LL); 415 assert_time(0x82, 0, 0); 416 417 /* 12 PM -> 1 PM */ 418 set_time(REG_B_DM, 0x8c, 59, 59); 419 clock_step(1000000000LL); 420 assert_time(0x81, 0, 0); 421 422 /* 12 AM -> 1 AM */ 423 set_time(REG_B_DM, 0x0c, 59, 59); 424 clock_step(1000000000LL); 425 assert_time(0x01, 0, 0); 426 427 /* 11 AM -> 12 PM */ 428 set_time(REG_B_DM, 0x0b, 59, 59); 429 clock_step(1000000000LL); 430 assert_time(0x8c, 0, 0); 431 432 /* 11 PM -> 12 AM */ 433 set_time(REG_B_DM, 0x8b, 59, 59); 434 clock_step(1000000000LL); 435 assert_time(0x0c, 0, 0); 436 /* TODO: test day wraparound */ 437} 438 439static void basic_24h_bcd(void) 440{ 441 /* set BCD 24 hour mode */ 442 set_time(REG_B_24H, 0x09, 0x59, 0x00); 443 clock_step(1000000000LL); 444 assert_time(0x09, 0x59, 0x01); 445 clock_step(59000000000LL); 446 assert_time(0x10, 0x00, 0x00); 447 448 /* test BCD wraparound */ 449 set_time(REG_B_24H, 0x09, 0x59, 0x00); 450 clock_step(60000000000LL); 451 assert_time(0x10, 0x00, 0x00); 452 453 /* TODO: test day wraparound */ 454 set_time(REG_B_24H, 0x23, 0x59, 0x00); 455 clock_step(60000000000LL); 456 assert_time(0x00, 0x00, 0x00); 457} 458 459static void basic_24h_dec(void) 460{ 461 /* set decimal 24 hour mode */ 462 set_time(REG_B_24H | REG_B_DM, 9, 59, 0); 463 clock_step(1000000000LL); 464 assert_time(9, 59, 1); 465 clock_step(59000000000LL); 466 assert_time(10, 0, 0); 467 468 /* test BCD wraparound */ 469 set_time(REG_B_24H | REG_B_DM, 9, 59, 0); 470 clock_step(60000000000LL); 471 assert_time(10, 0, 0); 472 473 /* TODO: test day wraparound */ 474 set_time(REG_B_24H | REG_B_DM, 23, 59, 0); 475 clock_step(60000000000LL); 476 assert_time(0, 0, 0); 477} 478 479static void am_pm_alarm(void) 480{ 481 cmos_write(RTC_MINUTES_ALARM, 0xC0); 482 cmos_write(RTC_SECONDS_ALARM, 0xC0); 483 484 /* set BCD 12 hour mode */ 485 cmos_write(RTC_REG_B, 0); 486 487 /* Set time and alarm hour. */ 488 cmos_write(RTC_REG_A, 0x76); 489 cmos_write(RTC_HOURS_ALARM, 0x82); 490 cmos_write(RTC_HOURS, 0x81); 491 cmos_write(RTC_MINUTES, 0x59); 492 cmos_write(RTC_SECONDS, 0x00); 493 cmos_read(RTC_REG_C); 494 cmos_write(RTC_REG_A, 0x26); 495 496 /* Check that alarm triggers when AM/PM is set. */ 497 clock_step(60000000000LL); 498 g_assert(cmos_read(RTC_HOURS) == 0x82); 499 g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0); 500 501 /* 502 * Each of the following two tests takes over 60 seconds due to the time 503 * needed to report the PIT interrupts. Unfortunately, our PIT device 504 * model keeps counting even when GATE=0, so we cannot simply disable 505 * it in main(). 506 */ 507 if (g_test_quick()) { 508 return; 509 } 510 511 /* set DEC 12 hour mode */ 512 cmos_write(RTC_REG_B, REG_B_DM); 513 514 /* Set time and alarm hour. */ 515 cmos_write(RTC_REG_A, 0x76); 516 cmos_write(RTC_HOURS_ALARM, 0x82); 517 cmos_write(RTC_HOURS, 3); 518 cmos_write(RTC_MINUTES, 0); 519 cmos_write(RTC_SECONDS, 0); 520 cmos_read(RTC_REG_C); 521 cmos_write(RTC_REG_A, 0x26); 522 523 /* Check that alarm triggers. */ 524 clock_step(3600 * 11 * 1000000000LL); 525 g_assert(cmos_read(RTC_HOURS) == 0x82); 526 g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0); 527 528 /* Same as above, with inverted HOURS and HOURS_ALARM. */ 529 cmos_write(RTC_REG_A, 0x76); 530 cmos_write(RTC_HOURS_ALARM, 2); 531 cmos_write(RTC_HOURS, 3); 532 cmos_write(RTC_MINUTES, 0); 533 cmos_write(RTC_SECONDS, 0); 534 cmos_read(RTC_REG_C); 535 cmos_write(RTC_REG_A, 0x26); 536 537 /* Check that alarm does not trigger if hours differ only by AM/PM. */ 538 clock_step(3600 * 11 * 1000000000LL); 539 g_assert(cmos_read(RTC_HOURS) == 0x82); 540 g_assert((cmos_read(RTC_REG_C) & REG_C_AF) == 0); 541} 542 543/* success if no crash or abort */ 544static void fuzz_registers(void) 545{ 546 unsigned int i; 547 548 for (i = 0; i < 1000; i++) { 549 uint8_t reg, val; 550 551 reg = (uint8_t)g_test_rand_int_range(0, 16); 552 val = (uint8_t)g_test_rand_int_range(0, 256); 553 554 cmos_write(reg, val); 555 cmos_read(reg); 556 } 557} 558 559static void register_b_set_flag(void) 560{ 561 if (cmos_read(RTC_REG_A) & REG_A_UIP) { 562 clock_step(UIP_HOLD_LENGTH + NANOSECONDS_PER_SECOND / 5); 563 } 564 g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0); 565 566 /* Enable binary-coded decimal (BCD) mode and SET flag in Register B*/ 567 cmos_write(RTC_REG_B, REG_B_24H | REG_B_SET); 568 569 set_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011); 570 571 assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011); 572 573 /* Since SET flag is still enabled, time does not advance. */ 574 clock_step(1000000000LL); 575 assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011); 576 577 /* Disable SET flag in Register B */ 578 cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_SET); 579 580 assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011); 581 582 /* Since SET flag is disabled, the clock now advances. */ 583 clock_step(1000000000LL); 584 assert_datetime_bcd(0x02, 0x04, 0x59, 0x02, 0x02, 0x2011); 585} 586 587static void divider_reset(void) 588{ 589 /* Enable binary-coded decimal (BCD) mode in Register B*/ 590 cmos_write(RTC_REG_B, REG_B_24H); 591 592 /* Enter divider reset */ 593 cmos_write(RTC_REG_A, 0x76); 594 set_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011); 595 596 assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011); 597 598 /* Since divider reset flag is still enabled, these are equality checks. */ 599 clock_step(1000000000LL); 600 assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011); 601 602 /* The first update ends 500 ms after divider reset */ 603 cmos_write(RTC_REG_A, 0x26); 604 clock_step(500000000LL - UIP_HOLD_LENGTH - 1); 605 g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0); 606 assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011); 607 608 clock_step(1); 609 g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, !=, 0); 610 clock_step(UIP_HOLD_LENGTH); 611 g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0); 612 613 assert_datetime_bcd(0x02, 0x04, 0x59, 0x02, 0x02, 0x2011); 614} 615 616static void uip_stuck(void) 617{ 618 set_datetime(REG_B_24H, 0x02, 0x04, 0x58, 0x02, 0x02, 0x2011); 619 620 /* The first update ends 500 ms after divider reset */ 621 (void)cmos_read(RTC_REG_C); 622 clock_step(500000000LL); 623 g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0); 624 assert_datetime_bcd(0x02, 0x04, 0x59, 0x02, 0x02, 0x2011); 625 626 /* UF is now set. */ 627 cmos_write(RTC_HOURS_ALARM, 0x02); 628 cmos_write(RTC_MINUTES_ALARM, 0xC0); 629 cmos_write(RTC_SECONDS_ALARM, 0xC0); 630 631 /* Because the alarm will fire soon, reading register A will latch UIP. */ 632 clock_step(1000000000LL - UIP_HOLD_LENGTH / 2); 633 g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, !=, 0); 634 635 /* Move the alarm far away. This must not cause UIP to remain stuck! */ 636 cmos_write(RTC_HOURS_ALARM, 0x03); 637 clock_step(UIP_HOLD_LENGTH); 638 g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0); 639} 640 641#define RTC_PERIOD_CODE1 13 /* 8 Hz */ 642#define RTC_PERIOD_CODE2 15 /* 2 Hz */ 643 644#define RTC_PERIOD_TEST_NR 50 645 646static uint64_t wait_periodic_interrupt(uint64_t real_time) 647{ 648 while (!get_irq(RTC_ISA_IRQ)) { 649 real_time = clock_step_next(); 650 } 651 652 g_assert((cmos_read(RTC_REG_C) & REG_C_PF) != 0); 653 return real_time; 654} 655 656static void periodic_timer(void) 657{ 658 int i; 659 uint64_t period_clocks, period_time, start_time, real_time; 660 661 /* disable all interrupts. */ 662 cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & 663 ~(REG_B_PIE | REG_B_AIE | REG_B_UIE)); 664 cmos_write(RTC_REG_A, RTC_PERIOD_CODE1); 665 /* enable periodic interrupt after properly configure the period. */ 666 cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_PIE); 667 668 start_time = real_time = clock_step_next(); 669 670 for (i = 0; i < RTC_PERIOD_TEST_NR; i++) { 671 cmos_write(RTC_REG_A, RTC_PERIOD_CODE1); 672 real_time = wait_periodic_interrupt(real_time); 673 cmos_write(RTC_REG_A, RTC_PERIOD_CODE2); 674 real_time = wait_periodic_interrupt(real_time); 675 } 676 677 period_clocks = periodic_period_to_clock(RTC_PERIOD_CODE1) + 678 periodic_period_to_clock(RTC_PERIOD_CODE2); 679 period_clocks *= RTC_PERIOD_TEST_NR; 680 period_time = periodic_clock_to_ns(period_clocks); 681 682 real_time -= start_time; 683 g_assert_cmpint(ABS((int64_t)(real_time - period_time)), <=, 684 NANOSECONDS_PER_SECOND * 0.5); 685} 686 687int main(int argc, char **argv) 688{ 689 QTestState *s; 690 int ret; 691 692 g_test_init(&argc, &argv, NULL); 693 694 s = qtest_start("-rtc clock=vm"); 695 qtest_irq_intercept_in(s, "ioapic"); 696 697 qtest_add_func("/rtc/check-time/bcd", bcd_check_time); 698 qtest_add_func("/rtc/check-time/dec", dec_check_time); 699 qtest_add_func("/rtc/alarm/interrupt", alarm_time); 700 qtest_add_func("/rtc/alarm/am-pm", am_pm_alarm); 701 qtest_add_func("/rtc/basic/dec-24h", basic_24h_dec); 702 qtest_add_func("/rtc/basic/bcd-24h", basic_24h_bcd); 703 qtest_add_func("/rtc/basic/dec-12h", basic_12h_dec); 704 qtest_add_func("/rtc/basic/bcd-12h", basic_12h_bcd); 705 qtest_add_func("/rtc/set-year/20xx", set_year_20xx); 706 qtest_add_func("/rtc/set-year/1980", set_year_1980); 707 qtest_add_func("/rtc/update/register_b_set_flag", register_b_set_flag); 708 qtest_add_func("/rtc/update/divider-reset", divider_reset); 709 qtest_add_func("/rtc/update/uip-stuck", uip_stuck); 710 qtest_add_func("/rtc/misc/fuzz-registers", fuzz_registers); 711 qtest_add_func("/rtc/periodic/interrupt", periodic_timer); 712 713 ret = g_test_run(); 714 715 qtest_quit(s); 716 717 return ret; 718}