1 /* 2 * High Precision Event Timer emulation 3 * 4 * Copyright (c) 2007 Alexander Graf 5 * Copyright (c) 2008 IBM Corporation 6 * 7 * Authors: Beth Kon <bkon@us.ibm.com> 8 * 9 * This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU Lesser General Public 11 * License as published by the Free Software Foundation; either 12 * version 2 of the License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * Lesser General Public License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public 20 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 21 * 22 * ***************************************************************** 23 * 24 * This driver attempts to emulate an HPET device in software. 25 */ 26 27 #include "qemu/osdep.h" 28 #include "hw/i386/pc.h" 29 #include "hw/irq.h" 30 #include "ui/console.h" 31 #include "qapi/error.h" 32 #include "qemu/error-report.h" 33 #include "qemu/timer.h" 34 #include "hw/timer/hpet.h" 35 #include "hw/sysbus.h" 36 #include "hw/rtc/mc146818rtc.h" 37 #include "hw/rtc/mc146818rtc_regs.h" 38 #include "migration/vmstate.h" 39 #include "hw/timer/i8254.h" 40 41 //#define HPET_DEBUG 42 #ifdef HPET_DEBUG 43 #define DPRINTF printf 44 #else 45 #define DPRINTF(...) 46 #endif 47 48 #define HPET_MSI_SUPPORT 0 49 50 #define HPET(obj) OBJECT_CHECK(HPETState, (obj), TYPE_HPET) 51 52 struct HPETState; 53 typedef struct HPETTimer { /* timers */ 54 uint8_t tn; /*timer number*/ 55 QEMUTimer *qemu_timer; 56 struct HPETState *state; 57 /* Memory-mapped, software visible timer registers */ 58 uint64_t config; /* configuration/cap */ 59 uint64_t cmp; /* comparator */ 60 uint64_t fsb; /* FSB route */ 61 /* Hidden register state */ 62 uint64_t period; /* Last value written to comparator */ 63 uint8_t wrap_flag; /* timer pop will indicate wrap for one-shot 32-bit 64 * mode. Next pop will be actual timer expiration. 65 */ 66 } HPETTimer; 67 68 typedef struct HPETState { 69 /*< private >*/ 70 SysBusDevice parent_obj; 71 /*< public >*/ 72 73 MemoryRegion iomem; 74 uint64_t hpet_offset; 75 bool hpet_offset_saved; 76 qemu_irq irqs[HPET_NUM_IRQ_ROUTES]; 77 uint32_t flags; 78 uint8_t rtc_irq_level; 79 qemu_irq pit_enabled; 80 uint8_t num_timers; 81 uint32_t intcap; 82 HPETTimer timer[HPET_MAX_TIMERS]; 83 84 /* Memory-mapped, software visible registers */ 85 uint64_t capability; /* capabilities */ 86 uint64_t config; /* configuration */ 87 uint64_t isr; /* interrupt status reg */ 88 uint64_t hpet_counter; /* main counter */ 89 uint8_t hpet_id; /* instance id */ 90 } HPETState; 91 92 static uint32_t hpet_in_legacy_mode(HPETState *s) 93 { 94 return s->config & HPET_CFG_LEGACY; 95 } 96 97 static uint32_t timer_int_route(struct HPETTimer *timer) 98 { 99 return (timer->config & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT; 100 } 101 102 static uint32_t timer_fsb_route(HPETTimer *t) 103 { 104 return t->config & HPET_TN_FSB_ENABLE; 105 } 106 107 static uint32_t hpet_enabled(HPETState *s) 108 { 109 return s->config & HPET_CFG_ENABLE; 110 } 111 112 static uint32_t timer_is_periodic(HPETTimer *t) 113 { 114 return t->config & HPET_TN_PERIODIC; 115 } 116 117 static uint32_t timer_enabled(HPETTimer *t) 118 { 119 return t->config & HPET_TN_ENABLE; 120 } 121 122 static uint32_t hpet_time_after(uint64_t a, uint64_t b) 123 { 124 return ((int32_t)(b - a) < 0); 125 } 126 127 static uint32_t hpet_time_after64(uint64_t a, uint64_t b) 128 { 129 return ((int64_t)(b - a) < 0); 130 } 131 132 static uint64_t ticks_to_ns(uint64_t value) 133 { 134 return value * HPET_CLK_PERIOD; 135 } 136 137 static uint64_t ns_to_ticks(uint64_t value) 138 { 139 return value / HPET_CLK_PERIOD; 140 } 141 142 static uint64_t hpet_fixup_reg(uint64_t new, uint64_t old, uint64_t mask) 143 { 144 new &= mask; 145 new |= old & ~mask; 146 return new; 147 } 148 149 static int activating_bit(uint64_t old, uint64_t new, uint64_t mask) 150 { 151 return (!(old & mask) && (new & mask)); 152 } 153 154 static int deactivating_bit(uint64_t old, uint64_t new, uint64_t mask) 155 { 156 return ((old & mask) && !(new & mask)); 157 } 158 159 static uint64_t hpet_get_ticks(HPETState *s) 160 { 161 return ns_to_ticks(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->hpet_offset); 162 } 163 164 /* 165 * calculate diff between comparator value and current ticks 166 */ 167 static inline uint64_t hpet_calculate_diff(HPETTimer *t, uint64_t current) 168 { 169 170 if (t->config & HPET_TN_32BIT) { 171 uint32_t diff, cmp; 172 173 cmp = (uint32_t)t->cmp; 174 diff = cmp - (uint32_t)current; 175 diff = (int32_t)diff > 0 ? diff : (uint32_t)1; 176 return (uint64_t)diff; 177 } else { 178 uint64_t diff, cmp; 179 180 cmp = t->cmp; 181 diff = cmp - current; 182 diff = (int64_t)diff > 0 ? diff : (uint64_t)1; 183 return diff; 184 } 185 } 186 187 static void update_irq(struct HPETTimer *timer, int set) 188 { 189 uint64_t mask; 190 HPETState *s; 191 int route; 192 193 if (timer->tn <= 1 && hpet_in_legacy_mode(timer->state)) { 194 /* if LegacyReplacementRoute bit is set, HPET specification requires 195 * timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC, 196 * timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC. 197 */ 198 route = (timer->tn == 0) ? 0 : RTC_ISA_IRQ; 199 } else { 200 route = timer_int_route(timer); 201 } 202 s = timer->state; 203 mask = 1 << timer->tn; 204 if (!set || !timer_enabled(timer) || !hpet_enabled(timer->state)) { 205 s->isr &= ~mask; 206 if (!timer_fsb_route(timer)) { 207 qemu_irq_lower(s->irqs[route]); 208 } 209 } else if (timer_fsb_route(timer)) { 210 address_space_stl_le(&address_space_memory, timer->fsb >> 32, 211 timer->fsb & 0xffffffff, MEMTXATTRS_UNSPECIFIED, 212 NULL); 213 } else if (timer->config & HPET_TN_TYPE_LEVEL) { 214 s->isr |= mask; 215 qemu_irq_raise(s->irqs[route]); 216 } else { 217 s->isr &= ~mask; 218 qemu_irq_pulse(s->irqs[route]); 219 } 220 } 221 222 static int hpet_pre_save(void *opaque) 223 { 224 HPETState *s = opaque; 225 226 /* save current counter value */ 227 if (hpet_enabled(s)) { 228 s->hpet_counter = hpet_get_ticks(s); 229 } 230 231 return 0; 232 } 233 234 static int hpet_pre_load(void *opaque) 235 { 236 HPETState *s = opaque; 237 238 /* version 1 only supports 3, later versions will load the actual value */ 239 s->num_timers = HPET_MIN_TIMERS; 240 return 0; 241 } 242 243 static bool hpet_validate_num_timers(void *opaque, int version_id) 244 { 245 HPETState *s = opaque; 246 247 if (s->num_timers < HPET_MIN_TIMERS) { 248 return false; 249 } else if (s->num_timers > HPET_MAX_TIMERS) { 250 return false; 251 } 252 return true; 253 } 254 255 static int hpet_post_load(void *opaque, int version_id) 256 { 257 HPETState *s = opaque; 258 259 /* Recalculate the offset between the main counter and guest time */ 260 if (!s->hpet_offset_saved) { 261 s->hpet_offset = ticks_to_ns(s->hpet_counter) 262 - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 263 } 264 265 /* Push number of timers into capability returned via HPET_ID */ 266 s->capability &= ~HPET_ID_NUM_TIM_MASK; 267 s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT; 268 hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability; 269 270 /* Derive HPET_MSI_SUPPORT from the capability of the first timer. */ 271 s->flags &= ~(1 << HPET_MSI_SUPPORT); 272 if (s->timer[0].config & HPET_TN_FSB_CAP) { 273 s->flags |= 1 << HPET_MSI_SUPPORT; 274 } 275 return 0; 276 } 277 278 static bool hpet_offset_needed(void *opaque) 279 { 280 HPETState *s = opaque; 281 282 return hpet_enabled(s) && s->hpet_offset_saved; 283 } 284 285 static bool hpet_rtc_irq_level_needed(void *opaque) 286 { 287 HPETState *s = opaque; 288 289 return s->rtc_irq_level != 0; 290 } 291 292 static const VMStateDescription vmstate_hpet_rtc_irq_level = { 293 .name = "hpet/rtc_irq_level", 294 .version_id = 1, 295 .minimum_version_id = 1, 296 .needed = hpet_rtc_irq_level_needed, 297 .fields = (VMStateField[]) { 298 VMSTATE_UINT8(rtc_irq_level, HPETState), 299 VMSTATE_END_OF_LIST() 300 } 301 }; 302 303 static const VMStateDescription vmstate_hpet_offset = { 304 .name = "hpet/offset", 305 .version_id = 1, 306 .minimum_version_id = 1, 307 .needed = hpet_offset_needed, 308 .fields = (VMStateField[]) { 309 VMSTATE_UINT64(hpet_offset, HPETState), 310 VMSTATE_END_OF_LIST() 311 } 312 }; 313 314 static const VMStateDescription vmstate_hpet_timer = { 315 .name = "hpet_timer", 316 .version_id = 1, 317 .minimum_version_id = 1, 318 .fields = (VMStateField[]) { 319 VMSTATE_UINT8(tn, HPETTimer), 320 VMSTATE_UINT64(config, HPETTimer), 321 VMSTATE_UINT64(cmp, HPETTimer), 322 VMSTATE_UINT64(fsb, HPETTimer), 323 VMSTATE_UINT64(period, HPETTimer), 324 VMSTATE_UINT8(wrap_flag, HPETTimer), 325 VMSTATE_TIMER_PTR(qemu_timer, HPETTimer), 326 VMSTATE_END_OF_LIST() 327 } 328 }; 329 330 static const VMStateDescription vmstate_hpet = { 331 .name = "hpet", 332 .version_id = 2, 333 .minimum_version_id = 1, 334 .pre_save = hpet_pre_save, 335 .pre_load = hpet_pre_load, 336 .post_load = hpet_post_load, 337 .fields = (VMStateField[]) { 338 VMSTATE_UINT64(config, HPETState), 339 VMSTATE_UINT64(isr, HPETState), 340 VMSTATE_UINT64(hpet_counter, HPETState), 341 VMSTATE_UINT8_V(num_timers, HPETState, 2), 342 VMSTATE_VALIDATE("num_timers in range", hpet_validate_num_timers), 343 VMSTATE_STRUCT_VARRAY_UINT8(timer, HPETState, num_timers, 0, 344 vmstate_hpet_timer, HPETTimer), 345 VMSTATE_END_OF_LIST() 346 }, 347 .subsections = (const VMStateDescription*[]) { 348 &vmstate_hpet_rtc_irq_level, 349 &vmstate_hpet_offset, 350 NULL 351 } 352 }; 353 354 /* 355 * timer expiration callback 356 */ 357 static void hpet_timer(void *opaque) 358 { 359 HPETTimer *t = opaque; 360 uint64_t diff; 361 362 uint64_t period = t->period; 363 uint64_t cur_tick = hpet_get_ticks(t->state); 364 365 if (timer_is_periodic(t) && period != 0) { 366 if (t->config & HPET_TN_32BIT) { 367 while (hpet_time_after(cur_tick, t->cmp)) { 368 t->cmp = (uint32_t)(t->cmp + t->period); 369 } 370 } else { 371 while (hpet_time_after64(cur_tick, t->cmp)) { 372 t->cmp += period; 373 } 374 } 375 diff = hpet_calculate_diff(t, cur_tick); 376 timer_mod(t->qemu_timer, 377 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (int64_t)ticks_to_ns(diff)); 378 } else if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) { 379 if (t->wrap_flag) { 380 diff = hpet_calculate_diff(t, cur_tick); 381 timer_mod(t->qemu_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 382 (int64_t)ticks_to_ns(diff)); 383 t->wrap_flag = 0; 384 } 385 } 386 update_irq(t, 1); 387 } 388 389 static void hpet_set_timer(HPETTimer *t) 390 { 391 uint64_t diff; 392 uint32_t wrap_diff; /* how many ticks until we wrap? */ 393 uint64_t cur_tick = hpet_get_ticks(t->state); 394 395 /* whenever new timer is being set up, make sure wrap_flag is 0 */ 396 t->wrap_flag = 0; 397 diff = hpet_calculate_diff(t, cur_tick); 398 399 /* hpet spec says in one-shot 32-bit mode, generate an interrupt when 400 * counter wraps in addition to an interrupt with comparator match. 401 */ 402 if (t->config & HPET_TN_32BIT && !timer_is_periodic(t)) { 403 wrap_diff = 0xffffffff - (uint32_t)cur_tick; 404 if (wrap_diff < (uint32_t)diff) { 405 diff = wrap_diff; 406 t->wrap_flag = 1; 407 } 408 } 409 timer_mod(t->qemu_timer, 410 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (int64_t)ticks_to_ns(diff)); 411 } 412 413 static void hpet_del_timer(HPETTimer *t) 414 { 415 timer_del(t->qemu_timer); 416 update_irq(t, 0); 417 } 418 419 #ifdef HPET_DEBUG 420 static uint32_t hpet_ram_readb(void *opaque, hwaddr addr) 421 { 422 printf("qemu: hpet_read b at %" PRIx64 "\n", addr); 423 return 0; 424 } 425 426 static uint32_t hpet_ram_readw(void *opaque, hwaddr addr) 427 { 428 printf("qemu: hpet_read w at %" PRIx64 "\n", addr); 429 return 0; 430 } 431 #endif 432 433 static uint64_t hpet_ram_read(void *opaque, hwaddr addr, 434 unsigned size) 435 { 436 HPETState *s = opaque; 437 uint64_t cur_tick, index; 438 439 DPRINTF("qemu: Enter hpet_ram_readl at %" PRIx64 "\n", addr); 440 index = addr; 441 /*address range of all TN regs*/ 442 if (index >= 0x100 && index <= 0x3ff) { 443 uint8_t timer_id = (addr - 0x100) / 0x20; 444 HPETTimer *timer = &s->timer[timer_id]; 445 446 if (timer_id > s->num_timers) { 447 DPRINTF("qemu: timer id out of range\n"); 448 return 0; 449 } 450 451 switch ((addr - 0x100) % 0x20) { 452 case HPET_TN_CFG: 453 return timer->config; 454 case HPET_TN_CFG + 4: // Interrupt capabilities 455 return timer->config >> 32; 456 case HPET_TN_CMP: // comparator register 457 return timer->cmp; 458 case HPET_TN_CMP + 4: 459 return timer->cmp >> 32; 460 case HPET_TN_ROUTE: 461 return timer->fsb; 462 case HPET_TN_ROUTE + 4: 463 return timer->fsb >> 32; 464 default: 465 DPRINTF("qemu: invalid hpet_ram_readl\n"); 466 break; 467 } 468 } else { 469 switch (index) { 470 case HPET_ID: 471 return s->capability; 472 case HPET_PERIOD: 473 return s->capability >> 32; 474 case HPET_CFG: 475 return s->config; 476 case HPET_CFG + 4: 477 DPRINTF("qemu: invalid HPET_CFG + 4 hpet_ram_readl\n"); 478 return 0; 479 case HPET_COUNTER: 480 if (hpet_enabled(s)) { 481 cur_tick = hpet_get_ticks(s); 482 } else { 483 cur_tick = s->hpet_counter; 484 } 485 DPRINTF("qemu: reading counter = %" PRIx64 "\n", cur_tick); 486 return cur_tick; 487 case HPET_COUNTER + 4: 488 if (hpet_enabled(s)) { 489 cur_tick = hpet_get_ticks(s); 490 } else { 491 cur_tick = s->hpet_counter; 492 } 493 DPRINTF("qemu: reading counter + 4 = %" PRIx64 "\n", cur_tick); 494 return cur_tick >> 32; 495 case HPET_STATUS: 496 return s->isr; 497 default: 498 DPRINTF("qemu: invalid hpet_ram_readl\n"); 499 break; 500 } 501 } 502 return 0; 503 } 504 505 static void hpet_ram_write(void *opaque, hwaddr addr, 506 uint64_t value, unsigned size) 507 { 508 int i; 509 HPETState *s = opaque; 510 uint64_t old_val, new_val, val, index; 511 512 DPRINTF("qemu: Enter hpet_ram_writel at %" PRIx64 " = %#x\n", addr, value); 513 index = addr; 514 old_val = hpet_ram_read(opaque, addr, 4); 515 new_val = value; 516 517 /*address range of all TN regs*/ 518 if (index >= 0x100 && index <= 0x3ff) { 519 uint8_t timer_id = (addr - 0x100) / 0x20; 520 HPETTimer *timer = &s->timer[timer_id]; 521 522 DPRINTF("qemu: hpet_ram_writel timer_id = %#x\n", timer_id); 523 if (timer_id > s->num_timers) { 524 DPRINTF("qemu: timer id out of range\n"); 525 return; 526 } 527 switch ((addr - 0x100) % 0x20) { 528 case HPET_TN_CFG: 529 DPRINTF("qemu: hpet_ram_writel HPET_TN_CFG\n"); 530 if (activating_bit(old_val, new_val, HPET_TN_FSB_ENABLE)) { 531 update_irq(timer, 0); 532 } 533 val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK); 534 timer->config = (timer->config & 0xffffffff00000000ULL) | val; 535 if (new_val & HPET_TN_32BIT) { 536 timer->cmp = (uint32_t)timer->cmp; 537 timer->period = (uint32_t)timer->period; 538 } 539 if (activating_bit(old_val, new_val, HPET_TN_ENABLE) && 540 hpet_enabled(s)) { 541 hpet_set_timer(timer); 542 } else if (deactivating_bit(old_val, new_val, HPET_TN_ENABLE)) { 543 hpet_del_timer(timer); 544 } 545 break; 546 case HPET_TN_CFG + 4: // Interrupt capabilities 547 DPRINTF("qemu: invalid HPET_TN_CFG+4 write\n"); 548 break; 549 case HPET_TN_CMP: // comparator register 550 DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP\n"); 551 if (timer->config & HPET_TN_32BIT) { 552 new_val = (uint32_t)new_val; 553 } 554 if (!timer_is_periodic(timer) 555 || (timer->config & HPET_TN_SETVAL)) { 556 timer->cmp = (timer->cmp & 0xffffffff00000000ULL) | new_val; 557 } 558 if (timer_is_periodic(timer)) { 559 /* 560 * FIXME: Clamp period to reasonable min value? 561 * Clamp period to reasonable max value 562 */ 563 new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1; 564 timer->period = 565 (timer->period & 0xffffffff00000000ULL) | new_val; 566 } 567 timer->config &= ~HPET_TN_SETVAL; 568 if (hpet_enabled(s)) { 569 hpet_set_timer(timer); 570 } 571 break; 572 case HPET_TN_CMP + 4: // comparator register high order 573 DPRINTF("qemu: hpet_ram_writel HPET_TN_CMP + 4\n"); 574 if (!timer_is_periodic(timer) 575 || (timer->config & HPET_TN_SETVAL)) { 576 timer->cmp = (timer->cmp & 0xffffffffULL) | new_val << 32; 577 } else { 578 /* 579 * FIXME: Clamp period to reasonable min value? 580 * Clamp period to reasonable max value 581 */ 582 new_val &= (timer->config & HPET_TN_32BIT ? ~0u : ~0ull) >> 1; 583 timer->period = 584 (timer->period & 0xffffffffULL) | new_val << 32; 585 } 586 timer->config &= ~HPET_TN_SETVAL; 587 if (hpet_enabled(s)) { 588 hpet_set_timer(timer); 589 } 590 break; 591 case HPET_TN_ROUTE: 592 timer->fsb = (timer->fsb & 0xffffffff00000000ULL) | new_val; 593 break; 594 case HPET_TN_ROUTE + 4: 595 timer->fsb = (new_val << 32) | (timer->fsb & 0xffffffff); 596 break; 597 default: 598 DPRINTF("qemu: invalid hpet_ram_writel\n"); 599 break; 600 } 601 return; 602 } else { 603 switch (index) { 604 case HPET_ID: 605 return; 606 case HPET_CFG: 607 val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK); 608 s->config = (s->config & 0xffffffff00000000ULL) | val; 609 if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) { 610 /* Enable main counter and interrupt generation. */ 611 s->hpet_offset = 612 ticks_to_ns(s->hpet_counter) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 613 for (i = 0; i < s->num_timers; i++) { 614 if ((&s->timer[i])->cmp != ~0ULL) { 615 hpet_set_timer(&s->timer[i]); 616 } 617 } 618 } else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) { 619 /* Halt main counter and disable interrupt generation. */ 620 s->hpet_counter = hpet_get_ticks(s); 621 for (i = 0; i < s->num_timers; i++) { 622 hpet_del_timer(&s->timer[i]); 623 } 624 } 625 /* i8254 and RTC output pins are disabled 626 * when HPET is in legacy mode */ 627 if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) { 628 qemu_set_irq(s->pit_enabled, 0); 629 qemu_irq_lower(s->irqs[0]); 630 qemu_irq_lower(s->irqs[RTC_ISA_IRQ]); 631 } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) { 632 qemu_irq_lower(s->irqs[0]); 633 qemu_set_irq(s->pit_enabled, 1); 634 qemu_set_irq(s->irqs[RTC_ISA_IRQ], s->rtc_irq_level); 635 } 636 break; 637 case HPET_CFG + 4: 638 DPRINTF("qemu: invalid HPET_CFG+4 write\n"); 639 break; 640 case HPET_STATUS: 641 val = new_val & s->isr; 642 for (i = 0; i < s->num_timers; i++) { 643 if (val & (1 << i)) { 644 update_irq(&s->timer[i], 0); 645 } 646 } 647 break; 648 case HPET_COUNTER: 649 if (hpet_enabled(s)) { 650 DPRINTF("qemu: Writing counter while HPET enabled!\n"); 651 } 652 s->hpet_counter = 653 (s->hpet_counter & 0xffffffff00000000ULL) | value; 654 DPRINTF("qemu: HPET counter written. ctr = %#x -> %" PRIx64 "\n", 655 value, s->hpet_counter); 656 break; 657 case HPET_COUNTER + 4: 658 if (hpet_enabled(s)) { 659 DPRINTF("qemu: Writing counter while HPET enabled!\n"); 660 } 661 s->hpet_counter = 662 (s->hpet_counter & 0xffffffffULL) | (((uint64_t)value) << 32); 663 DPRINTF("qemu: HPET counter + 4 written. ctr = %#x -> %" PRIx64 "\n", 664 value, s->hpet_counter); 665 break; 666 default: 667 DPRINTF("qemu: invalid hpet_ram_writel\n"); 668 break; 669 } 670 } 671 } 672 673 static const MemoryRegionOps hpet_ram_ops = { 674 .read = hpet_ram_read, 675 .write = hpet_ram_write, 676 .valid = { 677 .min_access_size = 4, 678 .max_access_size = 4, 679 }, 680 .endianness = DEVICE_NATIVE_ENDIAN, 681 }; 682 683 static void hpet_reset(DeviceState *d) 684 { 685 HPETState *s = HPET(d); 686 SysBusDevice *sbd = SYS_BUS_DEVICE(d); 687 int i; 688 689 for (i = 0; i < s->num_timers; i++) { 690 HPETTimer *timer = &s->timer[i]; 691 692 hpet_del_timer(timer); 693 timer->cmp = ~0ULL; 694 timer->config = HPET_TN_PERIODIC_CAP | HPET_TN_SIZE_CAP; 695 if (s->flags & (1 << HPET_MSI_SUPPORT)) { 696 timer->config |= HPET_TN_FSB_CAP; 697 } 698 /* advertise availability of ioapic int */ 699 timer->config |= (uint64_t)s->intcap << 32; 700 timer->period = 0ULL; 701 timer->wrap_flag = 0; 702 } 703 704 qemu_set_irq(s->pit_enabled, 1); 705 s->hpet_counter = 0ULL; 706 s->hpet_offset = 0ULL; 707 s->config = 0ULL; 708 hpet_cfg.hpet[s->hpet_id].event_timer_block_id = (uint32_t)s->capability; 709 hpet_cfg.hpet[s->hpet_id].address = sbd->mmio[0].addr; 710 711 /* to document that the RTC lowers its output on reset as well */ 712 s->rtc_irq_level = 0; 713 } 714 715 static void hpet_handle_legacy_irq(void *opaque, int n, int level) 716 { 717 HPETState *s = HPET(opaque); 718 719 if (n == HPET_LEGACY_PIT_INT) { 720 if (!hpet_in_legacy_mode(s)) { 721 qemu_set_irq(s->irqs[0], level); 722 } 723 } else { 724 s->rtc_irq_level = level; 725 if (!hpet_in_legacy_mode(s)) { 726 qemu_set_irq(s->irqs[RTC_ISA_IRQ], level); 727 } 728 } 729 } 730 731 static void hpet_init(Object *obj) 732 { 733 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 734 HPETState *s = HPET(obj); 735 736 /* HPET Area */ 737 memory_region_init_io(&s->iomem, obj, &hpet_ram_ops, s, "hpet", HPET_LEN); 738 sysbus_init_mmio(sbd, &s->iomem); 739 } 740 741 static void hpet_realize(DeviceState *dev, Error **errp) 742 { 743 SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 744 HPETState *s = HPET(dev); 745 int i; 746 HPETTimer *timer; 747 748 if (!s->intcap) { 749 warn_report("Hpet's intcap not initialized"); 750 } 751 if (hpet_cfg.count == UINT8_MAX) { 752 /* first instance */ 753 hpet_cfg.count = 0; 754 } 755 756 if (hpet_cfg.count == 8) { 757 error_setg(errp, "Only 8 instances of HPET is allowed"); 758 return; 759 } 760 761 s->hpet_id = hpet_cfg.count++; 762 763 for (i = 0; i < HPET_NUM_IRQ_ROUTES; i++) { 764 sysbus_init_irq(sbd, &s->irqs[i]); 765 } 766 767 if (s->num_timers < HPET_MIN_TIMERS) { 768 s->num_timers = HPET_MIN_TIMERS; 769 } else if (s->num_timers > HPET_MAX_TIMERS) { 770 s->num_timers = HPET_MAX_TIMERS; 771 } 772 for (i = 0; i < HPET_MAX_TIMERS; i++) { 773 timer = &s->timer[i]; 774 timer->qemu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, hpet_timer, timer); 775 timer->tn = i; 776 timer->state = s; 777 } 778 779 /* 64-bit main counter; LegacyReplacementRoute. */ 780 s->capability = 0x8086a001ULL; 781 s->capability |= (s->num_timers - 1) << HPET_ID_NUM_TIM_SHIFT; 782 s->capability |= ((uint64_t)(HPET_CLK_PERIOD * FS_PER_NS) << 32); 783 784 qdev_init_gpio_in(dev, hpet_handle_legacy_irq, 2); 785 qdev_init_gpio_out(dev, &s->pit_enabled, 1); 786 } 787 788 static Property hpet_device_properties[] = { 789 DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS), 790 DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false), 791 DEFINE_PROP_UINT32(HPET_INTCAP, HPETState, intcap, 0), 792 DEFINE_PROP_BOOL("hpet-offset-saved", HPETState, hpet_offset_saved, true), 793 DEFINE_PROP_END_OF_LIST(), 794 }; 795 796 static void hpet_device_class_init(ObjectClass *klass, void *data) 797 { 798 DeviceClass *dc = DEVICE_CLASS(klass); 799 800 dc->realize = hpet_realize; 801 dc->reset = hpet_reset; 802 dc->vmsd = &vmstate_hpet; 803 device_class_set_props(dc, hpet_device_properties); 804 } 805 806 static const TypeInfo hpet_device_info = { 807 .name = TYPE_HPET, 808 .parent = TYPE_SYS_BUS_DEVICE, 809 .instance_size = sizeof(HPETState), 810 .instance_init = hpet_init, 811 .class_init = hpet_device_class_init, 812 }; 813 814 static void hpet_register_types(void) 815 { 816 type_register_static(&hpet_device_info); 817 } 818 819 type_init(hpet_register_types) 820