Changeset 45543 in vbox for trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
- Timestamp:
- Apr 14, 2013 4:19:03 PM (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp
r45534 r45543 124 124 | RT_BIT(X86_XCPT_MF) | RT_BIT(X86_XCPT_AC) | RT_BIT(X86_XCPT_MC) \ 125 125 | RT_BIT(X86_XCPT_XF)) 126 127 /** 128 * Exception bitmap mask for all contributory exceptions. 129 */ 130 #define VMX_CONTRIBUTORY_XCPT_BITMAP ( RT_BIT(X86_XCPT_GP) | RT_BIT(X86_XCPT_NP) | RT_BIT(X86_XCPT_SS) | RT_BIT(X86_XCPT_TS) \ 131 | RT_BIT(X86_XCPT_DE)) 126 132 127 133 /** Maximum VM-instruction error number. */ … … 4577 4583 4578 4584 /** 4585 * Determines if an exception is a contributory exception. Contributory 4586 * exceptions are ones which can cause double-faults. 4587 * 4588 * @returns true if the exception is contributory, false otherwise. 4589 * @param uVector The exception vector. 4590 */ 4591 DECLINLINE(bool) hmR0VmxIsContributoryXcpt(const uint32_t uVector) 4592 { 4593 switch (uVector) 4594 { 4595 case X86_XCPT_GP: 4596 case X86_XCPT_SS: 4597 case X86_XCPT_NP: 4598 case X86_XCPT_TS: 4599 case X86_XCPT_DE: 4600 return true; 4601 default: 4602 break; 4603 } 4604 return false; 4605 } 4606 4607 4608 /** 4579 4609 * Determines if an exception is a benign exception. Benign exceptions 4580 4610 * are ones which cannot cause double-faults. … … 4585 4615 DECLINLINE(bool) hmR0VmxIsBenignXcpt(const uint32_t uVector) 4586 4616 { 4617 if ( uVector == X86_XCPT_PF 4618 || uVector == X86_XCPT_DF) 4619 { 4620 return false; 4621 } 4622 4623 bool fIsBenignXcpt = !hmR0VmxIsContributoryXcpt(uVector); 4624 #ifdef VBOX_STRICT 4587 4625 switch (uVector) 4588 4626 { … … 4599 4637 case X86_XCPT_MC: 4600 4638 case X86_XCPT_XF: 4601 return true; 4639 AssertMsg(fIsBenignXcpt, ("%#x\n", uVector)); 4640 break; 4602 4641 default: 4603 return false; 4604 } 4605 } 4606 4607 4608 /** 4609 * Determines if an exception is a contributory exception. Contributory 4610 * exceptions are ones which can cause double-faults. 4611 * 4612 * @returns true if the exception is contributory, false otherwise. 4613 * @param uVector The exception vector. 4614 */ 4615 DECLINLINE(bool) hmR0VmxIsContributoryXcpt(const uint32_t uVector) 4616 { 4617 switch (uVector) 4618 { 4619 case X86_XCPT_GP: 4620 case X86_XCPT_SS: 4621 case X86_XCPT_NP: 4622 case X86_XCPT_TS: 4623 case X86_XCPT_DE: 4624 return true; 4625 default: 4626 return false; 4627 } 4628 return false; 4629 } 4630 4631 4632 /** 4633 * Determines if we are intercepting any contributory exceptions. 4634 * 4635 * @returns true if we are intercepting any contributory exception, false 4636 * otherwise. 4642 AssertMsg(!fIsBenignXcpt, ("%#x\n", uVector)); 4643 break; 4644 } 4645 #endif 4646 return fIsBenignXcpt; 4647 } 4648 4649 4650 /** 4651 * Determines if we are intercepting any contributory exceptions or page-faults. 4652 * 4653 * @returns true if we are intercepting them, false otherwise. 4637 4654 * @param pVCpu Pointer to the VMCPU. 4638 4655 */ 4639 DECLINLINE(bool) hmR0VmxInterceptingContributoryXcpts(PVMCPU pVCpu) 4640 { 4641 if ( (pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT(X86_XCPT_GP)) 4642 || (pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT(X86_XCPT_SS)) 4643 || (pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT(X86_XCPT_NP)) 4644 || (pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT(X86_XCPT_TS)) 4645 || (pVCpu->hm.s.vmx.u32XcptBitmap & RT_BIT(X86_XCPT_DE))) 4646 { 4656 DECLINLINE(bool) hmR0VmxInterceptingContributoryXcptsOrPF(PVMCPU pVCpu) 4657 { 4658 if (pVCpu->hm.s.vmx.u32XcptBitmap & (VMX_CONTRIBUTORY_XCPT_BITMAP | RT_BIT(X86_XCPT_PF))) 4647 4659 return true; 4648 }4649 4660 return false; 4650 4661 } … … 4672 4683 pVCpu->hm.s.Event.cbInstr = cbInstr; 4673 4684 pVCpu->hm.s.Event.GCPtrFaultAddress = GCPtrFaultAddress; 4685 } 4686 4687 4688 /** 4689 * Sets a double-fault (#DF) exception as pending-for-injection into the VM. 4690 * 4691 * @param pVCpu Pointer to the VMCPU. 4692 * @param pMixedCtx Pointer to the guest-CPU context. The data may be 4693 * out-of-sync. Make sure to update the required fields 4694 * before using them. 4695 */ 4696 DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPU pVCpu, PCPUMCTX pMixedCtx) 4697 { 4698 /* Inject the double-fault. */ 4699 uint32_t u32IntrInfo = X86_XCPT_DF | (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT); 4700 u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT); 4701 u32IntrInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID; 4702 STAM_COUNTER_INC(&pVCpu->hm.s.StatIntInject); 4703 hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */); 4674 4704 } 4675 4705 … … 4736 4766 enmReflect = VMXREFLECTXCPT_DF; 4737 4767 } 4738 else if ( hmR0VmxInterceptingContributoryXcpts (pVCpu)4768 else if ( hmR0VmxInterceptingContributoryXcptsOrPF(pVCpu) 4739 4769 && uIdtVector == X86_XCPT_PF 4740 4770 && hmR0VmxIsContributoryXcpt(uExitVector)) … … 4777 4807 case VMXREFLECTXCPT_DF: 4778 4808 { 4779 uint32_t u32IntrInfo; 4780 u32IntrInfo = X86_XCPT_DF | (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT); 4781 u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT); 4782 u32IntrInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID; 4783 hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */); 4809 hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx); 4784 4810 rc = VINF_VMX_DOUBLE_FAULT; 4785 Log(("Pending #DF %#RX64 uIdt=%#x uExit=%#x\n", pVCpu->hm.s.Event.u64IntrInfo, uIdtVector, uExitVector)); 4811 Log(("Pending #DF %#RX64 uIdtVector=%#x uExitVector=%#x\n", pVCpu->hm.s.Event.u64IntrInfo, uIdtVector, 4812 uExitVector)); 4786 4813 break; 4787 4814 } … … 5567 5594 { 5568 5595 if (!TRPMHasTrap(pVCpu)) 5596 { 5597 Assert(!pVCpu->hm.s.Event.fPending); 5569 5598 return; 5599 } 5570 5600 5571 5601 uint8_t uVector; … … 5593 5623 } 5594 5624 5625 case X86_XCPT_PF: 5626 pCtx->cr2 = GCPtrFaultAddress; 5627 /* no break */ 5595 5628 case X86_XCPT_DF: 5596 5629 case X86_XCPT_TS: … … 5598 5631 case X86_XCPT_SS: 5599 5632 case X86_XCPT_GP: 5600 case X86_XCPT_PF:5601 5633 case X86_XCPT_AC: 5602 5634 /* These exceptions must be delivered as hardware exceptions. They have error codes associated with … … 5607 5639 { 5608 5640 u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT); 5609 if (uVector == X86_XCPT_PF)5610 pCtx->cr2 = TRPMGetFaultAddress(pVCpu);5611 5641 break; 5612 5642 } … … 5627 5657 rc = TRPMResetTrap(pVCpu); 5628 5658 AssertRC(rc); 5629 Log(("Convert edTRPM trap: u32IntrInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u u32ErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n",5659 Log(("Converting TRPM trap: u32IntrInfo=%#RX32 enmTrpmEvent=%d cbInstr=%u u32ErrCode=%#RX32 GCPtrFaultAddress=%#RGv\n", 5630 5660 u32IntrInfo, enmTrpmEvent, u32ErrCode, GCPtrFaultAddress)); 5631 5661 hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, cbInstr, u32ErrCode, GCPtrFaultAddress); … … 5867 5897 * before using them. 5868 5898 */ 5869 static int hmR0VmxInject Event(PVMCPU pVCpu, PCPUMCTX pMixedCtx)5899 static int hmR0VmxInjectPendingEvent(PVMCPU pVCpu, PCPUMCTX pMixedCtx) 5870 5900 { 5871 5901 /* Get the current interruptibility-state of the guest and then figure out what can be injected. */ 5872 uint32_t uIntrState = hmR0VmxGetGuestIntrState(pVCpu, pMixedCtx);5902 uint32_t uIntrState = hmR0VmxGetGuestIntrState(pVCpu, pMixedCtx); 5873 5903 const bool fBlockMovSS = (uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_MOVSS); 5874 5904 const bool fBlockSti = (uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI); 5875 5905 5876 5906 Assert(!fBlockSti || (pVCpu->hm.s.vmx.fUpdatedGuestState & VMX_UPDATED_GUEST_RFLAGS)); 5877 Assert(!fBlockSti || pMixedCtx->eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */ 5907 Assert( !(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_NMI) /* We don't support block-by-NMI and SMI yet.*/ 5908 && !(uIntrState & VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_SMI)); 5909 Assert(!fBlockSti || pMixedCtx->eflags.Bits.u1IF); /* Cannot set block-by-STI when interrupts are disabled. */ 5878 5910 5879 5911 int rc = VINF_SUCCESS; 5880 5912 if (pVCpu->hm.s.Event.fPending) /* First, inject any pending HM events. */ 5881 5913 { 5882 uint32_t uIntrType = VMX_EXIT_INTERRUPTION_INFO_TYPE( (uint32_t)pVCpu->hm.s.Event.u64IntrInfo);5914 uint32_t uIntrType = VMX_EXIT_INTERRUPTION_INFO_TYPE(pVCpu->hm.s.Event.u64IntrInfo); 5883 5915 bool fInject = true; 5884 5916 if (uIntrType == VMX_EXIT_INTERRUPTION_INFO_TYPE_EXT_INT) … … 5910 5942 pVCpu->hm.s.Event.fPending = false; 5911 5943 } 5944 else 5945 hmR0VmxSetIntWindowExitVmcs(pVCpu); 5912 5946 } /** @todo SMI. SMIs take priority over NMIs. */ 5913 5947 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_NMI)) /* NMI. NMIs take priority over regular interrupts . */ 5914 5948 { 5915 5949 /* On some CPUs block-by-STI also blocks NMIs. See Intel spec. 26.3.1.5 "Checks On Guest Non-Register State". */ 5916 if (!fBlockMovSS && !fBlockSti) 5950 if ( !fBlockMovSS 5951 && !fBlockSti) 5917 5952 { 5918 5953 Log(("Injecting NMI\n")); … … 5987 6022 5988 6023 /** 5989 * Sets a double-fault (#DF) exception as pending-for-injection into the VM.5990 *5991 * @param pVCpu Pointer to the VMCPU.5992 * @param pMixedCtx Pointer to the guest-CPU context. The data may be5993 * out-of-sync. Make sure to update the required fields5994 * before using them.5995 */5996 DECLINLINE(void) hmR0VmxSetPendingXcptDF(PVMCPU pVCpu, PCPUMCTX pMixedCtx)5997 {5998 /* Inject the double-fault. */5999 uint32_t u32IntrInfo = X86_XCPT_DF | (1 << VMX_EXIT_INTERRUPTION_INFO_VALID_SHIFT);6000 u32IntrInfo |= (VMX_EXIT_INTERRUPTION_INFO_TYPE_HW_XCPT << VMX_EXIT_INTERRUPTION_INFO_TYPE_SHIFT);6001 u32IntrInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;6002 STAM_COUNTER_INC(&pVCpu->hm.s.StatIntInject);6003 hmR0VmxSetPendingEvent(pVCpu, u32IntrInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */);6004 }6005 6006 6007 /**6008 6024 * Injects a double-fault (#DF) exception into the VM. 6009 6025 * … … 6548 6564 * This is why this is done after all possible exits-to-ring-3 paths in this code. 6549 6565 */ 6550 rc = hmR0VmxInject Event(pVCpu, pMixedCtx);6566 rc = hmR0VmxInjectPendingEvent(pVCpu, pMixedCtx); 6551 6567 AssertRCReturn(rc, rc); 6552 6568 return rc; … … 8068 8084 { 8069 8085 uint32_t uIntType = VMX_IDT_VECTORING_INFO_TYPE(pVmxTransient->uIdtVectoringInfo); 8086 /* Software interrupts and exceptions will be regenerated when the recompiler restarts the instruction. */ 8070 8087 if ( uIntType != VMX_IDT_VECTORING_INFO_TYPE_SW_INT 8071 8088 && uIntType != VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT … … 8073 8090 { 8074 8091 /* Save it as a pending event and it'll be converted to a TRPM event on the way out to ring-3. */ 8092 Log(("Pending event on TaskSwitch uIntrType=%#x uVector=%#x\n", uIntType, 8093 VMX_IDT_VECTORING_INFO_VECTOR(pVmxTransient->uIdtVectoringInfo))); 8094 Assert(!pVCpu->hm.s.Event.fPending); 8075 8095 pVCpu->hm.s.Event.fPending = true; 8076 8096 pVCpu->hm.s.Event.u64IntrInfo = pVmxTransient->uIdtVectoringInfo; … … 8804 8824 { 8805 8825 /* A guest page-fault occurred during delivery of a page-fault. Inject #DF. */ 8826 Log(("Pending #DF due to vectoring #PF.\n")); 8806 8827 rc = hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx); 8807 8828 } … … 8883 8904 TRPMResetTrap(pVCpu); 8884 8905 hmR0VmxSetPendingXcptDF(pVCpu, pMixedCtx); 8885 Log(("#PF: Pending #DF injection\n")); 8886 } 8906 Log(("#PF: Pending #DF due to vectoring #PF\n")); 8907 } 8908 8887 8909 STAM_COUNTER_INC(&pVCpu->hm.s.StatExitGuestPF); 8888 8910 return VINF_SUCCESS;
Note:
See TracChangeset
for help on using the changeset viewer.