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