Changeset 21620 in vbox for trunk/src/VBox/VMM
- Timestamp:
- Jul 15, 2009 3:59:30 PM (16 years ago)
- svn:sync-xref-src-repo-rev:
- 50144
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/HWACCMInternal.h
r21210 r21620 34 34 #include <iprt/cpuset.h> 35 35 #include <iprt/mp.h> 36 #include <iprt/avl.h> 36 37 37 38 #if HC_ARCH_BITS == 64 || defined(VBOX_WITH_HYBRID_32BIT_KERNEL) || defined (VBOX_WITH_64_BITS_GUESTS) … … 179 180 HWACCMPENDINGIO_32BIT_HACK = 0x7fffffff 180 181 } HWACCMPENDINGIO; 182 183 184 typedef enum 185 { 186 HWACCMTPRINSTR_READ, 187 HWACCMTPRINSTR_READ_SHR4, 188 HWACCMTPRINSTR_WRITE_REG, 189 HWACCMTPRINSTR_WRITE_IMM, 190 HWACCMTPRINSTR_MOV, 191 /** The usual 32-bit paranoia. */ 192 HWACCMTPRINSTR_32BIT_HACK = 0x7fffffff 193 } HWACCMTPRINSTR; 194 195 typedef struct 196 { 197 /** The key is the address of patched instruction. (32 bits GC ptr) */ 198 AVLOU32NODECORE Core; 199 /** Original opcode. */ 200 uint8_t aOpcode[16]; 201 /** Instruction size. */ 202 uint32_t cbOp; 203 /** Instruction type. */ 204 HWACCMTPRINSTR enmType; 205 /** Source operand. */ 206 uint32_t uSrcOperand; 207 /** Destination operand. */ 208 uint32_t uDstOperand; 209 /** Number of times the instruction caused a fault. */ 210 uint32_t cFaults; 211 } HWACCMTPRPATCH; 212 /** Pointer to HWACCMTPRPATCH. */ 213 typedef HWACCMTPRPATCH *PHWACCMTPRPATCH; 181 214 182 215 /** … … 373 406 /** SVM feature bits from cpuid 0x8000000a */ 374 407 uint32_t u32Features; 408 409 /** 410 * AVL tree with all patches (active or disabled) sorted by guest instruction address 411 */ 412 AVLOU32TREE PatchTree; 413 414 uint32_t cPatches; 415 HWACCMTPRPATCH aPatches[64]; 375 416 } svm; 376 417 -
trunk/src/VBox/VMM/VMMR0/HWSVMR0.cpp
r21574 r21620 55 55 static int svmR0InterpretInvpg(PVM pVM, PVMCPU pVCpu, PCPUMCTXCORE pRegFrame, uint32_t uASID); 56 56 static int svmR0ReplaceTprInstr(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx); 57 static int svmR0EmulateTprVMMCall(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx); 57 58 58 59 /******************************************************************************* … … 2262 2263 break; 2263 2264 2265 case SVM_EXIT_VMMCALL: 2266 rc = svmR0EmulateTprVMMCall(pVM, pVCpu, pCtx); 2267 if (rc == VINF_SUCCESS) 2268 { 2269 goto ResumeExecution; /* rip already updated. */ 2270 } 2271 /* no break */ 2272 2264 2273 case SVM_EXIT_RSM: 2265 2274 case SVM_EXIT_INVLPGA: 2266 2275 case SVM_EXIT_VMRUN: 2267 case SVM_EXIT_VMMCALL:2268 2276 case SVM_EXIT_VMLOAD: 2269 2277 case SVM_EXIT_VMSAVE: … … 2436 2444 2437 2445 /** 2446 * Emulate simple mov tpr instruction 2447 * 2448 * @returns VBox status code. 2449 * @param pVM The VM to operate on. 2450 * @param pVCpu The VM CPU to operate on. 2451 * @param pCtx CPU context 2452 */ 2453 static int svmR0EmulateTprVMMCall(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx) 2454 { 2455 int rc; 2456 2457 Log(("Emulated VMMCall TPR access replacement at %RGv\n", pCtx->rip)); 2458 2459 while (true) 2460 { 2461 bool fPending; 2462 uint8_t u8Tpr; 2463 2464 PHWACCMTPRPATCH pPatch = (PHWACCMTPRPATCH)RTAvloU32Get(&pVM->hwaccm.s.svm.PatchTree, (AVLOU32KEY)pCtx->eip); 2465 if (!pPatch) 2466 break; 2467 2468 switch(pPatch->enmType) 2469 { 2470 case HWACCMTPRINSTR_READ: 2471 /* TPR caching in CR8 */ 2472 rc = PDMApicGetTPR(pVCpu, &u8Tpr, &fPending); 2473 AssertRC(rc); 2474 2475 rc = DISWriteReg32(CPUMCTX2CORE(pCtx), pPatch->uDstOperand, u8Tpr); 2476 AssertRC(rc); 2477 2478 Log(("Emulated read successfully\n")); 2479 pCtx->rip += pPatch->cbOp; 2480 break; 2481 2482 case HWACCMTPRINSTR_WRITE_REG: 2483 case HWACCMTPRINSTR_WRITE_IMM: 2484 /* Fetch the new TPR value */ 2485 if (pPatch->enmType == HWACCMTPRINSTR_WRITE_REG) 2486 { 2487 uint32_t val; 2488 2489 rc = DISFetchReg32(CPUMCTX2CORE(pCtx), pPatch->uSrcOperand, &val); 2490 AssertRC(rc); 2491 u8Tpr = val; 2492 } 2493 else 2494 u8Tpr = (uint8_t)pPatch->uSrcOperand; 2495 2496 rc = PDMApicSetTPR(pVCpu, u8Tpr); 2497 AssertRC(rc); 2498 Log(("Emulated write successfully\n")); 2499 pCtx->rip += pPatch->cbOp; 2500 break; 2501 } 2502 } 2503 return VINF_SUCCESS; 2504 } 2505 2506 /** 2438 2507 * Attempt to patch TPR mmio instructions 2439 2508 * … … 2456 2525 && pDis->pCurInstr->opcode == OP_MOV) 2457 2526 { 2458 #if 0 2459 uint8_t szInstr[15]; 2460 if ( cbOp == 10 2461 && pDis->param1.flags == USE_DISPLACEMENT32 2462 && pDis->param2.flags == USE_IMMEDIATE32) 2463 { 2464 /* Found: 2465 * mov [fffe0080], immediate_dword (10 bytes) 2466 * 2467 * Replace with: 2468 * mov free_register, immediate_dword >> 4 (5 bytes) 2469 * mov cr8, free_register (4 bytes) 2470 * nop (1 byte) 2471 * 2472 */ 2473 uint32_t u32tpr = (uint32_t)pDis->param2.parval; 2474 2475 u32tpr = (u32tpr >> 4) & 0xf; 2476 2477 /* Check if the next instruction overwrites a general purpose register. If 2478 * it does, then we can safely use it ourselves. 2479 */ 2480 pCtx->rip += cbOp; 2481 rc = EMInterpretDisasOne(pVM, pVCpu, CPUMCTX2CORE(pCtx), pDis, &cbOp); 2482 pCtx->rip = oldrip; 2483 if ( rc == VINF_SUCCESS 2484 && pDis->pCurInstr->opcode == OP_MOV 2485 && pDis->param1.flags == USE_REG_GEN32) 2527 if (pVM->hwaccm.s.svm.cPatches < RT_ELEMENTS(pVM->hwaccm.s.svm.aPatches)) 2528 { 2529 uint8_t aVMMCall[3] = { 0xf, 0x1, 0xd9}; 2530 uint32_t idx = pVM->hwaccm.s.svm.cPatches; 2531 PHWACCMTPRPATCH pPatch = &pVM->hwaccm.s.svm.aPatches[idx]; 2532 2533 rc = PGMPhysSimpleReadGCPtr(pVCpu, pPatch->aOpcode, pCtx->rip, cbOp); 2534 AssertRC(rc); 2535 2536 pPatch->cbOp = cbOp; 2537 2538 if (pDis->param1.flags == USE_DISPLACEMENT32) 2486 2539 { 2487 /* 0xB8, dword immediate = mov eax, dword immediate */ 2488 szInstr[0] = 0xB8 + pDis->param1.base.reg_gen; 2489 szInstr[1] = (uint8_t)u32tpr; 2490 szInstr[2] = 0; 2491 szInstr[3] = 0; 2492 szInstr[4] = 0; 2493 2494 /* 0xF0, 0x0F, 0x22, 0xC0 = mov cr8, eax */ 2495 szInstr[5] = 0xF0; 2496 szInstr[6] = 0x0F; 2497 szInstr[7] = 0x22; 2498 szInstr[8] = 0xC0 | pDis->param1.base.reg_gen; 2499 szInstr[9] = 0x90; /* nop */ 2500 2501 rc = PGMPhysSimpleWriteGCPtr(pVCpu, pCtx->rip, szInstr, 10); 2540 /* write. */ 2541 if (pDis->param2.flags == USE_REG_GEN32) 2542 { 2543 pPatch->enmType = HWACCMTPRINSTR_WRITE_REG; 2544 pPatch->uSrcOperand = pDis->param2.base.reg_gen; 2545 } 2546 else 2547 { 2548 Assert(pDis->param2.flags == USE_IMMEDIATE32); 2549 pPatch->enmType = HWACCMTPRINSTR_WRITE_IMM; 2550 pPatch->uSrcOperand = pDis->param2.parval; 2551 } 2552 rc = PGMPhysSimpleWriteGCPtr(pVCpu, pCtx->rip, aVMMCall, sizeof(aVMMCall)); 2502 2553 AssertRC(rc); 2503 2504 Log(("Acceptable write candidate!\n"));2505 return VINF_SUCCESS;2506 }2507 }2508 else2509 {2510 if ( pDis->param2.flags == USE_REG_GEN322511 && cbOp == 6)2512 {2513 RTGCPTR GCPtrTpr = (uint32_t)pDis->param1.disp32;2514 uint32_t uMmioReg = pDis->param2.base.reg_gen;2515 2516 /* Found:2517 * mov dword [fffe0080], eax (6 bytes)2518 * Check if next instruction is a TPR read:2519 * mov ecx, dword [fffe0080] (5 bytes)2520 */2521 pCtx->rip += cbOp;2522 rc = EMInterpretDisasOne(pVM, pVCpu, CPUMCTX2CORE(pCtx), pDis, &cbOp);2523 pCtx->rip = oldrip;2524 if ( rc == VINF_SUCCESS2525 && pDis->pCurInstr->opcode == OP_MOV2526 && pDis->param1.flags == USE_REG_GEN322527 && pDis->param2.flags == USE_DISPLACEMENT322528 && pDis->param2.disp32 == (uint32_t)GCPtrTpr2529 && cbOp == 5)2530 {2531 /* mov new_reg, uMmioReg */2532 szInstr[0] = 0x89;2533 szInstr[1] = MAKE_MODRM(3, uMmioReg, pDis->param1.base.reg_gen);2534 2535 /* Let's hope the guest won't mind us trashing the source register...2536 * shr uMmioReg, 42537 */2538 szInstr[2] = 0xC1;2539 szInstr[3] = 0xE8 | uMmioReg;2540 szInstr[4] = 4;2541 2542 /* 0xF0, 0x0F, 0x22, 0xC0 = mov cr8, eax */2543 szInstr[5] = 0xF0;2544 szInstr[6] = 0x0F;2545 szInstr[7] = 0x22;2546 szInstr[8] = 0xC0 | uMmioReg;2547 2548 /* Two nop instructions */2549 szInstr[9] = 0x90;2550 szInstr[10] = 0x90;2551 2552 rc = PGMPhysSimpleWriteGCPtr(pVCpu, pCtx->rip, szInstr, 6+cbOp);2553 AssertRC(rc);2554 2555 Log(("Acceptable read/write candidate!\n"));2556 return VINF_SUCCESS;2557 }2558 2554 } 2559 2555 else 2560 if ( pDis->param1.flags == USE_REG_GEN322561 && cbOp == 5)2562 2556 { 2557 RTGCPTR oldrip = pCtx->rip; 2558 uint32_t oldcbOp = cbOp; 2563 2559 uint32_t uMmioReg = pDis->param1.base.reg_gen; 2560 2561 /* read */ 2562 Assert(pDis->param1.flags == USE_REG_GEN32); 2564 2563 2565 2564 /* Found: … … 2576 2575 && pDis->param1.base.reg_gen == uMmioReg 2577 2576 && pDis->param2.flags == USE_IMMEDIATE8 2578 && pDis->param2.parval == 4) 2577 && pDis->param2.parval == 4 2578 && oldcbOp + cbOp < sizeof(pVM->hwaccm.s.svm.aPatches[idx])) 2579 2579 { 2580 uint8_t szInstr[15]; 2581 2582 /* Replacing two instructions now. */ 2583 rc = PGMPhysSimpleReadGCPtr(pVCpu, &pPatch->aOpcode, pCtx->rip, oldcbOp + cbOp); 2584 AssertRC(rc); 2585 2586 pPatch->cbOp = oldcbOp + cbOp; 2587 2580 2588 /* 0xF0, 0x0F, 0x20, 0xC0 = mov eax, cr8 */ 2581 2589 szInstr[0] = 0xF0; … … 2589 2597 AssertRC(rc); 2590 2598 2591 Log(("Acceptable read candidate!\n")); 2592 return VINF_SUCCESS; 2599 Log(("Acceptable read/shr candidate!\n")); 2600 pPatch->enmType = HWACCMTPRINSTR_READ_SHR4; 2601 } 2602 else 2603 { 2604 pPatch->enmType = HWACCMTPRINSTR_READ; 2605 pPatch->uDstOperand = pDis->param1.base.reg_gen; 2606 2607 rc = PGMPhysSimpleWriteGCPtr(pVCpu, pCtx->rip, aVMMCall, sizeof(aVMMCall)); 2608 AssertRC(rc); 2593 2609 } 2594 2610 } 2595 } 2596 #endif 2597 rc = svmR0EmulateTprMov(pVCpu, pDis, pCtx, cbOp); 2598 if (rc != VINF_SUCCESS) 2599 return rc; 2600 2601 /* Emulated successfully, so continue. */ 2602 return VINF_SUCCESS; 2611 2612 pPatch->Core.Key = pCtx->eip; 2613 rc = RTAvloU32Insert(&pVM->hwaccm.s.svm.PatchTree, &pPatch->Core); 2614 AssertRC(rc); 2615 2616 pVM->hwaccm.s.svm.cPatches++; 2617 return VINF_SUCCESS; 2618 } 2619 return svmR0EmulateTprMov(pVCpu, pDis, pCtx, cbOp); 2603 2620 } 2604 2621 return VERR_ACCESS_DENIED;
Note:
See TracChangeset
for help on using the changeset viewer.