VirtualBox

Changeset 47684 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Aug 12, 2013 11:45:20 PM (11 years ago)
Author:
vboxsync
Message:

SVM: I/O breakpoints.

File:
1 edited

Legend:

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

    r47671 r47684  
    40694069    IoExitInfo.u       = (uint32_t)pVmcb->ctrl.u64ExitInfo1;
    40704070    uint32_t uIOWidth  = (IoExitInfo.u >> 4) & 0x7;
    4071     uint32_t uIOSize   = s_aIOSize[uIOWidth];
     4071    uint32_t cbValue   = s_aIOSize[uIOWidth];
    40724072    uint32_t uAndVal   = s_aIOOpAnd[uIOWidth];
    40734073
    4074     if (RT_UNLIKELY(!uIOSize))
     4074    if (RT_UNLIKELY(!cbValue))
    40754075    {
    40764076        AssertMsgFailed(("hmR0SvmExitIOInstr: Invalid IO operation. uIOWidth=%u\n", uIOWidth));
     
    40784078    }
    40794079
    4080     int rc;
     4080    VBOXSTRICTRC rcStrict;
    40814081    if (IoExitInfo.n.u1STR)
    40824082    {
     
    40874087         *        in EXITINFO1? Investigate once this thing is up and running. */
    40884088
    4089         rc = EMInterpretDisasCurrent(pVM, pVCpu, pDis, NULL);
    4090         if (rc == VINF_SUCCESS)
     4089        rcStrict = EMInterpretDisasCurrent(pVM, pVCpu, pDis, NULL);
     4090        if (rcStrict == VINF_SUCCESS)
    40914091        {
    40924092            if (IoExitInfo.n.u1Type == SVM_IOIO_WRITE)
    40934093            {
    4094                 VBOXSTRICTRC rc2 = IOMInterpretOUTSEx(pVM, pVCpu, CPUMCTX2CORE(pCtx), IoExitInfo.n.u16Port, pDis->fPrefix,
    4095                                                       (DISCPUMODE)pDis->uAddrMode, uIOSize);
    4096                 rc = VBOXSTRICTRC_VAL(rc2);
     4094                rcStrict = IOMInterpretOUTSEx(pVM, pVCpu, CPUMCTX2CORE(pCtx), IoExitInfo.n.u16Port, pDis->fPrefix,
     4095                                              (DISCPUMODE)pDis->uAddrMode, cbValue);
    40974096                STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOStringWrite);
    40984097            }
    40994098            else
    41004099            {
    4101                 VBOXSTRICTRC rc2 = IOMInterpretINSEx(pVM, pVCpu, CPUMCTX2CORE(pCtx), IoExitInfo.n.u16Port, pDis->fPrefix,
    4102                                                      (DISCPUMODE)pDis->uAddrMode, uIOSize);
    4103                 rc = VBOXSTRICTRC_VAL(rc2);
     4100                rcStrict = IOMInterpretINSEx(pVM, pVCpu, CPUMCTX2CORE(pCtx), IoExitInfo.n.u16Port, pDis->fPrefix,
     4101                                             (DISCPUMODE)pDis->uAddrMode, cbValue);
    41044102                STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOStringRead);
    41054103            }
    41064104        }
    41074105        else
    4108             rc = VINF_EM_RAW_EMULATE_INSTR;
     4106            rcStrict = VINF_EM_RAW_EMULATE_INSTR;
    41094107    }
    41104108    else
     
    41154113        if (IoExitInfo.n.u1Type == SVM_IOIO_WRITE)
    41164114        {
    4117             VBOXSTRICTRC rc2 = IOMIOPortWrite(pVM, pVCpu, IoExitInfo.n.u16Port, pCtx->eax & uAndVal, uIOSize);
    4118             rc = VBOXSTRICTRC_VAL(rc2);
    4119             if (rc == VINF_IOM_R3_IOPORT_WRITE)
    4120                 HMR0SavePendingIOPortWrite(pVCpu, pCtx->rip, pVmcb->ctrl.u64ExitInfo2, IoExitInfo.n.u16Port, uAndVal, uIOSize);
     4115            rcStrict = IOMIOPortWrite(pVM, pVCpu, IoExitInfo.n.u16Port, pCtx->eax & uAndVal, cbValue);
     4116            if (rcStrict == VINF_IOM_R3_IOPORT_WRITE)
     4117                HMR0SavePendingIOPortWrite(pVCpu, pCtx->rip, pVmcb->ctrl.u64ExitInfo2, IoExitInfo.n.u16Port, uAndVal, cbValue);
    41214118
    41224119            STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIOWrite);
     
    41264123            uint32_t u32Val = 0;
    41274124
    4128             VBOXSTRICTRC rc2 = IOMIOPortRead(pVM, pVCpu, IoExitInfo.n.u16Port, &u32Val, uIOSize);
    4129             rc = VBOXSTRICTRC_VAL(rc2);
    4130             if (IOM_SUCCESS(rc))
     4125            rcStrict = IOMIOPortRead(pVM, pVCpu, IoExitInfo.n.u16Port, &u32Val, cbValue);
     4126            if (IOM_SUCCESS(rcStrict))
    41314127            {
    41324128                /* Save result of I/O IN instr. in AL/AX/EAX. */
    41334129                pCtx->eax = (pCtx->eax & ~uAndVal) | (u32Val & uAndVal);
    41344130            }
    4135             else if (rc == VINF_IOM_R3_IOPORT_READ)
    4136                 HMR0SavePendingIOPortRead(pVCpu, pCtx->rip, pVmcb->ctrl.u64ExitInfo2, IoExitInfo.n.u16Port, uAndVal, uIOSize);
     4131            else if (rcStrict == VINF_IOM_R3_IOPORT_READ)
     4132                HMR0SavePendingIOPortRead(pVCpu, pCtx->rip, pVmcb->ctrl.u64ExitInfo2, IoExitInfo.n.u16Port, uAndVal, cbValue);
    41374133
    41384134            STAM_COUNTER_INC(&pVCpu->hm.s.StatExitIORead);
     
    41404136    }
    41414137
    4142     if (IOM_SUCCESS(rc))
     4138    if (IOM_SUCCESS(rcStrict))
    41434139    {
    41444140        /* AMD-V saves the RIP of the instruction following the IO instruction in EXITINFO2. */
    41454141        pCtx->rip = pVmcb->ctrl.u64ExitInfo2;
    41464142
    4147         if (RT_LIKELY(rc == VINF_SUCCESS))
    4148         {
    4149             /* If any IO breakpoints are armed, then we should check if a debug trap needs to be generated. */
    4150             /** @todo This is inefficient and wrong according to intel and amd specs
    4151              *        (regardless of which is correct).  See the same code in the VT-x case.
    4152              *        write testcase and refactor the code to use a mostly shared
    4153              *        implementation after the initial DR7/CR4 checks. */
    4154             if (pCtx->dr[7] & X86_DR7_ENABLED_MASK)
     4143        /*
     4144         * If any I/O breakpoints are armed, we need to check if one triggered
     4145         * and take appropriate action.
     4146         * Note that the I/O breakpoint type is undefined if CR4.DE is 0.
     4147         */
     4148        /** @todo Optimize away the DBGFBpIsHwIoArmed call by having DBGF tell the
     4149         *  execution engines about whether hyper BPs and such are pending. */
     4150        uint32_t const uDr7 = pCtx->dr[7];
     4151        if (RT_UNLIKELY(   (   (uDr7 & X86_DR7_ENABLED_MASK)
     4152                            && X86_DR7_ANY_RW_IO(uDr7)
     4153                            && (pCtx->cr4 & X86_CR4_DE))
     4154                        || DBGFBpIsHwIoArmed(pVM)))
     4155        {
     4156            STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxIoCheck);
     4157            CPUMR0DebugStateMaybeSaveGuest(pVCpu, false /*fDr6*/);
     4158
     4159            VBOXSTRICTRC rcStrict2 = DBGFBpCheckIo(pVM, pVCpu, pCtx, IoExitInfo.n.u16Port, cbValue);
     4160            if (rcStrict2 == VINF_EM_RAW_GUEST_TRAP)
    41554161            {
    4156                 /* I/O breakpoint length, in bytes. */
    4157                 static uint32_t const s_aIOBPLen[4] = { 1, 2, 0, 4 };
    4158 
    4159                 STAM_COUNTER_INC(&pVCpu->hm.s.StatDRxIoCheck);
    4160                 for (unsigned i = 0; i < 4; i++)
    4161                 {
    4162                     unsigned uBPLen = s_aIOBPLen[X86_DR7_GET_LEN(pCtx->dr[7], i)];
    4163 
    4164                     if (   IoExitInfo.n.u16Port >= pCtx->dr[i]
    4165                         && IoExitInfo.n.u16Port < pCtx->dr[i] + uBPLen
    4166                         && (pCtx->dr[7] & (X86_DR7_L(i) | X86_DR7_G(i)))
    4167                         && (pCtx->dr[7] & X86_DR7_RW(i, X86_DR7_RW_IO)) == X86_DR7_RW(i, X86_DR7_RW_IO))
    4168                     {
    4169                         Assert(CPUMIsGuestDebugStateActive(pVCpu));
    4170 
    4171                         /* Clear all breakpoint status flags and set the one we just hit. */
    4172                         pCtx->dr[6] &= ~(X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3);
    4173                         pCtx->dr[6] |= (uint64_t)RT_BIT(i);
    4174 
    4175                         /*
    4176                          * Note: AMD64 Architecture Programmer's Manual 13.1:
    4177                          * Bits 15:13 of the DR6 register is never cleared by the processor and must be cleared
    4178                          * by software after the contents have been read.
    4179                          */
    4180                         pVmcb->guest.u64DR6 = pCtx->dr[6];
    4181 
    4182                         /* X86_DR7_GD will be cleared if drx accesses should be trapped inside the guest. */
    4183                         pCtx->dr[7] &= ~X86_DR7_GD;
    4184 
    4185                         /* Paranoia. */
    4186                         pCtx->dr[7] &= 0xffffffff;                                             /* Upper 32 bits MBZ. */
    4187                         pCtx->dr[7] &= ~(RT_BIT(11) | RT_BIT(12) | RT_BIT(14) | RT_BIT(15));   /* MBZ. */
    4188                         pCtx->dr[7] |= 0x400;                                                  /* MB1. */
    4189 
    4190                         pVmcb->guest.u64DR7 = pCtx->dr[7];
    4191                         pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_DRX;
    4192 
    4193                         /* Inject the debug exception. */
    4194                         hmR0SvmSetPendingXcptDB(pVCpu);
    4195                         break;
    4196                     }
    4197                 }
     4162                /* Raise #DB. */
     4163                pVmcb->guest.u64DR6 = pCtx->dr[6];
     4164                pVmcb->guest.u64DR7 = pCtx->dr[7];
     4165                pVmcb->ctrl.u64VmcbCleanBits &= ~HMSVM_VMCB_CLEAN_DRX;
     4166                hmR0SvmSetPendingXcptDB(pVCpu);
    41984167            }
     4168            /* rcStrict is VINF_SUCCESS or in [VINF_EM_FIRST..VINF_EM_LAST]. */
     4169            else if (   rcStrict2 != VINF_SUCCESS
     4170                     && (rcStrict == VINF_SUCCESS || rcStrict2 < rcStrict))
     4171                rcStrict = rcStrict2;
    41994172        }
    42004173    }
    42014174
    42024175#ifdef VBOX_STRICT
    4203     if (rc == VINF_IOM_R3_IOPORT_READ)
     4176    if (rcStrict == VINF_IOM_R3_IOPORT_READ)
    42044177        Assert(IoExitInfo.n.u1Type == SVM_IOIO_READ);
    4205     else if (rc == VINF_IOM_R3_IOPORT_WRITE)
     4178    else if (rcStrict == VINF_IOM_R3_IOPORT_WRITE)
    42064179        Assert(IoExitInfo.n.u1Type == SVM_IOIO_WRITE);
    42074180    else
    42084181    {
    4209         AssertMsg(   RT_FAILURE(rc)
    4210                   || rc == VINF_SUCCESS
    4211                   || rc == VINF_EM_RAW_EMULATE_INSTR
    4212                   || rc == VINF_EM_RAW_GUEST_TRAP
    4213                   || rc == VINF_TRPM_XCPT_DISPATCHED, ("%Rrc\n", rc));
     4182        /** @todo r=bird: This is missing a bunch of VINF_EM_FIRST..VINF_EM_LAST
     4183         *        statuses, that the VMM device and some others may return. See
     4184         *        IOM_SUCCESS() for guidance. */
     4185        AssertMsg(   RT_FAILURE(rcStrict)
     4186                  || rcStrict == VINF_SUCCESS
     4187                  || rcStrict == VINF_EM_RAW_EMULATE_INSTR
     4188                  || rcStrict == VINF_EM_DBG_BREAKPOINT
     4189                  || rcStrict == VINF_EM_RAW_GUEST_TRAP
     4190                  || rcStrict == VINF_TRPM_XCPT_DISPATCHED, ("%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
    42144191    }
    42154192#endif
    4216     return rc;
     4193    return VBOXSTRICTRC_TODO(rcStrict);
    42174194}
    42184195
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