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 "qemu/main-loop.h" 30 #include "cpu.h" 31 #include "exec/helper-proto.h" 32 #include "qemu/host-utils.h" 33 #include "exec/exec-all.h" 34 #include "exec/cpu_ldst.h" 35 #include "exec/address-spaces.h" 36 #include "qemu/timer.h" 37 38 #ifndef CONFIG_USER_ONLY 39 40 void HELPER(update_ccount)(CPUXtensaState *env) 41 { 42 uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 43 44 env->ccount_time = now; 45 env->sregs[CCOUNT] = env->ccount_base + 46 (uint32_t)((now - env->time_base) * 47 env->config->clock_freq_khz / 1000000); 48 } 49 50 void HELPER(wsr_ccount)(CPUXtensaState *env, uint32_t v) 51 { 52 int i; 53 54 HELPER(update_ccount)(env); 55 env->ccount_base += v - env->sregs[CCOUNT]; 56 for (i = 0; i < env->config->nccompare; ++i) { 57 HELPER(update_ccompare)(env, i); 58 } 59 } 60 61 void HELPER(update_ccompare)(CPUXtensaState *env, uint32_t i) 62 { 63 uint64_t dcc; 64 65 qatomic_and(&env->sregs[INTSET], 66 ~(1u << env->config->timerint[i])); 67 HELPER(update_ccount)(env); 68 dcc = (uint64_t)(env->sregs[CCOMPARE + i] - env->sregs[CCOUNT] - 1) + 1; 69 timer_mod(env->ccompare[i].timer, 70 env->ccount_time + (dcc * 1000000) / env->config->clock_freq_khz); 71 env->yield_needed = 1; 72 } 73 74 /*! 75 * Check vaddr accessibility/cache attributes and raise an exception if 76 * specified by the ATOMCTL SR. 77 * 78 * Note: local memory exclusion is not implemented 79 */ 80 void HELPER(check_atomctl)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr) 81 { 82 uint32_t paddr, page_size, access; 83 uint32_t atomctl = env->sregs[ATOMCTL]; 84 int rc = xtensa_get_physical_addr(env, true, vaddr, 1, 85 xtensa_get_cring(env), &paddr, &page_size, &access); 86 87 /* 88 * s32c1i never causes LOAD_PROHIBITED_CAUSE exceptions, 89 * see opcode description in the ISA 90 */ 91 if (rc == 0 && 92 (access & (PAGE_READ | PAGE_WRITE)) != (PAGE_READ | PAGE_WRITE)) { 93 rc = STORE_PROHIBITED_CAUSE; 94 } 95 96 if (rc) { 97 HELPER(exception_cause_vaddr)(env, pc, rc, vaddr); 98 } 99 100 /* 101 * When data cache is not configured use ATOMCTL bypass field. 102 * See ISA, 4.3.12.4 The Atomic Operation Control Register (ATOMCTL) 103 * under the Conditional Store Option. 104 */ 105 if (!xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) { 106 access = PAGE_CACHE_BYPASS; 107 } 108 109 switch (access & PAGE_CACHE_MASK) { 110 case PAGE_CACHE_WB: 111 atomctl >>= 2; 112 /* fall through */ 113 case PAGE_CACHE_WT: 114 atomctl >>= 2; 115 /* fall through */ 116 case PAGE_CACHE_BYPASS: 117 if ((atomctl & 0x3) == 0) { 118 HELPER(exception_cause_vaddr)(env, pc, 119 LOAD_STORE_ERROR_CAUSE, vaddr); 120 } 121 break; 122 123 case PAGE_CACHE_ISOLATE: 124 HELPER(exception_cause_vaddr)(env, pc, 125 LOAD_STORE_ERROR_CAUSE, vaddr); 126 break; 127 128 default: 129 break; 130 } 131 } 132 133 void HELPER(check_exclusive)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr, 134 uint32_t is_write) 135 { 136 uint32_t paddr, page_size, access; 137 uint32_t atomctl = env->sregs[ATOMCTL]; 138 int rc = xtensa_get_physical_addr(env, true, vaddr, is_write, 139 xtensa_get_cring(env), &paddr, 140 &page_size, &access); 141 142 if (rc) { 143 HELPER(exception_cause_vaddr)(env, pc, rc, vaddr); 144 } 145 146 /* When data cache is not configured use ATOMCTL bypass field. */ 147 if (!xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) { 148 access = PAGE_CACHE_BYPASS; 149 } 150 151 switch (access & PAGE_CACHE_MASK) { 152 case PAGE_CACHE_WB: 153 atomctl >>= 2; 154 /* fall through */ 155 case PAGE_CACHE_WT: 156 atomctl >>= 2; 157 /* fall through */ 158 case PAGE_CACHE_BYPASS: 159 if ((atomctl & 0x3) == 0) { 160 HELPER(exception_cause_vaddr)(env, pc, 161 EXCLUSIVE_ERROR_CAUSE, vaddr); 162 } 163 break; 164 165 case PAGE_CACHE_ISOLATE: 166 HELPER(exception_cause_vaddr)(env, pc, 167 LOAD_STORE_ERROR_CAUSE, vaddr); 168 break; 169 170 default: 171 break; 172 } 173 } 174 175 void HELPER(wsr_memctl)(CPUXtensaState *env, uint32_t v) 176 { 177 if (xtensa_option_enabled(env->config, XTENSA_OPTION_ICACHE)) { 178 if (extract32(v, MEMCTL_IUSEWAYS_SHIFT, MEMCTL_IUSEWAYS_LEN) > 179 env->config->icache_ways) { 180 deposit32(v, MEMCTL_IUSEWAYS_SHIFT, MEMCTL_IUSEWAYS_LEN, 181 env->config->icache_ways); 182 } 183 } 184 if (xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) { 185 if (extract32(v, MEMCTL_DUSEWAYS_SHIFT, MEMCTL_DUSEWAYS_LEN) > 186 env->config->dcache_ways) { 187 deposit32(v, MEMCTL_DUSEWAYS_SHIFT, MEMCTL_DUSEWAYS_LEN, 188 env->config->dcache_ways); 189 } 190 if (extract32(v, MEMCTL_DALLOCWAYS_SHIFT, MEMCTL_DALLOCWAYS_LEN) > 191 env->config->dcache_ways) { 192 deposit32(v, MEMCTL_DALLOCWAYS_SHIFT, MEMCTL_DALLOCWAYS_LEN, 193 env->config->dcache_ways); 194 } 195 } 196 env->sregs[MEMCTL] = v & env->config->memctl_mask; 197 } 198 199 #endif 200 201 uint32_t HELPER(rer)(CPUXtensaState *env, uint32_t addr) 202 { 203 #ifndef CONFIG_USER_ONLY 204 return address_space_ldl(env->address_space_er, addr, 205 MEMTXATTRS_UNSPECIFIED, NULL); 206 #else 207 return 0; 208 #endif 209 } 210 211 void HELPER(wer)(CPUXtensaState *env, uint32_t data, uint32_t addr) 212 { 213 #ifndef CONFIG_USER_ONLY 214 address_space_stl(env->address_space_er, addr, data, 215 MEMTXATTRS_UNSPECIFIED, NULL); 216 #endif 217 } 218