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