VirtualBox

Ignore:
Timestamp:
Jun 19, 2012 1:54:17 PM (13 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
78649
Message:

EMAll/IEM work.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/EMAll.cpp

    r41823 r41824  
    646646
    647647#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 */
     672VMMDECL(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 */
     698VMMDECL(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 */
     732VMMDECL(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 */
     757VMMDECL(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 */
     806static 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 */
     946VMMDECL(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 */
     978VMMDECL(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 */
     999VMMDECL(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 */
     1020VMMDECL(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 */
     1052VMMDECL(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 */
     1092VMMDECL(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
    6481113#ifndef VBOX_WITH_IEM
    6491114
     
    20862551
    20872552/**
    2088  * Interpret CRx read
    2089  *
    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     else
    2108         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 CLTS
    2122  *
    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 /**
    21382553 * CLTS Emulation.
    21392554 */
     
    21442559}
    21452560
    2146 
    2147 /**
    2148  * Update CRx
    2149  *
    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 value
    2156  *
    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_RC
    2172         /* 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 #endif
    2177         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             else
    2211             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_RC
    2262         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 # endif
    2269         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 write
    2288  *
    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     else
    2307     {
    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 LMSW
    2321  *
    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 }
    23392561
    23402562/**
     
    24372659
    24382660/**
    2439  * Interpret DRx write
    2440  *
    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     else
    2460     {
    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 read
    2480  *
    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     else
    2501         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 /**
    25112661 * MOV DRx
    25122662 */
     
    26662816
    26672817/**
    2668  * Interpret RDTSC
    2669  *
    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 RDTSCP
    2695  *
    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 /**
    27282818 * RDTSC Emulation.
    27292819 */
     
    27322822    NOREF(pDis); NOREF(pvFault); NOREF(pcbSize);
    27332823    return EMInterpretRdtsc(pVM, pVCpu, pRegFrame);
    2734 }
    2735 
    2736 /**
    2737  * Interpret RDPMC
    2738  *
    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;
    27642824}
    27652825
     
    28052865    NOREF(pDis); NOREF(pvFault); NOREF(pcbSize);
    28062866    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=0
    2830      */
    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);
    28452867}
    28462868
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette