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