Changeset 17106 in vbox for trunk/src/VBox/VMM
- Timestamp:
- Feb 25, 2009 12:35:15 AM (16 years ago)
- svn:sync-xref-src-repo-rev:
- 43338
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/SELM.cpp
r17035 r17106 1474 1474 Assert( trHid.Attr.n.u4Type == X86_SEL_TYPE_SYS_286_TSS_BUSY 1475 1475 || trHid.Attr.n.u4Type == X86_SEL_TYPE_SYS_386_TSS_BUSY); 1476 if ( ++cbTss)1476 if (!++cbTss) 1477 1477 cbTss = UINT32_MAX; 1478 1478 } … … 1488 1488 1489 1489 /* 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; 1500 1494 if ( trHid.Attr.n.u4Type != X86_SEL_TYPE_SYS_386_TSS_AVAIL 1501 1495 && trHid.Attr.n.u4Type != X86_SEL_TYPE_SYS_386_TSS_BUSY) 1502 1496 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; 1551 1499 bool fNoRing1Stack = true; 1552 1500 if (cbMonitoredTss) 1553 1501 { 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 */ 1554 1507 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 */ 1556 1548 if (RT_SUCCESS(rc)) 1557 1549 { … … 1576 1568 AssertMsg(!(Tss.ss0 & 3), ("ring-1 leak into TSS.SS0? %04X:%08X\n", Tss.ss0, Tss.esp0)); 1577 1569 1578 1579 1570 /* Update our TSS structure for the guest's ring 1 stack */ 1580 1571 selmSetRing1Stack(pVM, Tss.ss0 | 1, Tss.esp0); 1581 1572 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. 1611 1579 */ 1612 1580 if (fNoRing1Stack) … … 1618 1586 TRPMR3SetGuestTrapHandler(pVM, 0x2E, TRPM_INVALID_HANDLER); 1619 1587 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 } 1620 1629 } 1621 1630 … … 1793 1802 || trHid.Attr.n.u4Type == X86_SEL_TYPE_SYS_386_TSS_BUSY, 1794 1803 false); 1795 if ( ++cbTss)1804 if (!++cbTss) 1796 1805 cbTss = UINT32_MAX; 1797 1806 } … … 1817 1826 false); 1818 1827 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)); 1840 1865 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)) 1844 1886 { 1845 1887 RTGCPHYS GCPhys; 1846 rc = PGMGstGetPage(pVM, GCPtr GuestTSS, NULL, &GCPhys); AssertRC(rc);1888 rc = PGMGstGetPage(pVM, GCPtrTss, NULL, &GCPhys); AssertRC(rc); 1847 1889 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)); 1849 1892 return false; 1850 1893 } 1851 1894 } 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 1858 1898 { 1859 1899 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); 1860 1900 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 1862 1906 return true; 1863 1907 -
trunk/src/VBox/VMM/SELMInternal.h
r17035 r17106 140 140 * Contains RTSEL_MAX if not set. */ 141 141 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; 142 145 143 146 /** Indicates that the Guest GDT access handler have been registered. */ … … 149 152 /** Indicates whether the TSS stack selector & base address need to be refreshed. */ 150 153 bool fSyncTSSRing0Stack; 151 /** alignment . */ 152 RTUINT uPadding2; 154 bool fPadding2[1+2]; 153 155 154 156 /** SELMR3UpdateFromCPUM() profiling. */ -
trunk/src/VBox/VMM/VMMAll/CPUMAllRegs.cpp
r17035 r17106 640 640 PCPUMCPU pCpumCpu = cpumGetCpumCpu(pVM); 641 641 642 if ( (cr4 642 if ( (cr4 & (X86_CR4_PGE | X86_CR4_PAE | X86_CR4_PSE)) 643 643 != (pCpumCpu->Guest.cr4 & (X86_CR4_PGE | X86_CR4_PAE | X86_CR4_PSE))) 644 644 pCpumCpu->fChanged |= CPUM_CHANGED_GLOBAL_TLB_FLUSH; -
trunk/src/VBox/VMM/VMMAll/EMAll.cpp
r15635 r17106 2094 2094 oldval = CPUMGetGuestCR4(pVM); 2095 2095 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) */ 2098 2099 msrEFER = CPUMGetGuestEFER(pVM); 2099 /* Illegal to disable PAE when long mode is active. (AMD Arch. Programmer's Manual Volume 2: Table 14-5) */2100 2100 if ( (msrEFER & MSR_K6_EFER_LMA) 2101 2101 && (oldval & X86_CR4_PAE) 2102 2102 && !(val & X86_CR4_PAE)) 2103 2103 { 2104 return VERR_EM_INTERPRETER; /* @todo generate #GP(0) */2104 return VERR_EM_INTERPRETER; /** @todo generate #GP(0) */ 2105 2105 } 2106 2106 … … 2112 2112 AssertRCReturn(rc, rc); 2113 2113 } 2114 2115 /* Feeling extremely lazy. */ 2114 2116 # ifdef IN_RC 2115 /* Feeling extremely lazy. */2116 2117 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)) 2117 2118 != (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))) … … 2121 2122 } 2122 2123 # endif 2124 if ((val ^ oldval) & X86_CR4_VME) 2125 VM_FF_SET(pVM, VM_FF_SELM_SYNC_TSS); 2126 2123 2127 return PGMChangeMode(pVM, CPUMGetGuestCR0(pVM), CPUMGetGuestCR4(pVM), CPUMGetGuestEFER(pVM)); 2124 2128 -
trunk/src/VBox/VMM/VMMGC/SELMGC.cpp
r17035 r17106 255 255 256 256 /** 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 */ 264 DECLINLINE(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 /** 257 282 * \#PF Virtual Handler callback for Guest write access to the Guest's own current TSS. 258 283 * … … 271 296 272 297 /* 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. 279 299 */ 280 300 uint32_t cb; … … 282 302 if (RT_SUCCESS(rc) && cb) 283 303 { 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 ) 287 316 { 288 317 Log(("selmRCGuestTSSWriteHandler: R0 stack: %RTsel:%RGv -> %RTsel:%RGv\n", 289 (RTSEL)(pVM->selm.s.Tss.ss1 & ~1), (RTGCPTR)pVM->selm.s.Tss.esp1, (RTSEL)pGuestT SS->ss0, (RTGCPTR)pGuestTSS->esp0));290 pVM->selm.s.Tss.esp1 = pGuestT SS->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; 292 321 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestTSSHandledChanged); 293 322 } 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 302 328 { 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) 306 359 { 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++) 309 380 { 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) 315 384 break; 316 }317 rc = MMGCRamRead(pVM, &pVM->selm.s.Tss.IntRedirBitmap[i * 8], (uint8_t *)pGuestTSS + offIntRedirBitmap + i * 8, 8);318 385 } 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); 320 387 } 321 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestTSSRedir);322 388 } 323 389 } 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 324 400 STAM_COUNTER_INC(&pVM->selm.s.StatRCWriteGuestTSSHandled); 325 401 }
Note:
See TracChangeset
for help on using the changeset viewer.