VirtualBox

Ignore:
Timestamp:
Apr 2, 2013 8:17:11 AM (12 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
84670
Message:

Ring-1 compression patches, courtesy of trivirt AG:

  • main: diff to remove the hwvirt requirement for QNX
  • rem: diff for dealing with raw ring 0/1 selectors and general changes to allowed guest execution states
  • vmm: changes for using the guest's TSS selector index as our hypervisor TSS selector (makes str safe) (VBOX_WITH_SAFE_STR )
  • vmm: changes for dealing with guest ring 1 code (VBOX_WITH_RAW_RING1)
  • vmm: change to emulate smsw in RC/R0 (QNX uses this old style instruction a lot so going to qemu for emulation is very expensive)
  • vmm: change (hack) to kick out patm virtual handlers in case they conflict with guest GDT/TSS write monitors; we should allow multiple handlers per page, but that change would be rather invasive
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR3/SELM.cpp

    r44528 r45276  
    8080#include <iprt/string.h>
    8181
    82 
    83 /**
    84  * Enable or disable tracking of Shadow GDT/LDT/TSS.
    85  * @{
    86  */
    87 #define SELM_TRACK_SHADOW_GDT_CHANGES
    88 #define SELM_TRACK_SHADOW_LDT_CHANGES
    89 #define SELM_TRACK_SHADOW_TSS_CHANGES
    90 /** @} */
    9182
    9283
     
    565556     * Uninstall guest GDT/LDT/TSS write access handlers.
    566557     */
    567     int rc;
     558    int rc = VINF_SUCCESS;
    568559    if (pVM->selm.s.GuestGdtr.pGdt != RTRCPTR_MAX && pVM->selm.s.fGDTRangeRegistered)
    569560    {
     561#ifdef SELM_TRACK_GUEST_GDT_CHANGES
    570562        rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GuestGdtr.pGdt);
    571563        AssertRC(rc);
     564#endif
    572565        pVM->selm.s.GuestGdtr.pGdt = RTRCPTR_MAX;
    573566        pVM->selm.s.GuestGdtr.cbGdt = 0;
     
    576569    if (pVM->selm.s.GCPtrGuestLdt != RTRCPTR_MAX)
    577570    {
     571#ifdef SELM_TRACK_GUEST_LDT_CHANGES
    578572        rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GCPtrGuestLdt);
    579573        AssertRC(rc);
     574#endif
    580575        pVM->selm.s.GCPtrGuestLdt = RTRCPTR_MAX;
    581576    }
    582577    if (pVM->selm.s.GCPtrGuestTss != RTRCPTR_MAX)
    583578    {
     579#ifdef SELM_TRACK_GUEST_TSS_CHANGES
    584580        rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GCPtrGuestTss);
    585581        AssertRC(rc);
     582#endif
    586583        pVM->selm.s.GCPtrGuestTss = RTRCPTR_MAX;
    587584        pVM->selm.s.GCSelTss      = RTSEL_MAX;
     
    619616    if (pVM->selm.s.GuestGdtr.pGdt != RTRCPTR_MAX && pVM->selm.s.fGDTRangeRegistered)
    620617    {
     618#ifdef SELM_TRACK_GUEST_GDT_CHANGES
    621619        rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GuestGdtr.pGdt);
    622620        AssertRC(rc);
     621#endif
    623622        pVM->selm.s.GuestGdtr.pGdt = RTRCPTR_MAX;
    624623        pVM->selm.s.GuestGdtr.cbGdt = 0;
     
    627626    if (pVM->selm.s.GCPtrGuestLdt != RTRCPTR_MAX)
    628627    {
     628#ifdef SELM_TRACK_GUEST_LDT_CHANGES
    629629        rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GCPtrGuestLdt);
    630630        AssertRC(rc);
     631#endif
    631632        pVM->selm.s.GCPtrGuestLdt = RTRCPTR_MAX;
    632633    }
    633634    if (pVM->selm.s.GCPtrGuestTss != RTRCPTR_MAX)
    634635    {
     636#ifdef SELM_TRACK_GUEST_TSS_CHANGES
    635637        rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GCPtrGuestTss);
    636638        AssertRC(rc);
     639#endif
    637640        pVM->selm.s.GCPtrGuestTss = RTRCPTR_MAX;
    638641        pVM->selm.s.GCSelTss      = RTSEL_MAX;
     
    953956    }
    954957
     958#ifdef VBOX_WITH_SAFE_STR
     959    /** Use the guest's TR selector to plug the str virtualization hole. */
     960    if (CPUMGetGuestTR(pVCpu, NULL) != 0)
     961    {
     962        Log(("SELM: Use guest TSS selector %x\n", CPUMGetGuestTR(pVCpu, NULL)));
     963        aHyperSel[SELM_HYPER_SEL_TSS] = CPUMGetGuestTR(pVCpu, NULL);
     964    }
     965#endif
     966
    955967    /*
    956968     * Work thru the copied GDT entries adjusting them for correct virtualization.
     
    960972    {
    961973        if (pGDTE->Gen.u1Present)
    962             selmGuestToShadowDesc(pGDTE);
     974            selmGuestToShadowDesc(pVM, pGDTE);
    963975
    964976        /* Next GDT entry. */
     
    9901002        VMR3Relocate(pVM, 0);
    9911003    }
    992     else if (cbEffLimit >= SELM_HYPER_DEFAULT_BASE)
     1004    else
     1005#ifdef VBOX_WITH_SAFE_STR
     1006    if (    cbEffLimit >= SELM_HYPER_DEFAULT_BASE
     1007        ||  CPUMGetGuestTR(pVCpu, NULL) != 0)       /* Our shadow TR entry was overwritten when we synced the guest's GDT. */
     1008#else
     1009    if (cbEffLimit >= SELM_HYPER_DEFAULT_BASE)
     1010#endif
    9931011        /* We overwrote all entries above, so we have to save them again. */
    9941012        selmR3SetupHyperGDTSelectors(pVM);
     
    10111029    {
    10121030        Log(("SELMR3UpdateFromCPUM: Guest's GDT is changed to pGdt=%016RX64 cbGdt=%08X\n", GDTR.pGdt, GDTR.cbGdt));
    1013 
     1031#ifdef SELM_TRACK_GUEST_GDT_CHANGES
    10141032        /*
    10151033         * [Re]Register write virtual handler for guest's GDT.
     
    10251043                                         0, selmR3GuestGDTWriteHandler, "selmRCGuestGDTWriteHandler", 0,
    10261044                                         "Guest GDT write access handler");
     1045# ifdef VBOX_WITH_RAW_RING1
     1046        /* Some guest OSes (QNX) share code and the GDT on the same page; PGMR3HandlerVirtualRegister doesn't support more than one handler, so we kick out the
     1047         * PATM handler as this one is more important.
     1048         * @todo fix this properly in PGMR3HandlerVirtualRegister
     1049         */
     1050        if (rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT)
     1051        {
     1052            LogRel(("selmR3UpdateShadowGdt: Virtual handler conflict %RGv -> kick out PATM handler for the higher priority GDT page monitor\n", GDTR.pGdt));
     1053            rc = PGMHandlerVirtualDeregister(pVM, GDTR.pGdt & PAGE_BASE_GC_MASK);
     1054            AssertRC(rc);
     1055
     1056            rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE,
     1057                                             GDTR.pGdt, GDTR.pGdt + GDTR.cbGdt /* already inclusive */,
     1058                                             0, selmR3GuestGDTWriteHandler, "selmRCGuestGDTWriteHandler", 0,
     1059                                             "Guest GDT write access handler");
     1060        }
     1061# endif
    10271062        if (RT_FAILURE(rc))
    10281063            return rc;
    1029 
     1064#endif
    10301065        /* Update saved Guest GDTR. */
    10311066        pVM->selm.s.GuestGdtr = GDTR;
     
    11371172                 pVM->selm.s.GCPtrGuestLdt, pVM->selm.s.cbLdtLimit, GCPtrLdt, cbLdt, pVM->selm.s.GuestGdtr.pGdt, pVM->selm.s.GuestGdtr.cbGdt));
    11381173
     1174#ifdef SELM_TRACK_GUEST_LDT_CHANGES
    11391175            /*
    11401176             * [Re]Register write virtual handler for guest's GDT.
     
    11461182                AssertRC(rc);
    11471183            }
    1148 #ifdef DEBUG
     1184# ifdef DEBUG
    11491185            if (pDesc->Gen.u1Present)
    11501186                Log(("LDT selector marked not present!!\n"));
    1151 #endif
     1187# endif
    11521188            rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, GCPtrLdt, GCPtrLdt + cbLdt /* already inclusive */,
    11531189                                             0, selmR3GuestLDTWriteHandler, "selmRCGuestLDTWriteHandler", 0, "Guest LDT write access handler");
     
    11661202                return rc;
    11671203            }
    1168 
     1204#else
     1205            pVM->selm.s.GCPtrGuestLdt = GCPtrLdt;
     1206#endif
    11691207            pVM->selm.s.cbLdtLimit = cbLdt;
    11701208        }
     
    12051243    /** @todo investigate how intel handle various operations on half present cross page entries. */
    12061244    off = GCPtrLdt & (sizeof(X86DESC) - 1);
    1207     AssertMsg(!off, ("LDT is not aligned on entry size! GCPtrLdt=%08x\n", GCPtrLdt));
     1245////    AssertMsg(!off, ("LDT is not aligned on entry size! GCPtrLdt=%08x\n", GCPtrLdt));
    12081246
    12091247    /* Note: Do not skip the first selector; unlike the GDT, a zero LDT selector is perfectly valid. */
     
    12391277            {
    12401278                if (pLDTE->Gen.u1Present)
    1241                     selmGuestToShadowDesc(pLDTE);
     1279                    selmGuestToShadowDesc(pVM, pLDTE);
    12421280
    12431281                /* Next LDT entry. */
     
    14381476}
    14391477
    1440 
     1478#ifdef SELM_TRACK_GUEST_GDT_CHANGES
    14411479/**
    14421480 * \#PF Handler callback for virtual access handler ranges.
     
    14651503    return VINF_PGM_HANDLER_DO_DEFAULT;
    14661504}
    1467 
    1468 
     1505#endif
     1506
     1507#ifdef SELM_TRACK_GUEST_LDT_CHANGES
    14691508/**
    14701509 * \#PF Handler callback for virtual access handler ranges.
     
    14931532    return VINF_PGM_HANDLER_DO_DEFAULT;
    14941533}
    1495 
    1496 
     1534#endif
     1535
     1536
     1537#ifdef SELM_TRACK_GUEST_TSS_CHANGES
    14971538/**
    14981539 * \#PF Handler callback for virtual access handler ranges.
     
    15261567    return VINF_PGM_HANDLER_DO_DEFAULT;
    15271568}
    1528 
     1569#endif
    15291570
    15301571/**
     
    16751716            selmSetRing1Stack(pVM, Tss.ss0 | 1, Tss.esp0);
    16761717            pVM->selm.s.fSyncTSSRing0Stack = fNoRing1Stack = false;
     1718
     1719#ifdef VBOX_WITH_RAW_RING1
     1720            /* Update our TSS structure for the guest's ring 2 stack */
     1721            selmSetRing2Stack(pVM, (Tss.ss1 & ~1) | 2, Tss.esp1);
     1722
     1723            if (    (pVM->selm.s.Tss.ss2 != ((Tss.ss1 & ~2) | 1))
     1724                ||  pVM->selm.s.Tss.esp2 != Tss.esp1)
     1725            {
     1726                Log(("SELMR3SyncTSS: Updating TSS ring 1 stack to %04X:%08X from %04X:%08X\n", Tss.ss1, Tss.esp1, (pVM->selm.s.Tss.ss2 & ~2) | 1, pVM->selm.s.Tss.esp2));
     1727            }
     1728#endif
    16771729        }
    16781730    }
     
    17111763        if (cbMonitoredTss != 0)
    17121764        {
     1765#ifdef SELM_TRACK_GUEST_TSS_CHANGES
    17131766            rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, GCPtrTss, GCPtrTss + cbMonitoredTss - 1,
    17141767                                             0, selmR3GuestTSSWriteHandler,
     
    17161769            if (RT_FAILURE(rc))
    17171770            {
     1771# ifdef VBOX_WITH_RAW_RING1
     1772                /* Some guest OSes (QNX) share code and the TSS on the same page; PGMR3HandlerVirtualRegister doesn't support more than one handler, so we kick out the
     1773                 * PATM handler as this one is more important.
     1774                 * @todo fix this properly in PGMR3HandlerVirtualRegister
     1775                 */
     1776                if (rc == VERR_PGM_HANDLER_VIRTUAL_CONFLICT)
     1777                {
     1778                    LogRel(("SELMR3SyncTSS: Virtual handler conflict %RGv -> kick out PATM handler for the higher priority TSS page monitor\n", GCPtrTss));
     1779                    rc = PGMHandlerVirtualDeregister(pVM, GCPtrTss & PAGE_BASE_GC_MASK);
     1780                    AssertRC(rc);
     1781
     1782                    rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, GCPtrTss, GCPtrTss + cbMonitoredTss - 1,
     1783                                                     0, selmR3GuestTSSWriteHandler,
     1784                                                     "selmRCGuestTSSWriteHandler", 0, "Guest TSS write access handler");
     1785                    if (RT_FAILURE(rc))
     1786                    {
     1787                        STAM_PROFILE_STOP(&pVM->selm.s.StatUpdateFromCPUM, a);
     1788                        return rc;
     1789                    }
     1790                }
     1791# else
    17181792                STAM_PROFILE_STOP(&pVM->selm.s.StatUpdateFromCPUM, a);
    17191793                return rc;
    1720             }
    1721 
     1794# endif
     1795           }
     1796#endif
    17221797            /* Update saved Guest TSS info. */
    17231798            pVM->selm.s.GCPtrGuestTss       = GCPtrTss;
     
    18881963VMMR3DECL(bool) SELMR3CheckTSS(PVM pVM)
    18891964{
    1890 #ifdef VBOX_STRICT
     1965#if defined(VBOX_STRICT) && defined(SELM_TRACK_GUEST_TSS_CHANGES)
    18911966    PVMCPU pVCpu = VMMGetCpu(pVM);
    18921967
     
    20192094#endif /* !VBOX_STRICT */
    20202095}
     2096
     2097# ifdef VBOX_WITH_SAFE_STR
     2098/**
     2099 * Validates the RawR0 TR shadow GDT entry
     2100 *
     2101 * @returns true if it matches.
     2102 * @returns false and assertions on mismatch..
     2103 * @param   pVM     Pointer to the VM.
     2104 */
     2105VMMR3DECL(bool) SELMR3CheckShadowTR(PVM pVM)
     2106{
     2107#  ifdef VBOX_STRICT
     2108    PX86DESC paGdt = pVM->selm.s.paGdtR3;
     2109
     2110    /*
     2111     * TSS descriptor
     2112     */
     2113    PX86DESC pDesc = &paGdt[pVM->selm.s.aHyperSel[SELM_HYPER_SEL_TSS] >> 3];
     2114    RTRCPTR RCPtrTSS = VM_RC_ADDR(pVM, &pVM->selm.s.Tss);
     2115
     2116    if (    pDesc->Gen.u16BaseLow      != RT_LOWORD(RCPtrTSS)
     2117        ||  pDesc->Gen.u8BaseHigh1     != RT_BYTE3(RCPtrTSS)
     2118        ||  pDesc->Gen.u8BaseHigh2     != RT_BYTE4(RCPtrTSS)
     2119        ||  pDesc->Gen.u16LimitLow     != sizeof(VBOXTSS) - 1
     2120        ||  pDesc->Gen.u4LimitHigh     != 0
     2121        ||  (pDesc->Gen.u4Type         != X86_SEL_TYPE_SYS_386_TSS_AVAIL && pDesc->Gen.u4Type != X86_SEL_TYPE_SYS_386_TSS_BUSY)
     2122        ||  pDesc->Gen.u1DescType      != 0 /* system */
     2123        ||  pDesc->Gen.u2Dpl           != 0 /* supervisor */
     2124        ||  pDesc->Gen.u1Present       != 1
     2125        ||  pDesc->Gen.u1Available     != 0
     2126        ||  pDesc->Gen.u1Long          != 0
     2127        ||  pDesc->Gen.u1DefBig        != 0
     2128        ||  pDesc->Gen.u1Granularity   != 0 /* byte limit */
     2129        )
     2130    {
     2131        AssertFailed();
     2132        return false;
     2133    }
     2134#  endif
     2135    return true;
     2136}
     2137# endif
    20212138
    20222139#endif /* VBOX_WITH_RAW_MODE */
Note: See TracChangeset for help on using the changeset viewer.

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