VirtualBox

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


Ignore:
Timestamp:
Aug 12, 2013 10:51:55 PM (11 years ago)
Author:
vboxsync
Message:

VMM: I/O breakpoints.

File:
1 edited

Legend:

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

    r47671 r47681  
    2424#include "DBGFInternal.h"
    2525#include <VBox/vmm/vm.h>
     26#include <VBox/err.h>
    2627#include <iprt/assert.h>
    2728
     
    131132
    132133/**
     134 * Checks if any of the hardware I/O breakpoints are armed.
     135 *
     136 * @returns true if armed, false if not.
     137 * @param   pVM         The cross context VM structure.
     138 */
     139VMM_INT_DECL(bool) DBGFBpIsHwIoArmed(PVM pVM)
     140{
     141    Assert(RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints) == 4);
     142    /** @todo cache this! */
     143    return (   pVM->dbgf.s.aHwBreakpoints[0].u.Reg.fType == X86_DR7_RW_IO
     144            && pVM->dbgf.s.aHwBreakpoints[0].fEnabled
     145            && pVM->dbgf.s.aHwBreakpoints[0].enmType     == DBGFBPTYPE_REG
     146           )
     147        || (   pVM->dbgf.s.aHwBreakpoints[1].u.Reg.fType == X86_DR7_RW_IO
     148            && pVM->dbgf.s.aHwBreakpoints[1].fEnabled
     149            && pVM->dbgf.s.aHwBreakpoints[1].enmType     == DBGFBPTYPE_REG
     150           )
     151        || (   pVM->dbgf.s.aHwBreakpoints[2].u.Reg.fType == X86_DR7_RW_IO
     152            && pVM->dbgf.s.aHwBreakpoints[2].fEnabled
     153            && pVM->dbgf.s.aHwBreakpoints[2].enmType     == DBGFBPTYPE_REG
     154           )
     155        || (   pVM->dbgf.s.aHwBreakpoints[3].u.Reg.fType == X86_DR7_RW_IO
     156            && pVM->dbgf.s.aHwBreakpoints[3].fEnabled
     157            && pVM->dbgf.s.aHwBreakpoints[3].enmType     == DBGFBPTYPE_REG
     158           );
     159}
     160
     161
     162/**
     163 * Checks I/O access for guest or hypervisor breakpoints.
     164 *
     165 * @returns Strict VBox status code
     166 * @retval  VINF_SUCCESS no breakpoint.
     167 * @retval  VINF_EM_DBG_BREAKPOINT hypervisor breakpoint triggered.
     168 * @retval  VINF_EM_RAW_GUEST_TRAP guest breakpoint triggered, DR6 and DR7 have
     169 *          been updated appropriately.
     170 *
     171 * @param   pVM         The cross context VM structure.
     172 * @param   pVCpu       The cross context CPU structure for the calling EMT.
     173 * @param   pCtx        The CPU context for the calling EMT.
     174 * @param   uIoPort     The I/O port being accessed.
     175 * @param   cbValue     The size/width of the access, in bytes.
     176 */
     177VMM_INT_DECL(VBOXSTRICTRC)  DBGFBpCheckIo(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, RTIOPORT uIoPort, uint8_t cbValue)
     178{
     179    static uint8_t const s_abInvAlign[4] = { 0, 1, 7, 3 };
     180    uint32_t const uIoPortFirst = uIoPort;
     181    uint32_t const uIoPortLast  = uIoPortFirst + cbValue - 1;
     182
     183
     184    /*
     185     * Check hyper breakpoints first as the VMM debugger has priority over
     186     * the guest.
     187     */
     188    for (unsigned iBp = 0; iBp < RT_ELEMENTS(pVM->dbgf.s.aHwBreakpoints); iBp++)
     189    {
     190        if (   pVM->dbgf.s.aHwBreakpoints[iBp].u.Reg.fType == X86_DR7_RW_IO
     191            && pVM->dbgf.s.aHwBreakpoints[iBp].fEnabled
     192            && pVM->dbgf.s.aHwBreakpoints[iBp].enmType     == DBGFBPTYPE_REG )
     193        {
     194            uint8_t  cbReg      = pVM->dbgf.s.aHwBreakpoints[iBp].u.Reg.cb; Assert(RT_IS_POWER_OF_TWO(cbReg));
     195            uint64_t uDrXFirst  = pVM->dbgf.s.aHwBreakpoints[iBp].GCPtr & ~(uint64_t)(cbReg - 1);
     196            uint64_t uDrXLast   = uDrXFirst + cbReg - 1;
     197            if (uDrXFirst <= uIoPortLast && uDrXLast >= uIoPortFirst)
     198            {
     199                /* (See also DBGFRZTrap01Handler.) */
     200                pVCpu->dbgf.s.iActiveBp = pVM->dbgf.s.aHwBreakpoints[iBp].iBp;
     201                pVCpu->dbgf.s.fSingleSteppingRaw = false;
     202
     203                LogFlow(("DBGFBpCheckIo: hit hw breakpoint %d at %04x:%RGv (iop %#x)\n",
     204                         pVM->dbgf.s.aHwBreakpoints[iBp].iBp, pCtx->cs.Sel, pCtx->rip, uIoPort));
     205                return VINF_EM_DBG_BREAKPOINT;
     206            }
     207        }
     208    }
     209
     210    /*
     211     * Check the guest.
     212     */
     213    uint32_t const uDr7 = pCtx->dr[7];
     214    if (   (uDr7 & X86_DR7_ENABLED_MASK)
     215        && X86_DR7_ANY_RW_IO(uDr7)
     216        && (pCtx->cr4 & X86_CR4_DE) )
     217    {
     218        for (unsigned iBp = 0; iBp < 4; iBp++)
     219        {
     220            if (   (uDr7 & X86_DR7_L_G(iBp))
     221                && X86_DR7_GET_RW(uDr7, iBp) == X86_DR7_RW_IO)
     222            {
     223                /* ASSUME the breakpoint and the I/O width qualifier uses the same encoding (1 2 x 4). */
     224                static uint8_t const s_abInvAlign[4] = { 0, 1, 7, 3 };
     225                uint8_t  cbInvAlign = s_abInvAlign[X86_DR7_GET_LEN(uDr7, iBp)];
     226                uint64_t uDrXFirst  = pCtx->dr[iBp] & ~(uint64_t)cbInvAlign;
     227                uint64_t uDrXLast   = uDrXFirst + cbInvAlign;
     228
     229                if (uDrXFirst <= uIoPortLast && uDrXLast >= uIoPortFirst)
     230                {
     231                    /*
     232                     * Update DR6 and DR7.
     233                     *
     234                     * See "AMD64 Architecture Programmer's Manual Volume 2",
     235                     * chapter 13.1.1.3 for details on DR6 bits.  The basics is
     236                     * that the B0..B3 bits are always cleared while the others
     237                     * must be cleared by software.
     238                     *
     239                     * The following section says the GD bit is always cleared
     240                     * when generating a #DB so the handler can safely access
     241                     * the debug registers.
     242                     */
     243                    pCtx->dr[6] &= ~X86_DR6_B_MASK;
     244                    pCtx->dr[6] |= X86_DR6_B(iBp);
     245                    pCtx->dr[7] &= ~X86_DR7_GD;
     246                    LogFlow(("DBGFBpCheckIo: hit hw breakpoint %d at %04x:%RGv (iop %#x)\n",
     247                             pVM->dbgf.s.aHwBreakpoints[iBp].iBp, pCtx->cs.Sel, pCtx->rip, uIoPort));
     248                    return VINF_EM_RAW_GUEST_TRAP;
     249                }
     250            }
     251        }
     252    }
     253    return VINF_SUCCESS;
     254}
     255
     256
     257/**
    133258 * Returns the single stepping state for a virtual CPU.
    134259 *
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