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" 298803bfeaSMax Filippov #include "qemu/main-loop.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 static void tb_invalidate_virtual_addr(CPUXtensaState *env, uint32_t vaddr) 378803bfeaSMax Filippov { 388803bfeaSMax Filippov uint32_t paddr; 398803bfeaSMax Filippov uint32_t page_size; 408803bfeaSMax Filippov unsigned access; 418803bfeaSMax Filippov int ret = xtensa_get_physical_addr(env, false, vaddr, 2, 0, 428803bfeaSMax Filippov &paddr, &page_size, &access); 438803bfeaSMax Filippov if (ret == 0) { 448803bfeaSMax Filippov tb_invalidate_phys_addr(&address_space_memory, paddr, 458803bfeaSMax Filippov MEMTXATTRS_UNSPECIFIED); 468803bfeaSMax Filippov } 478803bfeaSMax Filippov } 488803bfeaSMax Filippov 498803bfeaSMax Filippov void HELPER(wsr_ibreakenable)(CPUXtensaState *env, uint32_t v) 508803bfeaSMax Filippov { 518803bfeaSMax Filippov uint32_t change = v ^ env->sregs[IBREAKENABLE]; 528803bfeaSMax Filippov unsigned i; 538803bfeaSMax Filippov 548803bfeaSMax Filippov for (i = 0; i < env->config->nibreak; ++i) { 558803bfeaSMax Filippov if (change & (1 << i)) { 568803bfeaSMax Filippov tb_invalidate_virtual_addr(env, env->sregs[IBREAKA + i]); 578803bfeaSMax Filippov } 588803bfeaSMax Filippov } 598803bfeaSMax Filippov env->sregs[IBREAKENABLE] = v & ((1 << env->config->nibreak) - 1); 608803bfeaSMax Filippov } 618803bfeaSMax Filippov 628803bfeaSMax Filippov void HELPER(wsr_ibreaka)(CPUXtensaState *env, uint32_t i, uint32_t v) 638803bfeaSMax Filippov { 648803bfeaSMax Filippov if (env->sregs[IBREAKENABLE] & (1 << i) && env->sregs[IBREAKA + i] != v) { 658803bfeaSMax Filippov tb_invalidate_virtual_addr(env, env->sregs[IBREAKA + i]); 668803bfeaSMax Filippov tb_invalidate_virtual_addr(env, v); 678803bfeaSMax Filippov } 688803bfeaSMax Filippov env->sregs[IBREAKA + i] = v; 698803bfeaSMax Filippov } 708803bfeaSMax Filippov 718803bfeaSMax Filippov static void set_dbreak(CPUXtensaState *env, unsigned i, uint32_t dbreaka, 728803bfeaSMax Filippov uint32_t dbreakc) 738803bfeaSMax Filippov { 74*92fddfbdSRichard Henderson CPUState *cs = env_cpu(env); 758803bfeaSMax Filippov int flags = BP_CPU | BP_STOP_BEFORE_ACCESS; 768803bfeaSMax Filippov uint32_t mask = dbreakc | ~DBREAKC_MASK; 778803bfeaSMax Filippov 788803bfeaSMax Filippov if (env->cpu_watchpoint[i]) { 798803bfeaSMax Filippov cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[i]); 808803bfeaSMax Filippov } 818803bfeaSMax Filippov if (dbreakc & DBREAKC_SB) { 828803bfeaSMax Filippov flags |= BP_MEM_WRITE; 838803bfeaSMax Filippov } 848803bfeaSMax Filippov if (dbreakc & DBREAKC_LB) { 858803bfeaSMax Filippov flags |= BP_MEM_READ; 868803bfeaSMax Filippov } 878803bfeaSMax Filippov /* contiguous mask after inversion is one less than some power of 2 */ 888803bfeaSMax Filippov if ((~mask + 1) & ~mask) { 898803bfeaSMax Filippov qemu_log_mask(LOG_GUEST_ERROR, 908803bfeaSMax Filippov "DBREAKC mask is not contiguous: 0x%08x\n", dbreakc); 918803bfeaSMax Filippov /* cut mask after the first zero bit */ 928803bfeaSMax Filippov mask = 0xffffffff << (32 - clo32(mask)); 938803bfeaSMax Filippov } 948803bfeaSMax Filippov if (cpu_watchpoint_insert(cs, dbreaka & mask, ~mask + 1, 958803bfeaSMax Filippov flags, &env->cpu_watchpoint[i])) { 968803bfeaSMax Filippov env->cpu_watchpoint[i] = NULL; 978803bfeaSMax Filippov qemu_log_mask(LOG_GUEST_ERROR, 988803bfeaSMax Filippov "Failed to set data breakpoint at 0x%08x/%d\n", 998803bfeaSMax Filippov dbreaka & mask, ~mask + 1); 1008803bfeaSMax Filippov } 1018803bfeaSMax Filippov } 1028803bfeaSMax Filippov 1038803bfeaSMax Filippov void HELPER(wsr_dbreaka)(CPUXtensaState *env, uint32_t i, uint32_t v) 1048803bfeaSMax Filippov { 1058803bfeaSMax Filippov uint32_t dbreakc = env->sregs[DBREAKC + i]; 1068803bfeaSMax Filippov 1078803bfeaSMax Filippov if ((dbreakc & DBREAKC_SB_LB) && 1088803bfeaSMax Filippov env->sregs[DBREAKA + i] != v) { 1098803bfeaSMax Filippov set_dbreak(env, i, v, dbreakc); 1108803bfeaSMax Filippov } 1118803bfeaSMax Filippov env->sregs[DBREAKA + i] = v; 1128803bfeaSMax Filippov } 1138803bfeaSMax Filippov 1148803bfeaSMax Filippov void HELPER(wsr_dbreakc)(CPUXtensaState *env, uint32_t i, uint32_t v) 1158803bfeaSMax Filippov { 1168803bfeaSMax Filippov if ((env->sregs[DBREAKC + i] ^ v) & (DBREAKC_SB_LB | DBREAKC_MASK)) { 1178803bfeaSMax Filippov if (v & DBREAKC_SB_LB) { 1188803bfeaSMax Filippov set_dbreak(env, i, env->sregs[DBREAKA + i], v); 1198803bfeaSMax Filippov } else { 1208803bfeaSMax Filippov if (env->cpu_watchpoint[i]) { 121*92fddfbdSRichard Henderson CPUState *cs = env_cpu(env); 1228803bfeaSMax Filippov 1238803bfeaSMax Filippov cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[i]); 1248803bfeaSMax Filippov env->cpu_watchpoint[i] = NULL; 1258803bfeaSMax Filippov } 1268803bfeaSMax Filippov } 1278803bfeaSMax Filippov } 1288803bfeaSMax Filippov env->sregs[DBREAKC + i] = v; 1298803bfeaSMax Filippov } 130