VirtualBox

Changeset 17106 in vbox for trunk/src/VBox/VMM


Ignore:
Timestamp:
Feb 25, 2009 12:35:15 AM (16 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
43338
Message:

VMM,REM: Removed the single page limitation on the TSS monitoring and going over the interrupt redirection bitmap monitoring.

Location:
trunk/src/VBox/VMM
Files:
5 edited

Legend:

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

    r17035 r17106  
    14741474        Assert(   trHid.Attr.n.u4Type == X86_SEL_TYPE_SYS_286_TSS_BUSY
    14751475               || trHid.Attr.n.u4Type == X86_SEL_TYPE_SYS_386_TSS_BUSY);
    1476         if (++cbTss)
     1476        if (!++cbTss)
    14771477            cbTss = UINT32_MAX;
    14781478    }
     
    14881488
    14891489    /*
    1490      * Presently we monitor the TSS and the interrupt redirection bitmap if it's present.
    1491      * We're assuming the guest is playing nice and that the bits we're monitoring won't
    1492      * cross page boundraries. (The TSS core must be on a single page, while the bitmap
    1493      * probably doesn't need to be.)
    1494      */
    1495     uint32_t cbMonitoredTss = cbTss > sizeof(VBOXTSS) ? sizeof(VBOXTSS) : cbTss;
    1496 
    1497     /*
    1498      * We're also completely uninterested in a 16-bit TSS.
    1499      */
     1490     * Figure out the size of what need to monitor.
     1491     */
     1492    /* We're not interested in any 16-bit TSSes. */
     1493    uint32_t cbMonitoredTss = cbTss;
    15001494    if (    trHid.Attr.n.u4Type != X86_SEL_TYPE_SYS_386_TSS_AVAIL
    15011495        &&  trHid.Attr.n.u4Type != X86_SEL_TYPE_SYS_386_TSS_BUSY)
    15021496        cbMonitoredTss = 0;
    1503     AssertMsg((GCPtrTss >> PAGE_SHIFT) == ((GCPtrTss + cbMonitoredTss - 1) >> PAGE_SHIFT) || !cbMonitoredTss,
    1504               ("GCPtrTss=%RGv cbMonitoredTss=%#x - We assume everything is inside one page!\n", GCPtrTss, cbMonitoredTss));
    1505 
    1506     /*
    1507      * Check for monitor changes and apply them.
    1508      */
    1509     if (    GCPtrTss        != pVM->selm.s.GCPtrGuestTss
    1510         ||  cbMonitoredTss  != pVM->selm.s.cbMonitoredGuestTss)
    1511     {
    1512         Log(("SELMR3SyncTSS: Guest's TSS is changed to pTss=%RGv cbMonitoredTss=%08X cbGuestTss=%#08x\n",
    1513              GCPtrTss, cbMonitoredTss, pVM->selm.s.cbGuestTss));
    1514 
    1515         /* Release the old range first. */
    1516         if (pVM->selm.s.GCPtrGuestTss != RTRCPTR_MAX)
    1517         {
    1518             rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GCPtrGuestTss);
    1519             AssertRC(rc);
    1520         }
    1521 
    1522         /* Register the write handler if TS != 0. */
    1523         if (cbMonitoredTss != 0)
    1524         {
    1525             rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, GCPtrTss, GCPtrTss + cbMonitoredTss - 1,
    1526                                              0, selmR3GuestTSSWriteHandler,
    1527                                              "selmRCGuestTSSWriteHandler", 0, "Guest TSS write access handler");
    1528             if (RT_FAILURE(rc))
    1529             {
    1530                 STAM_PROFILE_STOP(&pVM->selm.s.StatUpdateFromCPUM, a);
    1531                 return rc;
    1532             }
    1533 
    1534             /* Update saved Guest TSS info. */
    1535             pVM->selm.s.GCPtrGuestTss       = GCPtrTss;
    1536             pVM->selm.s.cbMonitoredGuestTss = cbMonitoredTss;
    1537             pVM->selm.s.GCSelTss            = SelTss;
    1538         }
    1539         else
    1540         {
    1541             pVM->selm.s.GCPtrGuestTss       = RTRCPTR_MAX;
    1542             pVM->selm.s.cbMonitoredGuestTss = 0;
    1543             pVM->selm.s.GCSelTss            = 0;
    1544         }
    1545     }
    1546 
    1547     /*
    1548      * Update the ring 0 stack selector and base address.
    1549      * (Reading up to and including offIoBitmap to save effort in the VME case.)
    1550      */
     1497
     1498    pVM->selm.s.offGuestIoBitmap = 0;
    15511499    bool fNoRing1Stack = true;
    15521500    if (cbMonitoredTss)
    15531501    {
     1502        /*
     1503         * 32-bit TSS. What we're really keen on is the SS0 and ESP0 fields.
     1504         * If VME is enabled we also want to keep an eye on the interrupt
     1505         * redirection bitmap.
     1506         */
    15541507        VBOXTSS Tss;
    1555         rc = PGMPhysSimpleReadGCPtr(pVM, &Tss, GCPtrTss, RT_OFFSETOF(VBOXTSS, offIoBitmap) + sizeof(Tss.offIoBitmap));
     1508        uint32_t cr4 = CPUMGetGuestCR4(pVM);
     1509        rc = PGMPhysSimpleReadGCPtr(pVM, &Tss, GCPtrTss, RT_OFFSETOF(VBOXTSS, IntRedirBitmap));
     1510        if (    !(cr4 & X86_CR4_VME)
     1511            ||   (  VBOX_SUCCESS(rc)
     1512                 && Tss.offIoBitmap < sizeof(VBOXTSS) /* too small */
     1513                 && Tss.offIoBitmap > cbTss)          /* beyond the end */ /** @todo not sure how the partial case is handled; probably not allowed. */
     1514           )
     1515            /* No interrupt redirection bitmap, just ESP0 and SS0. */
     1516            cbMonitoredTss = RT_UOFFSETOF(VBOXTSS, padding_ss0);
     1517        else if (RT_SUCCESS(rc))
     1518        {
     1519            /*
     1520             * Everything up to and including the interrupt redirection bitmap. Unfortunately
     1521             * this can be quite a large chunk. We use to skip it earlier and just hope it
     1522             * was kind of static...
     1523             *
     1524             * Update the virtual interrupt redirection bitmap while we're here.
     1525             * (It is located in the 32 bytes before TR:offIoBitmap.)
     1526             */
     1527            cbMonitoredTss = Tss.offIoBitmap;
     1528            pVM->selm.s.offGuestIoBitmap = Tss.offIoBitmap;
     1529
     1530            uint32_t offRedirBitmap = Tss.offIoBitmap - sizeof(Tss.IntRedirBitmap);
     1531            rc = PGMPhysSimpleReadGCPtr(pVM, &pVM->selm.s.Tss.IntRedirBitmap,
     1532                                        GCPtrTss + offRedirBitmap, sizeof(Tss.IntRedirBitmap));
     1533            AssertRC(rc);
     1534            /** @todo memset the bitmap on failure? */
     1535            Log2(("Redirection bitmap:\n"));
     1536            Log2(("%.*Rhxd\n", sizeof(Tss.IntRedirBitmap), &pVM->selm.s.Tss.IntRedirBitmap));
     1537        }
     1538        else
     1539        {
     1540            cbMonitoredTss = RT_OFFSETOF(VBOXTSS, IntRedirBitmap);
     1541            pVM->selm.s.offGuestIoBitmap = 0;
     1542            /** @todo memset the bitmap? */
     1543        }
     1544
     1545        /*
     1546         * Update the ring 0 stack selector and base address.
     1547         */
    15561548        if (RT_SUCCESS(rc))
    15571549        {
     
    15761568            AssertMsg(!(Tss.ss0 & 3), ("ring-1 leak into TSS.SS0? %04X:%08X\n", Tss.ss0, Tss.esp0));
    15771569
    1578 
    15791570            /* Update our TSS structure for the guest's ring 1 stack */
    15801571            selmSetRing1Stack(pVM, Tss.ss0 | 1, Tss.esp0);
    15811572            pVM->selm.s.fSyncTSSRing0Stack = fNoRing1Stack = false;
    1582 
    1583             /*
    1584              * Should we sync the virtual interrupt redirection bitmap as well?
    1585              */
    1586             if (CPUMGetGuestCR4(pVM) & X86_CR4_VME)
    1587             {
    1588                 /* Make sure the io bitmap offset is valid; anything less than sizeof(VBOXTSS) means there's none. */
    1589                 if (Tss.offIoBitmap < RT_OFFSETOF(VBOXTSS, IntRedirBitmap) + sizeof(Tss.IntRedirBitmap))
    1590                 {
    1591                     Log(("Invalid io bitmap offset detected (%x)!\n", Tss.offIoBitmap));
    1592                     Tss.offIoBitmap = RT_OFFSETOF(VBOXTSS, IntRedirBitmap) + sizeof(Tss.IntRedirBitmap);
    1593                 }
    1594 
    1595                 uint32_t offRedirBitmap = Tss.offIoBitmap - sizeof(Tss.IntRedirBitmap);
    1596 
    1597                 /** @todo not sure how the partial case is handled; probably not allowed */
    1598                 if (offRedirBitmap + sizeof(Tss.IntRedirBitmap) <= pVM->selm.s.cbGuestTss)
    1599                 {
    1600                     rc = PGMPhysSimpleReadGCPtr(pVM, &pVM->selm.s.Tss.IntRedirBitmap, GCPtrTss + offRedirBitmap, sizeof(Tss.IntRedirBitmap));
    1601                     AssertRC(rc);
    1602                     Log2(("Redirection bitmap:\n"));
    1603                     Log2(("%.*Rhxd\n", sizeof(Tss.IntRedirBitmap), &pVM->selm.s.Tss.IntRedirBitmap));
    1604                 }
    1605             }
    1606         }
    1607     }
    1608 
    1609     /*
    1610      * Flush the ring-1 stack and the direct syscall dispatching if we cannot obtain SS0:ESP0.
     1573        }
     1574    }
     1575
     1576    /*
     1577     * Flush the ring-1 stack and the direct syscall dispatching if we
     1578     * cannot obtain SS0:ESP0.
    16111579     */
    16121580    if (fNoRing1Stack)
     
    16181586        TRPMR3SetGuestTrapHandler(pVM, 0x2E, TRPM_INVALID_HANDLER);
    16191587        TRPMR3SetGuestTrapHandler(pVM, 0x80, TRPM_INVALID_HANDLER);
     1588    }
     1589
     1590    /*
     1591     * Check for monitor changes and apply them.
     1592     */
     1593    if (    GCPtrTss        != pVM->selm.s.GCPtrGuestTss
     1594        ||  cbMonitoredTss  != pVM->selm.s.cbMonitoredGuestTss)
     1595    {
     1596        Log(("SELMR3SyncTSS: Guest's TSS is changed to pTss=%RGv cbMonitoredTss=%08X cbGuestTss=%#08x\n",
     1597             GCPtrTss, cbMonitoredTss, pVM->selm.s.cbGuestTss));
     1598
     1599        /* Release the old range first. */
     1600        if (pVM->selm.s.GCPtrGuestTss != RTRCPTR_MAX)
     1601        {
     1602            rc = PGMHandlerVirtualDeregister(pVM, pVM->selm.s.GCPtrGuestTss);
     1603            AssertRC(rc);
     1604        }
     1605
     1606        /* Register the write handler if TS != 0. */
     1607        if (cbMonitoredTss != 0)
     1608        {
     1609            rc = PGMR3HandlerVirtualRegister(pVM, PGMVIRTHANDLERTYPE_WRITE, GCPtrTss, GCPtrTss + cbMonitoredTss - 1,
     1610                                             0, selmR3GuestTSSWriteHandler,
     1611                                             "selmRCGuestTSSWriteHandler", 0, "Guest TSS write access handler");
     1612            if (RT_FAILURE(rc))
     1613            {
     1614                STAM_PROFILE_STOP(&pVM->selm.s.StatUpdateFromCPUM, a);
     1615                return rc;
     1616            }
     1617
     1618            /* Update saved Guest TSS info. */
     1619            pVM->selm.s.GCPtrGuestTss       = GCPtrTss;
     1620            pVM->selm.s.cbMonitoredGuestTss = cbMonitoredTss;
     1621            pVM->selm.s.GCSelTss            = SelTss;
     1622        }
     1623        else
     1624        {
     1625            pVM->selm.s.GCPtrGuestTss       = RTRCPTR_MAX;
     1626            pVM->selm.s.cbMonitoredGuestTss = 0;
     1627            pVM->selm.s.GCSelTss            = 0;
     1628        }
    16201629    }
    16211630
     
    17931802                     || trHid.Attr.n.u4Type == X86_SEL_TYPE_SYS_386_TSS_BUSY,
    17941803                     false);
    1795         if (++cbTss)
     1804        if (!++cbTss)
    17961805            cbTss = UINT32_MAX;
    17971806    }
     
    18171826                    false);
    18181827
    1819     /*
    1820      * Cap the TSS size, see SELMR3SyncTSS for details.
    1821      */
    1822     uint32_t cbMonitoredTss = cbTss > sizeof(VBOXTSS) ? sizeof(VBOXTSS) : cbTss;
    1823     AssertMsg((GCPtrTss >> PAGE_SHIFT) == ((GCPtrTss + cbMonitoredTss - 1) >> PAGE_SHIFT) || !cbMonitoredTss,
    1824               ("GCPtrTss=%RGv cbMonitoredTss=%#x - We assume everything is inside one page!\n", GCPtrTss, cbMonitoredTss));
    1825     AssertMsgReturn(pVM->selm.s.cbMonitoredGuestTss == cbMonitoredTss, ("%#x %#x\n", pVM->selm.s.cbMonitoredGuestTss, cbMonitoredTss), false);
    1826 
    1827     /*
    1828      * Check SS0 and ESP0.
    1829      */
    1830     if (    cbMonitoredTss
    1831         &&  !pVM->selm.s.fSyncTSSRing0Stack)
    1832     {
    1833         RTGCPTR     GCPtrGuestTSS = pVM->selm.s.GCPtrGuestTss;
    1834         uint32_t    ESPR0;
    1835         int rc = PGMPhysSimpleReadGCPtr(pVM, &ESPR0, GCPtrGuestTSS + RT_OFFSETOF(VBOXTSS, esp0), sizeof(ESPR0));
    1836         if (RT_SUCCESS(rc))
    1837         {
    1838             RTSEL   SelSS0;
    1839             rc = PGMPhysSimpleReadGCPtr(pVM, &SelSS0, GCPtrGuestTSS + RT_OFFSETOF(VBOXTSS, ss0), sizeof(SelSS0));
     1828
     1829    /*
     1830     * Figure out the size of what need to monitor.
     1831     */
     1832    bool fNoRing1Stack = true;
     1833    /* We're not interested in any 16-bit TSSes. */
     1834    uint32_t cbMonitoredTss = cbTss;
     1835    if (    trHid.Attr.n.u4Type != X86_SEL_TYPE_SYS_386_TSS_AVAIL
     1836        &&  trHid.Attr.n.u4Type != X86_SEL_TYPE_SYS_386_TSS_BUSY)
     1837        cbMonitoredTss = 0;
     1838    if (cbMonitoredTss)
     1839    {
     1840        VBOXTSS Tss;
     1841        uint32_t cr4 = CPUMGetGuestCR4(pVM);
     1842        int rc = PGMPhysSimpleReadGCPtr(pVM, &Tss, GCPtrTss, RT_OFFSETOF(VBOXTSS, IntRedirBitmap));
     1843        AssertReturn(   rc == VINF_SUCCESS
     1844                        /* Happends early in XP boot during page table switching. */
     1845                     || (   (rc == VERR_PAGE_TABLE_NOT_PRESENT || rc == VERR_PAGE_NOT_PRESENT)
     1846                         && !(CPUMGetGuestEFlags(pVM) & X86_EFL_IF)),
     1847                     false);
     1848        if (    !(cr4 & X86_CR4_VME)
     1849            ||   (  VBOX_SUCCESS(rc)
     1850                 && Tss.offIoBitmap < sizeof(VBOXTSS) /* too small */
     1851                 && Tss.offIoBitmap > cbTss)
     1852           )
     1853            cbMonitoredTss = RT_UOFFSETOF(VBOXTSS, padding_ss0);
     1854        else if (RT_SUCCESS(rc))
     1855        {
     1856            cbMonitoredTss = Tss.offIoBitmap;
     1857            AssertMsgReturn(pVM->selm.s.offGuestIoBitmap == Tss.offIoBitmap,
     1858                            ("#x %#x\n", pVM->selm.s.offGuestIoBitmap, Tss.offIoBitmap),
     1859                            false);
     1860
     1861            /* check the bitmap */
     1862            uint32_t offRedirBitmap = Tss.offIoBitmap - sizeof(Tss.IntRedirBitmap);
     1863            rc = PGMPhysSimpleReadGCPtr(pVM, &Tss.IntRedirBitmap,
     1864                                        GCPtrTss + offRedirBitmap, sizeof(Tss.IntRedirBitmap));
    18401865            AssertRCReturn(rc, false);
    1841 
    1842             if (    ESPR0 != pVM->selm.s.Tss.esp1
    1843                 ||  SelSS0 != (pVM->selm.s.Tss.ss1 & ~1))
     1866            AssertMsgReturn(!memcmp(&Tss.IntRedirBitmap[0], &pVM->selm.s.Tss.IntRedirBitmap[0], sizeof(Tss.IntRedirBitmap)),
     1867                            ("offIoBitmap=%#x cbTss=%#x\n"
     1868                             " Guest: %.32Rhxs\n"
     1869                             "Shadow: %.32Rhxs\n",
     1870                             Tss.offIoBitmap, cbTss,
     1871                             &Tss.IntRedirBitmap[0],
     1872                             &pVM->selm.s.Tss.IntRedirBitmap[0]),
     1873                            false);
     1874        }
     1875        else
     1876            cbMonitoredTss = RT_OFFSETOF(VBOXTSS, IntRedirBitmap);
     1877
     1878        /*
     1879         * Check SS0 and ESP0.
     1880         */
     1881        if (    !pVM->selm.s.fSyncTSSRing0Stack
     1882            &&  RT_SUCCESS(rc))
     1883        {
     1884            if (    Tss.esp0 != pVM->selm.s.Tss.esp1
     1885                ||  Tss.ss0  != (pVM->selm.s.Tss.ss1 & ~1))
    18441886            {
    18451887                RTGCPHYS GCPhys;
    1846                 rc = PGMGstGetPage(pVM, GCPtrGuestTSS, NULL, &GCPhys); AssertRC(rc);
     1888                rc = PGMGstGetPage(pVM, GCPtrTss, NULL, &GCPhys); AssertRC(rc);
    18471889                AssertMsgFailed(("TSS out of sync!! (%04X:%08X vs %04X:%08X (guest)) Tss=%RGv Phys=%RGp\n",
    1848                                  (pVM->selm.s.Tss.ss1 & ~1), pVM->selm.s.Tss.esp1, SelSS0, ESPR0, GCPtrGuestTSS, GCPhys));
     1890                                 (pVM->selm.s.Tss.ss1 & ~1), pVM->selm.s.Tss.esp1,
     1891                                 Tss.ss1, Tss.esp1, GCPtrTss, GCPhys));
    18491892                return false;
    18501893            }
    18511894        }
    1852         else
    1853             /* Happens during early Windows XP boot when it is switching page tables. */
    1854             AssertReturn(rc == VINF_SUCCESS || ((rc == VERR_PAGE_TABLE_NOT_PRESENT || rc == VERR_PAGE_NOT_PRESENT) && !(CPUMGetGuestEFlags(pVM) & X86_EFL_IF)),
    1855                          false);
    1856     }
    1857     else if (!cbMonitoredTss)
     1895        AssertMsgReturn(pVM->selm.s.cbMonitoredGuestTss == cbMonitoredTss, ("%#x %#x\n", pVM->selm.s.cbMonitoredGuestTss, cbMonitoredTss), false);
     1896    }
     1897    else
    18581898    {
    18591899        AssertMsgReturn(pVM->selm.s.Tss.ss1 == 0 && pVM->selm.s.Tss.esp1 == 0, ("%04x:%08x\n", pVM->selm.s.Tss.ss1, pVM->selm.s.Tss.esp1), false);
    18601900        AssertReturn(!pVM->selm.s.fSyncTSSRing0Stack, false);
    1861     }
     1901        AssertMsgReturn(pVM->selm.s.cbMonitoredGuestTss == cbMonitoredTss, ("%#x %#x\n", pVM->selm.s.cbMonitoredGuestTss, cbMonitoredTss), false);
     1902    }
     1903
     1904
     1905
    18621906    return true;
    18631907
  • trunk/src/VBox/VMM/SELMInternal.h

    r17035 r17106  
    140140     * Contains RTSEL_MAX if not set. */
    141141    RTSEL                   GCSelTss;
     142    /** The last known offset of the I/O bitmap.
     143     * This is only used if we monitor the bitmap. */
     144    uint16_t                offGuestIoBitmap;
    142145
    143146    /** Indicates that the Guest GDT access handler have been registered. */
     
    149152    /** Indicates whether the TSS stack selector & base address need to be refreshed.  */
    150153    bool                    fSyncTSSRing0Stack;
    151     /** alignment . */
    152     RTUINT                  uPadding2;
     154    bool                    fPadding2[1+2];
    153155
    154156    /** SELMR3UpdateFromCPUM() profiling. */
  • trunk/src/VBox/VMM/VMMAll/CPUMAllRegs.cpp

    r17035 r17106  
    640640    PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM);
    641641
    642     if (    (cr4                   & (X86_CR4_PGE | X86_CR4_PAE | X86_CR4_PSE))
     642    if (    (cr4                 & (X86_CR4_PGE | X86_CR4_PAE | X86_CR4_PSE))
    643643        !=  (pCpumCpu->Guest.cr4 & (X86_CR4_PGE | X86_CR4_PAE | X86_CR4_PSE)))
    644644        pCpumCpu->fChanged |= CPUM_CHANGED_GLOBAL_TLB_FLUSH;
  • trunk/src/VBox/VMM/VMMAll/EMAll.cpp

    r15635 r17106  
    20942094        oldval = CPUMGetGuestCR4(pVM);
    20952095        rc = CPUMSetGuestCR4(pVM, val); AssertRC(rc);
    2096         val   = CPUMGetGuestCR4(pVM);
    2097 
     2096        val = CPUMGetGuestCR4(pVM);
     2097
     2098        /* Illegal to disable PAE when long mode is active. (AMD Arch. Programmer's Manual Volume 2: Table 14-5) */
    20982099        msrEFER = CPUMGetGuestEFER(pVM);
    2099         /* Illegal to disable PAE when long mode is active. (AMD Arch. Programmer's Manual Volume 2: Table 14-5) */
    21002100        if (    (msrEFER & MSR_K6_EFER_LMA)
    21012101            &&  (oldval & X86_CR4_PAE)
    21022102            &&  !(val & X86_CR4_PAE))
    21032103        {
    2104             return VERR_EM_INTERPRETER; /* @todo generate #GP(0) */
     2104            return VERR_EM_INTERPRETER; /** @todo generate #GP(0) */
    21052105        }
    21062106
     
    21122112            AssertRCReturn(rc, rc);
    21132113        }
     2114
     2115        /* Feeling extremely lazy. */
    21142116# ifdef IN_RC
    2115         /* Feeling extremely lazy. */
    21162117        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))
    21172118            !=  (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)))
     
    21212122        }
    21222123# endif
     2124        if ((val ^ oldval) & X86_CR4_VME)
     2125            VM_FF_SET(pVM, VM_FF_SELM_SYNC_TSS);
     2126
    21232127        return PGMChangeMode(pVM, CPUMGetGuestCR0(pVM), CPUMGetGuestCR4(pVM), CPUMGetGuestEFER(pVM));
    21242128
  • trunk/src/VBox/VMM/VMMGC/SELMGC.cpp

    r17035 r17106  
    255255
    256256/**
     257 * Read wrapper used by selmRCGuestTSSWriteHandler.
     258 * @returns VBox status code (appropriate for trap handling and GC return).
     259 * @param   pVM         The VM handle
     260 * @param   pvDst       Where to put the bits we read.
     261 * @param   pvSrc       Guest address to read from.
     262 * @param   cb          The number of bytes to read.
     263 */
     264DECLINLINE(int) selmRCReadTssBits(PVM pVM, void *pvDst, void const *pvSrc, size_t cb)
     265{
     266    int rc = MMGCRamRead(pVM, pvDst, (void *)pvSrc, cb);
     267    if (RT_SUCCESS(rc))
     268        return VINF_SUCCESS;
     269
     270    /** @todo use different fallback?    */
     271    rc = PGMPrefetchPage(pVM, (uintptr_t)pvSrc);
     272    AssertMsg(rc == VINF_SUCCESS, ("PGMPrefetchPage %p failed with %Rrc\n", &pvSrc, rc));
     273    if (rc == VINF_SUCCESS)
     274    {
     275        rc = MMGCRamRead(pVM, pvDst, (void *)pvSrc, cb);
     276        AssertMsg(rc == VINF_SUCCESS, ("MMGCRamRead %p failed with %Rrc\n", &pvSrc, rc));
     277    }
     278    return rc;
     279}
     280
     281/**
    257282 * \#PF Virtual Handler callback for Guest write access to the Guest's own current TSS.
    258283 *
     
    271296
    272297    /*
    273      * Try emulate the access and compare the R0 ss:esp with the shadow tss values.
    274      *
    275      * Note, that it's safe to access the TSS after a successfull instruction emulation,
    276      * even if the stuff that was changed wasn't the ss0 or esp0 bits. The CPU insists
    277      * on the TSS being all one physical page, so ASSUMING that we're not trapping
    278      * I/O map accesses this is safe.
     298     * Try emulate the access.
    279299     */
    280300    uint32_t cb;
     
    282302    if (RT_SUCCESS(rc) && cb)
    283303    {
    284         PCVBOXTSS pGuestTSS = (PVBOXTSS)pVM->selm.s.GCPtrGuestTss;
    285         if (    pGuestTSS->esp0 !=  pVM->selm.s.Tss.esp1
    286             ||  pGuestTSS->ss0  != (pVM->selm.s.Tss.ss1 & ~1)) /* undo raw-r0 */
     304        rc = VINF_SUCCESS;
     305
     306        /*
     307         * If it's on the same page as the esp0 and ss0 fields or actually one of them,
     308         * then check if any of these has changed.
     309         */
     310        PCVBOXTSS pGuestTss = (PVBOXTSS)pVM->selm.s.GCPtrGuestTss;
     311        if (    PAGE_ADDRESS(&pGuestTss->esp0) == PAGE_ADDRESS(&pGuestTss->padding_ss0)
     312            &&  PAGE_ADDRESS(&pGuestTss->esp0) == PAGE_ADDRESS((uint8_t *)pGuestTss + offRange)
     313            &&  (    pGuestTss->esp0 !=  pVM->selm.s.Tss.esp1
     314                 ||  pGuestTss->ss0  != (pVM->selm.s.Tss.ss1 & ~1)) /* undo raw-r0 */
     315           )
    287316        {
    288317            Log(("selmRCGuestTSSWriteHandler: R0 stack: %RTsel:%RGv -> %RTsel:%RGv\n",
    289                  (RTSEL)(pVM->selm.s.Tss.ss1 & ~1), (RTGCPTR)pVM->selm.s.Tss.esp1, (RTSEL)pGuestTSS->ss0, (RTGCPTR)pGuestTSS->esp0));
    290             pVM->selm.s.Tss.esp1 = pGuestTSS->esp0;
    291             pVM->selm.s.Tss.ss1 = pGuestTSS->ss0 | 1;
     318                 (RTSEL)(pVM->selm.s.Tss.ss1 & ~1), (RTGCPTR)pVM->selm.s.Tss.esp1, (RTSEL)pGuestTss->ss0, (RTGCPTR)pGuestTss->esp0));
     319            pVM->selm.s.Tss.esp1 = pGuestTss->esp0;
     320            pVM->selm.s.Tss.ss1  = pGuestTss->ss0 | 1;
    292321            STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestTSSHandledChanged);
    293322        }
    294         if (CPUMGetGuestCR4(pVM) & X86_CR4_VME)
    295         {
    296             uint32_t offIntRedirBitmap = pGuestTSS->offIoBitmap - sizeof(pVM->selm.s.Tss.IntRedirBitmap);
    297 
    298             /** @todo not sure how the partial case is handled; probably not allowed */
    299             if (   offIntRedirBitmap <= offRange
    300                 && offIntRedirBitmap + sizeof(pVM->selm.s.Tss.IntRedirBitmap) >= offRange + cb
    301                 && offIntRedirBitmap + sizeof(pVM->selm.s.Tss.IntRedirBitmap) <= pVM->selm.s.cbGuestTss)
     323        /* Handle misaligned TSS in a safe manner (just in case). */
     324        else if (   offRange >= RT_UOFFSETOF(VBOXTSS, esp0)
     325                 && offRange < RT_UOFFSETOF(VBOXTSS, padding_ss0))
     326        {
     327            struct
    302328            {
    303                 Log(("offIoBitmap=%x offIntRedirBitmap=%x cbTSS=%x\n", pGuestTSS->offIoBitmap, offIntRedirBitmap, pVM->selm.s.cbGuestTss));
    304                 /** @todo only update the changed part. */
    305                 for (uint32_t i = 0; i < sizeof(pVM->selm.s.Tss.IntRedirBitmap) / 8;i++)
     329                uint32_t esp0;
     330                uint16_t ss0;
     331                uint16_t padding_ss0;
     332            } s;
     333            AssertCompileSize(s, 8);
     334            rc = selmRCReadTssBits(pVM, &s, &pGuestTss->esp0, sizeof(s));
     335            if (    rc == VINF_SUCCESS
     336                &&  (    s.esp0 !=  pVM->selm.s.Tss.esp1
     337                     ||  s.ss0  != (pVM->selm.s.Tss.ss1 & ~1)) /* undo raw-r0 */
     338               )
     339            {
     340                Log(("selmRCGuestTSSWriteHandler: R0 stack: %RTsel:%RGv -> %RTsel:%RGv\n",
     341                     (RTSEL)(pVM->selm.s.Tss.ss1 & ~1), (RTGCPTR)pVM->selm.s.Tss.esp1, (RTSEL)s.ss0, (RTGCPTR)s.esp0));
     342                pVM->selm.s.Tss.esp1 = s.esp0;
     343                pVM->selm.s.Tss.ss1  = s.ss0 | 1;
     344                STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestTSSHandledChanged);
     345            }
     346        }
     347
     348        /*
     349         * If VME is enabled we need to check if the interrupt redirection bitmap
     350         * needs updating.
     351         */
     352        if (    offRange >= RT_UOFFSETOF(VBOXTSS, offIoBitmap)
     353            &&  (CPUMGetGuestCR4(pVM) & X86_CR4_VME))
     354        {
     355            if (offRange - RT_UOFFSETOF(VBOXTSS, offIoBitmap) < sizeof(pGuestTss->offIoBitmap))
     356            {
     357                uint16_t offIoBitmap = pGuestTss->offIoBitmap;
     358                if (offIoBitmap != pVM->selm.s.offGuestIoBitmap)
    306359                {
    307                     rc = MMGCRamRead(pVM, &pVM->selm.s.Tss.IntRedirBitmap[i * 8], (uint8_t *)pGuestTSS + offIntRedirBitmap + i * 8, 8);
    308                     if (RT_FAILURE(rc))
     360                    Log(("TSS offIoBitmap changed: old=%#x new=%#x -> resync in ring-3\n", pVM->selm.s.offGuestIoBitmap, offIoBitmap));
     361                    VM_FF_SET(pVM, VM_FF_SELM_SYNC_TSS);
     362                    VM_FF_SET(pVM, VM_FF_TO_R3);
     363                }
     364                else
     365                    Log(("TSS offIoBitmap: old=%#x new=%#x [unchanged]\n", pVM->selm.s.offGuestIoBitmap, offIoBitmap));
     366            }
     367            else
     368            {
     369                /** @todo not sure how the partial case is handled; probably not allowed */
     370                uint32_t offIntRedirBitmap = pVM->selm.s.offGuestIoBitmap - sizeof(pVM->selm.s.Tss.IntRedirBitmap);
     371                if (   offIntRedirBitmap <= offRange
     372                    && offIntRedirBitmap + sizeof(pVM->selm.s.Tss.IntRedirBitmap) >= offRange + cb
     373                    && offIntRedirBitmap + sizeof(pVM->selm.s.Tss.IntRedirBitmap) <= pVM->selm.s.cbGuestTss)
     374                {
     375                    Log(("TSS IntRedirBitmap Changed: offIoBitmap=%x offIntRedirBitmap=%x cbTSS=%x offRange=%x cb=%x\n",
     376                         pVM->selm.s.offGuestIoBitmap, offIntRedirBitmap, pVM->selm.s.cbGuestTss, offRange, cb));
     377
     378                    /** @todo only update the changed part. */
     379                    for (uint32_t i = 0; i < sizeof(pVM->selm.s.Tss.IntRedirBitmap) / 8; i++)
    309380                    {
    310                         /* Shadow page table might be out of sync */
    311                         rc = PGMPrefetchPage(pVM, (RTGCPTR)(RTRCUINTPTR)((uint8_t *)pGuestTSS + offIntRedirBitmap + i*8));
    312                         if (RT_FAILURE(rc))
    313                         {
    314                             AssertMsg(rc == VINF_SUCCESS, ("PGMPrefetchPage %RGv failed with %Rrc\n", (RTGCPTR)((uintptr_t)pGuestTSS + offIntRedirBitmap + i*8), rc));
     381                        rc = selmRCReadTssBits(pVM, &pVM->selm.s.Tss.IntRedirBitmap[i * 8],
     382                                               (uint8_t *)pGuestTss + offIntRedirBitmap + i * 8, 8);
     383                        if (rc != VINF_SUCCESS)
    315384                            break;
    316                         }
    317                         rc = MMGCRamRead(pVM, &pVM->selm.s.Tss.IntRedirBitmap[i * 8], (uint8_t *)pGuestTSS + offIntRedirBitmap + i * 8, 8);
    318385                    }
    319                     AssertMsg(rc == VINF_SUCCESS, ("MMGCRamRead %RGv failed with %Rrc\n", (RTGCPTR)((uintptr_t)pGuestTSS + offIntRedirBitmap + i * 8), rc));
     386                    STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestTSSRedir);
    320387                }
    321                 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestTSSRedir);
    322388            }
    323389        }
     390
     391        /* Return to ring-3 for a full resync if any of the above fails... (?) */
     392        if (rc != VINF_SUCCESS)
     393        {
     394            VM_FF_SET(pVM, VM_FF_SELM_SYNC_TSS);
     395            VM_FF_SET(pVM, VM_FF_TO_R3);
     396            if (RT_SUCCESS(rc))
     397                rc = VINF_SUCCESS;
     398        }
     399
    324400        STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestTSSHandled);
    325401    }
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