Changeset 20328 in vbox for trunk/src/VBox/VMM/VMMR0
- Timestamp:
- Jun 5, 2009 1:23:52 PM (16 years ago)
- svn:sync-xref-src-repo-rev:
- 48232
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR0/HWSVMR0.cpp
r20325 r20328 53 53 * Internal Functions * 54 54 *******************************************************************************/ 55 static int SVMR0InterpretInvpg(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t uASID); 55 static int svmR0InterpretInvpg(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t uASID); 56 static int svmR0ReplaceTprInstr(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx); 56 57 57 58 /******************************************************************************* … … 1712 1713 if (uFaultAddress == GCPhysApicBase + 0x80) 1713 1714 { 1714 Log(("Replace TPR access at %RGv\n", pCtx->rip)); 1715 DISCPUSTATE Cpu; 1716 unsigned cbOp; 1717 rc = EMInterpretDisasOne(pVM, pVCpu, CPUMCTX2CORE(pCtx), &Cpu, &cbOp); 1718 AssertRC(rc); 1719 if ( rc == VINF_SUCCESS 1720 && Cpu.pCurInstr->opcode == OP_MOV) 1715 rc = svmR0ReplaceTprInstr(pVM, pVCpu, pCtx); 1716 if (rc == VINF_SUCCESS) 1721 1717 { 1722 uint8_t szInstr[15]; 1723 if ( cbOp == 10 1724 && (errCode & X86_TRAP_PF_RW) 1725 && Cpu.param2.flags == USE_IMMEDIATE32) 1726 { 1727 /* Found: 1728 * mov [fffe0080], immediate_dword (10 bytes) 1729 * 1730 * Replace with: 1731 * mov free_register, immediate_dword >> 4 (5 bytes) 1732 * mov cr8, free_register (4 bytes) 1733 * nop (1 byte) 1734 * 1735 */ 1736 RTGCPTR oldEip = pCtx->eip; 1737 uint32_t u32tpr = (uint32_t)Cpu.param2.parval; 1738 1739 u32tpr = (u32tpr >> 4) & 0xf; 1740 1741 /* Check if the next instruction overwrites a general purpose register. If 1742 * it does, then we can safely use it ourselves. 1743 */ 1744 pCtx->eip += cbOp; 1745 rc = EMInterpretDisasOne(pVM, pVCpu, CPUMCTX2CORE(pCtx), &Cpu, &cbOp); 1746 pCtx->eip = oldEip; 1747 if ( rc == VINF_SUCCESS 1748 && Cpu.pCurInstr->opcode == OP_MOV 1749 && Cpu.param1.flags == USE_REG_GEN32) 1750 { 1751 /* 0xB8, dword immediate = mov eax, dword immediate */ 1752 szInstr[0] = 0xB8 + Cpu.param1.base.reg_gen; 1753 szInstr[1] = (uint8_t)u32tpr; 1754 szInstr[2] = 0; 1755 szInstr[3] = 0; 1756 szInstr[4] = 0; 1757 1758 /* 0xF0, 0x0F, 0x22, 0xC0 = mov cr8, eax */ 1759 szInstr[5] = 0xF0; 1760 szInstr[6] = 0x0F; 1761 szInstr[7] = 0x22; 1762 szInstr[8] = 0xC0 | Cpu.param1.base.reg_gen; 1763 szInstr[9] = 0x90; /* nop */ 1764 1765 rc = PGMPhysSimpleWriteGCPtr(pVCpu, pCtx->rip, szInstr, 10); 1766 AssertRC(rc); 1767 1768 Log(("Acceptable write candidate!\n")); 1769 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x); 1770 goto ResumeExecution; 1771 } 1772 } 1773 else 1774 { 1775 if ( Cpu.param2.flags == USE_REG_GEN32 1776 && cbOp == 6) 1777 { 1778 RTGCPTR oldEip = pCtx->eip; 1779 RTGCPTR GCPtrTpr = (uint32_t)Cpu.param1.disp32; 1780 uint32_t uMmioReg = Cpu.param2.base.reg_gen; 1781 1782 /* Found: 1783 * mov dword [fffe0080], eax (6 bytes) 1784 * Check if next instruction is a TPR read: 1785 * mov ecx, dword [fffe0080] (5 bytes) 1786 */ 1787 pCtx->eip += cbOp; 1788 rc = EMInterpretDisasOne(pVM, pVCpu, CPUMCTX2CORE(pCtx), &Cpu, &cbOp); 1789 pCtx->eip = oldEip; 1790 if ( rc == VINF_SUCCESS 1791 && Cpu.pCurInstr->opcode == OP_MOV 1792 && Cpu.param1.flags == USE_REG_GEN32 1793 && Cpu.param2.flags == USE_DISPLACEMENT32 1794 && Cpu.param2.disp32 == (uint32_t)GCPtrTpr 1795 && cbOp == 5) 1796 { 1797 /* mov new_reg, uMmioReg */ 1798 szInstr[0] = 0x89; 1799 szInstr[1] = MAKE_MODRM(3, uMmioReg, Cpu.param1.base.reg_gen); 1800 1801 /* Let's hope the guest won't mind us trashing the source register... 1802 * shr uMmioReg, 4 1803 */ 1804 szInstr[2] = 0xC1; 1805 szInstr[3] = 0xE8 | uMmioReg; 1806 szInstr[4] = 4; 1807 1808 /* 0xF0, 0x0F, 0x22, 0xC0 = mov cr8, eax */ 1809 szInstr[5] = 0xF0; 1810 szInstr[6] = 0x0F; 1811 szInstr[7] = 0x22; 1812 szInstr[8] = 0xC0 | uMmioReg; 1813 1814 /* Two nop instructions */ 1815 szInstr[9] = 0x90; 1816 szInstr[10] = 0x90; 1817 1818 rc = PGMPhysSimpleWriteGCPtr(pVCpu, pCtx->rip, szInstr, 6+cbOp); 1819 AssertRC(rc); 1820 1821 Log(("Acceptable write candidate!\n")); 1822 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x); 1823 goto ResumeExecution; 1824 } 1825 } 1826 else 1827 if ( Cpu.param1.flags == USE_REG_GEN32 1828 && cbOp == 5) 1829 { 1830 RTGCPTR oldEip = pCtx->eip; 1831 uint32_t uMmioReg = Cpu.param1.base.reg_gen; 1832 1833 /* Found: 1834 * mov eax, dword [fffe0080] (5 bytes) 1835 * Check if next instruction is: 1836 * shr eax, 4 1837 */ 1838 pCtx->eip += cbOp; 1839 rc = EMInterpretDisasOne(pVM, pVCpu, CPUMCTX2CORE(pCtx), &Cpu, &cbOp); 1840 pCtx->eip = oldEip; 1841 if ( rc == VINF_SUCCESS 1842 && Cpu.pCurInstr->opcode == OP_SHR 1843 && Cpu.param1.flags == USE_REG_GEN32 1844 && Cpu.param1.base.reg_gen == uMmioReg 1845 && Cpu.param2.flags == USE_IMMEDIATE8 1846 && Cpu.param2.parval == 4) 1847 { 1848 /* 0xF0, 0x0F, 0x20, 0xC0 = mov eax, cr8 */ 1849 szInstr[0] = 0xF0; 1850 szInstr[1] = 0x0F; 1851 szInstr[2] = 0x20; 1852 szInstr[3] = 0xC0 | Cpu.param1.base.reg_gen; 1853 for (unsigned i = 4; i < 5+cbOp; i++) 1854 szInstr[i] = 0x90; /* nop */ 1855 1856 rc = PGMPhysSimpleWriteGCPtr(pVCpu, pCtx->rip, szInstr, 5+cbOp); 1857 AssertRC(rc); 1858 1859 Log(("Acceptable read candidate!\n")); 1860 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x); 1861 goto ResumeExecution; 1862 } 1863 } 1864 } 1718 STAM_PROFILE_ADV_STOP(&pVCpu->hwaccm.s.StatExit1, x); 1719 goto ResumeExecution; 1865 1720 } 1721 1866 1722 rc = IOMMMIOPhysHandler(pVM, errCode, CPUMCTX2CORE(pCtx), uFaultAddress); 1867 1723 if (rc == VINF_SUCCESS) … … 2004 1860 2005 1861 /* Truly a pita. Why can't SVM give the same information as VT-x? */ 2006 rc = SVMR0InterpretInvpg(pVM, pVCpu, CPUMCTX2CORE(pCtx), pVMCB->ctrl.TLBCtrl.n.u32ASID);1862 rc = svmR0InterpretInvpg(pVM, pVCpu, CPUMCTX2CORE(pCtx), pVMCB->ctrl.TLBCtrl.n.u32ASID); 2007 1863 if (rc == VINF_SUCCESS) 2008 1864 { … … 2475 2331 } 2476 2332 2333 2334 /** 2335 * Attempt to patch TPR mmio instructions 2336 * 2337 * @returns VBox status code. 2338 * @param pVM The VM to operate on. 2339 * @param pVCpu The VM CPU to operate on. 2340 * @param pCtx CPU context 2341 */ 2342 static int svmR0ReplaceTprInstr(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx) 2343 { 2344 DISCPUSTATE Cpu; 2345 unsigned cbOp; 2346 2347 Log(("Replace TPR access at %RGv\n", pCtx->rip)); 2348 2349 int rc = EMInterpretDisasOne(pVM, pVCpu, CPUMCTX2CORE(pCtx), &Cpu, &cbOp); 2350 AssertRC(rc); 2351 if ( rc == VINF_SUCCESS 2352 && Cpu.pCurInstr->opcode == OP_MOV) 2353 { 2354 uint8_t szInstr[15]; 2355 if ( cbOp == 10 2356 && Cpu.param1.flags == USE_DISPLACEMENT32 2357 && Cpu.param2.flags == USE_IMMEDIATE32) 2358 { 2359 /* Found: 2360 * mov [fffe0080], immediate_dword (10 bytes) 2361 * 2362 * Replace with: 2363 * mov free_register, immediate_dword >> 4 (5 bytes) 2364 * mov cr8, free_register (4 bytes) 2365 * nop (1 byte) 2366 * 2367 */ 2368 RTGCPTR oldEip = pCtx->eip; 2369 uint32_t u32tpr = (uint32_t)Cpu.param2.parval; 2370 2371 u32tpr = (u32tpr >> 4) & 0xf; 2372 2373 /* Check if the next instruction overwrites a general purpose register. If 2374 * it does, then we can safely use it ourselves. 2375 */ 2376 pCtx->eip += cbOp; 2377 rc = EMInterpretDisasOne(pVM, pVCpu, CPUMCTX2CORE(pCtx), &Cpu, &cbOp); 2378 pCtx->eip = oldEip; 2379 if ( rc == VINF_SUCCESS 2380 && Cpu.pCurInstr->opcode == OP_MOV 2381 && Cpu.param1.flags == USE_REG_GEN32) 2382 { 2383 /* 0xB8, dword immediate = mov eax, dword immediate */ 2384 szInstr[0] = 0xB8 + Cpu.param1.base.reg_gen; 2385 szInstr[1] = (uint8_t)u32tpr; 2386 szInstr[2] = 0; 2387 szInstr[3] = 0; 2388 szInstr[4] = 0; 2389 2390 /* 0xF0, 0x0F, 0x22, 0xC0 = mov cr8, eax */ 2391 szInstr[5] = 0xF0; 2392 szInstr[6] = 0x0F; 2393 szInstr[7] = 0x22; 2394 szInstr[8] = 0xC0 | Cpu.param1.base.reg_gen; 2395 szInstr[9] = 0x90; /* nop */ 2396 2397 rc = PGMPhysSimpleWriteGCPtr(pVCpu, pCtx->rip, szInstr, 10); 2398 AssertRC(rc); 2399 2400 Log(("Acceptable write candidate!\n")); 2401 return VINF_SUCCESS; 2402 } 2403 } 2404 else 2405 { 2406 if ( Cpu.param2.flags == USE_REG_GEN32 2407 && cbOp == 6) 2408 { 2409 RTGCPTR oldEip = pCtx->eip; 2410 RTGCPTR GCPtrTpr = (uint32_t)Cpu.param1.disp32; 2411 uint32_t uMmioReg = Cpu.param2.base.reg_gen; 2412 2413 /* Found: 2414 * mov dword [fffe0080], eax (6 bytes) 2415 * Check if next instruction is a TPR read: 2416 * mov ecx, dword [fffe0080] (5 bytes) 2417 */ 2418 pCtx->eip += cbOp; 2419 rc = EMInterpretDisasOne(pVM, pVCpu, CPUMCTX2CORE(pCtx), &Cpu, &cbOp); 2420 pCtx->eip = oldEip; 2421 if ( rc == VINF_SUCCESS 2422 && Cpu.pCurInstr->opcode == OP_MOV 2423 && Cpu.param1.flags == USE_REG_GEN32 2424 && Cpu.param2.flags == USE_DISPLACEMENT32 2425 && Cpu.param2.disp32 == (uint32_t)GCPtrTpr 2426 && cbOp == 5) 2427 { 2428 /* mov new_reg, uMmioReg */ 2429 szInstr[0] = 0x89; 2430 szInstr[1] = MAKE_MODRM(3, uMmioReg, Cpu.param1.base.reg_gen); 2431 2432 /* Let's hope the guest won't mind us trashing the source register... 2433 * shr uMmioReg, 4 2434 */ 2435 szInstr[2] = 0xC1; 2436 szInstr[3] = 0xE8 | uMmioReg; 2437 szInstr[4] = 4; 2438 2439 /* 0xF0, 0x0F, 0x22, 0xC0 = mov cr8, eax */ 2440 szInstr[5] = 0xF0; 2441 szInstr[6] = 0x0F; 2442 szInstr[7] = 0x22; 2443 szInstr[8] = 0xC0 | uMmioReg; 2444 2445 /* Two nop instructions */ 2446 szInstr[9] = 0x90; 2447 szInstr[10] = 0x90; 2448 2449 rc = PGMPhysSimpleWriteGCPtr(pVCpu, pCtx->rip, szInstr, 6+cbOp); 2450 AssertRC(rc); 2451 2452 Log(("Acceptable write candidate!\n")); 2453 return VINF_SUCCESS; 2454 } 2455 } 2456 else 2457 if ( Cpu.param1.flags == USE_REG_GEN32 2458 && cbOp == 5) 2459 { 2460 RTGCPTR oldEip = pCtx->eip; 2461 uint32_t uMmioReg = Cpu.param1.base.reg_gen; 2462 2463 /* Found: 2464 * mov eax, dword [fffe0080] (5 bytes) 2465 * Check if next instruction is: 2466 * shr eax, 4 2467 */ 2468 pCtx->eip += cbOp; 2469 rc = EMInterpretDisasOne(pVM, pVCpu, CPUMCTX2CORE(pCtx), &Cpu, &cbOp); 2470 pCtx->eip = oldEip; 2471 if ( rc == VINF_SUCCESS 2472 && Cpu.pCurInstr->opcode == OP_SHR 2473 && Cpu.param1.flags == USE_REG_GEN32 2474 && Cpu.param1.base.reg_gen == uMmioReg 2475 && Cpu.param2.flags == USE_IMMEDIATE8 2476 && Cpu.param2.parval == 4) 2477 { 2478 /* 0xF0, 0x0F, 0x20, 0xC0 = mov eax, cr8 */ 2479 szInstr[0] = 0xF0; 2480 szInstr[1] = 0x0F; 2481 szInstr[2] = 0x20; 2482 szInstr[3] = 0xC0 | Cpu.param1.base.reg_gen; 2483 for (unsigned i = 4; i < 5+cbOp; i++) 2484 szInstr[i] = 0x90; /* nop */ 2485 2486 rc = PGMPhysSimpleWriteGCPtr(pVCpu, pCtx->rip, szInstr, 5+cbOp); 2487 AssertRC(rc); 2488 2489 Log(("Acceptable read candidate!\n")); 2490 return VINF_SUCCESS; 2491 } 2492 } 2493 } 2494 } 2495 return VERR_ACCESS_DENIED; 2496 } 2497 2477 2498 /** 2478 2499 * Enters the AMD-V session … … 2581 2602 * Updates the EIP if an instruction was executed successfully. 2582 2603 */ 2583 static int SVMR0InterpretInvpg(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t uASID)2604 static int svmR0InterpretInvpg(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t uASID) 2584 2605 { 2585 2606 /*
Note:
See TracChangeset
for help on using the changeset viewer.