1 /* 2 * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * * Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * * Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * * Neither the name of the Open Source and Linux Lab nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "qemu/osdep.h" 29 #include "cpu.h" 30 #include "exec/helper-proto.h" 31 #include "qemu/host-utils.h" 32 #include "exec/exec-all.h" 33 #include "qemu/atomic.h" 34 #include "qemu/timer.h" 35 36 #ifndef CONFIG_USER_ONLY 37 38 void HELPER(update_ccount)(CPUXtensaState *env) 39 { 40 XtensaCPU *cpu = XTENSA_CPU(env_cpu(env)); 41 uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 42 43 env->ccount_time = now; 44 env->sregs[CCOUNT] = env->ccount_base + 45 (uint32_t)clock_ns_to_ticks(cpu->clock, now - env->time_base); 46 } 47 48 void HELPER(wsr_ccount)(CPUXtensaState *env, uint32_t v) 49 { 50 int i; 51 52 HELPER(update_ccount)(env); 53 env->ccount_base += v - env->sregs[CCOUNT]; 54 for (i = 0; i < env->config->nccompare; ++i) { 55 HELPER(update_ccompare)(env, i); 56 } 57 } 58 59 void HELPER(update_ccompare)(CPUXtensaState *env, uint32_t i) 60 { 61 XtensaCPU *cpu = XTENSA_CPU(env_cpu(env)); 62 uint64_t dcc; 63 64 qatomic_and(&env->sregs[INTSET], 65 ~(1u << env->config->timerint[i])); 66 HELPER(update_ccount)(env); 67 dcc = (uint64_t)(env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] - 1) + 1; 68 timer_mod(env->ccompare[i].timer, 69 env->ccount_time + clock_ticks_to_ns(cpu->clock, dcc)); 70 env->yield_needed = 1; 71 } 72 73 /*! 74 * Check vaddr accessibility/cache attributes and raise an exception if 75 * specified by the ATOMCTL SR. 76 * 77 * Note: local memory exclusion is not implemented 78 */ 79 void HELPER(check_atomctl)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr) 80 { 81 uint32_t paddr, page_size, access; 82 uint32_t atomctl = env->sregs[ATOMCTL]; 83 int rc = xtensa_get_physical_addr(env, true, vaddr, 1, 84 xtensa_get_cring(env), &paddr, &page_size, &access); 85 86 /* 87 * s32c1i never causes LOAD_PROHIBITED_CAUSE exceptions, 88 * see opcode description in the ISA 89 */ 90 if (rc == 0 && 91 (access & (PAGE_READ | PAGE_WRITE)) != (PAGE_READ | PAGE_WRITE)) { 92 rc = STORE_PROHIBITED_CAUSE; 93 } 94 95 if (rc) { 96 HELPER(exception_cause_vaddr)(env, pc, rc, vaddr); 97 } 98 99 /* 100 * When data cache is not configured use ATOMCTL bypass field. 101 * See ISA, 4.3.12.4 The Atomic Operation Control Register (ATOMCTL) 102 * under the Conditional Store Option. 103 */ 104 if (!xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) { 105 access = PAGE_CACHE_BYPASS; 106 } 107 108 switch (access & PAGE_CACHE_MASK) { 109 case PAGE_CACHE_WB: 110 atomctl >>= 2; 111 /* fall through */ 112 case PAGE_CACHE_WT: 113 atomctl >>= 2; 114 /* fall through */ 115 case PAGE_CACHE_BYPASS: 116 if ((atomctl & 0x3) == 0) { 117 HELPER(exception_cause_vaddr)(env, pc, 118 LOAD_STORE_ERROR_CAUSE, vaddr); 119 } 120 break; 121 122 case PAGE_CACHE_ISOLATE: 123 HELPER(exception_cause_vaddr)(env, pc, 124 LOAD_STORE_ERROR_CAUSE, vaddr); 125 break; 126 127 default: 128 break; 129 } 130 } 131 132 void HELPER(check_exclusive)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr, 133 uint32_t is_write) 134 { 135 uint32_t paddr, page_size, access; 136 uint32_t atomctl = env->sregs[ATOMCTL]; 137 int rc = xtensa_get_physical_addr(env, true, vaddr, is_write, 138 xtensa_get_cring(env), &paddr, 139 &page_size, &access); 140 141 if (rc) { 142 HELPER(exception_cause_vaddr)(env, pc, rc, vaddr); 143 } 144 145 /* When data cache is not configured use ATOMCTL bypass field. */ 146 if (!xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) { 147 access = PAGE_CACHE_BYPASS; 148 } 149 150 switch (access & PAGE_CACHE_MASK) { 151 case PAGE_CACHE_WB: 152 atomctl >>= 2; 153 /* fall through */ 154 case PAGE_CACHE_WT: 155 atomctl >>= 2; 156 /* fall through */ 157 case PAGE_CACHE_BYPASS: 158 if ((atomctl & 0x3) == 0) { 159 HELPER(exception_cause_vaddr)(env, pc, 160 EXCLUSIVE_ERROR_CAUSE, vaddr); 161 } 162 break; 163 164 case PAGE_CACHE_ISOLATE: 165 HELPER(exception_cause_vaddr)(env, pc, 166 LOAD_STORE_ERROR_CAUSE, vaddr); 167 break; 168 169 default: 170 break; 171 } 172 } 173 174 void HELPER(wsr_memctl)(CPUXtensaState *env, uint32_t v) 175 { 176 if (xtensa_option_enabled(env->config, XTENSA_OPTION_ICACHE)) { 177 if (extract32(v, MEMCTL_IUSEWAYS_SHIFT, MEMCTL_IUSEWAYS_LEN) > 178 env->config->icache_ways) { 179 deposit32(v, MEMCTL_IUSEWAYS_SHIFT, MEMCTL_IUSEWAYS_LEN, 180 env->config->icache_ways); 181 } 182 } 183 if (xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) { 184 if (extract32(v, MEMCTL_DUSEWAYS_SHIFT, MEMCTL_DUSEWAYS_LEN) > 185 env->config->dcache_ways) { 186 deposit32(v, MEMCTL_DUSEWAYS_SHIFT, MEMCTL_DUSEWAYS_LEN, 187 env->config->dcache_ways); 188 } 189 if (extract32(v, MEMCTL_DALLOCWAYS_SHIFT, MEMCTL_DALLOCWAYS_LEN) > 190 env->config->dcache_ways) { 191 deposit32(v, MEMCTL_DALLOCWAYS_SHIFT, MEMCTL_DALLOCWAYS_LEN, 192 env->config->dcache_ways); 193 } 194 } 195 env->sregs[MEMCTL] = v & env->config->memctl_mask; 196 } 197 198 #endif 199 200 uint32_t HELPER(rer)(CPUXtensaState *env, uint32_t addr) 201 { 202 #ifndef CONFIG_USER_ONLY 203 return address_space_ldl(env->address_space_er, addr, 204 MEMTXATTRS_UNSPECIFIED, NULL); 205 #else 206 return 0; 207 #endif 208 } 209 210 void HELPER(wer)(CPUXtensaState *env, uint32_t data, uint32_t addr) 211 { 212 #ifndef CONFIG_USER_ONLY 213 address_space_stl(env->address_space_er, addr, data, 214 MEMTXATTRS_UNSPECIFIED, NULL); 215 #endif 216 } 217