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