Changeset 47432 in vbox
- Timestamp:
- Jul 27, 2013 12:35:49 AM (11 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/x86.h
r47406 r47432 738 738 /** Bit 3 - B3 - Breakpoint 3 condition detected. */ 739 739 #define X86_DR6_B3 RT_BIT(3) 740 /** Mask of all the Bx bits. */ 741 #define X86_DR6_B_MASK UINT64_C(0x0000000f) 740 742 /** Bit 13 - BD - Debug register access detected. Corresponds to the X86_DR7_GD bit. */ 741 743 #define X86_DR6_BD RT_BIT(13) … … 753 755 #define X86_DR6_MBZ_MASK UINT64_C(0xffffffff00000000) 754 756 /** @} */ 757 758 /** Get the DR6.Bx bit for a the given breakpoint. */ 759 #define X86_DR6_B(iBp) RT_BIT_64(iBp) 755 760 756 761 … … 815 820 #define X86_DR7_G(iBp) ( UINT32_C(1) << (iBp * 2 + 1) ) 816 821 822 /** Calcs the L and G bits of Nth breakpoint. 823 * @param iBp The breakpoint number [0..3]. 824 */ 825 #define X86_DR7_L_G(iBp) ( UINT32_C(3) << (iBp * 2) ) 826 817 827 /** @name Read/Write values. 818 828 * @{ */ … … 833 843 #define X86_DR7_RW(iBp, fRw) ( (fRw) << ((iBp) * 4 + 16) ) 834 844 845 /** Fetch the the R/Wx bits for a given breakpoint (so it can be compared with 846 * one of the X86_DR7_RW_XXX constants). 847 * 848 * @returns X86_DR7_RW_XXX 849 * @param uDR7 DR7 value 850 * @param iBp The breakpoint number [0..3]. 851 */ 852 #define X86_DR7_GET_RW(uDR7, iBp) ( ( (uDR7) >> ((iBp) * 4 + 16) ) & UINT32_C(3) ) 853 854 /** R/W0, R/W1, R/W2, and R/W3. */ 855 #define X86_DR7_RW_ALL_MASKS UINT32_C(0x33330000) 856 857 /** Checks if there are any I/O breakpoint types configured in the RW 858 * registers. Does NOT check if these are enabled, sorry. */ 859 #define X86_DR7_ANY_RW_IO(uDR7) \ 860 ( ( UINT32_C(0x22220000) & (uDR7) ) /* any candidates? */ \ 861 && ( ( (UINT32_C(0x22220000) & (uDR7) ) >> 1 ) & ~(uDR7) ) ) 862 AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x33330000)) == 0); 863 AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x22220000)) == 1); 864 AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x32320000)) == 1); 865 AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x23230000)) == 1); 866 AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x00000000)) == 0); 867 AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x00010000)) == 0); 868 AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x00020000)) == 1); 869 AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x00030000)) == 0); 870 AssertCompile(X86_DR7_ANY_RW_IO(UINT32_C(0x00040000)) == 0); 871 835 872 /** @name Length values. 836 873 * @{ */ … … 851 888 * @param iBp The breakpoint number [0..3]. 852 889 */ 853 #define X86_DR7_GET_LEN(uDR7, iBp) ( ( (uDR7) >> ((iBp) * 4 + 18) ) & 0x3U)890 #define X86_DR7_GET_LEN(uDR7, iBp) ( ( (uDR7) >> ((iBp) * 4 + 18) ) & UINT32_C(0x3) ) 854 891 855 892 /** Mask used to check if any breakpoints are enabled. */ 856 #define X86_DR7_ENABLED_MASK (RT_BIT(0) | RT_BIT(1) | RT_BIT(2) | RT_BIT(3) | RT_BIT(4) | RT_BIT(5) | RT_BIT(6) | RT_BIT(7)) 857 858 /** Mask used to check if any io breakpoints are set. */ 859 #define X86_DR7_IO_ENABLED_MASK (X86_DR7_RW(0, X86_DR7_RW_IO) | X86_DR7_RW(1, X86_DR7_RW_IO) | X86_DR7_RW(2, X86_DR7_RW_IO) | X86_DR7_RW(3, X86_DR7_RW_IO)) 893 #define X86_DR7_ENABLED_MASK UINT32_C(0x000000ff) 860 894 861 895 /** Value of DR7 after powerup/reset. */ -
trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
r47378 r47432 5584 5584 * 5585 5585 * @remarks No-long-jump zone!!! 5586 * @todo r=bird: Why is this plural when it only saves DR7? I almost jumped to 5587 * the wrong conclusions looking at the I/O code just now (it most likely 5588 * only needs DR7). 5586 5589 */ 5587 5590 static int hmR0VmxSaveGuestDebugRegs(PVMCPU pVCpu, PCPUMCTX pMixedCtx) 5588 5591 { 5589 int rc = VINF_SUCCESS;5590 5592 if (!(pVCpu->hm.s.vmx.fUpdatedGuestState & HMVMX_UPDATED_GUEST_DEBUG)) 5591 5593 { 5592 5594 /* Upper 32-bits are always zero. See Intel spec. 2.7.3 "Loading and Storing Debug Registers". */ 5593 5595 uint32_t u32Val; 5594 rc = VMXReadVmcs32(VMX_VMCS_GUEST_DR7, &u32Val);AssertRCReturn(rc, rc);5596 int rc = VMXReadVmcs32(VMX_VMCS_GUEST_DR7, &u32Val); AssertRCReturn(rc, rc); 5595 5597 pMixedCtx->dr[7] = u32Val; 5596 5598 5597 5599 pVCpu->hm.s.vmx.fUpdatedGuestState |= HMVMX_UPDATED_GUEST_DEBUG; 5598 5600 } 5599 return rc;5601 return VINF_SUCCESS; 5600 5602 } 5601 5603 … … 8337 8339 /* Refer Intel spec. 27-5. "Exit Qualifications for I/O Instructions" for the format. */ 8338 8340 uint32_t uIOPort = VMX_EXIT_QUALIFICATION_IO_PORT(pVmxTransient->uExitQualification); 8339 uint 32_tuIOWidth = VMX_EXIT_QUALIFICATION_IO_WIDTH(pVmxTransient->uExitQualification);8340 bool fIOWrite = ( VMX_EXIT_QUALIFICATION_IO_DIRECTION(pVmxTransient->uExitQualification)8341 uint8_t uIOWidth = VMX_EXIT_QUALIFICATION_IO_WIDTH(pVmxTransient->uExitQualification); 8342 bool fIOWrite = ( VMX_EXIT_QUALIFICATION_IO_DIRECTION(pVmxTransient->uExitQualification) 8341 8343 == VMX_EXIT_QUALIFICATION_IO_DIRECTION_OUT); 8342 8344 bool fIOString = (VMX_EXIT_QUALIFICATION_IO_STRING(pVmxTransient->uExitQualification) == 1); 8343 Assert (uIOWidth == 0 || uIOWidth == 1 || uIOWidth ==3);8345 AssertReturn(uIOWidth <= 3 && uIOWidth != 2, VERR_HM_IPE_3); 8344 8346 8345 8347 /* I/O operation lookup arrays. */ 8346 static const uint32_t s_aIOSize [4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses. */8348 static const uint32_t s_aIOSizes[4] = { 1, 2, 0, 4 }; /* Size of the I/O accesses. */ 8347 8349 static const uint32_t s_aIOOpAnd[4] = { 0xff, 0xffff, 0, 0xffffffff }; /* AND masks for saving the result (in AL/AX/EAX). */ 8348 8350 8349 const uint32_t cb Size = s_aIOSize[uIOWidth];8350 const uint32_t cbInstr = pVmxTransient->cbInstr;8351 PVM pVM = pVCpu->CTX_SUFF(pVM);8351 const uint32_t cbValue = s_aIOSizes[uIOWidth]; 8352 const uint32_t cbInstr = pVmxTransient->cbInstr; 8353 PVM pVM = pVCpu->CTX_SUFF(pVM); 8352 8354 if (fIOString) 8353 8355 { 8354 8356 /* INS/OUTS - I/O String instruction. */ 8355 PDISCPUSTATE pDis = &pVCpu->hm.s.DisState;8356 8357 /** @todo for now manually disassemble later optimize by getting the fields from 8357 8358 * the VMCS. VMX_VMCS_RO_EXIT_GUEST_LINEAR_ADDR contains the flat pointer 8358 8359 * operand of the instruction. VMX_VMCS32_RO_EXIT_INSTR_INFO contains 8359 8360 * segment prefix info. */ 8361 PDISCPUSTATE pDis = &pVCpu->hm.s.DisState; 8360 8362 rc = EMInterpretDisasCurrent(pVM, pVCpu, pDis, NULL); 8361 8363 if (RT_SUCCESS(rc)) … … 8364 8366 { 8365 8367 VBOXSTRICTRC rc2 = IOMInterpretOUTSEx(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), uIOPort, pDis->fPrefix, 8366 (DISCPUMODE)pDis->uAddrMode, cb Size);8368 (DISCPUMODE)pDis->uAddrMode, cbValue); 8367 8369 rc = VBOXSTRICTRC_VAL(rc2); 8368 8370 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOStringWrite); … … 8371 8373 { 8372 8374 VBOXSTRICTRC rc2 = IOMInterpretINSEx(pVM, pVCpu, CPUMCTX2CORE(pMixedCtx), uIOPort, pDis->fPrefix, 8373 (DISCPUMODE)pDis->uAddrMode, cb Size);8375 (DISCPUMODE)pDis->uAddrMode, cbValue); 8374 8376 rc = VBOXSTRICTRC_VAL(rc2); 8375 8377 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOStringRead); … … 8389 8391 if (fIOWrite) 8390 8392 { 8391 VBOXSTRICTRC rc2 = IOMIOPortWrite(pVM, pVCpu, uIOPort, pMixedCtx->eax & uAndVal, cb Size);8393 VBOXSTRICTRC rc2 = IOMIOPortWrite(pVM, pVCpu, uIOPort, pMixedCtx->eax & uAndVal, cbValue); 8392 8394 rc = VBOXSTRICTRC_VAL(rc2); 8393 8395 if (rc == VINF_IOM_R3_IOPORT_WRITE) 8394 HMR0SavePendingIOPortWrite(pVCpu, pMixedCtx->rip, pMixedCtx->rip + cbInstr, uIOPort, uAndVal, cb Size);8396 HMR0SavePendingIOPortWrite(pVCpu, pMixedCtx->rip, pMixedCtx->rip + cbInstr, uIOPort, uAndVal, cbValue); 8395 8397 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOWrite); 8396 8398 } … … 8398 8400 { 8399 8401 uint32_t u32Result = 0; 8400 VBOXSTRICTRC rc2 = IOMIOPortRead(pVM, pVCpu, uIOPort, &u32Result, cb Size);8402 VBOXSTRICTRC rc2 = IOMIOPortRead(pVM, pVCpu, uIOPort, &u32Result, cbValue); 8401 8403 rc = VBOXSTRICTRC_VAL(rc2); 8402 8404 if (IOM_SUCCESS(rc)) … … 8406 8408 } 8407 8409 else if (rc == VINF_IOM_R3_IOPORT_READ) 8408 HMR0SavePendingIOPortRead(pVCpu, pMixedCtx->rip, pMixedCtx->rip + cbInstr, uIOPort, uAndVal, cb Size);8410 HMR0SavePendingIOPortRead(pVCpu, pMixedCtx->rip, pMixedCtx->rip + cbInstr, uIOPort, uAndVal, cbValue); 8409 8411 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIORead); 8410 8412 } … … 8417 8419 if (RT_LIKELY(rc == VINF_SUCCESS)) 8418 8420 { 8421 /* 8422 * If any I/O breakpoints are armed, then we should check if a 8423 * debug trap needs to be generated. 8424 * Note that the I/O breakpoint type is undefined if CR4.DE is 0. 8425 */ 8419 8426 rc = hmR0VmxSaveGuestDebugRegs(pVCpu, pMixedCtx); /* For DR7. */ 8420 8427 AssertRCReturn(rc, rc); 8421 8422 /* If any IO breakpoints are armed, then we should check if a debug trap needs to be generated. */ 8423 if (pMixedCtx->dr[7] & X86_DR7_ENABLED_MASK) 8428 uint32_t const uDr7 = pMixedCtx->dr[7]; 8429 if ( (uDr7 & X86_DR7_ENABLED_MASK) 8430 && X86_DR7_ANY_RW_IO(uDr7) 8431 && (pMixedCtx->cr4 & X86_CR4_DE) ) 8424 8432 { 8433 /** @todo We're a little late here if we're doing string I/O, as we're supposed 8434 * to break after the each repetition. Not sooo important, just for a 8435 * rainy day. (Should probably refactor some of this code; after the uDr7 8436 * detection let someone else handle it.) */ 8437 /** @todo The AMD is mumbling something that sounds like cbValue == cbBp. The 8438 * Intel manual describes it differently, data and I/O breakpoints are to 8439 * be matched in the same way, probably. Bochs does it that way. We've 8440 * implemented it that way too, but it would be worth having a 8441 * bootsector testcase for asserting the correct behavior (as well as 8442 * correctness of this code). */ 8425 8443 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxIoCheck); 8426 for (unsigned i = 0; i < 4; i++) 8444 uint32_t uIOPortLast = uIOPort + cbValue - 1; 8445 for (unsigned iBp = 0; iBp < 4; iBp++) 8427 8446 { 8428 uint32_t uBPLen = s_aIOSize[X86_DR7_GET_LEN(pMixedCtx->dr[7], i)]; 8429 if ( ( uIOPort >= pMixedCtx->dr[i] 8430 && uIOPort < pMixedCtx->dr[i] + uBPLen) 8431 && (pMixedCtx->dr[7] & (X86_DR7_L(i) | X86_DR7_G(i))) 8432 && (pMixedCtx->dr[7] & X86_DR7_RW(i, X86_DR7_RW_IO)) == X86_DR7_RW(i, X86_DR7_RW_IO)) 8447 if ( (uDr7 & X86_DR7_L_G(iBp)) 8448 && X86_DR7_GET_RW(uDr7, iBp) == X86_DR7_RW_IO) 8433 8449 { 8434 Assert(CPUMIsGuestDebugStateActive(pVCpu)); 8435 uint64_t uDR6 = ASMGetDR6(); 8436 8437 /* Clear all breakpoint status flags and set the one we just hit. */ 8438 uDR6 &= ~(X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3); 8439 uDR6 |= (uint64_t)RT_BIT(i); 8440 8441 /* 8442 * Note: AMD64 Architecture Programmer's Manual 13.1: 8443 * Bits 15:13 of the DR6 register is never cleared by the processor and must 8444 * be cleared by software after the contents have been read. 8445 */ 8446 ASMSetDR6(uDR6); 8447 8448 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */ 8449 pMixedCtx->dr[7] &= ~X86_DR7_GD; 8450 8451 /* Paranoia. */ 8452 pMixedCtx->dr[7] &= 0xffffffff; /* Upper 32 bits MBZ. */ 8453 pMixedCtx->dr[7] &= ~(RT_BIT(11) | RT_BIT(12) | RT_BIT(14) | RT_BIT(15)); /* MBZ. */ 8454 pMixedCtx->dr[7] |= 0x400; /* MB1. */ 8455 8456 /* Resync DR7 */ 8457 /** @todo probably cheaper to just reload DR7, nothing else needs changing. */ 8458 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_DEBUG; 8459 8460 /* Set #DB to be injected into the VM and continue guest execution. */ 8461 hmR0VmxSetPendingXcptDB(pVCpu, pMixedCtx); 8462 break; 8450 /* ASSUME the breakpoint and the I/O width qualifier uses the same encoding (1 2 x 4). */ 8451 static uint8_t const s_abInvAlign[4] = { 0, 1, 7, 3 }; 8452 uint8_t cbInvAlign = s_abInvAlign[X86_DR7_GET_LEN(uDr7, iBp)]; 8453 uint64_t uDrXFirst = pMixedCtx->dr[iBp] & ~(uint64_t)cbInvAlign; 8454 uint64_t uDrXLast = uDrXFirst + cbInvAlign; 8455 if (uDrXFirst <= uIOPortLast && uDrXLast >= uIOPort) 8456 { 8457 Assert(CPUMIsGuestDebugStateActive(pVCpu)); 8458 uint64_t uDR6 = ASMGetDR6(); 8459 8460 /* Clear all breakpoint status flags and set the one we just hit. */ 8461 uDR6 &= ~X86_DR6_B_MASK; 8462 uDR6 |= X86_DR6_B(iBp); 8463 8464 /* 8465 * Note: AMD64 Architecture Programmer's Manual 13.1: 8466 * Bits 15:13 of the DR6 register is never cleared by the processor and must 8467 * be cleared by software after the contents have been read. 8468 */ 8469 ASMSetDR6(uDR6); 8470 8471 /* X86_DR7_GD will be cleared if DRx accesses should be trapped inside the guest. */ 8472 pMixedCtx->dr[7] &= ~X86_DR7_GD; 8473 8474 /* Paranoia. */ 8475 pMixedCtx->dr[7] &= ~(X86_DR7_RAZ_MASK | X86_DR7_MBZ_MASK); 8476 pMixedCtx->dr[7] |= X86_DR7_RA1_MASK; 8477 8478 /* Resync DR7 */ 8479 /** @todo probably cheaper to just reload DR7, nothing else needs changing. */ 8480 pVCpu->hm.s.fContextUseFlags |= HM_CHANGED_GUEST_DEBUG; 8481 8482 /* Set #DB to be injected into the VM and continue guest execution. */ 8483 hmR0VmxSetPendingXcptDB(pVCpu, pMixedCtx); 8484 break; 8485 } 8463 8486 } 8464 8487 }
Note:
See TracChangeset
for help on using the changeset viewer.