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 { 385f3ebbc8SMax 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)) { 445f3ebbc8SMax Filippov if (v & (1 << i)) { 455f3ebbc8SMax Filippov cpu_breakpoint_insert(cs, env->sregs[IBREAKA + i], 465f3ebbc8SMax Filippov BP_CPU, &env->cpu_breakpoint[i]); 475f3ebbc8SMax Filippov } else { 485f3ebbc8SMax Filippov cpu_breakpoint_remove_by_ref(cs, env->cpu_breakpoint[i]); 495f3ebbc8SMax Filippov env->cpu_breakpoint[i] = NULL; 505f3ebbc8SMax 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) { 595f3ebbc8SMax Filippov CPUState *cs = env_cpu(env); 605f3ebbc8SMax Filippov 615f3ebbc8SMax Filippov cpu_breakpoint_remove_by_ref(cs, env->cpu_breakpoint[i]); 625f3ebbc8SMax 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 675f3ebbc8SMax Filippov bool xtensa_debug_check_breakpoint(CPUState *cs) 685f3ebbc8SMax Filippov { 69*52049266SPhilippe Mathieu-Daudé CPUXtensaState *env = cpu_env(cs); 705f3ebbc8SMax Filippov unsigned int i; 715f3ebbc8SMax Filippov 725f3ebbc8SMax Filippov if (xtensa_get_cintlevel(env) >= env->config->debug_level) { 735f3ebbc8SMax Filippov return false; 745f3ebbc8SMax Filippov } 755f3ebbc8SMax Filippov for (i = 0; i < env->config->nibreak; ++i) { 765f3ebbc8SMax Filippov if (env->sregs[IBREAKENABLE] & (1 << i) && 775f3ebbc8SMax Filippov env->sregs[IBREAKA + i] == env->pc) { 785f3ebbc8SMax Filippov return true; 795f3ebbc8SMax Filippov } 805f3ebbc8SMax Filippov } 815f3ebbc8SMax Filippov return false; 825f3ebbc8SMax Filippov } 835f3ebbc8SMax Filippov 848803bfeaSMax Filippov static void set_dbreak(CPUXtensaState *env, unsigned i, uint32_t dbreaka, 858803bfeaSMax Filippov uint32_t dbreakc) 868803bfeaSMax Filippov { 8792fddfbdSRichard Henderson CPUState *cs = env_cpu(env); 888803bfeaSMax Filippov int flags = BP_CPU | BP_STOP_BEFORE_ACCESS; 898803bfeaSMax Filippov uint32_t mask = dbreakc | ~DBREAKC_MASK; 908803bfeaSMax Filippov 918803bfeaSMax Filippov if (env->cpu_watchpoint[i]) { 928803bfeaSMax Filippov cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[i]); 938803bfeaSMax Filippov } 948803bfeaSMax Filippov if (dbreakc & DBREAKC_SB) { 958803bfeaSMax Filippov flags |= BP_MEM_WRITE; 968803bfeaSMax Filippov } 978803bfeaSMax Filippov if (dbreakc & DBREAKC_LB) { 988803bfeaSMax Filippov flags |= BP_MEM_READ; 998803bfeaSMax Filippov } 1008803bfeaSMax Filippov /* contiguous mask after inversion is one less than some power of 2 */ 1018803bfeaSMax Filippov if ((~mask + 1) & ~mask) { 1028803bfeaSMax Filippov qemu_log_mask(LOG_GUEST_ERROR, 1038803bfeaSMax Filippov "DBREAKC mask is not contiguous: 0x%08x\n", dbreakc); 1048803bfeaSMax Filippov /* cut mask after the first zero bit */ 1058803bfeaSMax Filippov mask = 0xffffffff << (32 - clo32(mask)); 1068803bfeaSMax Filippov } 1078803bfeaSMax Filippov if (cpu_watchpoint_insert(cs, dbreaka & mask, ~mask + 1, 1088803bfeaSMax Filippov flags, &env->cpu_watchpoint[i])) { 1098803bfeaSMax Filippov env->cpu_watchpoint[i] = NULL; 1108803bfeaSMax Filippov qemu_log_mask(LOG_GUEST_ERROR, 1118803bfeaSMax Filippov "Failed to set data breakpoint at 0x%08x/%d\n", 1128803bfeaSMax Filippov dbreaka & mask, ~mask + 1); 1138803bfeaSMax Filippov } 1148803bfeaSMax Filippov } 1158803bfeaSMax Filippov 1168803bfeaSMax Filippov void HELPER(wsr_dbreaka)(CPUXtensaState *env, uint32_t i, uint32_t v) 1178803bfeaSMax Filippov { 1188803bfeaSMax Filippov uint32_t dbreakc = env->sregs[DBREAKC + i]; 1198803bfeaSMax Filippov 1208803bfeaSMax Filippov if ((dbreakc & DBREAKC_SB_LB) && 1218803bfeaSMax Filippov env->sregs[DBREAKA + i] != v) { 1228803bfeaSMax Filippov set_dbreak(env, i, v, dbreakc); 1238803bfeaSMax Filippov } 1248803bfeaSMax Filippov env->sregs[DBREAKA + i] = v; 1258803bfeaSMax Filippov } 1268803bfeaSMax Filippov 1278803bfeaSMax Filippov void HELPER(wsr_dbreakc)(CPUXtensaState *env, uint32_t i, uint32_t v) 1288803bfeaSMax Filippov { 1298803bfeaSMax Filippov if ((env->sregs[DBREAKC + i] ^ v) & (DBREAKC_SB_LB | DBREAKC_MASK)) { 1308803bfeaSMax Filippov if (v & DBREAKC_SB_LB) { 1318803bfeaSMax Filippov set_dbreak(env, i, env->sregs[DBREAKA + i], v); 1328803bfeaSMax Filippov } else { 1338803bfeaSMax Filippov if (env->cpu_watchpoint[i]) { 13492fddfbdSRichard Henderson CPUState *cs = env_cpu(env); 1358803bfeaSMax Filippov 1368803bfeaSMax Filippov cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[i]); 1378803bfeaSMax Filippov env->cpu_watchpoint[i] = NULL; 1388803bfeaSMax Filippov } 1398803bfeaSMax Filippov } 1408803bfeaSMax Filippov } 1418803bfeaSMax Filippov env->sregs[DBREAKC + i] = v; 1428803bfeaSMax Filippov } 143