1*8803bfeaSMax Filippov /* 2*8803bfeaSMax Filippov * Copyright (c) 2011 - 2019, Max Filippov, Open Source and Linux Lab. 3*8803bfeaSMax Filippov * All rights reserved. 4*8803bfeaSMax Filippov * 5*8803bfeaSMax Filippov * Redistribution and use in source and binary forms, with or without 6*8803bfeaSMax Filippov * modification, are permitted provided that the following conditions are met: 7*8803bfeaSMax Filippov * * Redistributions of source code must retain the above copyright 8*8803bfeaSMax Filippov * notice, this list of conditions and the following disclaimer. 9*8803bfeaSMax Filippov * * Redistributions in binary form must reproduce the above copyright 10*8803bfeaSMax Filippov * notice, this list of conditions and the following disclaimer in the 11*8803bfeaSMax Filippov * documentation and/or other materials provided with the distribution. 12*8803bfeaSMax Filippov * * Neither the name of the Open Source and Linux Lab nor the 13*8803bfeaSMax Filippov * names of its contributors may be used to endorse or promote products 14*8803bfeaSMax Filippov * derived from this software without specific prior written permission. 15*8803bfeaSMax Filippov * 16*8803bfeaSMax Filippov * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17*8803bfeaSMax Filippov * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18*8803bfeaSMax Filippov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19*8803bfeaSMax Filippov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20*8803bfeaSMax Filippov * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21*8803bfeaSMax Filippov * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22*8803bfeaSMax Filippov * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23*8803bfeaSMax Filippov * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24*8803bfeaSMax Filippov * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25*8803bfeaSMax Filippov * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26*8803bfeaSMax Filippov */ 27*8803bfeaSMax Filippov 28*8803bfeaSMax Filippov #include "qemu/osdep.h" 29*8803bfeaSMax Filippov #include "qemu/main-loop.h" 30*8803bfeaSMax Filippov #include "cpu.h" 31*8803bfeaSMax Filippov #include "exec/helper-proto.h" 32*8803bfeaSMax Filippov #include "qemu/host-utils.h" 33*8803bfeaSMax Filippov #include "exec/exec-all.h" 34*8803bfeaSMax Filippov #include "exec/address-spaces.h" 35*8803bfeaSMax Filippov 36*8803bfeaSMax Filippov static void tb_invalidate_virtual_addr(CPUXtensaState *env, uint32_t vaddr) 37*8803bfeaSMax Filippov { 38*8803bfeaSMax Filippov uint32_t paddr; 39*8803bfeaSMax Filippov uint32_t page_size; 40*8803bfeaSMax Filippov unsigned access; 41*8803bfeaSMax Filippov int ret = xtensa_get_physical_addr(env, false, vaddr, 2, 0, 42*8803bfeaSMax Filippov &paddr, &page_size, &access); 43*8803bfeaSMax Filippov if (ret == 0) { 44*8803bfeaSMax Filippov tb_invalidate_phys_addr(&address_space_memory, paddr, 45*8803bfeaSMax Filippov MEMTXATTRS_UNSPECIFIED); 46*8803bfeaSMax Filippov } 47*8803bfeaSMax Filippov } 48*8803bfeaSMax Filippov 49*8803bfeaSMax Filippov void HELPER(wsr_ibreakenable)(CPUXtensaState *env, uint32_t v) 50*8803bfeaSMax Filippov { 51*8803bfeaSMax Filippov uint32_t change = v ^ env->sregs[IBREAKENABLE]; 52*8803bfeaSMax Filippov unsigned i; 53*8803bfeaSMax Filippov 54*8803bfeaSMax Filippov for (i = 0; i < env->config->nibreak; ++i) { 55*8803bfeaSMax Filippov if (change & (1 << i)) { 56*8803bfeaSMax Filippov tb_invalidate_virtual_addr(env, env->sregs[IBREAKA + i]); 57*8803bfeaSMax Filippov } 58*8803bfeaSMax Filippov } 59*8803bfeaSMax Filippov env->sregs[IBREAKENABLE] = v & ((1 << env->config->nibreak) - 1); 60*8803bfeaSMax Filippov } 61*8803bfeaSMax Filippov 62*8803bfeaSMax Filippov void HELPER(wsr_ibreaka)(CPUXtensaState *env, uint32_t i, uint32_t v) 63*8803bfeaSMax Filippov { 64*8803bfeaSMax Filippov if (env->sregs[IBREAKENABLE] & (1 << i) && env->sregs[IBREAKA + i] != v) { 65*8803bfeaSMax Filippov tb_invalidate_virtual_addr(env, env->sregs[IBREAKA + i]); 66*8803bfeaSMax Filippov tb_invalidate_virtual_addr(env, v); 67*8803bfeaSMax Filippov } 68*8803bfeaSMax Filippov env->sregs[IBREAKA + i] = v; 69*8803bfeaSMax Filippov } 70*8803bfeaSMax Filippov 71*8803bfeaSMax Filippov static void set_dbreak(CPUXtensaState *env, unsigned i, uint32_t dbreaka, 72*8803bfeaSMax Filippov uint32_t dbreakc) 73*8803bfeaSMax Filippov { 74*8803bfeaSMax Filippov CPUState *cs = CPU(xtensa_env_get_cpu(env)); 75*8803bfeaSMax Filippov int flags = BP_CPU | BP_STOP_BEFORE_ACCESS; 76*8803bfeaSMax Filippov uint32_t mask = dbreakc | ~DBREAKC_MASK; 77*8803bfeaSMax Filippov 78*8803bfeaSMax Filippov if (env->cpu_watchpoint[i]) { 79*8803bfeaSMax Filippov cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[i]); 80*8803bfeaSMax Filippov } 81*8803bfeaSMax Filippov if (dbreakc & DBREAKC_SB) { 82*8803bfeaSMax Filippov flags |= BP_MEM_WRITE; 83*8803bfeaSMax Filippov } 84*8803bfeaSMax Filippov if (dbreakc & DBREAKC_LB) { 85*8803bfeaSMax Filippov flags |= BP_MEM_READ; 86*8803bfeaSMax Filippov } 87*8803bfeaSMax Filippov /* contiguous mask after inversion is one less than some power of 2 */ 88*8803bfeaSMax Filippov if ((~mask + 1) & ~mask) { 89*8803bfeaSMax Filippov qemu_log_mask(LOG_GUEST_ERROR, 90*8803bfeaSMax Filippov "DBREAKC mask is not contiguous: 0x%08x\n", dbreakc); 91*8803bfeaSMax Filippov /* cut mask after the first zero bit */ 92*8803bfeaSMax Filippov mask = 0xffffffff << (32 - clo32(mask)); 93*8803bfeaSMax Filippov } 94*8803bfeaSMax Filippov if (cpu_watchpoint_insert(cs, dbreaka & mask, ~mask + 1, 95*8803bfeaSMax Filippov flags, &env->cpu_watchpoint[i])) { 96*8803bfeaSMax Filippov env->cpu_watchpoint[i] = NULL; 97*8803bfeaSMax Filippov qemu_log_mask(LOG_GUEST_ERROR, 98*8803bfeaSMax Filippov "Failed to set data breakpoint at 0x%08x/%d\n", 99*8803bfeaSMax Filippov dbreaka & mask, ~mask + 1); 100*8803bfeaSMax Filippov } 101*8803bfeaSMax Filippov } 102*8803bfeaSMax Filippov 103*8803bfeaSMax Filippov void HELPER(wsr_dbreaka)(CPUXtensaState *env, uint32_t i, uint32_t v) 104*8803bfeaSMax Filippov { 105*8803bfeaSMax Filippov uint32_t dbreakc = env->sregs[DBREAKC + i]; 106*8803bfeaSMax Filippov 107*8803bfeaSMax Filippov if ((dbreakc & DBREAKC_SB_LB) && 108*8803bfeaSMax Filippov env->sregs[DBREAKA + i] != v) { 109*8803bfeaSMax Filippov set_dbreak(env, i, v, dbreakc); 110*8803bfeaSMax Filippov } 111*8803bfeaSMax Filippov env->sregs[DBREAKA + i] = v; 112*8803bfeaSMax Filippov } 113*8803bfeaSMax Filippov 114*8803bfeaSMax Filippov void HELPER(wsr_dbreakc)(CPUXtensaState *env, uint32_t i, uint32_t v) 115*8803bfeaSMax Filippov { 116*8803bfeaSMax Filippov if ((env->sregs[DBREAKC + i] ^ v) & (DBREAKC_SB_LB | DBREAKC_MASK)) { 117*8803bfeaSMax Filippov if (v & DBREAKC_SB_LB) { 118*8803bfeaSMax Filippov set_dbreak(env, i, env->sregs[DBREAKA + i], v); 119*8803bfeaSMax Filippov } else { 120*8803bfeaSMax Filippov if (env->cpu_watchpoint[i]) { 121*8803bfeaSMax Filippov CPUState *cs = CPU(xtensa_env_get_cpu(env)); 122*8803bfeaSMax Filippov 123*8803bfeaSMax Filippov cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[i]); 124*8803bfeaSMax Filippov env->cpu_watchpoint[i] = NULL; 125*8803bfeaSMax Filippov } 126*8803bfeaSMax Filippov } 127*8803bfeaSMax Filippov } 128*8803bfeaSMax Filippov env->sregs[DBREAKC + i] = v; 129*8803bfeaSMax Filippov } 130