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