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