Changeset 37504 in vbox for trunk/src/VBox/Devices/PC
- Timestamp:
- Jun 16, 2011 4:36:24 PM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/PC/DevHPET.cpp
r37501 r37504 110 110 /** The version of the saved state. */ 111 111 #define HPET_SAVED_STATE_VERSION 2 112 113 112 /** Empty saved state */ 114 113 #define HPET_SAVED_STATE_VERSION_EMPTY 1 … … 217 216 218 217 /** If we emulate ICH9 HPET (different frequency). 219 * @todo different number of timers 220 uint8_tfIch9;218 * @todo different number of timers */ 219 bool fIch9; 221 220 uint8_t padding0[7]; 222 221 } HpetState; … … 248 247 } 249 248 250 DECLINLINE(uint64_t) hpetTicksToNs(HpetState *pThis, uint64_t value)249 DECLINLINE(uint64_t) hpetTicksToNs(HpetState *pThis, uint64_t value) 251 250 { 252 251 return (ASMMultU64ByU32DivByU32(value, (uint32_t)(pThis->u64Capabilities >> 32), FS_PER_NS)); 253 252 } 254 253 255 DECLINLINE(uint64_t) nsToHpetTicks(HpetState *pThis, uint64_t u64Value)254 DECLINLINE(uint64_t) nsToHpetTicks(HpetState const *pThis, uint64_t u64Value) 256 255 { 257 256 return (ASMMultU64ByU32DivByU32(u64Value, FS_PER_NS, (uint32_t)(pThis->u64Capabilities >> 32))); 258 257 } 259 258 260 DECLINLINE(uint64_t) hpetGetTicks(HpetState *pThis)259 DECLINLINE(uint64_t) hpetGetTicks(HpetState const *pThis) 261 260 { 262 261 /* … … 282 281 uint64_t u64Mask) 283 282 { 284 return (!(u64OldValue & u64Mask) && !!(u64NewValue & u64Mask)); 283 return !(u64OldValue & u64Mask) 284 && !!(u64NewValue & u64Mask); 285 285 } 286 286 … … 289 289 uint64_t u64Mask) 290 290 { 291 return (!!(u64OldValue & u64Mask) && !(u64NewValue & u64Mask)); 291 return !!(u64OldValue & u64Mask) 292 && !(u64NewValue & u64Mask); 292 293 } 293 294 … … 377 378 } 378 379 379 static uint32_t getTimerIrq(struct HpetTimer *pHpetTimer) 380 381 /** 382 * Reads a HPET timer register. 383 * 384 * @returns VBox strict status code. 385 * @param pThis The HPET instance. 386 * @param iTimerNo The timer index. 387 * @param iTimerReg The index of the timer register to read. 388 * @param pu32Value Where to return the register value. 389 * 390 * @remarks ASSUMES the caller does holds the HPET lock. 391 */ 392 static int hpetTimerRegRead32(HpetState const *pThis, uint32_t iTimerNo, uint32_t iTimerReg, uint32_t *pu32Value) 393 { 394 if (iTimerNo >= HPET_NUM_TIMERS) 395 { 396 static unsigned s_cOccurences = 0; 397 if (s_cOccurences++ < 10) 398 LogRel(("HPET: using timer above configured range: %d\n", iTimerNo)); 399 *pu32Value = 0; 400 return VINF_SUCCESS; 401 } 402 403 HpetTimer const *pHpetTimer = &pThis->aTimers[iTimerNo]; 404 uint32_t u32Value; 405 switch (iTimerReg) 406 { 407 case HPET_TN_CFG: 408 u32Value = (uint32_t)pHpetTimer->u64Config; 409 Log(("read HPET_TN_CFG on %d: %#x\n", iTimerNo, u32Value)); 410 break; 411 412 case HPET_TN_CFG + 4: 413 u32Value = (uint32_t)(pHpetTimer->u64Config >> 32); 414 Log(("read HPET_TN_CFG+4 on %d: %#x\n", iTimerNo, u32Value)); 415 break; 416 417 case HPET_TN_CMP: 418 u32Value = (uint32_t)pHpetTimer->u64Cmp; 419 Log(("read HPET_TN_CMP on %d: %#x (%#llx)\n", pHpetTimer->idxTimer, u32Value, pHpetTimer->u64Cmp)); 420 break; 421 422 case HPET_TN_CMP + 4: 423 u32Value = (uint32_t)(pHpetTimer->u64Cmp >> 32); 424 Log(("read HPET_TN_CMP+4 on %d: %#x (%#llx)\n", pHpetTimer->idxTimer, u32Value, pHpetTimer->u64Cmp)); 425 break; 426 427 case HPET_TN_ROUTE: 428 u32Value = (uint32_t)(pHpetTimer->u64Fsb >> 32); /** @todo Looks wrong, but since it's not supported, who cares. */ 429 Log(("read HPET_TN_ROUTE on %d: %#x\n", iTimerNo, u32Value)); 430 break; 431 432 default: 433 { 434 static unsigned s_cOccurences = 0; 435 if (s_cOccurences++ < 10) 436 LogRel(("invalid HPET register read %d on %d\n", iTimerReg, pHpetTimer->idxTimer)); 437 u32Value = 0; 438 break; 439 } 440 } 441 *pu32Value = u32Value; 442 return VINF_SUCCESS; 443 } 444 445 446 /** 447 * Read a 32-bit HPET register. 448 * 449 * @returns Strict VBox status code. 450 * @param pThis The HPET state. 451 * @param idxReg The register to read. 452 * @param pu32Value Where to return the register value. 453 */ 454 static int hpetConfigRegRead32(HpetState const *pThis, uint32_t idxReg, uint32_t *pu32Value) 455 { 456 uint32_t u32Value; 457 switch (idxReg) 458 { 459 case HPET_ID: 460 u32Value = (uint32_t)pThis->u64Capabilities; 461 Log(("read HPET_ID: %#x\n", u32Value)); 462 break; 463 464 case HPET_PERIOD: 465 u32Value = (uint32_t)(pThis->u64Capabilities >> 32); 466 Log(("read HPET_PERIOD: %#x\n", u32Value)); 467 break; 468 469 case HPET_CFG: 470 u32Value = (uint32_t)pThis->u64HpetConfig; 471 Log(("read HPET_CFG: %#x\n", u32Value)); 472 break; 473 474 case HPET_CFG + 4: 475 u32Value = (uint32_t)(pThis->u64HpetConfig >> 32); 476 Log(("read of HPET_CFG + 4: %#x\n", u32Value)); 477 break; 478 479 case HPET_COUNTER: 480 case HPET_COUNTER + 4: 481 { 482 uint64_t u64Ticks; 483 if (pThis->u64HpetConfig & HPET_CFG_ENABLE) 484 u64Ticks = hpetGetTicks(pThis); 485 else 486 u64Ticks = pThis->u64HpetCounter; 487 /** @todo is it correct? */ 488 u32Value = (idxReg == HPET_COUNTER) ? (uint32_t)u64Ticks : (uint32_t)(u64Ticks >> 32); 489 Log(("read HPET_COUNTER: %s part value %x (%#llx)\n", 490 (idxReg == HPET_COUNTER) ? "low" : "high", u32Value, u64Ticks)); 491 break; 492 } 493 494 case HPET_STATUS: 495 Log(("read HPET_STATUS\n")); 496 u32Value = (uint32_t)pThis->u64Isr; 497 break; 498 499 default: 500 Log(("invalid HPET register read: %x\n", idxReg)); 501 u32Value = 0; 502 break; 503 } 504 505 *pu32Value = u32Value; 506 return VINF_SUCCESS; 507 } 508 509 510 /** 511 * 32-bit write to a HPET timer register. 512 * 513 * @returns Strict VBox status code. 514 * 515 * @param pThis The HPET state. 516 * @param idxReg The register being written to. 517 * @param u32NewValue The value being written. 518 */ 519 static int hpetTimerRegWrite32(HpetState *pThis, uint32_t iTimerNo, uint32_t iTimerReg, uint32_t u32NewValue) 520 { 521 if (iTimerNo >= HPET_NUM_TIMERS) 522 { 523 LogRel(("HPET: using timer above configured range: %d\n", iTimerNo)); 524 return VINF_SUCCESS; 525 } 526 HpetTimer *pHpetTimer = &pThis->aTimers[iTimerNo]; 527 528 /** @todo iOldValue is only used by in HPET_TN_CFG, so this is a waste of 529 * time. */ 530 uint32_t u32Temp; 531 int rc = hpetTimerRegRead32(pThis, iTimerNo, iTimerReg, &u32Temp); 532 if (RT_FAILURE(rc)) 533 return rc; 534 uint64_t iOldValue = u32Temp; 535 536 switch (iTimerReg) 537 { 538 case HPET_TN_CFG: 539 { 540 Log(("write HPET_TN_CFG: %d: %x\n", iTimerNo, u32NewValue)); 541 542 uint64_t u64Mask = HPET_TN_CFG_WRITE_MASK; 543 if ((pHpetTimer->u64Config & HPET_TN_PERIODIC_CAP) != 0) 544 u64Mask |= HPET_TN_PERIODIC; 545 546 if ((pHpetTimer->u64Config & HPET_TN_SIZE_CAP) != 0) 547 u64Mask |= HPET_TN_32BIT; 548 else 549 u32NewValue &= ~HPET_TN_32BIT; 550 551 if ((u32NewValue & HPET_TN_32BIT) != 0) 552 { 553 Log(("setting timer %d to 32-bit mode\n", iTimerNo)); 554 pHpetTimer->u64Cmp = (uint32_t)pHpetTimer->u64Cmp; 555 pHpetTimer->u64Period = (uint32_t)pHpetTimer->u64Period; 556 } 557 if ((u32NewValue & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_LEVEL) 558 { 559 LogRel(("level-triggered config not yet supported\n")); 560 AssertFailed(); 561 } 562 563 /* We only care about lower 32-bits so far */ 564 pHpetTimer->u64Config = hpetUpdateMasked(u32NewValue, iOldValue, u64Mask); 565 break; 566 } 567 568 case HPET_TN_CFG + 4: /* Interrupt capabilities */ 569 { 570 Log(("write HPET_TN_CFG + 4, useless\n")); 571 break; 572 } 573 574 case HPET_TN_CMP: /* lower bits of comparator register */ 575 { 576 Log(("write HPET_TN_CMP on %d: %x\n", iTimerNo, u32NewValue)); 577 if (pHpetTimer->u64Config & HPET_TN_PERIODIC) 578 { 579 u32NewValue &= hpetInvalidValue(pHpetTimer) >> 1; 580 pHpetTimer->u64Period = (pHpetTimer->u64Period & UINT64_C(0xffffffff00000000)) 581 | u32NewValue; 582 } 583 584 pHpetTimer->u64Cmp = (pHpetTimer->u64Cmp & UINT64_C(0xffffffff00000000)) 585 | u32NewValue; 586 587 pHpetTimer->u64Config &= ~HPET_TN_SETVAL; 588 Log2(("after HPET_TN_CMP cmp=%llx per=%llx\n", pHpetTimer->u64Cmp, pHpetTimer->u64Period)); 589 590 if (pThis->u64HpetConfig & HPET_CFG_ENABLE) 591 hpetProgramTimer(pHpetTimer); 592 break; 593 } 594 595 case HPET_TN_CMP + 4: /* upper bits of comparator register */ 596 { 597 Log(("write HPET_TN_CMP + 4 on %d: %x\n", iTimerNo, u32NewValue)); 598 if (hpet32bitTimer(pHpetTimer)) 599 break; 600 601 if (pHpetTimer->u64Config & HPET_TN_PERIODIC) 602 pHpetTimer->u64Period = RT_MAKE_U64(pHpetTimer->u64Period, u32NewValue); 603 pHpetTimer->u64Cmp = RT_MAKE_U64(pHpetTimer->u64Cmp, u32NewValue); 604 605 Log2(("after HPET_TN_CMP+4 cmp=%llx per=%llx tmr=%d\n", pHpetTimer->u64Cmp, pHpetTimer->u64Period, iTimerNo)); 606 607 pHpetTimer->u64Config &= ~HPET_TN_SETVAL; 608 609 if (pThis->u64HpetConfig & HPET_CFG_ENABLE) 610 hpetProgramTimer(pHpetTimer); 611 break; 612 } 613 614 case HPET_TN_ROUTE: 615 { 616 Log(("write HPET_TN_ROUTE\n")); 617 break; 618 } 619 620 case HPET_TN_ROUTE + 4: 621 { 622 Log(("write HPET_TN_ROUTE + 4\n")); 623 break; 624 } 625 626 default: 627 { 628 LogRel(("invalid timer register write: %d\n", iTimerReg)); 629 AssertFailed(); 630 break; 631 } 632 } 633 634 return VINF_SUCCESS; 635 } 636 637 638 /** 639 * 32-bit write to a config register. 640 * 641 * @returns Strict VBox status code. 642 * 643 * @param pThis The HPET state. 644 * @param idxReg The register being written to. 645 * @param u32NewValue The value being written. 646 */ 647 static int hpetConfigRegWrite32(HpetState *pThis, uint32_t idxReg, uint32_t u32NewValue) 648 { 649 int rc = VINF_SUCCESS; 650 switch (idxReg) 651 { 652 case HPET_ID: 653 case HPET_ID + 4: 654 { 655 Log(("write HPET_ID, useless\n")); 656 break; 657 } 658 659 case HPET_CFG: 660 { 661 uint32_t const iOldValue = (uint32_t)(pThis->u64HpetConfig); 662 Log(("write HPET_CFG: %x (old %x)\n", u32NewValue, iOldValue)); 663 664 /* 665 * This check must be here, before actual update, as hpetLegacyMode 666 * may request retry in R3 - so we must keep state intact. 667 */ 668 if ( ((iOldValue ^ u32NewValue) & HPET_CFG_LEGACY) 669 && pThis->pHpetHlpR3 != NIL_RTR3PTR) 670 { 671 #ifdef IN_RING3 672 rc = pThis->pHpetHlpR3->pfnSetLegacyMode(pThis->pDevInsR3, RT_BOOL(u32NewValue & HPET_CFG_LEGACY)); 673 if (rc != VINF_SUCCESS) 674 break; 675 #else 676 rc = VINF_IOM_HC_MMIO_WRITE; 677 break; 678 #endif 679 } 680 681 pThis->u64HpetConfig = hpetUpdateMasked(u32NewValue, iOldValue, HPET_CFG_WRITE_MASK); 682 683 if (hpetBitJustSet(iOldValue, u32NewValue, HPET_CFG_ENABLE)) 684 { 685 /** @todo Only get the time stamp once when reprogramming? */ 686 /* Enable main counter and interrupt generation. */ 687 pThis->u64HpetOffset = hpetTicksToNs(pThis, pThis->u64HpetCounter) 688 - TMTimerGet(pThis->aTimers[0].CTX_SUFF(pTimer)); 689 for (uint32_t i = 0; i < HPET_NUM_TIMERS; i++) 690 if (pThis->aTimers[i].u64Cmp != hpetInvalidValue(&pThis->aTimers[i])) 691 hpetProgramTimer(&pThis->aTimers[i]); 692 } 693 else if (hpetBitJustCleared(iOldValue, u32NewValue, HPET_CFG_ENABLE)) 694 { 695 /* Halt main counter and disable interrupt generation. */ 696 pThis->u64HpetCounter = hpetGetTicks(pThis); 697 for (uint32_t i = 0; i < HPET_NUM_TIMERS; i++) 698 TMTimerStop(pThis->aTimers[i].CTX_SUFF(pTimer)); 699 } 700 break; 701 } 702 703 case HPET_CFG + 4: 704 { 705 /** @todo why do we let the guest write to the high bits but not 706 * read them? */ 707 pThis->u64HpetConfig = hpetUpdateMasked((uint64_t)u32NewValue << 32, 708 pThis->u64HpetConfig, 709 UINT64_C(0xffffffff00000000)); 710 Log(("write HPET_CFG + 4: %x -> %#llx\n", u32NewValue, pThis->u64HpetConfig)); 711 break; 712 } 713 714 case HPET_STATUS: 715 { 716 /* Clear ISR for all set bits in u32NewValue, see p. 14 of the HPET spec. */ 717 pThis->u64Isr &= ~((uint64_t)u32NewValue); 718 Log(("write HPET_STATUS: %x -> ISR=%#llx\n", u32NewValue, pThis->u64Isr)); 719 break; 720 } 721 722 case HPET_STATUS + 4: 723 { 724 Log(("write HPET_STATUS + 4: %x\n", u32NewValue)); 725 if (u32NewValue != 0) 726 { 727 static unsigned s_cOccurrences = 0; 728 if (s_cOccurrences++ < 10) 729 LogRel(("Writing HPET_STATUS + 4 with non-zero, ignored\n")); 730 } 731 break; 732 } 733 734 case HPET_COUNTER: 735 { 736 pThis->u64HpetCounter = RT_MAKE_U64(u32NewValue, pThis->u64HpetCounter); 737 Log(("write HPET_COUNTER: %#x -> %llx\n", u32NewValue, pThis->u64HpetCounter)); 738 break; 739 } 740 741 case HPET_COUNTER + 4: 742 { 743 pThis->u64HpetCounter = RT_MAKE_U64(pThis->u64HpetCounter, u32NewValue); 744 Log(("write HPET_COUNTER + 4: %#x -> %llx\n", u32NewValue, pThis->u64HpetCounter)); 745 break; 746 } 747 748 default: 749 LogRel(("invalid HPET config write: %x\n", idxReg)); 750 break; 751 } 752 753 return rc; 754 } 755 756 757 /* -=-=-=-=-=- MMIO callbacks -=-=-=-=-=- */ 758 759 760 /** 761 * @callback_method_impl{FNIOMMMIOREAD} 762 */ 763 PDMBOTHCBDECL(int) hpetMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb) 764 { 765 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState*); 766 uint32_t const idxReg = (uint32_t)(GCPhysAddr - HPET_BASE); 767 768 LogFlow(("hpetMMIORead (%d): %llx (%x)\n", cb, (uint64_t)GCPhysAddr, idxReg)); 769 DEVHPET_LOCK_RETURN(pThis, VINF_IOM_HC_MMIO_READ); 770 771 int rc = VINF_SUCCESS; 772 switch (cb) 773 { 774 case 4: 775 if (idxReg >= 0x100 && idxReg < 0x400) 776 rc = hpetTimerRegRead32(pThis, 777 (idxReg - 0x100) / 0x20, 778 (idxReg - 0x100) % 0x20, 779 (uint32_t *)pv); 780 else 781 rc = hpetConfigRegRead32(pThis, idxReg, (uint32_t *)pv); 782 break; 783 784 case 8: 785 { 786 /* Unaligned accesses not allowed */ 787 if (RT_UNLIKELY(idxReg % 8 != 0)) 788 { 789 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "idxReg=%#x cb=8\n", idxReg); 790 break; 791 } 792 793 /* Split the access except for timing sensitive registers. The 794 others assume the protection of the lock. */ 795 PRTUINT64U pValue = (PRTUINT64U)pv; 796 if (idxReg == HPET_COUNTER) 797 { 798 /* When reading HPET counter we must read it in a single read, 799 to avoid unexpected time jumps on 32-bit overflow. */ 800 pValue->u = (pThis->u64HpetConfig & HPET_CFG_ENABLE) != 0 801 ? hpetGetTicks(pThis) 802 : pThis->u64HpetCounter; 803 rc = VINF_SUCCESS; 804 } 805 else if (idxReg >= 0x100 && idxReg < 0x400) 806 { 807 uint32_t iTimer = (idxReg - 0x100) / 0x20; 808 uint32_t iTimerReg = (idxReg - 0x100) % 0x20; 809 rc = hpetTimerRegRead32(pThis, iTimer, iTimerReg, &pValue->s.Lo); 810 if (rc == VINF_SUCCESS) 811 rc = hpetTimerRegRead32(pThis, iTimer, iTimerReg + 4, &pValue->s.Hi); 812 } 813 else 814 { 815 /* for most 8-byte accesses we just split them, happens under lock anyway. */ 816 rc = hpetConfigRegRead32(pThis, idxReg, &pValue->s.Lo); 817 if (rc == VINF_SUCCESS) 818 rc = hpetConfigRegRead32(pThis, idxReg + 4, &pValue->s.Hi); 819 } 820 break; 821 } 822 823 case 1: 824 case 2: 825 Log(("Narrow read: %d\n", cb)); 826 rc = VINF_SUCCESS; 827 break; 828 829 default: 830 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */ 831 rc = VINF_SUCCESS; 832 } 833 834 DEVHPET_UNLOCK(pThis); 835 return rc; 836 } 837 838 839 /** 840 * @callback_method_impl{FNIOMMMIOWRITE} 841 */ 842 PDMBOTHCBDECL(int) hpetMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb) 843 { 844 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState*); 845 uint32_t idxReg = (uint32_t)(GCPhysAddr - HPET_BASE); 846 LogFlow(("hpetMMIOWrite: cb=%u reg=%03x (%RGp) val=%llx\n", 847 cb, idxReg, GCPhysAddr, cb == 4 ? *(uint32_t *)pv : cb == 8 ? *(uint64_t *)pv : 0xdeadbeef)); 848 849 DEVHPET_LOCK_RETURN(pThis, VINF_IOM_HC_MMIO_WRITE); 850 851 int rc; 852 switch (cb) 853 { 854 case 4: 855 if (idxReg >= 0x100 && idxReg < 0x400) 856 rc = hpetTimerRegWrite32(pThis, 857 (idxReg - 0x100) / 0x20, 858 (idxReg - 0x100) % 0x20, 859 *(uint32_t const *)pv); 860 else 861 rc = hpetConfigRegWrite32(pThis, idxReg, *(uint32_t const *)pv); 862 break; 863 864 case 8: 865 { 866 /* Unaligned accesses are not allowed. */ 867 if (RT_UNLIKELY(idxReg % 8 != 0)) 868 { 869 rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS, "idxReg=%#x cb=8\n", idxReg); 870 break; 871 } 872 873 /* Split the access and rely on the locking to prevent trouble. */ 874 RTUINT64U uValue; 875 uValue.u = *(uint64_t const *)pv; 876 if (idxReg >= 0x100 && idxReg < 0x400) 877 { 878 uint32_t iTimer = (idxReg - 0x100) / 0x20; 879 uint32_t iTimerReg = (idxReg - 0x100) % 0x20; 880 /** @todo Consider handling iTimerReg == HPET_TN_CMP specially here */ 881 rc = hpetTimerRegWrite32(pThis, iTimer, iTimerReg, uValue.s.Lo); 882 if (RT_LIKELY(rc == VINF_SUCCESS)) 883 rc = hpetTimerRegWrite32(pThis, iTimer, iTimerReg + 4, uValue.s.Hi); 884 } 885 else 886 { 887 rc = hpetConfigRegWrite32(pThis, idxReg, uValue.s.Lo); 888 if (RT_LIKELY(rc == VINF_SUCCESS)) 889 rc = hpetConfigRegWrite32(pThis, idxReg + 4, uValue.s.Hi); 890 } 891 break; 892 } 893 894 case 1: 895 case 2: 896 Log(("Narrow write: %d\n", cb)); 897 rc = VINF_SUCCESS; 898 break; 899 900 default: 901 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */ 902 rc = VERR_INTERNAL_ERROR; 903 break; 904 } 905 906 DEVHPET_UNLOCK(pThis); 907 return rc; 908 } 909 910 #ifdef IN_RING3 911 912 /* -=-=-=-=-=- Timer Callback Processing -=-=-=-=-=- */ 913 914 /** 915 * Gets the IRQ of an HPET timer. 916 * 917 * @returns IRQ number. 918 * @param pHpetTimer The HPET timer. 919 */ 920 static uint32_t hpetTimerCbGetIrq(struct HpetTimer const *pHpetTimer) 380 921 { 381 922 /* … … 394 935 } 395 936 396 static int hpetTimerRegRead32(HpetState *pThis, 397 uint32_t iTimerNo, 398 uint32_t iTimerReg, 399 uint32_t *pValue) 400 { 401 if (iTimerNo >= HPET_NUM_TIMERS) 402 { 403 LogRel(("HPET: using timer above configured range: %d\n", iTimerNo)); 404 return VINF_SUCCESS; 405 } 406 407 HpetTimer *pHpetTimer = &pThis->aTimers[iTimerNo]; 408 switch (iTimerReg) 409 { 410 case HPET_TN_CFG: 411 Log(("read HPET_TN_CFG on %d\n", pHpetTimer->idxTimer)); 412 *pValue = (uint32_t)(pHpetTimer->u64Config); 413 break; 414 case HPET_TN_CFG + 4: 415 Log(("read HPET_TN_CFG+4 on %d\n", pHpetTimer->idxTimer)); 416 *pValue = (uint32_t)(pHpetTimer->u64Config >> 32); 417 break; 418 case HPET_TN_CMP: 419 Log(("read HPET_TN_CMP on %d, cmp=%llx\n", pHpetTimer->idxTimer, pHpetTimer->u64Cmp)); 420 *pValue = (uint32_t)(pHpetTimer->u64Cmp); 421 break; 422 case HPET_TN_CMP + 4: 423 Log(("read HPET_TN_CMP+4 on %d, cmp=%llx\n", pHpetTimer->idxTimer, pHpetTimer->u64Cmp)); 424 *pValue = (uint32_t)(pHpetTimer->u64Cmp >> 32); 425 break; 426 case HPET_TN_ROUTE: 427 Log(("read HPET_TN_ROUTE on %d\n", pHpetTimer->idxTimer)); 428 *pValue = (uint32_t)(pHpetTimer->u64Fsb >> 32); 429 break; 430 default: 431 LogRel(("invalid HPET register read %d on %d\n", iTimerReg, pHpetTimer->idxTimer)); 432 *pValue = 0; 433 break; 434 } 435 436 return VINF_SUCCESS; 437 } 438 439 static int hpetConfigRegRead32(HpetState *pThis, 440 uint32_t iIndex, 441 uint32_t *pValue) 442 { 443 switch (iIndex) 444 { 445 case HPET_ID: 446 Log(("read HPET_ID\n")); 447 *pValue = (uint32_t)(pThis->u64Capabilities); 448 break; 449 case HPET_PERIOD: 450 Log(("read HPET_PERIOD\n")); 451 *pValue = (uint32_t)(pThis->u64Capabilities >> 32); 452 break; 453 case HPET_CFG: 454 Log(("read HPET_CFG\n")); 455 *pValue = (uint32_t)(pThis->u64HpetConfig); 456 break; 457 case HPET_CFG + 4: 458 Log(("read of HPET_CFG + 4\n")); 459 *pValue = (uint32_t)(pThis->u64HpetConfig >> 32); 460 break; 461 case HPET_COUNTER: 462 case HPET_COUNTER + 4: 463 { 464 uint64_t u64Ticks; 465 if (pThis->u64HpetConfig & HPET_CFG_ENABLE) 466 u64Ticks = hpetGetTicks(pThis); 467 else 468 u64Ticks = pThis->u64HpetCounter; 469 /** @todo: is it correct? */ 470 *pValue = (iIndex == HPET_COUNTER) ? (uint32_t)u64Ticks : (uint32_t)(u64Ticks >> 32); 471 Log(("read HPET_COUNTER: %s part value %x\n", (iIndex == HPET_COUNTER) ? "low" : "high", *pValue)); 472 break; 473 } 474 case HPET_STATUS: 475 Log(("read HPET_STATUS\n")); 476 *pValue = (uint32_t)(pThis->u64Isr); 477 break; 478 default: 479 Log(("invalid HPET register read: %x\n", iIndex)); 480 *pValue = 0; 481 break; 482 } 483 return VINF_SUCCESS; 484 } 485 486 static int hpetTimerRegWrite32(HpetState *pThis, 487 uint32_t iTimerNo, 488 uint32_t iTimerReg, 489 uint32_t iNewValue) 490 { 491 uint32_t u32Temp; 492 int rc; 493 494 if (iTimerNo >= HPET_NUM_TIMERS) 495 { 496 LogRel(("HPET: using timer above configured range: %d\n", iTimerNo)); 497 return VINF_SUCCESS; 498 } 499 500 HpetTimer *pHpetTimer = &pThis->aTimers[iTimerNo]; 501 rc = hpetTimerRegRead32(pThis, iTimerNo, iTimerReg, &u32Temp); 502 if (RT_FAILURE(rc)) 503 return rc; 504 uint64_t iOldValue = u32Temp; 505 506 switch (iTimerReg) 507 { 508 case HPET_TN_CFG: 509 { 510 uint64_t u64Mask = HPET_TN_CFG_WRITE_MASK; 511 512 Log(("write HPET_TN_CFG: %d: %x\n", iTimerNo, iNewValue)); 513 514 if ((pHpetTimer->u64Config & HPET_TN_PERIODIC_CAP) != 0) 515 u64Mask |= HPET_TN_PERIODIC; 516 517 if ((pHpetTimer->u64Config & HPET_TN_SIZE_CAP) != 0) 518 u64Mask |= HPET_TN_32BIT; 519 else 520 iNewValue &= ~HPET_TN_32BIT; 521 522 if ((iNewValue & HPET_TN_32BIT) != 0) 523 { 524 Log(("setting timer %d to 32-bit mode\n", iTimerNo)); 525 pHpetTimer->u64Cmp = (uint32_t)pHpetTimer->u64Cmp; 526 pHpetTimer->u64Period = (uint32_t)pHpetTimer->u64Period; 527 } 528 if ((iNewValue & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_LEVEL) 529 { 530 LogRel(("level-triggered config not yet supported\n")); 531 AssertFailed(); 532 } 533 /* We only care about lower 32-bits so far */ 534 pHpetTimer->u64Config = hpetUpdateMasked(iNewValue, iOldValue, u64Mask); 535 break; 536 } 537 538 case HPET_TN_CFG + 4: /* Interrupt capabilities */ 539 { 540 Log(("write HPET_TN_CFG + 4, useless\n")); 541 break; 542 } 543 544 case HPET_TN_CMP: /* lower bits of comparator register */ 545 { 546 Log(("write HPET_TN_CMP on %d: %x\n", iTimerNo, iNewValue)); 547 if (pHpetTimer->u64Config & HPET_TN_PERIODIC) 548 { 549 iNewValue &= hpetInvalidValue(pHpetTimer) >> 1; 550 pHpetTimer->u64Period = (pHpetTimer->u64Period & UINT64_C(0xffffffff00000000)) 551 | iNewValue; 552 } 553 554 pHpetTimer->u64Cmp = (pHpetTimer->u64Cmp & UINT64_C(0xffffffff00000000)) 555 | iNewValue; 556 557 pHpetTimer->u64Config &= ~HPET_TN_SETVAL; 558 Log2(("after HPET_TN_CMP cmp=%llx per=%llx\n", pHpetTimer->u64Cmp, pHpetTimer->u64Period)); 559 560 if (pThis->u64HpetConfig & HPET_CFG_ENABLE) 561 hpetProgramTimer(pHpetTimer); 562 break; 563 } 564 565 case HPET_TN_CMP + 4: /* upper bits of comparator register */ 566 { 567 Log(("write HPET_TN_CMP + 4 on %d: %x\n", iTimerNo, iNewValue)); 568 if (hpet32bitTimer(pHpetTimer)) 569 break; 570 571 if (pHpetTimer->u64Config & HPET_TN_PERIODIC) 572 pHpetTimer->u64Period = (pHpetTimer->u64Period & UINT64_C(0xffffffff)) 573 | ((uint64_t)iNewValue << 32); 574 575 pHpetTimer->u64Cmp = (pHpetTimer->u64Cmp & UINT64_C(0xffffffff)) 576 | ((uint64_t)iNewValue << 32); 577 578 Log2(("after HPET_TN_CMP+4 cmp=%llx per=%llx\n", pHpetTimer->u64Cmp, pHpetTimer->u64Period)); 579 580 pHpetTimer->u64Config &= ~HPET_TN_SETVAL; 581 582 if (pThis->u64HpetConfig & HPET_CFG_ENABLE) 583 hpetProgramTimer(pHpetTimer); 584 break; 585 } 586 587 case HPET_TN_ROUTE: 588 { 589 Log(("write HPET_TN_ROUTE\n")); 590 break; 591 } 592 593 case HPET_TN_ROUTE + 4: 594 { 595 Log(("write HPET_TN_ROUTE + 4\n")); 596 break; 597 } 598 599 default: 600 { 601 LogRel(("invalid timer register write: %d\n", iTimerReg)); 602 AssertFailed(); 603 break; 604 } 605 } 606 607 return VINF_SUCCESS; 608 } 609 610 static int hpetLegacyMode(HpetState* pThis, 611 bool fActivate) 612 { 613 int rc = VINF_SUCCESS; 614 #ifndef IN_RING3 615 /* Don't do anything complicated outside of R3 */ 616 rc = VINF_IOM_HC_MMIO_WRITE; 617 #else /* IN_RING3 */ 618 if (pThis->pHpetHlpR3) 619 rc = pThis->pHpetHlpR3->pfnSetLegacyMode(pThis->pDevInsR3, fActivate); 620 #endif 621 return rc; 622 } 623 624 static int hpetConfigRegWrite32(HpetState* pThis, 625 uint32_t iIndex, 626 uint32_t iNewValue) 627 { 628 int rc = VINF_SUCCESS; 629 630 switch (iIndex) 631 { 632 case HPET_ID: 633 case HPET_ID + 4: 634 { 635 Log(("write HPET_ID, useless\n")); 636 break; 637 } 638 639 case HPET_CFG: 640 { 641 uint32_t const iOldValue = (uint32_t)(pThis->u64HpetConfig); 642 Log(("write HPET_CFG: %x (old %x)\n", iNewValue, iOldValue)); 643 644 /* 645 * This check must be here, before actual update, as hpetLegacyMode 646 * may request retry in R3 - so we must keep state intact. 647 */ 648 if (hpetBitJustSet(iOldValue, iNewValue, HPET_CFG_LEGACY)) 649 rc = hpetLegacyMode(pThis, true); 650 else if (hpetBitJustCleared(iOldValue, iNewValue, HPET_CFG_LEGACY)) 651 rc = hpetLegacyMode(pThis, false); 652 if (rc != VINF_SUCCESS) 653 return rc; 654 655 pThis->u64HpetConfig = hpetUpdateMasked(iNewValue, iOldValue, HPET_CFG_WRITE_MASK); 656 if (hpetBitJustSet(iOldValue, iNewValue, HPET_CFG_ENABLE)) 657 { 658 /* Enable main counter and interrupt generation. */ 659 pThis->u64HpetOffset = hpetTicksToNs(pThis, pThis->u64HpetCounter) 660 - TMTimerGet(pThis->aTimers[0].CTX_SUFF(pTimer)); 661 for (uint32_t i = 0; i < HPET_NUM_TIMERS; i++) 662 if (pThis->aTimers[i].u64Cmp != hpetInvalidValue(&pThis->aTimers[i])) 663 hpetProgramTimer(&pThis->aTimers[i]); 664 } 665 else if (hpetBitJustCleared(iOldValue, iNewValue, HPET_CFG_ENABLE)) 666 { 667 /* Halt main counter and disable interrupt generation. */ 668 pThis->u64HpetCounter = hpetGetTicks(pThis); 669 for (uint32_t i = 0; i < HPET_NUM_TIMERS; i++) 670 TMTimerStop(pThis->aTimers[i].CTX_SUFF(pTimer)); 671 } 672 break; 673 } 674 675 case HPET_CFG + 4: 676 { 677 Log(("write HPET_CFG + 4: %x\n", iNewValue)); 678 pThis->u64HpetConfig = hpetUpdateMasked((uint64_t)iNewValue << 32, 679 pThis->u64HpetConfig, 680 UINT64_C(0xffffffff00000000)); 681 break; 682 } 683 684 case HPET_STATUS: 685 { 686 Log(("write HPET_STATUS: %x\n", iNewValue)); 687 // clear ISR for all set bits in iNewValue, see p. 14 of HPET spec 688 pThis->u64Isr &= ~((uint64_t)iNewValue); 689 break; 690 } 691 692 case HPET_STATUS + 4: 693 { 694 Log(("write HPET_STATUS + 4: %x\n", iNewValue)); 695 if (iNewValue != 0) 696 LogRel(("Writing HPET_STATUS + 4 with non-zero, ignored\n")); 697 break; 698 } 699 700 case HPET_COUNTER: 701 { 702 pThis->u64HpetCounter = (pThis->u64HpetCounter & UINT64_C(0xffffffff00000000)) | iNewValue; 703 Log(("write HPET_COUNTER: %#x -> %llx\n", 704 iNewValue, pThis->u64HpetCounter)); 705 break; 706 } 707 708 case HPET_COUNTER + 4: 709 { 710 pThis->u64HpetCounter = (pThis->u64HpetCounter & UINT64_C(0xffffffff)) 711 | (((uint64_t)iNewValue) << 32); 712 Log(("write HPET_COUNTER + 4: %#x -> %llx\n", 713 iNewValue, pThis->u64HpetCounter)); 714 break; 715 } 716 717 default: 718 LogRel(("invalid HPET config write: %x\n", iIndex)); 719 break; 720 } 721 722 return rc; 723 } 724 725 PDMBOTHCBDECL(int) hpetMMIORead(PPDMDEVINS pDevIns, 726 void * pvUser, 727 RTGCPHYS GCPhysAddr, 728 void * pv, 729 unsigned cb) 730 { 731 HpetState * pThis = PDMINS_2_DATA(pDevIns, HpetState*); 732 int rc = VINF_SUCCESS; 733 uint32_t iIndex = (uint32_t)(GCPhysAddr - HPET_BASE); 734 735 LogFlow(("hpetMMIORead (%d): %llx (%x)\n", cb, (uint64_t)GCPhysAddr, iIndex)); 736 DEVHPET_LOCK_RETURN(pThis, VINF_IOM_HC_MMIO_READ); 737 738 switch (cb) 739 { 740 case 1: 741 case 2: 742 Log(("Narrow read: %d\n", cb)); 743 rc = VINF_SUCCESS; 744 break; 745 case 4: 746 { 747 if (iIndex >= 0x100 && iIndex < 0x400) 748 rc = hpetTimerRegRead32(pThis, (iIndex - 0x100) / 0x20, (iIndex - 0x100) % 0x20, (uint32_t*)pv); 749 else 750 rc = hpetConfigRegRead32(pThis, iIndex, (uint32_t*)pv); 751 break; 752 } 753 case 8: 754 { 755 union 756 { 757 uint32_t u32[2]; 758 uint64_t u64; 759 } value; 760 761 /* Unaligned accesses not allowed */ 762 if (iIndex % 8 != 0) 763 { 764 AssertMsgFailed(("Unaligned HPET read access\n")); 765 rc = VINF_SUCCESS; 766 break; 767 } 768 if (iIndex >= 0x100 && iIndex < 0x400) 769 { 770 uint32_t iTimer = (iIndex - 0x100) / 0x20; 771 uint32_t iTimerReg = (iIndex - 0x100) % 0x20; 772 773 /* for most 8-byte accesses we just split them, happens under lock anyway. */ 774 rc = hpetTimerRegRead32(pThis, iTimer, iTimerReg, &value.u32[0]); 775 if (RT_UNLIKELY(rc != VINF_SUCCESS)) 776 break; 777 rc = hpetTimerRegRead32(pThis, iTimer, iTimerReg + 4, &value.u32[1]); 778 } 779 else 780 { 781 if (iIndex == HPET_COUNTER) 782 { 783 /* When reading HPET counter we must read it in a single read, 784 to avoid unexpected time jumps on 32-bit overflow. */ 785 value.u64 = (pThis->u64HpetConfig & HPET_CFG_ENABLE) != 0 786 ? hpetGetTicks(pThis) 787 : pThis->u64HpetCounter; 788 rc = VINF_SUCCESS; 789 } 790 else 791 { 792 /* for most 8-byte accesses we just split them, happens under lock anyway. */ 793 794 rc = hpetConfigRegRead32(pThis, iIndex, &value.u32[0]); 795 if (RT_UNLIKELY(rc != VINF_SUCCESS)) 796 break; 797 rc = hpetConfigRegRead32(pThis, iIndex+4, &value.u32[1]); 798 } 799 } 800 if (rc == VINF_SUCCESS) 801 *(uint64_t*)pv = value.u64; 802 break; 803 } 804 805 default: 806 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */ 807 rc = VINF_SUCCESS; 808 } 809 810 DEVHPET_UNLOCK(pThis); 811 return rc; 812 } 813 814 PDMBOTHCBDECL(int) hpetMMIOWrite(PPDMDEVINS pDevIns, 815 void * pvUser, 816 RTGCPHYS GCPhysAddr, 817 void * pv, 818 unsigned cb) 819 { 820 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState*); 821 uint32_t iIndex = (uint32_t)(GCPhysAddr - HPET_BASE); 822 int rc = VINF_SUCCESS; 823 824 LogFlow(("hpetMMIOWrite (%d): %llx (%x) <- %x\n", 825 cb, (uint64_t)GCPhysAddr, iIndex, cb >= 4 ? *(uint32_t*)pv : 0xdeadbeef)); 826 827 DEVHPET_LOCK_RETURN(pThis, VINF_IOM_HC_MMIO_WRITE); 828 829 switch (cb) 830 { 831 case 1: 832 case 2: 833 Log(("Narrow write: %d\n", cb)); 834 rc = VINF_SUCCESS; 835 break; 836 case 4: 837 { 838 if (iIndex >= 0x100 && iIndex < 0x400) 839 rc = hpetTimerRegWrite32(pThis, 840 (iIndex - 0x100) / 0x20, 841 (iIndex - 0x100) % 0x20, 842 *(uint32_t*)pv); 843 else 844 rc = hpetConfigRegWrite32(pThis, iIndex, *(uint32_t*)pv); 845 break; 846 } 847 848 case 8: 849 { 850 /* Unaligned accesses not allowed */ 851 if (iIndex % 8 != 0) 852 { 853 AssertMsgFailed(("Unaligned HPET write access\n")); 854 rc = VINF_SUCCESS; 855 break; 856 } 857 858 859 // for 8-byte accesses we just split them, happens under lock anyway 860 union 861 { 862 uint32_t u32[2]; 863 uint64_t u64; 864 } value; 865 value.u64 = *(uint64_t*)pv; 866 if (iIndex >= 0x100 && iIndex < 0x400) 867 { 868 uint32_t iTimer = (iIndex - 0x100) / 0x20; 869 uint32_t iTimerReg = (iIndex - 0x100) % 0x20; 870 871 rc = hpetTimerRegWrite32(pThis, iTimer, iTimerReg, value.u32[0]); 872 if (RT_LIKELY(rc == VINF_SUCCESS)) 873 rc = hpetTimerRegWrite32(pThis, iTimer, iTimerReg + 4, value.u32[1]); 874 } 875 else 876 { 877 rc = hpetConfigRegWrite32(pThis, iIndex, value.u32[0]); 878 if (RT_LIKELY(rc == VINF_SUCCESS)) 879 rc = hpetConfigRegWrite32(pThis, iIndex+4, value.u32[1]); 880 } 881 break; 882 } 883 884 default: 885 AssertReleaseMsgFailed(("cb=%d\n", cb)); /* for now we assume simple accesses. */ 886 rc = VERR_INTERNAL_ERROR; 887 break; 888 } 889 890 DEVHPET_UNLOCK(pThis); 891 return rc; 892 } 893 894 #ifdef IN_RING3 895 896 /** @todo move the saved state stuff down before the timer. */ 897 898 static int hpetSaveTimer(HpetTimer *pHpetTimer, PSSMHANDLE pSSM) 899 { 900 TMR3TimerSave(pHpetTimer->pTimerR3, pSSM); 901 SSMR3PutU8(pSSM, pHpetTimer->u8Wrap); 902 SSMR3PutU64(pSSM, pHpetTimer->u64Config); 903 SSMR3PutU64(pSSM, pHpetTimer->u64Cmp); 904 SSMR3PutU64(pSSM, pHpetTimer->u64Fsb); 905 return SSMR3PutU64(pSSM, pHpetTimer->u64Period); 906 } 907 908 static int hpetLoadTimer(HpetTimer *pHpetTimer, PSSMHANDLE pSSM) 909 { 910 TMR3TimerLoad(pHpetTimer->pTimerR3, pSSM); 911 SSMR3GetU8(pSSM, &pHpetTimer->u8Wrap); 912 SSMR3GetU64(pSSM, &pHpetTimer->u64Config); 913 SSMR3GetU64(pSSM, &pHpetTimer->u64Cmp); 914 SSMR3GetU64(pSSM, &pHpetTimer->u64Fsb); 915 return SSMR3GetU64(pSSM, &pHpetTimer->u64Period); 916 } 917 918 /** 919 * @copydoc FNSSMDEVLIVEEXEC 920 */ 921 static DECLCALLBACK(int) hpetLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass) 922 { 923 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *); 924 925 SSMR3PutU8(pSSM, HPET_NUM_TIMERS); 926 927 return VINF_SSM_DONT_CALL_AGAIN; 928 } 929 930 /** 931 * Saves a state of the HPET device. 937 938 /** 939 * Used by hpetTimerCb to update the IRQ status. 932 940 * 933 * @returns VBox status code. 934 * @param pDevIns The device instance. 935 * @param pSSMHandle The handle to save the state to. 936 */ 937 static DECLCALLBACK(int) hpetSaveExec(PPDMDEVINS pDevIns, 938 PSSMHANDLE pSSM) 939 { 940 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *); 941 uint32_t iTimer; 942 int rc; 943 944 /* The config. */ 945 hpetLiveExec(pDevIns, pSSM, SSM_PASS_FINAL); 946 947 for (iTimer = 0; iTimer < HPET_NUM_TIMERS; iTimer++) 948 { 949 rc = hpetSaveTimer(&pThis->aTimers[iTimer], pSSM); 950 AssertRCReturn(rc, rc); 951 } 952 953 SSMR3PutU64(pSSM, pThis->u64HpetOffset); 954 SSMR3PutU64(pSSM, pThis->u64Capabilities); 955 SSMR3PutU64(pSSM, pThis->u64HpetConfig); 956 SSMR3PutU64(pSSM, pThis->u64Isr); 957 SSMR3PutU64(pSSM, pThis->u64HpetCounter); 958 959 return VINF_SUCCESS; 960 } 961 962 /** 963 * Loads a HPET device state. 964 * 965 * @returns VBox status code. 966 * @param pDevIns The device instance. 967 * @param pSSMHandle The handle to the saved state. 968 * @param uVersion The data unit version number. 969 * @param uPass The data pass. 970 */ 971 static DECLCALLBACK(int) hpetLoadExec(PPDMDEVINS pDevIns, 972 PSSMHANDLE pSSM, 973 uint32_t uVersion, 974 uint32_t uPass) 975 { 976 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *); 977 978 if (uVersion == HPET_SAVED_STATE_VERSION_EMPTY) 979 return VINF_SUCCESS; 980 981 if (uVersion != HPET_SAVED_STATE_VERSION) 982 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION; 983 984 uint8_t u8NumTimers; 985 986 int rc = SSMR3GetU8(pSSM, &u8NumTimers); 987 AssertRCReturn(rc, rc); 988 if (u8NumTimers != HPET_NUM_TIMERS) 989 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - wrong number of timers: saved=%#x config=%#x"), u8NumTimers, HPET_NUM_TIMERS); 990 991 if (uPass != SSM_PASS_FINAL) 992 return VINF_SUCCESS; 993 994 for (uint32_t iTimer = 0; iTimer < HPET_NUM_TIMERS; iTimer++) 995 { 996 rc = hpetLoadTimer(&pThis->aTimers[iTimer], pSSM); 997 AssertRCReturn(rc, rc); 998 } 999 1000 SSMR3GetU64(pSSM, &pThis->u64HpetOffset); 1001 SSMR3GetU64(pSSM, &pThis->u64Capabilities); 1002 SSMR3GetU64(pSSM, &pThis->u64HpetConfig); 1003 SSMR3GetU64(pSSM, &pThis->u64Isr); 1004 SSMR3GetU64(pSSM, &pThis->u64HpetCounter); 1005 1006 return VINF_SUCCESS; 1007 } 1008 1009 static void hpetIrqUpdate(struct HpetTimer *pHpetTimer) 1010 { 1011 uint32_t irq = getTimerIrq(pHpetTimer); 1012 HpetState *pThis = pHpetTimer->CTX_SUFF(pHpet); 1013 941 * @param pThis The HPET device state. 942 * @param pHpetTimer The HPET timer. 943 */ 944 static void hpetTimerCbUpdateIrq(HpetState *pThis, struct HpetTimer *pHpetTimer) 945 { 1014 946 /** @todo: is it correct? */ 1015 947 if ( !!(pHpetTimer->u64Config & HPET_TN_ENABLE) 1016 948 && !!(pThis->u64HpetConfig & HPET_CFG_ENABLE)) 1017 949 { 950 uint32_t irq = hpetTimerCbGetIrq(pHpetTimer); 1018 951 Log4(("HPET: raising IRQ %d\n", irq)); 1019 952 1020 /* ISR bits are only set in level-triggered mode */953 /* ISR bits are only set in level-triggered mode. */ 1021 954 if ((pHpetTimer->u64Config & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_LEVEL) 1022 955 pThis->u64Isr |= (uint64_t)(1 << pHpetTimer->idxTimer); 1023 956 1024 /* We trigger flip/flop in edge-triggered mode and do nothing in level-triggered mode yet */ 957 /* We trigger flip/flop in edge-triggered mode and do nothing in 958 level-triggered mode yet. */ 1025 959 if ((pHpetTimer->u64Config & HPET_TN_INT_TYPE) == HPET_TIMER_TYPE_EDGE) 1026 960 pThis->pHpetHlpR3->pfnSetIrq(pThis->CTX_SUFF(pDevIns), irq, PDM_IRQ_LEVEL_FLIP_FLOP); 1027 961 else 1028 962 AssertFailed(); 1029 /* @todo: implement IRQs in level-triggered mode */963 /** @todo: implement IRQs in level-triggered mode */ 1030 964 } 1031 965 } … … 1038 972 * @param pvUser Pointer to the HPET timer state. 1039 973 */ 1040 static DECLCALLBACK(void) hpetTimer (PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)974 static DECLCALLBACK(void) hpetTimerCb(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser) 1041 975 { 1042 976 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *); … … 1071 1005 1072 1006 /* Should it really be under lock, does it really matter? */ 1073 hpet IrqUpdate(pHpetTimer);1007 hpetTimerCbUpdateIrq(pThis, pHpetTimer); 1074 1008 1075 1009 PDMCritSectLeave(&pThis->csLock); 1076 1010 } 1077 1011 1078 /** 1079 * Relocation notification. 1080 * 1081 * @returns VBox status. 1082 * @param pDevIns The device instance data. 1083 * @param offDelta The delta relative to the old address. 1012 1013 /* -=-=-=-=-=- DBGF Info Handlers -=-=-=-=-=- */ 1014 1015 1016 /** 1017 * @callback_method_impl{FNDBGFHANDLERDEV} 1018 */ 1019 static DECLCALLBACK(void) hpetInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) 1020 { 1021 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *); 1022 1023 pHlp->pfnPrintf(pHlp, 1024 "HPET status:\n" 1025 " config = %016RX64\n" 1026 " offset = %016RX64 counter = %016RX64 isr = %016RX64\n" 1027 " legacy mode is %s\n", 1028 pThis->u64HpetConfig, 1029 pThis->u64HpetOffset, pThis->u64HpetCounter, pThis->u64Isr, 1030 !!(pThis->u64HpetConfig & HPET_CFG_LEGACY) ? "on" : "off"); 1031 pHlp->pfnPrintf(pHlp, 1032 "Timers:\n"); 1033 for (unsigned i = 0; i < HPET_NUM_TIMERS; i++) 1034 { 1035 pHlp->pfnPrintf(pHlp, " %d: comparator=%016RX64 period(hidden)=%016RX64 cfg=%016RX64\n", 1036 pThis->aTimers[i].idxTimer, 1037 pThis->aTimers[i].u64Cmp, 1038 pThis->aTimers[i].u64Period, 1039 pThis->aTimers[i].u64Config); 1040 } 1041 } 1042 1043 1044 /* -=-=-=-=-=- Saved State -=-=-=-=-=- */ 1045 1046 1047 /** 1048 * @callback_method_impl{FNSSMDEVLIVEEXEC} 1049 */ 1050 static DECLCALLBACK(int) hpetLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass) 1051 { 1052 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *); 1053 1054 SSMR3PutU8(pSSM, HPET_NUM_TIMERS); 1055 1056 return VINF_SSM_DONT_CALL_AGAIN; 1057 } 1058 1059 1060 /** 1061 * @callback_method_impl{FNSSMDEVSAVEEXEC} 1062 */ 1063 static DECLCALLBACK(int) hpetSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) 1064 { 1065 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *); 1066 1067 /* 1068 * The config. 1069 */ 1070 hpetLiveExec(pDevIns, pSSM, SSM_PASS_FINAL); 1071 1072 /* 1073 * The state. 1074 */ 1075 for (uint32_t iTimer = 0; iTimer < HPET_NUM_TIMERS; iTimer++) 1076 { 1077 HpetTimer *pHpetTimer = &pThis->aTimers[iTimer]; 1078 TMR3TimerSave(pHpetTimer->pTimerR3, pSSM); 1079 SSMR3PutU8(pSSM, pHpetTimer->u8Wrap); 1080 SSMR3PutU64(pSSM, pHpetTimer->u64Config); 1081 SSMR3PutU64(pSSM, pHpetTimer->u64Cmp); 1082 SSMR3PutU64(pSSM, pHpetTimer->u64Fsb); 1083 SSMR3PutU64(pSSM, pHpetTimer->u64Period); 1084 } 1085 1086 SSMR3PutU64(pSSM, pThis->u64HpetOffset); 1087 SSMR3PutU64(pSSM, pThis->u64Capabilities); 1088 SSMR3PutU64(pSSM, pThis->u64HpetConfig); 1089 SSMR3PutU64(pSSM, pThis->u64Isr); 1090 return SSMR3PutU64(pSSM, pThis->u64HpetCounter); 1091 } 1092 1093 1094 /** 1095 * @callback_method_impl{FNSSMDEVLOADEXEC} 1096 */ 1097 static DECLCALLBACK(int) hpetLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass) 1098 { 1099 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *); 1100 1101 /* 1102 * Version checks. 1103 */ 1104 if (uVersion == HPET_SAVED_STATE_VERSION_EMPTY) 1105 return VINF_SUCCESS; 1106 if (uVersion != HPET_SAVED_STATE_VERSION) 1107 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION; 1108 1109 /* 1110 * The config. 1111 */ 1112 uint8_t cTimers; 1113 int rc = SSMR3GetU8(pSSM, &cTimers); 1114 AssertRCReturn(rc, rc); 1115 if (cTimers != HPET_NUM_TIMERS) 1116 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - wrong number of timers: saved=%#x config=%#x"), 1117 cTimers, HPET_NUM_TIMERS); 1118 1119 if (uPass != SSM_PASS_FINAL) 1120 return VINF_SUCCESS; 1121 1122 /* 1123 * The state. 1124 */ 1125 for (uint32_t iTimer = 0; iTimer < HPET_NUM_TIMERS; iTimer++) 1126 { 1127 HpetTimer *pHpetTimer = &pThis->aTimers[iTimer]; 1128 TMR3TimerLoad(pHpetTimer->pTimerR3, pSSM); 1129 SSMR3GetU8(pSSM, &pHpetTimer->u8Wrap); 1130 SSMR3GetU64(pSSM, &pHpetTimer->u64Config); 1131 SSMR3GetU64(pSSM, &pHpetTimer->u64Cmp); 1132 SSMR3GetU64(pSSM, &pHpetTimer->u64Fsb); 1133 SSMR3GetU64(pSSM, &pHpetTimer->u64Period); 1134 } 1135 1136 SSMR3GetU64(pSSM, &pThis->u64HpetOffset); 1137 SSMR3GetU64(pSSM, &pThis->u64Capabilities); 1138 SSMR3GetU64(pSSM, &pThis->u64HpetConfig); 1139 SSMR3GetU64(pSSM, &pThis->u64Isr); 1140 return SSMR3GetU64(pSSM, &pThis->u64HpetCounter); 1141 } 1142 1143 1144 /* -=-=-=-=-=- PDMDEVREG -=-=-=-=-=- */ 1145 1146 1147 /** 1148 * @interface_method_impl{PDMDEVREG,pfnRelocate} 1084 1149 */ 1085 1150 static DECLCALLBACK(void) hpetRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta) … … 1100 1165 } 1101 1166 1102 /** 1103 * Reset notification. 1104 * 1105 * @returns VBox status. 1106 * @param pDevIns The device instance data. 1167 1168 /** 1169 * @interface_method_impl{PDMDEVREG,pfnReset} 1107 1170 */ 1108 1171 static DECLCALLBACK(void) hpetReset(PPDMDEVINS pDevIns) … … 1131 1194 pHpetTimer->u8Wrap = 0; 1132 1195 pHpetTimer->u64Cmp = hpetInvalidValue(pHpetTimer); 1196 /** @todo shouldn't we stop any active timers at this point? */ 1133 1197 } 1134 1198 pThis->u64HpetCounter = 0; … … 1148 1212 1149 1213 /* Notify PIT/RTC devices */ 1150 hpetLegacyMode(pThis, false); 1151 } 1152 1153 /** 1154 * Info handler, device version. 1155 * 1156 * @param pDevIns Device instance which registered the info. 1157 * @param pHlp Callback functions for doing output. 1158 * @param pszArgs Argument string. Optional and specific to the handler. 1159 */ 1160 static DECLCALLBACK(void) hpetInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) 1161 { 1162 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *); 1163 1164 pHlp->pfnPrintf(pHlp, 1165 "HPET status:\n" 1166 " config = %016RX64\n" 1167 " offset = %016RX64 counter = %016RX64 isr = %016RX64\n" 1168 " legacy mode is %s\n", 1169 pThis->u64HpetConfig, 1170 pThis->u64HpetOffset, pThis->u64HpetCounter, pThis->u64Isr, 1171 !!(pThis->u64HpetConfig & HPET_CFG_LEGACY) ? "on" : "off"); 1172 pHlp->pfnPrintf(pHlp, 1173 "Timers:\n"); 1174 for (unsigned i = 0; i < HPET_NUM_TIMERS; i++) 1175 { 1176 pHlp->pfnPrintf(pHlp, " %d: comparator=%016RX64 period(hidden)=%016RX64 cfg=%016RX64\n", 1177 pThis->aTimers[i].idxTimer, 1178 pThis->aTimers[i].u64Cmp, 1179 pThis->aTimers[i].u64Period, 1180 pThis->aTimers[i].u64Config); 1181 } 1214 if (pThis->pHpetHlpR3) 1215 pThis->pHpetHlpR3->pfnSetLegacyMode(pDevIns, false /*fActive*/); 1182 1216 } 1183 1217 … … 1188 1222 static DECLCALLBACK(int) hpetConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) 1189 1223 { 1224 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); 1190 1225 HpetState *pThis = PDMINS_2_DATA(pDevIns, HpetState *); 1191 int rc;1192 1226 1193 1227 /* Only one HPET device now, as we use fixed MMIO region. */ … … 1195 1229 1196 1230 /* 1197 * Validate configuration.1231 * Validate and read the configuration. 1198 1232 */ 1199 if (!CFGMR3AreValuesValid(pCfg, 1200 "GCEnabled\0" 1201 "R0Enabled\0" 1202 "ICH9\0")) 1203 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES; 1204 1205 /* Query configuration. */ 1233 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "GCEnabled|R0Enabled|ICH9", ""); 1234 1206 1235 bool fRCEnabled; 1207 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fRCEnabled, true);1236 int rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fRCEnabled, true); 1208 1237 if (RT_FAILURE(rc)) 1209 1238 return PDMDEV_SET_ERROR(pDevIns, rc, … … 1216 1245 N_("Configuration error: failed to read R0Enabled as boolean")); 1217 1246 1218 bool fIch9; 1219 rc = CFGMR3QueryBoolDef(pCfg, "ICH9", &fIch9, false); 1247 rc = CFGMR3QueryBoolDef(pCfg, "ICH9", &pThis->fIch9, false); 1220 1248 if (RT_FAILURE(rc)) 1221 1249 return PDMDEV_SET_ERROR(pDevIns, rc, … … 1228 1256 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns); 1229 1257 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); 1230 pThis->fIch9 = (uint8_t)fIch9;1231 1258 1232 1259 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->csLock, RT_SRC_POS, "HPET#%u", pDevIns->iInstance); 1233 1260 AssertRCReturn(rc, rc); 1234 1261 1235 /* Init t imers. */1262 /* Init the HPET timers. */ 1236 1263 for (unsigned i = 0; i < HPET_NUM_TIMERS; i++) 1237 1264 { … … 1243 1270 pHpetTimer->pHpetRC = PDMINS_2_DATA_RCPTR(pDevIns); 1244 1271 1245 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hpetTimer , pHpetTimer,1246 1247 1272 rc = PDMDevHlpTMTimerCreate(pDevIns, TMCLOCK_VIRTUAL_SYNC, hpetTimerCb, pHpetTimer, 1273 TMTIMER_FLAGS_NO_CRIT_SECT, "HPET Timer", 1274 &pThis->aTimers[i].pTimerR3); 1248 1275 AssertRCReturn(rc, rc); 1249 1276 pThis->aTimers[i].pTimerRC = TMTimerRCPtr(pThis->aTimers[i].pTimerR3); … … 1252 1279 } 1253 1280 1281 /* This must be done prior to registering the HPET, right? */ 1254 1282 hpetReset(pDevIns); 1255 1283 … … 1294 1322 AssertRCReturn(rc, rc); 1295 1323 1296 /** 1297 * @todo Register statistics. 1298 */ 1324 /* Register an info callback. */ 1299 1325 PDMDevHlpDBGFInfoRegister(pDevIns, "hpet", "Display HPET status. (no arguments)", hpetInfo); 1300 1326
Note:
See TracChangeset
for help on using the changeset viewer.