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