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