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