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