Changeset 41824 in vbox for trunk/src/VBox/VMM/VMMAll/EMAll.cpp
- Timestamp:
- Jun 19, 2012 1:54:17 PM (13 years ago)
- svn:sync-xref-src-repo-rev:
- 78649
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/EMAll.cpp
r41823 r41824 646 646 647 647 #endif /* IN_RC && VBOX_WITH_PATM */ 648 649 650 651 /* 652 * 653 * Old interpreter primitives used by HM, move/eliminate later. 654 * Old interpreter primitives used by HM, move/eliminate later. 655 * Old interpreter primitives used by HM, move/eliminate later. 656 * Old interpreter primitives used by HM, move/eliminate later. 657 * Old interpreter primitives used by HM, move/eliminate later. 658 * 659 */ 660 661 662 663 /** 664 * Interpret RDTSC 665 * 666 * @returns VBox status code. 667 * @param pVM Pointer to the VM. 668 * @param pVCpu Pointer to the VMCPU. 669 * @param pRegFrame The register frame. 670 * 671 */ 672 VMMDECL(int) EMInterpretRdtsc(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) 673 { 674 unsigned uCR4 = CPUMGetGuestCR4(pVCpu); 675 676 if (uCR4 & X86_CR4_TSD) 677 return VERR_EM_INTERPRETER; /* genuine #GP */ 678 679 uint64_t uTicks = TMCpuTickGet(pVCpu); 680 681 /* Same behaviour in 32 & 64 bits mode */ 682 pRegFrame->rax = (uint32_t)uTicks; 683 pRegFrame->rdx = (uTicks >> 32ULL); 684 685 NOREF(pVM); 686 return VINF_SUCCESS; 687 } 688 689 /** 690 * Interpret RDTSCP 691 * 692 * @returns VBox status code. 693 * @param pVM Pointer to the VM. 694 * @param pVCpu Pointer to the VMCPU. 695 * @param pCtx The CPU context. 696 * 697 */ 698 VMMDECL(int) EMInterpretRdtscp(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx) 699 { 700 unsigned uCR4 = CPUMGetGuestCR4(pVCpu); 701 702 if (!CPUMGetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_RDTSCP)) 703 { 704 AssertFailed(); 705 return VERR_EM_INTERPRETER; /* genuine #UD */ 706 } 707 708 if (uCR4 & X86_CR4_TSD) 709 return VERR_EM_INTERPRETER; /* genuine #GP */ 710 711 uint64_t uTicks = TMCpuTickGet(pVCpu); 712 713 /* Same behaviour in 32 & 64 bits mode */ 714 pCtx->rax = (uint32_t)uTicks; 715 pCtx->rdx = (uTicks >> 32ULL); 716 /* Low dword of the TSC_AUX msr only. */ 717 CPUMQueryGuestMsr(pVCpu, MSR_K8_TSC_AUX, &pCtx->rcx); 718 pCtx->rcx &= UINT32_C(0xffffffff); 719 720 return VINF_SUCCESS; 721 } 722 723 /** 724 * Interpret RDPMC 725 * 726 * @returns VBox status code. 727 * @param pVM Pointer to the VM. 728 * @param pVCpu Pointer to the VMCPU. 729 * @param pRegFrame The register frame. 730 * 731 */ 732 VMMDECL(int) EMInterpretRdpmc(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) 733 { 734 unsigned uCR4 = CPUMGetGuestCR4(pVCpu); 735 736 /* If X86_CR4_PCE is not set, then CPL must be zero. */ 737 if ( !(uCR4 & X86_CR4_PCE) 738 && CPUMGetGuestCPL(pVCpu, pRegFrame) != 0) 739 { 740 Assert(CPUMGetGuestCR0(pVCpu) & X86_CR0_PE); 741 return VERR_EM_INTERPRETER; /* genuine #GP */ 742 } 743 744 /* Just return zero here; rather tricky to properly emulate this, especially as the specs are a mess. */ 745 pRegFrame->rax = 0; 746 pRegFrame->rdx = 0; 747 /** @todo We should trigger a #GP here if the cpu doesn't support the index in ecx. */ 748 749 NOREF(pVM); 750 return VINF_SUCCESS; 751 } 752 753 754 /** 755 * MWAIT Emulation. 756 */ 757 VMMDECL(VBOXSTRICTRC) EMInterpretMWait(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame) 758 { 759 uint32_t u32Dummy, u32ExtFeatures, cpl, u32MWaitFeatures; 760 NOREF(pVM); 761 762 /* Get the current privilege level. */ 763 cpl = CPUMGetGuestCPL(pVCpu, pRegFrame); 764 if (cpl != 0) 765 return VERR_EM_INTERPRETER; /* supervisor only */ 766 767 CPUMGetGuestCpuId(pVCpu, 1, &u32Dummy, &u32Dummy, &u32ExtFeatures, &u32Dummy); 768 if (!(u32ExtFeatures & X86_CPUID_FEATURE_ECX_MONITOR)) 769 return VERR_EM_INTERPRETER; /* not supported */ 770 771 /* 772 * CPUID.05H.ECX[0] defines support for power management extensions (eax) 773 * CPUID.05H.ECX[1] defines support for interrupts as break events for mwait even when IF=0 774 */ 775 CPUMGetGuestCpuId(pVCpu, 5, &u32Dummy, &u32Dummy, &u32MWaitFeatures, &u32Dummy); 776 if (pRegFrame->ecx > 1) 777 { 778 Log(("EMInterpretMWait: unexpected ecx value %x -> recompiler\n", pRegFrame->ecx)); 779 return VERR_EM_INTERPRETER; /* illegal value. */ 780 } 781 782 if (pRegFrame->ecx && !(u32MWaitFeatures & X86_CPUID_MWAIT_ECX_BREAKIRQIF0)) 783 { 784 Log(("EMInterpretMWait: unsupported X86_CPUID_MWAIT_ECX_BREAKIRQIF0 -> recompiler\n")); 785 return VERR_EM_INTERPRETER; /* illegal value. */ 786 } 787 788 return EMMonitorWaitPerform(pVCpu, pRegFrame->rax, pRegFrame->rcx); 789 } 790 791 792 793 /* VT-x only: */ 794 795 /** 796 * Update CRx 797 * 798 * @returns VBox status code. 799 * @param pVM Pointer to the VM. 800 * @param pVCpu Pointer to the VMCPU. 801 * @param pRegFrame The register frame. 802 * @param DestRegCRx CRx register index (DISUSE_REG_CR*) 803 * @param val New CRx value 804 * 805 */ 806 static int emUpdateCRx(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegCrx, uint64_t val) 807 { 808 uint64_t oldval; 809 uint64_t msrEFER; 810 int rc, rc2; 811 NOREF(pVM); 812 813 /** @todo Clean up this mess. */ 814 LogFlow(("EMInterpretCRxWrite at %RGv CR%d <- %RX64\n", (RTGCPTR)pRegFrame->rip, DestRegCrx, val)); 815 switch (DestRegCrx) 816 { 817 case DISCREG_CR0: 818 oldval = CPUMGetGuestCR0(pVCpu); 819 #ifdef IN_RC 820 /* CR0.WP and CR0.AM changes require a reschedule run in ring 3. */ 821 if ( (val & (X86_CR0_WP | X86_CR0_AM)) 822 != (oldval & (X86_CR0_WP | X86_CR0_AM))) 823 return VERR_EM_INTERPRETER; 824 #endif 825 rc = VINF_SUCCESS; 826 CPUMSetGuestCR0(pVCpu, val); 827 val = CPUMGetGuestCR0(pVCpu); 828 if ( (oldval & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)) 829 != (val & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE))) 830 { 831 /* global flush */ 832 rc = PGMFlushTLB(pVCpu, CPUMGetGuestCR3(pVCpu), true /* global */); 833 AssertRCReturn(rc, rc); 834 } 835 836 /* Deal with long mode enabling/disabling. */ 837 msrEFER = CPUMGetGuestEFER(pVCpu); 838 if (msrEFER & MSR_K6_EFER_LME) 839 { 840 if ( !(oldval & X86_CR0_PG) 841 && (val & X86_CR0_PG)) 842 { 843 /* Illegal to have an active 64 bits CS selector (AMD Arch. Programmer's Manual Volume 2: Table 14-5) */ 844 if (pRegFrame->csHid.Attr.n.u1Long) 845 { 846 AssertMsgFailed(("Illegal enabling of paging with CS.u1Long = 1!!\n")); 847 return VERR_EM_INTERPRETER; /* @todo generate #GP(0) */ 848 } 849 850 /* Illegal to switch to long mode before activating PAE first (AMD Arch. Programmer's Manual Volume 2: Table 14-5) */ 851 if (!(CPUMGetGuestCR4(pVCpu) & X86_CR4_PAE)) 852 { 853 AssertMsgFailed(("Illegal enabling of paging with PAE disabled!!\n")); 854 return VERR_EM_INTERPRETER; /* @todo generate #GP(0) */ 855 } 856 msrEFER |= MSR_K6_EFER_LMA; 857 } 858 else 859 if ( (oldval & X86_CR0_PG) 860 && !(val & X86_CR0_PG)) 861 { 862 msrEFER &= ~MSR_K6_EFER_LMA; 863 /* @todo Do we need to cut off rip here? High dword of rip is undefined, so it shouldn't really matter. */ 864 } 865 CPUMSetGuestEFER(pVCpu, msrEFER); 866 } 867 rc2 = PGMChangeMode(pVCpu, CPUMGetGuestCR0(pVCpu), CPUMGetGuestCR4(pVCpu), CPUMGetGuestEFER(pVCpu)); 868 return rc2 == VINF_SUCCESS ? rc : rc2; 869 870 case DISCREG_CR2: 871 rc = CPUMSetGuestCR2(pVCpu, val); AssertRC(rc); 872 return VINF_SUCCESS; 873 874 case DISCREG_CR3: 875 /* Reloading the current CR3 means the guest just wants to flush the TLBs */ 876 rc = CPUMSetGuestCR3(pVCpu, val); AssertRC(rc); 877 if (CPUMGetGuestCR0(pVCpu) & X86_CR0_PG) 878 { 879 /* flush */ 880 rc = PGMFlushTLB(pVCpu, val, !(CPUMGetGuestCR4(pVCpu) & X86_CR4_PGE)); 881 AssertRC(rc); 882 } 883 return rc; 884 885 case DISCREG_CR4: 886 oldval = CPUMGetGuestCR4(pVCpu); 887 rc = CPUMSetGuestCR4(pVCpu, val); AssertRC(rc); 888 val = CPUMGetGuestCR4(pVCpu); 889 890 /* Illegal to disable PAE when long mode is active. (AMD Arch. Programmer's Manual Volume 2: Table 14-5) */ 891 msrEFER = CPUMGetGuestEFER(pVCpu); 892 if ( (msrEFER & MSR_K6_EFER_LMA) 893 && (oldval & X86_CR4_PAE) 894 && !(val & X86_CR4_PAE)) 895 { 896 return VERR_EM_INTERPRETER; /** @todo generate #GP(0) */ 897 } 898 899 rc = VINF_SUCCESS; 900 if ( (oldval & (X86_CR4_PGE|X86_CR4_PAE|X86_CR4_PSE)) 901 != (val & (X86_CR4_PGE|X86_CR4_PAE|X86_CR4_PSE))) 902 { 903 /* global flush */ 904 rc = PGMFlushTLB(pVCpu, CPUMGetGuestCR3(pVCpu), true /* global */); 905 AssertRCReturn(rc, rc); 906 } 907 908 /* Feeling extremely lazy. */ 909 # ifdef IN_RC 910 if ( (oldval & (X86_CR4_OSFSXR|X86_CR4_OSXMMEEXCPT|X86_CR4_PCE|X86_CR4_MCE|X86_CR4_PAE|X86_CR4_DE|X86_CR4_TSD|X86_CR4_PVI|X86_CR4_VME)) 911 != (val & (X86_CR4_OSFSXR|X86_CR4_OSXMMEEXCPT|X86_CR4_PCE|X86_CR4_MCE|X86_CR4_PAE|X86_CR4_DE|X86_CR4_TSD|X86_CR4_PVI|X86_CR4_VME))) 912 { 913 Log(("emInterpretMovCRx: CR4: %#RX64->%#RX64 => R3\n", oldval, val)); 914 VMCPU_FF_SET(pVCpu, VMCPU_FF_TO_R3); 915 } 916 # endif 917 if ((val ^ oldval) & X86_CR4_VME) 918 VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_TSS); 919 920 rc2 = PGMChangeMode(pVCpu, CPUMGetGuestCR0(pVCpu), CPUMGetGuestCR4(pVCpu), CPUMGetGuestEFER(pVCpu)); 921 return rc2 == VINF_SUCCESS ? rc : rc2; 922 923 case DISCREG_CR8: 924 return PDMApicSetTPR(pVCpu, val << 4); /* cr8 bits 3-0 correspond to bits 7-4 of the task priority mmio register. */ 925 926 default: 927 AssertFailed(); 928 case DISCREG_CR1: /* illegal op */ 929 break; 930 } 931 return VERR_EM_INTERPRETER; 932 } 933 934 935 /** 936 * Interpret CRx write 937 * 938 * @returns VBox status code. 939 * @param pVM Pointer to the VM. 940 * @param pVCpu Pointer to the VMCPU. 941 * @param pRegFrame The register frame. 942 * @param DestRegCRx CRx register index (DISUSE_REG_CR*) 943 * @param SrcRegGen General purpose register index (USE_REG_E**)) 944 * 945 */ 946 VMMDECL(int) EMInterpretCRxWrite(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegCrx, uint32_t SrcRegGen) 947 { 948 uint64_t val; 949 int rc; 950 951 if (CPUMIsGuestIn64BitCode(pVCpu, pRegFrame)) 952 { 953 rc = DISFetchReg64(pRegFrame, SrcRegGen, &val); 954 } 955 else 956 { 957 uint32_t val32; 958 rc = DISFetchReg32(pRegFrame, SrcRegGen, &val32); 959 val = val32; 960 } 961 962 if (RT_SUCCESS(rc)) 963 return emUpdateCRx(pVM, pVCpu, pRegFrame, DestRegCrx, val); 964 965 return VERR_EM_INTERPRETER; 966 } 967 968 /** 969 * Interpret LMSW 970 * 971 * @returns VBox status code. 972 * @param pVM Pointer to the VM. 973 * @param pVCpu Pointer to the VMCPU. 974 * @param pRegFrame The register frame. 975 * @param u16Data LMSW source data. 976 * 977 */ 978 VMMDECL(int) EMInterpretLMSW(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint16_t u16Data) 979 { 980 uint64_t OldCr0 = CPUMGetGuestCR0(pVCpu); 981 982 /* Only PE, MP, EM and TS can be changed; note that PE can't be cleared by this instruction. */ 983 uint64_t NewCr0 = ( OldCr0 & ~( X86_CR0_MP | X86_CR0_EM | X86_CR0_TS)) 984 | (u16Data & (X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS)); 985 986 return emUpdateCRx(pVM, pVCpu, pRegFrame, DISCREG_CR0, NewCr0); 987 } 988 989 990 991 /** 992 * Interpret CLTS 993 * 994 * @returns VBox status code. 995 * @param pVM Pointer to the VM. 996 * @param pVCpu Pointer to the VMCPU. 997 * 998 */ 999 VMMDECL(int) EMInterpretCLTS(PVM pVM, PVMCPU pVCpu) 1000 { 1001 NOREF(pVM); 1002 uint64_t cr0 = CPUMGetGuestCR0(pVCpu); 1003 if (!(cr0 & X86_CR0_TS)) 1004 return VINF_SUCCESS; 1005 return CPUMSetGuestCR0(pVCpu, cr0 & ~X86_CR0_TS); 1006 } 1007 1008 1009 /** 1010 * Interpret CRx read 1011 * 1012 * @returns VBox status code. 1013 * @param pVM Pointer to the VM. 1014 * @param pVCpu Pointer to the VMCPU. 1015 * @param pRegFrame The register frame. 1016 * @param DestRegGen General purpose register index (USE_REG_E**)) 1017 * @param SrcRegCRx CRx register index (DISUSE_REG_CR*) 1018 * 1019 */ 1020 VMMDECL(int) EMInterpretCRxRead(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegCrx) 1021 { 1022 uint64_t val64; 1023 int rc = CPUMGetGuestCRx(pVCpu, SrcRegCrx, &val64); 1024 AssertMsgRCReturn(rc, ("CPUMGetGuestCRx %d failed\n", SrcRegCrx), VERR_EM_INTERPRETER); 1025 NOREF(pVM); 1026 1027 if (CPUMIsGuestIn64BitCode(pVCpu, pRegFrame)) 1028 rc = DISWriteReg64(pRegFrame, DestRegGen, val64); 1029 else 1030 rc = DISWriteReg32(pRegFrame, DestRegGen, val64); 1031 1032 if (RT_SUCCESS(rc)) 1033 { 1034 LogFlow(("MOV_CR: gen32=%d CR=%d val=%RX64\n", DestRegGen, SrcRegCrx, val64)); 1035 return VINF_SUCCESS; 1036 } 1037 return VERR_EM_INTERPRETER; 1038 } 1039 1040 1041 /** 1042 * Interpret DRx write 1043 * 1044 * @returns VBox status code. 1045 * @param pVM Pointer to the VM. 1046 * @param pVCpu Pointer to the VMCPU. 1047 * @param pRegFrame The register frame. 1048 * @param DestRegDRx DRx register index (USE_REG_DR*) 1049 * @param SrcRegGen General purpose register index (USE_REG_E**)) 1050 * 1051 */ 1052 VMMDECL(int) EMInterpretDRxWrite(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegDrx, uint32_t SrcRegGen) 1053 { 1054 uint64_t val; 1055 int rc; 1056 NOREF(pVM); 1057 1058 if (CPUMIsGuestIn64BitCode(pVCpu, pRegFrame)) 1059 { 1060 rc = DISFetchReg64(pRegFrame, SrcRegGen, &val); 1061 } 1062 else 1063 { 1064 uint32_t val32; 1065 rc = DISFetchReg32(pRegFrame, SrcRegGen, &val32); 1066 val = val32; 1067 } 1068 1069 if (RT_SUCCESS(rc)) 1070 { 1071 /** @todo we don't fail if illegal bits are set/cleared for e.g. dr7 */ 1072 rc = CPUMSetGuestDRx(pVCpu, DestRegDrx, val); 1073 if (RT_SUCCESS(rc)) 1074 return rc; 1075 AssertMsgFailed(("CPUMSetGuestDRx %d failed\n", DestRegDrx)); 1076 } 1077 return VERR_EM_INTERPRETER; 1078 } 1079 1080 1081 /** 1082 * Interpret DRx read 1083 * 1084 * @returns VBox status code. 1085 * @param pVM Pointer to the VM. 1086 * @param pVCpu Pointer to the VMCPU. 1087 * @param pRegFrame The register frame. 1088 * @param DestRegGen General purpose register index (USE_REG_E**)) 1089 * @param SrcRegDRx DRx register index (USE_REG_DR*) 1090 * 1091 */ 1092 VMMDECL(int) EMInterpretDRxRead(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegDrx) 1093 { 1094 uint64_t val64; 1095 NOREF(pVM); 1096 1097 int rc = CPUMGetGuestDRx(pVCpu, SrcRegDrx, &val64); 1098 AssertMsgRCReturn(rc, ("CPUMGetGuestDRx %d failed\n", SrcRegDrx), VERR_EM_INTERPRETER); 1099 if (CPUMIsGuestIn64BitCode(pVCpu, pRegFrame)) 1100 { 1101 rc = DISWriteReg64(pRegFrame, DestRegGen, val64); 1102 } 1103 else 1104 rc = DISWriteReg32(pRegFrame, DestRegGen, (uint32_t)val64); 1105 1106 if (RT_SUCCESS(rc)) 1107 return VINF_SUCCESS; 1108 1109 return VERR_EM_INTERPRETER; 1110 } 1111 1112 648 1113 #ifndef VBOX_WITH_IEM 649 1114 … … 2086 2551 2087 2552 /** 2088 * Interpret CRx read2089 *2090 * @returns VBox status code.2091 * @param pVM Pointer to the VM.2092 * @param pVCpu Pointer to the VMCPU.2093 * @param pRegFrame The register frame.2094 * @param DestRegGen General purpose register index (USE_REG_E**))2095 * @param SrcRegCRx CRx register index (DISUSE_REG_CR*)2096 *2097 */2098 VMMDECL(int) EMInterpretCRxRead(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegCrx)2099 {2100 uint64_t val64;2101 int rc = CPUMGetGuestCRx(pVCpu, SrcRegCrx, &val64);2102 AssertMsgRCReturn(rc, ("CPUMGetGuestCRx %d failed\n", SrcRegCrx), VERR_EM_INTERPRETER);2103 NOREF(pVM);2104 2105 if (CPUMIsGuestIn64BitCode(pVCpu, pRegFrame))2106 rc = DISWriteReg64(pRegFrame, DestRegGen, val64);2107 else2108 rc = DISWriteReg32(pRegFrame, DestRegGen, val64);2109 2110 if (RT_SUCCESS(rc))2111 {2112 LogFlow(("MOV_CR: gen32=%d CR=%d val=%RX64\n", DestRegGen, SrcRegCrx, val64));2113 return VINF_SUCCESS;2114 }2115 return VERR_EM_INTERPRETER;2116 }2117 2118 2119 2120 /**2121 * Interpret CLTS2122 *2123 * @returns VBox status code.2124 * @param pVM Pointer to the VM.2125 * @param pVCpu Pointer to the VMCPU.2126 *2127 */2128 VMMDECL(int) EMInterpretCLTS(PVM pVM, PVMCPU pVCpu)2129 {2130 NOREF(pVM);2131 uint64_t cr0 = CPUMGetGuestCR0(pVCpu);2132 if (!(cr0 & X86_CR0_TS))2133 return VINF_SUCCESS;2134 return CPUMSetGuestCR0(pVCpu, cr0 & ~X86_CR0_TS);2135 }2136 2137 /**2138 2553 * CLTS Emulation. 2139 2554 */ … … 2144 2559 } 2145 2560 2146 2147 /**2148 * Update CRx2149 *2150 * @returns VBox status code.2151 * @param pVM Pointer to the VM.2152 * @param pVCpu Pointer to the VMCPU.2153 * @param pRegFrame The register frame.2154 * @param DestRegCRx CRx register index (DISUSE_REG_CR*)2155 * @param val New CRx value2156 *2157 */2158 static int emUpdateCRx(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegCrx, uint64_t val)2159 {2160 uint64_t oldval;2161 uint64_t msrEFER;2162 int rc, rc2;2163 NOREF(pVM);2164 2165 /** @todo Clean up this mess. */2166 LogFlow(("EMInterpretCRxWrite at %RGv CR%d <- %RX64\n", (RTGCPTR)pRegFrame->rip, DestRegCrx, val));2167 switch (DestRegCrx)2168 {2169 case DISCREG_CR0:2170 oldval = CPUMGetGuestCR0(pVCpu);2171 #ifdef IN_RC2172 /* CR0.WP and CR0.AM changes require a reschedule run in ring 3. */2173 if ( (val & (X86_CR0_WP | X86_CR0_AM))2174 != (oldval & (X86_CR0_WP | X86_CR0_AM)))2175 return VERR_EM_INTERPRETER;2176 #endif2177 rc = VINF_SUCCESS;2178 CPUMSetGuestCR0(pVCpu, val);2179 val = CPUMGetGuestCR0(pVCpu);2180 if ( (oldval & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE))2181 != (val & (X86_CR0_PG | X86_CR0_WP | X86_CR0_PE)))2182 {2183 /* global flush */2184 rc = PGMFlushTLB(pVCpu, CPUMGetGuestCR3(pVCpu), true /* global */);2185 AssertRCReturn(rc, rc);2186 }2187 2188 /* Deal with long mode enabling/disabling. */2189 msrEFER = CPUMGetGuestEFER(pVCpu);2190 if (msrEFER & MSR_K6_EFER_LME)2191 {2192 if ( !(oldval & X86_CR0_PG)2193 && (val & X86_CR0_PG))2194 {2195 /* Illegal to have an active 64 bits CS selector (AMD Arch. Programmer's Manual Volume 2: Table 14-5) */2196 if (pRegFrame->csHid.Attr.n.u1Long)2197 {2198 AssertMsgFailed(("Illegal enabling of paging with CS.u1Long = 1!!\n"));2199 return VERR_EM_INTERPRETER; /* @todo generate #GP(0) */2200 }2201 2202 /* Illegal to switch to long mode before activating PAE first (AMD Arch. Programmer's Manual Volume 2: Table 14-5) */2203 if (!(CPUMGetGuestCR4(pVCpu) & X86_CR4_PAE))2204 {2205 AssertMsgFailed(("Illegal enabling of paging with PAE disabled!!\n"));2206 return VERR_EM_INTERPRETER; /* @todo generate #GP(0) */2207 }2208 msrEFER |= MSR_K6_EFER_LMA;2209 }2210 else2211 if ( (oldval & X86_CR0_PG)2212 && !(val & X86_CR0_PG))2213 {2214 msrEFER &= ~MSR_K6_EFER_LMA;2215 /* @todo Do we need to cut off rip here? High dword of rip is undefined, so it shouldn't really matter. */2216 }2217 CPUMSetGuestEFER(pVCpu, msrEFER);2218 }2219 rc2 = PGMChangeMode(pVCpu, CPUMGetGuestCR0(pVCpu), CPUMGetGuestCR4(pVCpu), CPUMGetGuestEFER(pVCpu));2220 return rc2 == VINF_SUCCESS ? rc : rc2;2221 2222 case DISCREG_CR2:2223 rc = CPUMSetGuestCR2(pVCpu, val); AssertRC(rc);2224 return VINF_SUCCESS;2225 2226 case DISCREG_CR3:2227 /* Reloading the current CR3 means the guest just wants to flush the TLBs */2228 rc = CPUMSetGuestCR3(pVCpu, val); AssertRC(rc);2229 if (CPUMGetGuestCR0(pVCpu) & X86_CR0_PG)2230 {2231 /* flush */2232 rc = PGMFlushTLB(pVCpu, val, !(CPUMGetGuestCR4(pVCpu) & X86_CR4_PGE));2233 AssertRC(rc);2234 }2235 return rc;2236 2237 case DISCREG_CR4:2238 oldval = CPUMGetGuestCR4(pVCpu);2239 rc = CPUMSetGuestCR4(pVCpu, val); AssertRC(rc);2240 val = CPUMGetGuestCR4(pVCpu);2241 2242 /* Illegal to disable PAE when long mode is active. (AMD Arch. Programmer's Manual Volume 2: Table 14-5) */2243 msrEFER = CPUMGetGuestEFER(pVCpu);2244 if ( (msrEFER & MSR_K6_EFER_LMA)2245 && (oldval & X86_CR4_PAE)2246 && !(val & X86_CR4_PAE))2247 {2248 return VERR_EM_INTERPRETER; /** @todo generate #GP(0) */2249 }2250 2251 rc = VINF_SUCCESS;2252 if ( (oldval & (X86_CR4_PGE|X86_CR4_PAE|X86_CR4_PSE))2253 != (val & (X86_CR4_PGE|X86_CR4_PAE|X86_CR4_PSE)))2254 {2255 /* global flush */2256 rc = PGMFlushTLB(pVCpu, CPUMGetGuestCR3(pVCpu), true /* global */);2257 AssertRCReturn(rc, rc);2258 }2259 2260 /* Feeling extremely lazy. */2261 # ifdef IN_RC2262 if ( (oldval & (X86_CR4_OSFSXR|X86_CR4_OSXMMEEXCPT|X86_CR4_PCE|X86_CR4_MCE|X86_CR4_PAE|X86_CR4_DE|X86_CR4_TSD|X86_CR4_PVI|X86_CR4_VME))2263 != (val & (X86_CR4_OSFSXR|X86_CR4_OSXMMEEXCPT|X86_CR4_PCE|X86_CR4_MCE|X86_CR4_PAE|X86_CR4_DE|X86_CR4_TSD|X86_CR4_PVI|X86_CR4_VME)))2264 {2265 Log(("emInterpretMovCRx: CR4: %#RX64->%#RX64 => R3\n", oldval, val));2266 VMCPU_FF_SET(pVCpu, VMCPU_FF_TO_R3);2267 }2268 # endif2269 if ((val ^ oldval) & X86_CR4_VME)2270 VMCPU_FF_SET(pVCpu, VMCPU_FF_SELM_SYNC_TSS);2271 2272 rc2 = PGMChangeMode(pVCpu, CPUMGetGuestCR0(pVCpu), CPUMGetGuestCR4(pVCpu), CPUMGetGuestEFER(pVCpu));2273 return rc2 == VINF_SUCCESS ? rc : rc2;2274 2275 case DISCREG_CR8:2276 return PDMApicSetTPR(pVCpu, val << 4); /* cr8 bits 3-0 correspond to bits 7-4 of the task priority mmio register. */2277 2278 default:2279 AssertFailed();2280 case DISCREG_CR1: /* illegal op */2281 break;2282 }2283 return VERR_EM_INTERPRETER;2284 }2285 2286 /**2287 * Interpret CRx write2288 *2289 * @returns VBox status code.2290 * @param pVM Pointer to the VM.2291 * @param pVCpu Pointer to the VMCPU.2292 * @param pRegFrame The register frame.2293 * @param DestRegCRx CRx register index (DISUSE_REG_CR*)2294 * @param SrcRegGen General purpose register index (USE_REG_E**))2295 *2296 */2297 VMMDECL(int) EMInterpretCRxWrite(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegCrx, uint32_t SrcRegGen)2298 {2299 uint64_t val;2300 int rc;2301 2302 if (CPUMIsGuestIn64BitCode(pVCpu, pRegFrame))2303 {2304 rc = DISFetchReg64(pRegFrame, SrcRegGen, &val);2305 }2306 else2307 {2308 uint32_t val32;2309 rc = DISFetchReg32(pRegFrame, SrcRegGen, &val32);2310 val = val32;2311 }2312 2313 if (RT_SUCCESS(rc))2314 return emUpdateCRx(pVM, pVCpu, pRegFrame, DestRegCrx, val);2315 2316 return VERR_EM_INTERPRETER;2317 }2318 2319 /**2320 * Interpret LMSW2321 *2322 * @returns VBox status code.2323 * @param pVM Pointer to the VM.2324 * @param pVCpu Pointer to the VMCPU.2325 * @param pRegFrame The register frame.2326 * @param u16Data LMSW source data.2327 *2328 */2329 VMMDECL(int) EMInterpretLMSW(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint16_t u16Data)2330 {2331 uint64_t OldCr0 = CPUMGetGuestCR0(pVCpu);2332 2333 /* Only PE, MP, EM and TS can be changed; note that PE can't be cleared by this instruction. */2334 uint64_t NewCr0 = ( OldCr0 & ~( X86_CR0_MP | X86_CR0_EM | X86_CR0_TS))2335 | (u16Data & (X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS));2336 2337 return emUpdateCRx(pVM, pVCpu, pRegFrame, DISCREG_CR0, NewCr0);2338 }2339 2561 2340 2562 /** … … 2437 2659 2438 2660 /** 2439 * Interpret DRx write2440 *2441 * @returns VBox status code.2442 * @param pVM Pointer to the VM.2443 * @param pVCpu Pointer to the VMCPU.2444 * @param pRegFrame The register frame.2445 * @param DestRegDRx DRx register index (USE_REG_DR*)2446 * @param SrcRegGen General purpose register index (USE_REG_E**))2447 *2448 */2449 VMMDECL(int) EMInterpretDRxWrite(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegDrx, uint32_t SrcRegGen)2450 {2451 uint64_t val;2452 int rc;2453 NOREF(pVM);2454 2455 if (CPUMIsGuestIn64BitCode(pVCpu, pRegFrame))2456 {2457 rc = DISFetchReg64(pRegFrame, SrcRegGen, &val);2458 }2459 else2460 {2461 uint32_t val32;2462 rc = DISFetchReg32(pRegFrame, SrcRegGen, &val32);2463 val = val32;2464 }2465 2466 if (RT_SUCCESS(rc))2467 {2468 /** @todo we don't fail if illegal bits are set/cleared for e.g. dr7 */2469 rc = CPUMSetGuestDRx(pVCpu, DestRegDrx, val);2470 if (RT_SUCCESS(rc))2471 return rc;2472 AssertMsgFailed(("CPUMSetGuestDRx %d failed\n", DestRegDrx));2473 }2474 return VERR_EM_INTERPRETER;2475 }2476 2477 2478 /**2479 * Interpret DRx read2480 *2481 * @returns VBox status code.2482 * @param pVM Pointer to the VM.2483 * @param pVCpu Pointer to the VMCPU.2484 * @param pRegFrame The register frame.2485 * @param DestRegGen General purpose register index (USE_REG_E**))2486 * @param SrcRegDRx DRx register index (USE_REG_DR*)2487 *2488 */2489 VMMDECL(int) EMInterpretDRxRead(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t DestRegGen, uint32_t SrcRegDrx)2490 {2491 uint64_t val64;2492 NOREF(pVM);2493 2494 int rc = CPUMGetGuestDRx(pVCpu, SrcRegDrx, &val64);2495 AssertMsgRCReturn(rc, ("CPUMGetGuestDRx %d failed\n", SrcRegDrx), VERR_EM_INTERPRETER);2496 if (CPUMIsGuestIn64BitCode(pVCpu, pRegFrame))2497 {2498 rc = DISWriteReg64(pRegFrame, DestRegGen, val64);2499 }2500 else2501 rc = DISWriteReg32(pRegFrame, DestRegGen, (uint32_t)val64);2502 2503 if (RT_SUCCESS(rc))2504 return VINF_SUCCESS;2505 2506 return VERR_EM_INTERPRETER;2507 }2508 2509 2510 /**2511 2661 * MOV DRx 2512 2662 */ … … 2666 2816 2667 2817 /** 2668 * Interpret RDTSC2669 *2670 * @returns VBox status code.2671 * @param pVM Pointer to the VM.2672 * @param pVCpu Pointer to the VMCPU.2673 * @param pRegFrame The register frame.2674 *2675 */2676 VMMDECL(int) EMInterpretRdtsc(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame)2677 {2678 unsigned uCR4 = CPUMGetGuestCR4(pVCpu);2679 2680 if (uCR4 & X86_CR4_TSD)2681 return VERR_EM_INTERPRETER; /* genuine #GP */2682 2683 uint64_t uTicks = TMCpuTickGet(pVCpu);2684 2685 /* Same behaviour in 32 & 64 bits mode */2686 pRegFrame->rax = (uint32_t)uTicks;2687 pRegFrame->rdx = (uTicks >> 32ULL);2688 2689 NOREF(pVM);2690 return VINF_SUCCESS;2691 }2692 2693 /**2694 * Interpret RDTSCP2695 *2696 * @returns VBox status code.2697 * @param pVM Pointer to the VM.2698 * @param pVCpu Pointer to the VMCPU.2699 * @param pCtx The CPU context.2700 *2701 */2702 VMMDECL(int) EMInterpretRdtscp(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx)2703 {2704 unsigned uCR4 = CPUMGetGuestCR4(pVCpu);2705 2706 if (!CPUMGetGuestCpuIdFeature(pVM, CPUMCPUIDFEATURE_RDTSCP))2707 {2708 AssertFailed();2709 return VERR_EM_INTERPRETER; /* genuine #UD */2710 }2711 2712 if (uCR4 & X86_CR4_TSD)2713 return VERR_EM_INTERPRETER; /* genuine #GP */2714 2715 uint64_t uTicks = TMCpuTickGet(pVCpu);2716 2717 /* Same behaviour in 32 & 64 bits mode */2718 pCtx->rax = (uint32_t)uTicks;2719 pCtx->rdx = (uTicks >> 32ULL);2720 /* Low dword of the TSC_AUX msr only. */2721 CPUMQueryGuestMsr(pVCpu, MSR_K8_TSC_AUX, &pCtx->rcx);2722 pCtx->rcx &= UINT32_C(0xffffffff);2723 2724 return VINF_SUCCESS;2725 }2726 2727 /**2728 2818 * RDTSC Emulation. 2729 2819 */ … … 2732 2822 NOREF(pDis); NOREF(pvFault); NOREF(pcbSize); 2733 2823 return EMInterpretRdtsc(pVM, pVCpu, pRegFrame); 2734 }2735 2736 /**2737 * Interpret RDPMC2738 *2739 * @returns VBox status code.2740 * @param pVM Pointer to the VM.2741 * @param pVCpu Pointer to the VMCPU.2742 * @param pRegFrame The register frame.2743 *2744 */2745 VMMDECL(int) EMInterpretRdpmc(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame)2746 {2747 unsigned uCR4 = CPUMGetGuestCR4(pVCpu);2748 2749 /* If X86_CR4_PCE is not set, then CPL must be zero. */2750 if ( !(uCR4 & X86_CR4_PCE)2751 && CPUMGetGuestCPL(pVCpu, pRegFrame) != 0)2752 {2753 Assert(CPUMGetGuestCR0(pVCpu) & X86_CR0_PE);2754 return VERR_EM_INTERPRETER; /* genuine #GP */2755 }2756 2757 /* Just return zero here; rather tricky to properly emulate this, especially as the specs are a mess. */2758 pRegFrame->rax = 0;2759 pRegFrame->rdx = 0;2760 /** @todo We should trigger a #GP here if the cpu doesn't support the index in ecx. */2761 2762 NOREF(pVM);2763 return VINF_SUCCESS;2764 2824 } 2765 2825 … … 2805 2865 NOREF(pDis); NOREF(pvFault); NOREF(pcbSize); 2806 2866 return EMInterpretMonitor(pVM, pVCpu, pRegFrame); 2807 }2808 2809 2810 /**2811 * MWAIT Emulation.2812 */2813 VMMDECL(VBOXSTRICTRC) EMInterpretMWait(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame)2814 {2815 uint32_t u32Dummy, u32ExtFeatures, cpl, u32MWaitFeatures;2816 NOREF(pVM);2817 2818 /* Get the current privilege level. */2819 cpl = CPUMGetGuestCPL(pVCpu, pRegFrame);2820 if (cpl != 0)2821 return VERR_EM_INTERPRETER; /* supervisor only */2822 2823 CPUMGetGuestCpuId(pVCpu, 1, &u32Dummy, &u32Dummy, &u32ExtFeatures, &u32Dummy);2824 if (!(u32ExtFeatures & X86_CPUID_FEATURE_ECX_MONITOR))2825 return VERR_EM_INTERPRETER; /* not supported */2826 2827 /*2828 * CPUID.05H.ECX[0] defines support for power management extensions (eax)2829 * CPUID.05H.ECX[1] defines support for interrupts as break events for mwait even when IF=02830 */2831 CPUMGetGuestCpuId(pVCpu, 5, &u32Dummy, &u32Dummy, &u32MWaitFeatures, &u32Dummy);2832 if (pRegFrame->ecx > 1)2833 {2834 Log(("EMInterpretMWait: unexpected ecx value %x -> recompiler\n", pRegFrame->ecx));2835 return VERR_EM_INTERPRETER; /* illegal value. */2836 }2837 2838 if (pRegFrame->ecx && !(u32MWaitFeatures & X86_CPUID_MWAIT_ECX_BREAKIRQIF0))2839 {2840 Log(("EMInterpretMWait: unsupported X86_CPUID_MWAIT_ECX_BREAKIRQIF0 -> recompiler\n"));2841 return VERR_EM_INTERPRETER; /* illegal value. */2842 }2843 2844 return EMMonitorWaitPerform(pVCpu, pRegFrame->rax, pRegFrame->rcx);2845 2867 } 2846 2868
Note:
See TracChangeset
for help on using the changeset viewer.