18803bfeaSMax Filippov /* 28803bfeaSMax Filippov * Copyright (c) 2011 - 2019, Max Filippov, Open Source and Linux Lab. 38803bfeaSMax Filippov * All rights reserved. 48803bfeaSMax Filippov * 58803bfeaSMax Filippov * Redistribution and use in source and binary forms, with or without 68803bfeaSMax Filippov * modification, are permitted provided that the following conditions are met: 78803bfeaSMax Filippov * * Redistributions of source code must retain the above copyright 88803bfeaSMax Filippov * notice, this list of conditions and the following disclaimer. 98803bfeaSMax Filippov * * Redistributions in binary form must reproduce the above copyright 108803bfeaSMax Filippov * notice, this list of conditions and the following disclaimer in the 118803bfeaSMax Filippov * documentation and/or other materials provided with the distribution. 128803bfeaSMax Filippov * * Neither the name of the Open Source and Linux Lab nor the 138803bfeaSMax Filippov * names of its contributors may be used to endorse or promote products 148803bfeaSMax Filippov * derived from this software without specific prior written permission. 158803bfeaSMax Filippov * 168803bfeaSMax Filippov * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 178803bfeaSMax Filippov * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 188803bfeaSMax Filippov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 198803bfeaSMax Filippov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 208803bfeaSMax Filippov * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 218803bfeaSMax Filippov * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 228803bfeaSMax Filippov * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 238803bfeaSMax Filippov * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 248803bfeaSMax Filippov * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 258803bfeaSMax Filippov * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 268803bfeaSMax Filippov */ 278803bfeaSMax Filippov 288803bfeaSMax Filippov #include "qemu/osdep.h" 29cd617484SPhilippe Mathieu-Daudé #include "qemu/log.h" 308803bfeaSMax Filippov #include "cpu.h" 318803bfeaSMax Filippov #include "exec/helper-proto.h" 328803bfeaSMax Filippov #include "qemu/host-utils.h" 338803bfeaSMax Filippov #include "exec/exec-all.h" 348803bfeaSMax Filippov #include "exec/address-spaces.h" 358803bfeaSMax Filippov 368803bfeaSMax Filippov void HELPER(wsr_ibreakenable)(CPUXtensaState *env, uint32_t v) 378803bfeaSMax Filippov { 38*5f3ebbc8SMax Filippov CPUState *cs = env_cpu(env); 398803bfeaSMax Filippov uint32_t change = v ^ env->sregs[IBREAKENABLE]; 408803bfeaSMax Filippov unsigned i; 418803bfeaSMax Filippov 428803bfeaSMax Filippov for (i = 0; i < env->config->nibreak; ++i) { 438803bfeaSMax Filippov if (change & (1 << i)) { 44*5f3ebbc8SMax Filippov if (v & (1 << i)) { 45*5f3ebbc8SMax Filippov cpu_breakpoint_insert(cs, env->sregs[IBREAKA + i], 46*5f3ebbc8SMax Filippov BP_CPU, &env->cpu_breakpoint[i]); 47*5f3ebbc8SMax Filippov } else { 48*5f3ebbc8SMax Filippov cpu_breakpoint_remove_by_ref(cs, env->cpu_breakpoint[i]); 49*5f3ebbc8SMax Filippov env->cpu_breakpoint[i] = NULL; 50*5f3ebbc8SMax Filippov } 518803bfeaSMax Filippov } 528803bfeaSMax Filippov } 538803bfeaSMax Filippov env->sregs[IBREAKENABLE] = v & ((1 << env->config->nibreak) - 1); 548803bfeaSMax Filippov } 558803bfeaSMax Filippov 568803bfeaSMax Filippov void HELPER(wsr_ibreaka)(CPUXtensaState *env, uint32_t i, uint32_t v) 578803bfeaSMax Filippov { 588803bfeaSMax Filippov if (env->sregs[IBREAKENABLE] & (1 << i) && env->sregs[IBREAKA + i] != v) { 59*5f3ebbc8SMax Filippov CPUState *cs = env_cpu(env); 60*5f3ebbc8SMax Filippov 61*5f3ebbc8SMax Filippov cpu_breakpoint_remove_by_ref(cs, env->cpu_breakpoint[i]); 62*5f3ebbc8SMax Filippov cpu_breakpoint_insert(cs, v, BP_CPU, &env->cpu_breakpoint[i]); 638803bfeaSMax Filippov } 648803bfeaSMax Filippov env->sregs[IBREAKA + i] = v; 658803bfeaSMax Filippov } 668803bfeaSMax Filippov 67*5f3ebbc8SMax Filippov bool xtensa_debug_check_breakpoint(CPUState *cs) 68*5f3ebbc8SMax Filippov { 69*5f3ebbc8SMax Filippov XtensaCPU *cpu = XTENSA_CPU(cs); 70*5f3ebbc8SMax Filippov CPUXtensaState *env = &cpu->env; 71*5f3ebbc8SMax Filippov unsigned int i; 72*5f3ebbc8SMax Filippov 73*5f3ebbc8SMax Filippov if (xtensa_get_cintlevel(env) >= env->config->debug_level) { 74*5f3ebbc8SMax Filippov return false; 75*5f3ebbc8SMax Filippov } 76*5f3ebbc8SMax Filippov for (i = 0; i < env->config->nibreak; ++i) { 77*5f3ebbc8SMax Filippov if (env->sregs[IBREAKENABLE] & (1 << i) && 78*5f3ebbc8SMax Filippov env->sregs[IBREAKA + i] == env->pc) { 79*5f3ebbc8SMax Filippov return true; 80*5f3ebbc8SMax Filippov } 81*5f3ebbc8SMax Filippov } 82*5f3ebbc8SMax Filippov return false; 83*5f3ebbc8SMax Filippov } 84*5f3ebbc8SMax Filippov 858803bfeaSMax Filippov static void set_dbreak(CPUXtensaState *env, unsigned i, uint32_t dbreaka, 868803bfeaSMax Filippov uint32_t dbreakc) 878803bfeaSMax Filippov { 8892fddfbdSRichard Henderson CPUState *cs = env_cpu(env); 898803bfeaSMax Filippov int flags = BP_CPU | BP_STOP_BEFORE_ACCESS; 908803bfeaSMax Filippov uint32_t mask = dbreakc | ~DBREAKC_MASK; 918803bfeaSMax Filippov 928803bfeaSMax Filippov if (env->cpu_watchpoint[i]) { 938803bfeaSMax Filippov cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[i]); 948803bfeaSMax Filippov } 958803bfeaSMax Filippov if (dbreakc & DBREAKC_SB) { 968803bfeaSMax Filippov flags |= BP_MEM_WRITE; 978803bfeaSMax Filippov } 988803bfeaSMax Filippov if (dbreakc & DBREAKC_LB) { 998803bfeaSMax Filippov flags |= BP_MEM_READ; 1008803bfeaSMax Filippov } 1018803bfeaSMax Filippov /* contiguous mask after inversion is one less than some power of 2 */ 1028803bfeaSMax Filippov if ((~mask + 1) & ~mask) { 1038803bfeaSMax Filippov qemu_log_mask(LOG_GUEST_ERROR, 1048803bfeaSMax Filippov "DBREAKC mask is not contiguous: 0x%08x\n", dbreakc); 1058803bfeaSMax Filippov /* cut mask after the first zero bit */ 1068803bfeaSMax Filippov mask = 0xffffffff << (32 - clo32(mask)); 1078803bfeaSMax Filippov } 1088803bfeaSMax Filippov if (cpu_watchpoint_insert(cs, dbreaka & mask, ~mask + 1, 1098803bfeaSMax Filippov flags, &env->cpu_watchpoint[i])) { 1108803bfeaSMax Filippov env->cpu_watchpoint[i] = NULL; 1118803bfeaSMax Filippov qemu_log_mask(LOG_GUEST_ERROR, 1128803bfeaSMax Filippov "Failed to set data breakpoint at 0x%08x/%d\n", 1138803bfeaSMax Filippov dbreaka & mask, ~mask + 1); 1148803bfeaSMax Filippov } 1158803bfeaSMax Filippov } 1168803bfeaSMax Filippov 1178803bfeaSMax Filippov void HELPER(wsr_dbreaka)(CPUXtensaState *env, uint32_t i, uint32_t v) 1188803bfeaSMax Filippov { 1198803bfeaSMax Filippov uint32_t dbreakc = env->sregs[DBREAKC + i]; 1208803bfeaSMax Filippov 1218803bfeaSMax Filippov if ((dbreakc & DBREAKC_SB_LB) && 1228803bfeaSMax Filippov env->sregs[DBREAKA + i] != v) { 1238803bfeaSMax Filippov set_dbreak(env, i, v, dbreakc); 1248803bfeaSMax Filippov } 1258803bfeaSMax Filippov env->sregs[DBREAKA + i] = v; 1268803bfeaSMax Filippov } 1278803bfeaSMax Filippov 1288803bfeaSMax Filippov void HELPER(wsr_dbreakc)(CPUXtensaState *env, uint32_t i, uint32_t v) 1298803bfeaSMax Filippov { 1308803bfeaSMax Filippov if ((env->sregs[DBREAKC + i] ^ v) & (DBREAKC_SB_LB | DBREAKC_MASK)) { 1318803bfeaSMax Filippov if (v & DBREAKC_SB_LB) { 1328803bfeaSMax Filippov set_dbreak(env, i, env->sregs[DBREAKA + i], v); 1338803bfeaSMax Filippov } else { 1348803bfeaSMax Filippov if (env->cpu_watchpoint[i]) { 13592fddfbdSRichard Henderson CPUState *cs = env_cpu(env); 1368803bfeaSMax Filippov 1378803bfeaSMax Filippov cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[i]); 1388803bfeaSMax Filippov env->cpu_watchpoint[i] = NULL; 1398803bfeaSMax Filippov } 1408803bfeaSMax Filippov } 1418803bfeaSMax Filippov } 1428803bfeaSMax Filippov env->sregs[DBREAKC + i] = v; 1438803bfeaSMax Filippov } 144