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