qemu/target/arm/debug_helper.c
<<
>>
Prefs
   1/*
   2 * ARM debug helpers.
   3 *
   4 * This code is licensed under the GNU GPL v2 or later.
   5 *
   6 * SPDX-License-Identifier: GPL-2.0-or-later
   7 */
   8#include "qemu/osdep.h"
   9#include "cpu.h"
  10#include "internals.h"
  11#include "exec/exec-all.h"
  12#include "exec/helper-proto.h"
  13
  14/* Return true if the linked breakpoint entry lbn passes its checks */
  15static bool linked_bp_matches(ARMCPU *cpu, int lbn)
  16{
  17    CPUARMState *env = &cpu->env;
  18    uint64_t bcr = env->cp15.dbgbcr[lbn];
  19    int brps = extract32(cpu->dbgdidr, 24, 4);
  20    int ctx_cmps = extract32(cpu->dbgdidr, 20, 4);
  21    int bt;
  22    uint32_t contextidr;
  23
  24    /*
  25     * Links to unimplemented or non-context aware breakpoints are
  26     * CONSTRAINED UNPREDICTABLE: either behave as if disabled, or
  27     * as if linked to an UNKNOWN context-aware breakpoint (in which
  28     * case DBGWCR<n>_EL1.LBN must indicate that breakpoint).
  29     * We choose the former.
  30     */
  31    if (lbn > brps || lbn < (brps - ctx_cmps)) {
  32        return false;
  33    }
  34
  35    bcr = env->cp15.dbgbcr[lbn];
  36
  37    if (extract64(bcr, 0, 1) == 0) {
  38        /* Linked breakpoint disabled : generate no events */
  39        return false;
  40    }
  41
  42    bt = extract64(bcr, 20, 4);
  43
  44    /*
  45     * We match the whole register even if this is AArch32 using the
  46     * short descriptor format (in which case it holds both PROCID and ASID),
  47     * since we don't implement the optional v7 context ID masking.
  48     */
  49    contextidr = extract64(env->cp15.contextidr_el[1], 0, 32);
  50
  51    switch (bt) {
  52    case 3: /* linked context ID match */
  53        if (arm_current_el(env) > 1) {
  54            /* Context matches never fire in EL2 or (AArch64) EL3 */
  55            return false;
  56        }
  57        return (contextidr == extract64(env->cp15.dbgbvr[lbn], 0, 32));
  58    case 5: /* linked address mismatch (reserved in AArch64) */
  59    case 9: /* linked VMID match (reserved if no EL2) */
  60    case 11: /* linked context ID and VMID match (reserved if no EL2) */
  61    default:
  62        /*
  63         * Links to Unlinked context breakpoints must generate no
  64         * events; we choose to do the same for reserved values too.
  65         */
  66        return false;
  67    }
  68
  69    return false;
  70}
  71
  72static bool bp_wp_matches(ARMCPU *cpu, int n, bool is_wp)
  73{
  74    CPUARMState *env = &cpu->env;
  75    uint64_t cr;
  76    int pac, hmc, ssc, wt, lbn;
  77    /*
  78     * Note that for watchpoints the check is against the CPU security
  79     * state, not the S/NS attribute on the offending data access.
  80     */
  81    bool is_secure = arm_is_secure(env);
  82    int access_el = arm_current_el(env);
  83
  84    if (is_wp) {
  85        CPUWatchpoint *wp = env->cpu_watchpoint[n];
  86
  87        if (!wp || !(wp->flags & BP_WATCHPOINT_HIT)) {
  88            return false;
  89        }
  90        cr = env->cp15.dbgwcr[n];
  91        if (wp->hitattrs.user) {
  92            /*
  93             * The LDRT/STRT/LDT/STT "unprivileged access" instructions should
  94             * match watchpoints as if they were accesses done at EL0, even if
  95             * the CPU is at EL1 or higher.
  96             */
  97            access_el = 0;
  98        }
  99    } else {
 100        uint64_t pc = is_a64(env) ? env->pc : env->regs[15];
 101
 102        if (!env->cpu_breakpoint[n] || env->cpu_breakpoint[n]->pc != pc) {
 103            return false;
 104        }
 105        cr = env->cp15.dbgbcr[n];
 106    }
 107    /*
 108     * The WATCHPOINT_HIT flag guarantees us that the watchpoint is
 109     * enabled and that the address and access type match; for breakpoints
 110     * we know the address matched; check the remaining fields, including
 111     * linked breakpoints. We rely on WCR and BCR having the same layout
 112     * for the LBN, SSC, HMC, PAC/PMC and is-linked fields.
 113     * Note that some combinations of {PAC, HMC, SSC} are reserved and
 114     * must act either like some valid combination or as if the watchpoint
 115     * were disabled. We choose the former, and use this together with
 116     * the fact that EL3 must always be Secure and EL2 must always be
 117     * Non-Secure to simplify the code slightly compared to the full
 118     * table in the ARM ARM.
 119     */
 120    pac = extract64(cr, 1, 2);
 121    hmc = extract64(cr, 13, 1);
 122    ssc = extract64(cr, 14, 2);
 123
 124    switch (ssc) {
 125    case 0:
 126        break;
 127    case 1:
 128    case 3:
 129        if (is_secure) {
 130            return false;
 131        }
 132        break;
 133    case 2:
 134        if (!is_secure) {
 135            return false;
 136        }
 137        break;
 138    }
 139
 140    switch (access_el) {
 141    case 3:
 142    case 2:
 143        if (!hmc) {
 144            return false;
 145        }
 146        break;
 147    case 1:
 148        if (extract32(pac, 0, 1) == 0) {
 149            return false;
 150        }
 151        break;
 152    case 0:
 153        if (extract32(pac, 1, 1) == 0) {
 154            return false;
 155        }
 156        break;
 157    default:
 158        g_assert_not_reached();
 159    }
 160
 161    wt = extract64(cr, 20, 1);
 162    lbn = extract64(cr, 16, 4);
 163
 164    if (wt && !linked_bp_matches(cpu, lbn)) {
 165        return false;
 166    }
 167
 168    return true;
 169}
 170
 171static bool check_watchpoints(ARMCPU *cpu)
 172{
 173    CPUARMState *env = &cpu->env;
 174    int n;
 175
 176    /*
 177     * If watchpoints are disabled globally or we can't take debug
 178     * exceptions here then watchpoint firings are ignored.
 179     */
 180    if (extract32(env->cp15.mdscr_el1, 15, 1) == 0
 181        || !arm_generate_debug_exceptions(env)) {
 182        return false;
 183    }
 184
 185    for (n = 0; n < ARRAY_SIZE(env->cpu_watchpoint); n++) {
 186        if (bp_wp_matches(cpu, n, true)) {
 187            return true;
 188        }
 189    }
 190    return false;
 191}
 192
 193static bool check_breakpoints(ARMCPU *cpu)
 194{
 195    CPUARMState *env = &cpu->env;
 196    int n;
 197
 198    /*
 199     * If breakpoints are disabled globally or we can't take debug
 200     * exceptions here then breakpoint firings are ignored.
 201     */
 202    if (extract32(env->cp15.mdscr_el1, 15, 1) == 0
 203        || !arm_generate_debug_exceptions(env)) {
 204        return false;
 205    }
 206
 207    for (n = 0; n < ARRAY_SIZE(env->cpu_breakpoint); n++) {
 208        if (bp_wp_matches(cpu, n, false)) {
 209            return true;
 210        }
 211    }
 212    return false;
 213}
 214
 215void HELPER(check_breakpoints)(CPUARMState *env)
 216{
 217    ARMCPU *cpu = env_archcpu(env);
 218
 219    if (check_breakpoints(cpu)) {
 220        HELPER(exception_internal(env, EXCP_DEBUG));
 221    }
 222}
 223
 224bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp)
 225{
 226    /*
 227     * Called by core code when a CPU watchpoint fires; need to check if this
 228     * is also an architectural watchpoint match.
 229     */
 230    ARMCPU *cpu = ARM_CPU(cs);
 231
 232    return check_watchpoints(cpu);
 233}
 234
 235void arm_debug_excp_handler(CPUState *cs)
 236{
 237    /*
 238     * Called by core code when a watchpoint or breakpoint fires;
 239     * need to check which one and raise the appropriate exception.
 240     */
 241    ARMCPU *cpu = ARM_CPU(cs);
 242    CPUARMState *env = &cpu->env;
 243    CPUWatchpoint *wp_hit = cs->watchpoint_hit;
 244
 245    if (wp_hit) {
 246        if (wp_hit->flags & BP_CPU) {
 247            bool wnr = (wp_hit->flags & BP_WATCHPOINT_HIT_WRITE) != 0;
 248            bool same_el = arm_debug_target_el(env) == arm_current_el(env);
 249
 250            cs->watchpoint_hit = NULL;
 251
 252            env->exception.fsr = arm_debug_exception_fsr(env);
 253            env->exception.vaddress = wp_hit->hitaddr;
 254            raise_exception(env, EXCP_DATA_ABORT,
 255                    syn_watchpoint(same_el, 0, wnr),
 256                    arm_debug_target_el(env));
 257        }
 258    } else {
 259        uint64_t pc = is_a64(env) ? env->pc : env->regs[15];
 260        bool same_el = (arm_debug_target_el(env) == arm_current_el(env));
 261
 262        /*
 263         * (1) GDB breakpoints should be handled first.
 264         * (2) Do not raise a CPU exception if no CPU breakpoint has fired,
 265         * since singlestep is also done by generating a debug internal
 266         * exception.
 267         */
 268        if (cpu_breakpoint_test(cs, pc, BP_GDB)
 269            || !cpu_breakpoint_test(cs, pc, BP_CPU)) {
 270            return;
 271        }
 272
 273        env->exception.fsr = arm_debug_exception_fsr(env);
 274        /*
 275         * FAR is UNKNOWN: clear vaddress to avoid potentially exposing
 276         * values to the guest that it shouldn't be able to see at its
 277         * exception/security level.
 278         */
 279        env->exception.vaddress = 0;
 280        raise_exception(env, EXCP_PREFETCH_ABORT,
 281                        syn_breakpoint(same_el),
 282                        arm_debug_target_el(env));
 283    }
 284}
 285
 286#if !defined(CONFIG_USER_ONLY)
 287
 288vaddr arm_adjust_watchpoint_address(CPUState *cs, vaddr addr, int len)
 289{
 290    ARMCPU *cpu = ARM_CPU(cs);
 291    CPUARMState *env = &cpu->env;
 292
 293    /*
 294     * In BE32 system mode, target memory is stored byteswapped (on a
 295     * little-endian host system), and by the time we reach here (via an
 296     * opcode helper) the addresses of subword accesses have been adjusted
 297     * to account for that, which means that watchpoints will not match.
 298     * Undo the adjustment here.
 299     */
 300    if (arm_sctlr_b(env)) {
 301        if (len == 1) {
 302            addr ^= 3;
 303        } else if (len == 2) {
 304            addr ^= 2;
 305        }
 306    }
 307
 308    return addr;
 309}
 310
 311#endif
 312