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