VirtualBox

Changeset 97406 in vbox for trunk/src/VBox/VMM/VMMAll


Ignore:
Timestamp:
Nov 5, 2022 12:42:14 PM (2 years ago)
Author:
vboxsync
Message:

VMM/IEM,CPUM: Partial single stepping support in the interpreter. bugref:9898

Location:
trunk/src/VBox/VMM/VMMAll
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/IEMAll.cpp

    r97370 r97406  
    1001210012                uint8_t b; IEM_OPCODE_GET_NEXT_U8(&b);
    1001310013                rcStrict = FNIEMOP_CALL(g_apfnOneByteMap[b]);
     10014#ifdef VBOX_STRICT
     10015                CPUMAssertGuestRFlagsCookie(pVM, pVCpu);
     10016#endif
    1001410017                if (RT_LIKELY(rcStrict == VINF_SUCCESS))
    1001510018                {
  • trunk/src/VBox/VMM/VMMAll/IEMAllCImpl.cpp

    r97370 r97406  
    45054505
    45064506/**
     4507 * Completes a MOV SReg,XXX or POP SReg instruction.
     4508 *
     4509 * When not modifying SS or when we're already in an interrupt shadow we
     4510 * can update RIP and finish the instruction the normal way.
     4511 *
     4512 * Otherwise, the MOV/POP SS interrupt shadow that we now enable will block
     4513 * both TF and DBx events.  The TF will be ignored while the DBx ones will
     4514 * be delayed till the next instruction boundrary.  For more details see
     4515 * @sdmv3{077,200,6.8.3,Masking Exceptions and Interrupts When Switching Stacks}.
     4516 */
     4517DECLINLINE(VBOXSTRICTRC) iemCImpl_LoadSRegFinish(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iSegReg)
     4518{
     4519    if (iSegReg != X86_SREG_SS || CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx))
     4520        return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
     4521
     4522    iemRegAddToRip(pVCpu, cbInstr);
     4523    pVCpu->cpum.GstCtx.eflags.uBoth &= ~X86_EFL_RF; /* Shadow int isn't set and DRx is delayed, so only clear RF. */
     4524    CPUMSetInInterruptShadowSs(&pVCpu->cpum.GstCtx);
     4525
     4526    return VINF_SUCCESS;
     4527}
     4528
     4529
     4530/**
    45074531 * Common worker for 'pop SReg', 'mov SReg, GReg' and 'lXs GReg, reg/mem'.
    45084532 *
     4533 * @param   pVCpu       The cross context virtual CPU structure of the calling
     4534 *                      thread.
    45094535 * @param   iSegReg     The segment register number (valid).
    45104536 * @param   uSel        The new selector value.
    45114537 */
    4512 IEM_CIMPL_DEF_2(iemCImpl_LoadSReg, uint8_t, iSegReg, uint16_t, uSel)
     4538static VBOXSTRICTRC iemCImpl_LoadSRegWorker(PVMCPUCC pVCpu, uint8_t iSegReg, uint16_t uSel)
    45134539{
    45144540    IEM_CTX_IMPORT_RET(pVCpu, CPUMCTX_EXTRN_SREG_FROM_IDX(iSegReg));
     
    45394565                                : X86_SEL_TYPE_READ | X86_SEL_TYPE_CODE;
    45404566#endif
    4541         CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_HIDDEN_SEL_REGS);
    4542         return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
    4543     }
    4544 
     4567    }
    45454568    /*
    45464569     * Protected mode.
     
    45494572     * FS and GS.  If not null, then we have to load and parse the descriptor.
    45504573     */
    4551     if (!(uSel & X86_SEL_MASK_OFF_RPL))
     4574    else if (!(uSel & X86_SEL_MASK_OFF_RPL))
    45524575    {
    45534576        Assert(iSegReg != X86_SREG_CS); /** @todo testcase for \#UD on MOV CS, ax! */
     
    45724595        if (iSegReg == X86_SREG_SS)
    45734596            pHid->Attr.u |= pVCpu->iem.s.uCpl << X86DESCATTR_DPL_SHIFT;
    4574 
    4575         Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pHid));
    4576         CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_HIDDEN_SEL_REGS);
    4577 
    4578         return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
    4579     }
    4580 
    4581     /* Fetch the descriptor. */
    4582     IEMSELDESC Desc;
    4583     VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pVCpu, &Desc, uSel, X86_XCPT_GP); /** @todo Correct exception? */
    4584     if (rcStrict != VINF_SUCCESS)
    4585         return rcStrict;
    4586 
    4587     /* Check GPs first. */
    4588     if (!Desc.Legacy.Gen.u1DescType)
    4589     {
    4590         Log(("load sreg %d (=%#x) - system selector (%#x) -> #GP\n", iSegReg, uSel, Desc.Legacy.Gen.u4Type));
    4591         return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
    4592     }
    4593     if (iSegReg == X86_SREG_SS) /* SS gets different treatment */
    4594     {
    4595         if (    (Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE)
    4596             || !(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_WRITE) )
    4597         {
    4598             Log(("load sreg SS, %#x - code or read only (%#x) -> #GP\n", uSel, Desc.Legacy.Gen.u4Type));
     4597    }
     4598    else
     4599    {
     4600
     4601        /* Fetch the descriptor. */
     4602        IEMSELDESC Desc;
     4603        VBOXSTRICTRC rcStrict = iemMemFetchSelDesc(pVCpu, &Desc, uSel, X86_XCPT_GP); /** @todo Correct exception? */
     4604        if (rcStrict != VINF_SUCCESS)
     4605            return rcStrict;
     4606
     4607        /* Check GPs first. */
     4608        if (!Desc.Legacy.Gen.u1DescType)
     4609        {
     4610            Log(("load sreg %d (=%#x) - system selector (%#x) -> #GP\n", iSegReg, uSel, Desc.Legacy.Gen.u4Type));
    45994611            return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
    46004612        }
    4601         if ((uSel & X86_SEL_RPL) != pVCpu->iem.s.uCpl)
    4602         {
    4603             Log(("load sreg SS, %#x - RPL and CPL (%d) differs -> #GP\n", uSel, pVCpu->iem.s.uCpl));
    4604             return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
    4605         }
    4606         if (Desc.Legacy.Gen.u2Dpl != pVCpu->iem.s.uCpl)
    4607         {
    4608             Log(("load sreg SS, %#x - DPL (%d) and CPL (%d) differs -> #GP\n", uSel, Desc.Legacy.Gen.u2Dpl, pVCpu->iem.s.uCpl));
    4609             return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
    4610         }
    4611     }
    4612     else
    4613     {
    4614         if ((Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_READ)) == X86_SEL_TYPE_CODE)
    4615         {
    4616             Log(("load sreg%u, %#x - execute only segment -> #GP\n", iSegReg, uSel));
    4617             return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
    4618         }
    4619         if (   (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
    4620             != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
    4621         {
    4622 #if 0 /* this is what intel says. */
    4623             if (   (uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl
    4624                 && pVCpu->iem.s.uCpl        > Desc.Legacy.Gen.u2Dpl)
     4613        if (iSegReg == X86_SREG_SS) /* SS gets different treatment */
     4614        {
     4615            if (    (Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_CODE)
     4616                || !(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_WRITE) )
    46254617            {
    4626                 Log(("load sreg%u, %#x - both RPL (%d) and CPL (%d) are greater than DPL (%d) -> #GP\n",
    4627                      iSegReg, uSel, (uSel & X86_SEL_RPL), pVCpu->iem.s.uCpl, Desc.Legacy.Gen.u2Dpl));
     4618                Log(("load sreg SS, %#x - code or read only (%#x) -> #GP\n", uSel, Desc.Legacy.Gen.u4Type));
    46284619                return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
    46294620            }
    4630 #else /* this is what makes more sense. */
    4631             if ((unsigned)(uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl)
     4621            if ((uSel & X86_SEL_RPL) != pVCpu->iem.s.uCpl)
    46324622            {
    4633                 Log(("load sreg%u, %#x - RPL (%d) is greater than DPL (%d) -> #GP\n",
    4634                      iSegReg, uSel, (uSel & X86_SEL_RPL), Desc.Legacy.Gen.u2Dpl));
     4623                Log(("load sreg SS, %#x - RPL and CPL (%d) differs -> #GP\n", uSel, pVCpu->iem.s.uCpl));
    46354624                return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
    46364625            }
    4637             if (pVCpu->iem.s.uCpl > Desc.Legacy.Gen.u2Dpl)
     4626            if (Desc.Legacy.Gen.u2Dpl != pVCpu->iem.s.uCpl)
    46384627            {
    4639                 Log(("load sreg%u, %#x - CPL (%d) is greater than DPL (%d) -> #GP\n",
    4640                      iSegReg, uSel, pVCpu->iem.s.uCpl, Desc.Legacy.Gen.u2Dpl));
     4628                Log(("load sreg SS, %#x - DPL (%d) and CPL (%d) differs -> #GP\n", uSel, Desc.Legacy.Gen.u2Dpl, pVCpu->iem.s.uCpl));
    46414629                return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
    46424630            }
     4631        }
     4632        else
     4633        {
     4634            if ((Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_READ)) == X86_SEL_TYPE_CODE)
     4635            {
     4636                Log(("load sreg%u, %#x - execute only segment -> #GP\n", iSegReg, uSel));
     4637                return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
     4638            }
     4639            if (   (Desc.Legacy.Gen.u4Type & (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
     4640                != (X86_SEL_TYPE_CODE | X86_SEL_TYPE_CONF))
     4641            {
     4642#if 0 /* this is what intel says. */
     4643                if (   (uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl
     4644                    && pVCpu->iem.s.uCpl        > Desc.Legacy.Gen.u2Dpl)
     4645                {
     4646                    Log(("load sreg%u, %#x - both RPL (%d) and CPL (%d) are greater than DPL (%d) -> #GP\n",
     4647                         iSegReg, uSel, (uSel & X86_SEL_RPL), pVCpu->iem.s.uCpl, Desc.Legacy.Gen.u2Dpl));
     4648                    return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
     4649                }
     4650#else /* this is what makes more sense. */
     4651                if ((unsigned)(uSel & X86_SEL_RPL) > Desc.Legacy.Gen.u2Dpl)
     4652                {
     4653                    Log(("load sreg%u, %#x - RPL (%d) is greater than DPL (%d) -> #GP\n",
     4654                         iSegReg, uSel, (uSel & X86_SEL_RPL), Desc.Legacy.Gen.u2Dpl));
     4655                    return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
     4656                }
     4657                if (pVCpu->iem.s.uCpl > Desc.Legacy.Gen.u2Dpl)
     4658                {
     4659                    Log(("load sreg%u, %#x - CPL (%d) is greater than DPL (%d) -> #GP\n",
     4660                         iSegReg, uSel, pVCpu->iem.s.uCpl, Desc.Legacy.Gen.u2Dpl));
     4661                    return iemRaiseGeneralProtectionFaultBySelector(pVCpu, uSel);
     4662                }
    46434663#endif
    4644         }
    4645     }
    4646 
    4647     /* Is it there? */
    4648     if (!Desc.Legacy.Gen.u1Present)
    4649     {
    4650         Log(("load sreg%d,%#x - segment not present -> #NP\n", iSegReg, uSel));
    4651         return iemRaiseSelectorNotPresentBySelector(pVCpu, uSel);
    4652     }
    4653 
    4654     /* The base and limit. */
    4655     uint32_t cbLimit = X86DESC_LIMIT_G(&Desc.Legacy);
    4656     uint64_t u64Base = X86DESC_BASE(&Desc.Legacy);
    4657 
    4658     /*
    4659      * Ok, everything checked out fine.  Now set the accessed bit before
    4660      * committing the result into the registers.
    4661      */
    4662     if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
    4663     {
    4664         rcStrict = iemMemMarkSelDescAccessed(pVCpu, uSel);
    4665         if (rcStrict != VINF_SUCCESS)
    4666             return rcStrict;
    4667         Desc.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
    4668     }
    4669 
    4670     /* commit */
    4671     *pSel = uSel;
    4672     pHid->Attr.u   = X86DESC_GET_HID_ATTR(&Desc.Legacy);
    4673     pHid->u32Limit = cbLimit;
    4674     pHid->u64Base  = u64Base;
    4675     pHid->ValidSel = uSel;
    4676     pHid->fFlags   = CPUMSELREG_FLAGS_VALID;
    4677 
    4678     /** @todo check if the hidden bits are loaded correctly for 64-bit
    4679      *        mode.  */
     4664            }
     4665        }
     4666
     4667        /* Is it there? */
     4668        if (!Desc.Legacy.Gen.u1Present)
     4669        {
     4670            Log(("load sreg%d,%#x - segment not present -> #NP\n", iSegReg, uSel));
     4671            return iemRaiseSelectorNotPresentBySelector(pVCpu, uSel);
     4672        }
     4673
     4674        /* The base and limit. */
     4675        uint32_t cbLimit = X86DESC_LIMIT_G(&Desc.Legacy);
     4676        uint64_t u64Base = X86DESC_BASE(&Desc.Legacy);
     4677
     4678        /*
     4679         * Ok, everything checked out fine.  Now set the accessed bit before
     4680         * committing the result into the registers.
     4681         */
     4682        if (!(Desc.Legacy.Gen.u4Type & X86_SEL_TYPE_ACCESSED))
     4683        {
     4684            rcStrict = iemMemMarkSelDescAccessed(pVCpu, uSel);
     4685            if (rcStrict != VINF_SUCCESS)
     4686                return rcStrict;
     4687            Desc.Legacy.Gen.u4Type |= X86_SEL_TYPE_ACCESSED;
     4688        }
     4689
     4690        /* commit */
     4691        *pSel = uSel;
     4692        pHid->Attr.u   = X86DESC_GET_HID_ATTR(&Desc.Legacy);
     4693        pHid->u32Limit = cbLimit;
     4694        pHid->u64Base  = u64Base;
     4695        pHid->ValidSel = uSel;
     4696        pHid->fFlags   = CPUMSELREG_FLAGS_VALID;
     4697
     4698        /** @todo check if the hidden bits are loaded correctly for 64-bit
     4699         *        mode.  */
     4700    }
     4701
    46804702    Assert(CPUMSELREG_ARE_HIDDEN_PARTS_VALID(pVCpu, pHid));
    4681 
    46824703    CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_HIDDEN_SEL_REGS);
    4683     return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
     4704    return VINF_SUCCESS;
    46844705}
    46854706
     
    46934714IEM_CIMPL_DEF_2(iemCImpl_load_SReg, uint8_t, iSegReg, uint16_t, uSel)
    46944715{
    4695     if (iSegReg != X86_SREG_SS)
    4696         return IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, uSel);
    4697     /** @todo only set it the shadow flag if it was clear before? */
    4698     VBOXSTRICTRC rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, uSel);
     4716    VBOXSTRICTRC rcStrict = iemCImpl_LoadSRegWorker(pVCpu, iSegReg, uSel);
    46994717    if (rcStrict == VINF_SUCCESS)
    4700         CPUMSetInInterruptShadowSs(&pVCpu->cpum.GstCtx);
     4718        rcStrict = iemCImpl_LoadSRegFinish(pVCpu, cbInstr, iSegReg);
    47014719    return rcStrict;
    47024720}
     
    47254743            rcStrict = iemMemStackPopU16Ex(pVCpu, &uSel, &TmpRsp);
    47264744            if (rcStrict == VINF_SUCCESS)
    4727                 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, uSel);
     4745                rcStrict = iemCImpl_LoadSRegWorker(pVCpu, iSegReg, uSel);
    47284746            break;
    47294747        }
     
    47344752            rcStrict = iemMemStackPopU32Ex(pVCpu, &u32Value, &TmpRsp);
    47354753            if (rcStrict == VINF_SUCCESS)
    4736                 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, (uint16_t)u32Value);
     4754                rcStrict = iemCImpl_LoadSRegWorker(pVCpu, iSegReg, (uint16_t)u32Value);
    47374755            break;
    47384756        }
     
    47434761            rcStrict = iemMemStackPopU64Ex(pVCpu, &u64Value, &TmpRsp);
    47444762            if (rcStrict == VINF_SUCCESS)
    4745                 rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, (uint16_t)u64Value);
     4763                rcStrict = iemCImpl_LoadSRegWorker(pVCpu, iSegReg, (uint16_t)u64Value);
    47464764            break;
    47474765        }
     
    47494767    }
    47504768
    4751     /*
    4752      * Commit the stack on success and set interrupt shadow flag if appropriate
    4753      * (the latter must be done after updating RIP).
     4769    /*
     4770     * If the load succeeded, commit the stack change and finish the instruction.
    47544771     */
    47554772    if (rcStrict == VINF_SUCCESS)
    47564773    {
    47574774        pVCpu->cpum.GstCtx.rsp = TmpRsp.u;
    4758         if (iSegReg == X86_SREG_SS)
    4759         {
    4760             /** @todo only set it the shadow flag if it was clear before? */
    4761             CPUMSetInInterruptShadowSs(&pVCpu->cpum.GstCtx);
    4762         }
    4763     }
     4775        rcStrict = iemCImpl_LoadSRegFinish(pVCpu, cbInstr, iSegReg);
     4776    }
     4777
    47644778    return rcStrict;
    47654779}
     
    47724786{
    47734787    /*
    4774      * Use iemCImpl_LoadSReg to do the tricky segment register loading.
     4788     * Use iemCImpl_LoadSRegWorker to do the tricky segment register loading.
    47754789     */
    47764790    /** @todo verify and test that mov, pop and lXs works the segment
    47774791     *        register loading in the exact same way. */
    4778     VBOXSTRICTRC rcStrict = IEM_CIMPL_CALL_2(iemCImpl_LoadSReg, iSegReg, uSel);
     4792    VBOXSTRICTRC rcStrict = iemCImpl_LoadSRegWorker(pVCpu, iSegReg, uSel);
    47794793    if (rcStrict == VINF_SUCCESS)
    47804794    {
     
    47854799                break;
    47864800            case IEMMODE_32BIT:
    4787                 *(uint64_t *)iemGRegRef(pVCpu, iGReg) = offSeg;
    4788                 break;
    47894801            case IEMMODE_64BIT:
    47904802                *(uint64_t *)iemGRegRef(pVCpu, iGReg) = offSeg;
     
    47924804            IEM_NOT_REACHED_DEFAULT_CASE_RET();
    47934805        }
    4794     }
    4795 
     4806        return iemRegAddToRipAndFinishingClearingRF(pVCpu, cbInstr);
     4807    }
    47964808    return rcStrict;
    47974809}
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