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