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