VirtualBox

Changeset 53178 in vbox for trunk/src/VBox/VMM/VMMR0


Ignore:
Timestamp:
Nov 2, 2014 9:04:12 PM (10 years ago)
Author:
vboxsync
Message:

HMVMXR0.cpp: Fixed several bugs in the real-mode-on-top-of-v86 instruction emulation: STI always set the inhibit interrupts. IRET used didn't keep enough flags in the high word, but incorrectly (I believe) kept the resume flags (RF). The RF flag was only cleared in by a few instructions, it should normally be cleared when an instruction is retired (with a couple of exception). Made the real-mode direct event injection code return VINF_EM_DBG_STEPPED when stepping (currently passing fStepping around as that clearer).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR0/HMVMXR0.cpp

    r53176 r53178  
    345345static void               hmR0VmxFlushVpid(PVM pVM, PVMCPU pVCpu, VMXFLUSHVPID enmFlush, RTGCPTR GCPtr);
    346346static int                hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint64_t u64IntInfo, uint32_t cbInstr,
    347                                                  uint32_t u32ErrCode, RTGCUINTREG GCPtrFaultAddress, uint32_t *puIntState);
     347                                                 uint32_t u32ErrCode, RTGCUINTREG GCPtrFaultAddress,
     348                                                 bool fStepping, uint32_t *puIntState);
    348349#if HC_ARCH_BITS == 32 && !defined(VBOX_WITH_HYBRID_32BIT_KERNEL)
    349350static int                hmR0VmxInitVmcsReadCache(PVM pVM, PVMCPU pVCpu);
     
    75037504 *                          out-of-sync. Make sure to update the required fields
    75047505 *                          before using them.
    7505  */
    7506 static int hmR0VmxInjectPendingEvent(PVMCPU pVCpu, PCPUMCTX pMixedCtx)
     7506 * @param   fStepping       Running in hmR0VmxRunGuestCodeStep and we should
     7507 *                          return VINF_EM_DBG_STEPPED an event was dispatched
     7508 *                          directly.
     7509 */
     7510static int hmR0VmxInjectPendingEvent(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fStepping)
    75077511{
    75087512    HMVMX_ASSERT_PREEMPT_SAFE();
     
    75547558              (uint8_t)uIntType));
    75557559        rc = hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, pVCpu->hm.s.Event.u64IntInfo, pVCpu->hm.s.Event.cbInstr,
    7556                                     pVCpu->hm.s.Event.u32ErrCode, pVCpu->hm.s.Event.GCPtrFaultAddress, &uIntrState);
     7560                                    pVCpu->hm.s.Event.u32ErrCode, pVCpu->hm.s.Event.GCPtrFaultAddress, fStepping, &uIntrState);
    75577561        AssertRCReturn(rc, rc);
    75587562
     
    76047608    AssertRC(rc2);
    76057609
    7606     Assert(rc == VINF_SUCCESS || rc == VINF_EM_RESET);
     7610    Assert(rc == VINF_SUCCESS || rc == VINF_EM_RESET || (rc == VINF_EM_DBG_STEPPED && fStepping));
    76077611    NOREF(fBlockMovSS); NOREF(fBlockSti);
    76087612    return rc;
     
    76347638 *                          out-of-sync. Make sure to update the required fields
    76357639 *                          before using them.
    7636  */
    7637 DECLINLINE(int) hmR0VmxInjectXcptDF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint32_t *puIntrState)
     7640 * @param   fStepping       Whether we're running in hmR0VmxRunGuestCodeStep and
     7641 *                          should return VINF_EM_DBG_STEPPED if the event is
     7642 *                          injected directly (registerd modified by us, not by
     7643 *                          hardware on VM entry).
     7644 * @param   puIntrState     Pointer to the current guest interruptibility-state.
     7645 *                          This interruptibility-state will be updated if
     7646 *                          necessary. This cannot not be NULL.
     7647 */
     7648DECLINLINE(int) hmR0VmxInjectXcptDF(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fStepping, uint32_t *puIntrState)
    76387649{
    76397650    uint32_t u32IntInfo  = X86_XCPT_DF | VMX_EXIT_INTERRUPTION_INFO_VALID;
     
    76417652    u32IntInfo          |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
    76427653    return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntInfo, 0 /* cbInstr */, 0 /* u32ErrCode */, 0 /* GCPtrFaultAddress */,
    7643                                   puIntrState);
     7654                                  fStepping, puIntrState);
    76447655}
    76457656
     
    76927703 *                              mode, i.e. in real-mode it's not valid).
    76937704 * @param   u32ErrorCode        The error code associated with the #GP.
     7705 * @param   fStepping           Whether we're running in hmR0VmxRunGuestCodeStep
     7706 *                              and should return VINF_EM_DBG_STEPPED if the
     7707 *                              event is injected directly (registerd modified
     7708 *                              by us, not by hardware on VM entry).
     7709 * @param   puIntrState         Pointer to the current guest interruptibility-state.
     7710 *                              This interruptibility-state will be updated if
     7711 *                              necessary. This cannot not be NULL.
    76947712 */
    76957713DECLINLINE(int) hmR0VmxInjectXcptGP(PVMCPU pVCpu, PCPUMCTX pMixedCtx, bool fErrorCodeValid, uint32_t u32ErrorCode,
    7696                                     uint32_t *puIntrState)
     7714                                    bool fStepping, uint32_t *puIntrState)
    76977715{
    76987716    uint32_t u32IntInfo  = X86_XCPT_GP | VMX_EXIT_INTERRUPTION_INFO_VALID;
     
    77017719        u32IntInfo |= VMX_EXIT_INTERRUPTION_INFO_ERROR_CODE_VALID;
    77027720    return hmR0VmxInjectEventVmcs(pVCpu, pMixedCtx, u32IntInfo, 0 /* cbInstr */, u32ErrorCode, 0 /* GCPtrFaultAddress */,
    7703                                   puIntrState);
     7721                                  fStepping, puIntrState);
    77047722}
    77057723
     
    77967814 *                              This interruptibility-state will be updated if
    77977815 *                              necessary. This cannot not be NULL.
     7816 * @param   fStepping           Whether we're running in hmR0VmxRunGuestCodeStep
     7817 *                              and should return VINF_EM_DBG_STEPPED if the
     7818 *                              event is injected directly (registerd modified
     7819 *                              by us, not by hardware on VM entry).
    77987820 *
    77997821 * @remarks Requires CR0!
     
    78017823 */
    78027824static int hmR0VmxInjectEventVmcs(PVMCPU pVCpu, PCPUMCTX pMixedCtx, uint64_t u64IntInfo, uint32_t cbInstr,
    7803                                   uint32_t u32ErrCode, RTGCUINTREG GCPtrFaultAddress, uint32_t *puIntrState)
     7825                                  uint32_t u32ErrCode, RTGCUINTREG GCPtrFaultAddress, bool fStepping, uint32_t *puIntrState)
    78047826{
    78057827    /* Intel spec. 24.8.3 "VM-Entry Controls for Event Injection" specifies the interruption-information field to be 32-bits. */
     
    78717893                if (uVector == X86_XCPT_DF)
    78727894                    return VINF_EM_RESET;
    7873                 else if (uVector == X86_XCPT_GP)
    7874                 {
    7875                     /* If we're injecting a #GP with no valid IDT entry, inject a double-fault. */
    7876                     return hmR0VmxInjectXcptDF(pVCpu, pMixedCtx, puIntrState);
    7877                 }
     7895
     7896                /* If we're injecting a #GP with no valid IDT entry, inject a double-fault. */
     7897                if (uVector == X86_XCPT_GP)
     7898                    return hmR0VmxInjectXcptDF(pVCpu, pMixedCtx, fStepping, puIntrState);
    78787899
    78797900                /* If we're injecting an interrupt/exception with no valid IDT entry, inject a general-protection fault. */
    78807901                /* No error codes for exceptions in real-mode. See Intel spec. 20.1.4 "Interrupt and Exception Handling" */
    7881                 return hmR0VmxInjectXcptGP(pVCpu, pMixedCtx, false /* fErrCodeValid */, 0 /* u32ErrCode */, puIntrState);
     7902                return hmR0VmxInjectXcptGP(pVCpu, pMixedCtx, false /* fErrCodeValid */, 0 /* u32ErrCode */,
     7903                                           fStepping, puIntrState);
    78827904            }
    78837905
     
    79327954                    *puIntrState &= ~VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE_BLOCK_STI;
    79337955                }
    7934                 Log4(("Injecting real-mode: u32IntInfo=%#x u32ErrCode=%#x instrlen=%#x\n", u32IntInfo, u32ErrCode, cbInstr));
     7956                Log4(("Injecting real-mode: u32IntInfo=%#x u32ErrCode=%#x instrlen=%#x efl=%#x cs:eip=%04x:%04x\n",
     7957                      u32IntInfo, u32ErrCode, cbInstr, pMixedCtx->eflags.u, pMixedCtx->cs.Sel, pMixedCtx->eip));
    79357958
    79367959                /* The event has been truly dispatched. Mark it as no longer pending so we don't attempt to 'undo'
    79377960                   it, if we are returning to ring-3 before executing guest code. */
    79387961                pVCpu->hm.s.Event.fPending = false;
     7962
     7963                /* Make hmR0VmxPreRunGuest return if we're stepping since we've changed cs:rip. */
     7964                if (fStepping)
     7965                    rc = VINF_EM_DBG_STEPPED;
    79397966            }
    7940             Assert(rc == VINF_SUCCESS || rc == VINF_EM_RESET);
     7967            Assert(rc == VINF_SUCCESS || rc == VINF_EM_RESET || (rc == VINF_EM_DBG_STEPPED && fStepping));
    79417968            return rc;
    79427969        }
     
    84028429 * @retval  VINF_EM_RESET if a triple-fault occurs while injecting a
    84038430 *          double-fault into the guest.
     8431 * @retval  VINF_EM_DBG_STEPPED if @a fStepping is true and an event was
     8432 *          dispatched directly.
    84048433 * @retval  VINF_* scheduling changes, we have to go back to ring-3.
    84058434 *
     
    84108439 *                          before using them.
    84118440 * @param   pVmxTransient   Pointer to the VMX transient structure.
    8412  * @param   fStepping       Set if called from hmR0VmxRunGuestCodeStep, makes us
    8413  *                          ignore some of the reasons for returning to ring-3.
     8441 * @param   fStepping       Set if called from hmR0VmxRunGuestCodeStep.  Makes
     8442 *                          us ignore some of the reasons for returning to
     8443 *                          ring-3, and return VINF_EM_DBG_STEPPED if event
     8444 *                          dispatching took place.
    84148445 */
    84158446static int hmR0VmxPreRunGuest(PVM pVM, PVMCPU pVCpu, PCPUMCTX pMixedCtx, PVMXTRANSIENT pVmxTransient, bool fStepping)
     
    84588489     * longjmps or interrupts + preemption enabled. Event injection might also result in triple-faulting the VM.
    84598490     */
    8460     rc = hmR0VmxInjectPendingEvent(pVCpu, pMixedCtx);
     8491    rc = hmR0VmxInjectPendingEvent(pVCpu, pMixedCtx, fStepping);
    84618492    if (RT_UNLIKELY(rc != VINF_SUCCESS))
    84628493    {
    8463         Assert(rc == VINF_EM_RESET);
     8494        Assert(rc == VINF_EM_RESET || (rc == VINF_EM_DBG_STEPPED && fStepping));
    84648495        return rc;
    84658496    }
     
    99189949        return VINF_SUCCESS;
    99199950    }
    9920     else if (RT_UNLIKELY(rc == VINF_EM_RESET))
     9951    if (RT_UNLIKELY(rc == VINF_EM_RESET))
    99219952    {
    99229953        STAM_PROFILE_ADV_STOP(&pVCpu->hm.s.StatExitXcptNmi, y3);
     
    1181411845            {
    1181511846                pMixedCtx->eflags.Bits.u1IF = 0;
     11847                pMixedCtx->eflags.Bits.u1RF = 0;
    1181611848                pMixedCtx->rip += pDis->cbInstr;
    1181711849                HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
     
    1182311855            case OP_STI:
    1182411856            {
     11857                bool fOldIF = pMixedCtx->eflags.Bits.u1IF;
    1182511858                pMixedCtx->eflags.Bits.u1IF = 1;
     11859                pMixedCtx->eflags.Bits.u1RF = 0;
    1182611860                pMixedCtx->rip += pDis->cbInstr;
    11827                 EMSetInhibitInterruptsPC(pVCpu, pMixedCtx->rip);
    11828                 Assert(VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
     11861                if (!fOldIF)
     11862                {
     11863                    EMSetInhibitInterruptsPC(pVCpu, pMixedCtx->rip);
     11864                    Assert(VMCPU_FF_IS_PENDING(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
     11865                }
    1182911866                HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
    1183011867                hmR0VmxSetPendingDebugXcpt(pVCpu, pMixedCtx);
     
    1183711874                rc = VINF_EM_HALT;
    1183811875                pMixedCtx->rip += pDis->cbInstr;
    11839                 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP);
     11876                pMixedCtx->eflags.Bits.u1RF = 0;
     11877                HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RFLAGS);
    1184011878                STAM_COUNTER_INC(&pVCpu->hm.s.StatExitHlt);
    1184111879                break;
     
    1187611914                }
    1187711915                Log4(("POPF %#x -> %#RX64 mask=%#x RIP=%#RX64\n", Eflags.u, pMixedCtx->rsp, uMask, pMixedCtx->rip));
    11878                 pMixedCtx->eflags.u32 =   (pMixedCtx->eflags.u32 & ~(X86_EFL_POPF_BITS & uMask))
    11879                                         | (Eflags.u32 & X86_EFL_POPF_BITS & uMask);
    11880                 pMixedCtx->eflags.Bits.u1RF  = 0;    /* The RF bit is always cleared by POPF; see Intel Instruction reference. */
     11916                pMixedCtx->eflags.u32 = (pMixedCtx->eflags.u32 & ~((X86_EFL_POPF_BITS & uMask) | X86_EFL_RF))
     11917                                      | (Eflags.u32 & X86_EFL_POPF_BITS & uMask);
    1188111918                pMixedCtx->esp              += cbParm;
    1188211919                pMixedCtx->esp              &= uMask;
     
    1193211969                pMixedCtx->esp               &= uMask;
    1193311970                pMixedCtx->rip               += pDis->cbInstr;
    11934                 HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RIP | HM_CHANGED_GUEST_RSP);
     11971                pMixedCtx->eflags.Bits.u1RF   = 0;
     11972                HMCPU_CF_SET(pVCpu,   HM_CHANGED_GUEST_RIP
     11973                                    | HM_CHANGED_GUEST_RSP
     11974                                    | HM_CHANGED_GUEST_RFLAGS);
    1193511975                hmR0VmxSetPendingDebugXcpt(pVCpu, pMixedCtx);
    1193611976                STAM_COUNTER_INC(&pVCpu->hm.s.StatExitPushf);
     
    1196512005                pMixedCtx->cs.ValidSel        = aIretFrame[1];
    1196612006                pMixedCtx->cs.u64Base         = (uint64_t)pMixedCtx->cs.Sel << 4;
    11967                 pMixedCtx->eflags.u32         = (pMixedCtx->eflags.u32 & ~(X86_EFL_POPF_BITS & uMask))
    11968                                                 | (aIretFrame[2] & X86_EFL_POPF_BITS & uMask);
     12007                pMixedCtx->eflags.u32         = (pMixedCtx->eflags.u32 & ((UINT32_C(0xffff0000) | X86_EFL_1) & ~X86_EFL_RF))
     12008                                              | (aIretFrame[2] & X86_EFL_POPF_BITS & uMask);
    1196912009                pMixedCtx->sp                += sizeof(aIretFrame);
    1197012010                HMCPU_CF_SET(pVCpu,   HM_CHANGED_GUEST_RIP
     
    1199712037                    STAM_COUNTER_INC(&pVCpu->hm.s.StatExitInt);
    1199812038                }
     12039                else
     12040                {
     12041                    pMixedCtx->eflags.Bits.u1RF = 0;
     12042                    HMCPU_CF_SET(pVCpu, HM_CHANGED_GUEST_RFLAGS);
     12043                }
    1199912044                break;
    1200012045            }
     
    1200212047            default:
    1200312048            {
     12049                pMixedCtx->eflags.Bits.u1RF = 0; /* This is correct most of the time... */
    1200412050                VBOXSTRICTRC rc2 = EMInterpretInstructionDisasState(pVCpu, pDis, CPUMCTX2CORE(pMixedCtx), 0 /* pvFault */,
    1200512051                                                                    EMCODETYPE_SUPERVISOR);
     
    1212212168        return rc;
    1212312169    }
    12124     else if (rc == VINF_EM_RAW_GUEST_TRAP)
     12170    if (rc == VINF_EM_RAW_GUEST_TRAP)
    1212512171    {
    1212612172        if (!pVmxTransient->fVectoringDoublePF)
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette