1d9bb58e5SYang Zhong /* 2d9bb58e5SYang Zhong * Common CPU TLB handling 3d9bb58e5SYang Zhong * 4d9bb58e5SYang Zhong * Copyright (c) 2003 Fabrice Bellard 5d9bb58e5SYang Zhong * 6d9bb58e5SYang Zhong * This library is free software; you can redistribute it and/or 7d9bb58e5SYang Zhong * modify it under the terms of the GNU Lesser General Public 8d9bb58e5SYang Zhong * License as published by the Free Software Foundation; either 9d9bb58e5SYang Zhong * version 2 of the License, or (at your option) any later version. 10d9bb58e5SYang Zhong * 11d9bb58e5SYang Zhong * This library is distributed in the hope that it will be useful, 12d9bb58e5SYang Zhong * but WITHOUT ANY WARRANTY; without even the implied warranty of 13d9bb58e5SYang Zhong * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14d9bb58e5SYang Zhong * Lesser General Public License for more details. 15d9bb58e5SYang Zhong * 16d9bb58e5SYang Zhong * You should have received a copy of the GNU Lesser General Public 17d9bb58e5SYang Zhong * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18d9bb58e5SYang Zhong */ 19d9bb58e5SYang Zhong 20d9bb58e5SYang Zhong #include "qemu/osdep.h" 21d9bb58e5SYang Zhong #include "qemu/main-loop.h" 22d9bb58e5SYang Zhong #include "cpu.h" 23d9bb58e5SYang Zhong #include "exec/exec-all.h" 24d9bb58e5SYang Zhong #include "exec/memory.h" 25d9bb58e5SYang Zhong #include "exec/address-spaces.h" 26d9bb58e5SYang Zhong #include "exec/cpu_ldst.h" 27d9bb58e5SYang Zhong #include "exec/cputlb.h" 28d9bb58e5SYang Zhong #include "exec/memory-internal.h" 29d9bb58e5SYang Zhong #include "exec/ram_addr.h" 30d9bb58e5SYang Zhong #include "tcg/tcg.h" 31d9bb58e5SYang Zhong #include "qemu/error-report.h" 32d9bb58e5SYang Zhong #include "exec/log.h" 33d9bb58e5SYang Zhong #include "exec/helper-proto.h" 34d9bb58e5SYang Zhong #include "qemu/atomic.h" 35e6cd4bb5SRichard Henderson #include "qemu/atomic128.h" 36d9bb58e5SYang Zhong 37d9bb58e5SYang Zhong /* DEBUG defines, enable DEBUG_TLB_LOG to log to the CPU_LOG_MMU target */ 38d9bb58e5SYang Zhong /* #define DEBUG_TLB */ 39d9bb58e5SYang Zhong /* #define DEBUG_TLB_LOG */ 40d9bb58e5SYang Zhong 41d9bb58e5SYang Zhong #ifdef DEBUG_TLB 42d9bb58e5SYang Zhong # define DEBUG_TLB_GATE 1 43d9bb58e5SYang Zhong # ifdef DEBUG_TLB_LOG 44d9bb58e5SYang Zhong # define DEBUG_TLB_LOG_GATE 1 45d9bb58e5SYang Zhong # else 46d9bb58e5SYang Zhong # define DEBUG_TLB_LOG_GATE 0 47d9bb58e5SYang Zhong # endif 48d9bb58e5SYang Zhong #else 49d9bb58e5SYang Zhong # define DEBUG_TLB_GATE 0 50d9bb58e5SYang Zhong # define DEBUG_TLB_LOG_GATE 0 51d9bb58e5SYang Zhong #endif 52d9bb58e5SYang Zhong 53d9bb58e5SYang Zhong #define tlb_debug(fmt, ...) do { \ 54d9bb58e5SYang Zhong if (DEBUG_TLB_LOG_GATE) { \ 55d9bb58e5SYang Zhong qemu_log_mask(CPU_LOG_MMU, "%s: " fmt, __func__, \ 56d9bb58e5SYang Zhong ## __VA_ARGS__); \ 57d9bb58e5SYang Zhong } else if (DEBUG_TLB_GATE) { \ 58d9bb58e5SYang Zhong fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); \ 59d9bb58e5SYang Zhong } \ 60d9bb58e5SYang Zhong } while (0) 61d9bb58e5SYang Zhong 62ea9025cbSEmilio G. Cota #define assert_cpu_is_self(cpu) do { \ 63d9bb58e5SYang Zhong if (DEBUG_TLB_GATE) { \ 64ea9025cbSEmilio G. Cota g_assert(!(cpu)->created || qemu_cpu_is_self(cpu)); \ 65d9bb58e5SYang Zhong } \ 66d9bb58e5SYang Zhong } while (0) 67d9bb58e5SYang Zhong 68d9bb58e5SYang Zhong /* run_on_cpu_data.target_ptr should always be big enough for a 69d9bb58e5SYang Zhong * target_ulong even on 32 bit builds */ 70d9bb58e5SYang Zhong QEMU_BUILD_BUG_ON(sizeof(target_ulong) > sizeof(run_on_cpu_data)); 71d9bb58e5SYang Zhong 72d9bb58e5SYang Zhong /* We currently can't handle more than 16 bits in the MMUIDX bitmask. 73d9bb58e5SYang Zhong */ 74d9bb58e5SYang Zhong QEMU_BUILD_BUG_ON(NB_MMU_MODES > 16); 75d9bb58e5SYang Zhong #define ALL_MMUIDX_BITS ((1 << NB_MMU_MODES) - 1) 76d9bb58e5SYang Zhong 77*86e1eff8SEmilio G. Cota #if TCG_TARGET_IMPLEMENTS_DYN_TLB 78*86e1eff8SEmilio G. Cota static inline size_t sizeof_tlb(CPUArchState *env, uintptr_t mmu_idx) 79*86e1eff8SEmilio G. Cota { 80*86e1eff8SEmilio G. Cota return env->tlb_mask[mmu_idx] + (1 << CPU_TLB_ENTRY_BITS); 81*86e1eff8SEmilio G. Cota } 82*86e1eff8SEmilio G. Cota 83*86e1eff8SEmilio G. Cota static void tlb_window_reset(CPUTLBWindow *window, int64_t ns, 84*86e1eff8SEmilio G. Cota size_t max_entries) 85*86e1eff8SEmilio G. Cota { 86*86e1eff8SEmilio G. Cota window->begin_ns = ns; 87*86e1eff8SEmilio G. Cota window->max_entries = max_entries; 88*86e1eff8SEmilio G. Cota } 89*86e1eff8SEmilio G. Cota 90*86e1eff8SEmilio G. Cota static void tlb_dyn_init(CPUArchState *env) 91*86e1eff8SEmilio G. Cota { 92*86e1eff8SEmilio G. Cota int i; 93*86e1eff8SEmilio G. Cota 94*86e1eff8SEmilio G. Cota for (i = 0; i < NB_MMU_MODES; i++) { 95*86e1eff8SEmilio G. Cota CPUTLBDesc *desc = &env->tlb_d[i]; 96*86e1eff8SEmilio G. Cota size_t n_entries = 1 << CPU_TLB_DYN_DEFAULT_BITS; 97*86e1eff8SEmilio G. Cota 98*86e1eff8SEmilio G. Cota tlb_window_reset(&desc->window, get_clock_realtime(), 0); 99*86e1eff8SEmilio G. Cota desc->n_used_entries = 0; 100*86e1eff8SEmilio G. Cota env->tlb_mask[i] = (n_entries - 1) << CPU_TLB_ENTRY_BITS; 101*86e1eff8SEmilio G. Cota env->tlb_table[i] = g_new(CPUTLBEntry, n_entries); 102*86e1eff8SEmilio G. Cota env->iotlb[i] = g_new(CPUIOTLBEntry, n_entries); 103*86e1eff8SEmilio G. Cota } 104*86e1eff8SEmilio G. Cota } 105*86e1eff8SEmilio G. Cota 106*86e1eff8SEmilio G. Cota /** 107*86e1eff8SEmilio G. Cota * tlb_mmu_resize_locked() - perform TLB resize bookkeeping; resize if necessary 108*86e1eff8SEmilio G. Cota * @env: CPU that owns the TLB 109*86e1eff8SEmilio G. Cota * @mmu_idx: MMU index of the TLB 110*86e1eff8SEmilio G. Cota * 111*86e1eff8SEmilio G. Cota * Called with tlb_lock_held. 112*86e1eff8SEmilio G. Cota * 113*86e1eff8SEmilio G. Cota * We have two main constraints when resizing a TLB: (1) we only resize it 114*86e1eff8SEmilio G. Cota * on a TLB flush (otherwise we'd have to take a perf hit by either rehashing 115*86e1eff8SEmilio G. Cota * the array or unnecessarily flushing it), which means we do not control how 116*86e1eff8SEmilio G. Cota * frequently the resizing can occur; (2) we don't have access to the guest's 117*86e1eff8SEmilio G. Cota * future scheduling decisions, and therefore have to decide the magnitude of 118*86e1eff8SEmilio G. Cota * the resize based on past observations. 119*86e1eff8SEmilio G. Cota * 120*86e1eff8SEmilio G. Cota * In general, a memory-hungry process can benefit greatly from an appropriately 121*86e1eff8SEmilio G. Cota * sized TLB, since a guest TLB miss is very expensive. This doesn't mean that 122*86e1eff8SEmilio G. Cota * we just have to make the TLB as large as possible; while an oversized TLB 123*86e1eff8SEmilio G. Cota * results in minimal TLB miss rates, it also takes longer to be flushed 124*86e1eff8SEmilio G. Cota * (flushes can be _very_ frequent), and the reduced locality can also hurt 125*86e1eff8SEmilio G. Cota * performance. 126*86e1eff8SEmilio G. Cota * 127*86e1eff8SEmilio G. Cota * To achieve near-optimal performance for all kinds of workloads, we: 128*86e1eff8SEmilio G. Cota * 129*86e1eff8SEmilio G. Cota * 1. Aggressively increase the size of the TLB when the use rate of the 130*86e1eff8SEmilio G. Cota * TLB being flushed is high, since it is likely that in the near future this 131*86e1eff8SEmilio G. Cota * memory-hungry process will execute again, and its memory hungriness will 132*86e1eff8SEmilio G. Cota * probably be similar. 133*86e1eff8SEmilio G. Cota * 134*86e1eff8SEmilio G. Cota * 2. Slowly reduce the size of the TLB as the use rate declines over a 135*86e1eff8SEmilio G. Cota * reasonably large time window. The rationale is that if in such a time window 136*86e1eff8SEmilio G. Cota * we have not observed a high TLB use rate, it is likely that we won't observe 137*86e1eff8SEmilio G. Cota * it in the near future. In that case, once a time window expires we downsize 138*86e1eff8SEmilio G. Cota * the TLB to match the maximum use rate observed in the window. 139*86e1eff8SEmilio G. Cota * 140*86e1eff8SEmilio G. Cota * 3. Try to keep the maximum use rate in a time window in the 30-70% range, 141*86e1eff8SEmilio G. Cota * since in that range performance is likely near-optimal. Recall that the TLB 142*86e1eff8SEmilio G. Cota * is direct mapped, so we want the use rate to be low (or at least not too 143*86e1eff8SEmilio G. Cota * high), since otherwise we are likely to have a significant amount of 144*86e1eff8SEmilio G. Cota * conflict misses. 145*86e1eff8SEmilio G. Cota */ 146*86e1eff8SEmilio G. Cota static void tlb_mmu_resize_locked(CPUArchState *env, int mmu_idx) 147*86e1eff8SEmilio G. Cota { 148*86e1eff8SEmilio G. Cota CPUTLBDesc *desc = &env->tlb_d[mmu_idx]; 149*86e1eff8SEmilio G. Cota size_t old_size = tlb_n_entries(env, mmu_idx); 150*86e1eff8SEmilio G. Cota size_t rate; 151*86e1eff8SEmilio G. Cota size_t new_size = old_size; 152*86e1eff8SEmilio G. Cota int64_t now = get_clock_realtime(); 153*86e1eff8SEmilio G. Cota int64_t window_len_ms = 100; 154*86e1eff8SEmilio G. Cota int64_t window_len_ns = window_len_ms * 1000 * 1000; 155*86e1eff8SEmilio G. Cota bool window_expired = now > desc->window.begin_ns + window_len_ns; 156*86e1eff8SEmilio G. Cota 157*86e1eff8SEmilio G. Cota if (desc->n_used_entries > desc->window.max_entries) { 158*86e1eff8SEmilio G. Cota desc->window.max_entries = desc->n_used_entries; 159*86e1eff8SEmilio G. Cota } 160*86e1eff8SEmilio G. Cota rate = desc->window.max_entries * 100 / old_size; 161*86e1eff8SEmilio G. Cota 162*86e1eff8SEmilio G. Cota if (rate > 70) { 163*86e1eff8SEmilio G. Cota new_size = MIN(old_size << 1, 1 << CPU_TLB_DYN_MAX_BITS); 164*86e1eff8SEmilio G. Cota } else if (rate < 30 && window_expired) { 165*86e1eff8SEmilio G. Cota size_t ceil = pow2ceil(desc->window.max_entries); 166*86e1eff8SEmilio G. Cota size_t expected_rate = desc->window.max_entries * 100 / ceil; 167*86e1eff8SEmilio G. Cota 168*86e1eff8SEmilio G. Cota /* 169*86e1eff8SEmilio G. Cota * Avoid undersizing when the max number of entries seen is just below 170*86e1eff8SEmilio G. Cota * a pow2. For instance, if max_entries == 1025, the expected use rate 171*86e1eff8SEmilio G. Cota * would be 1025/2048==50%. However, if max_entries == 1023, we'd get 172*86e1eff8SEmilio G. Cota * 1023/1024==99.9% use rate, so we'd likely end up doubling the size 173*86e1eff8SEmilio G. Cota * later. Thus, make sure that the expected use rate remains below 70%. 174*86e1eff8SEmilio G. Cota * (and since we double the size, that means the lowest rate we'd 175*86e1eff8SEmilio G. Cota * expect to get is 35%, which is still in the 30-70% range where 176*86e1eff8SEmilio G. Cota * we consider that the size is appropriate.) 177*86e1eff8SEmilio G. Cota */ 178*86e1eff8SEmilio G. Cota if (expected_rate > 70) { 179*86e1eff8SEmilio G. Cota ceil *= 2; 180*86e1eff8SEmilio G. Cota } 181*86e1eff8SEmilio G. Cota new_size = MAX(ceil, 1 << CPU_TLB_DYN_MIN_BITS); 182*86e1eff8SEmilio G. Cota } 183*86e1eff8SEmilio G. Cota 184*86e1eff8SEmilio G. Cota if (new_size == old_size) { 185*86e1eff8SEmilio G. Cota if (window_expired) { 186*86e1eff8SEmilio G. Cota tlb_window_reset(&desc->window, now, desc->n_used_entries); 187*86e1eff8SEmilio G. Cota } 188*86e1eff8SEmilio G. Cota return; 189*86e1eff8SEmilio G. Cota } 190*86e1eff8SEmilio G. Cota 191*86e1eff8SEmilio G. Cota g_free(env->tlb_table[mmu_idx]); 192*86e1eff8SEmilio G. Cota g_free(env->iotlb[mmu_idx]); 193*86e1eff8SEmilio G. Cota 194*86e1eff8SEmilio G. Cota tlb_window_reset(&desc->window, now, 0); 195*86e1eff8SEmilio G. Cota /* desc->n_used_entries is cleared by the caller */ 196*86e1eff8SEmilio G. Cota env->tlb_mask[mmu_idx] = (new_size - 1) << CPU_TLB_ENTRY_BITS; 197*86e1eff8SEmilio G. Cota env->tlb_table[mmu_idx] = g_try_new(CPUTLBEntry, new_size); 198*86e1eff8SEmilio G. Cota env->iotlb[mmu_idx] = g_try_new(CPUIOTLBEntry, new_size); 199*86e1eff8SEmilio G. Cota /* 200*86e1eff8SEmilio G. Cota * If the allocations fail, try smaller sizes. We just freed some 201*86e1eff8SEmilio G. Cota * memory, so going back to half of new_size has a good chance of working. 202*86e1eff8SEmilio G. Cota * Increased memory pressure elsewhere in the system might cause the 203*86e1eff8SEmilio G. Cota * allocations to fail though, so we progressively reduce the allocation 204*86e1eff8SEmilio G. Cota * size, aborting if we cannot even allocate the smallest TLB we support. 205*86e1eff8SEmilio G. Cota */ 206*86e1eff8SEmilio G. Cota while (env->tlb_table[mmu_idx] == NULL || env->iotlb[mmu_idx] == NULL) { 207*86e1eff8SEmilio G. Cota if (new_size == (1 << CPU_TLB_DYN_MIN_BITS)) { 208*86e1eff8SEmilio G. Cota error_report("%s: %s", __func__, strerror(errno)); 209*86e1eff8SEmilio G. Cota abort(); 210*86e1eff8SEmilio G. Cota } 211*86e1eff8SEmilio G. Cota new_size = MAX(new_size >> 1, 1 << CPU_TLB_DYN_MIN_BITS); 212*86e1eff8SEmilio G. Cota env->tlb_mask[mmu_idx] = (new_size - 1) << CPU_TLB_ENTRY_BITS; 213*86e1eff8SEmilio G. Cota 214*86e1eff8SEmilio G. Cota g_free(env->tlb_table[mmu_idx]); 215*86e1eff8SEmilio G. Cota g_free(env->iotlb[mmu_idx]); 216*86e1eff8SEmilio G. Cota env->tlb_table[mmu_idx] = g_try_new(CPUTLBEntry, new_size); 217*86e1eff8SEmilio G. Cota env->iotlb[mmu_idx] = g_try_new(CPUIOTLBEntry, new_size); 218*86e1eff8SEmilio G. Cota } 219*86e1eff8SEmilio G. Cota } 220*86e1eff8SEmilio G. Cota 221*86e1eff8SEmilio G. Cota static inline void tlb_table_flush_by_mmuidx(CPUArchState *env, int mmu_idx) 222*86e1eff8SEmilio G. Cota { 223*86e1eff8SEmilio G. Cota tlb_mmu_resize_locked(env, mmu_idx); 224*86e1eff8SEmilio G. Cota memset(env->tlb_table[mmu_idx], -1, sizeof_tlb(env, mmu_idx)); 225*86e1eff8SEmilio G. Cota env->tlb_d[mmu_idx].n_used_entries = 0; 226*86e1eff8SEmilio G. Cota } 227*86e1eff8SEmilio G. Cota 228*86e1eff8SEmilio G. Cota static inline void tlb_n_used_entries_inc(CPUArchState *env, uintptr_t mmu_idx) 229*86e1eff8SEmilio G. Cota { 230*86e1eff8SEmilio G. Cota env->tlb_d[mmu_idx].n_used_entries++; 231*86e1eff8SEmilio G. Cota } 232*86e1eff8SEmilio G. Cota 233*86e1eff8SEmilio G. Cota static inline void tlb_n_used_entries_dec(CPUArchState *env, uintptr_t mmu_idx) 234*86e1eff8SEmilio G. Cota { 235*86e1eff8SEmilio G. Cota env->tlb_d[mmu_idx].n_used_entries--; 236*86e1eff8SEmilio G. Cota } 237*86e1eff8SEmilio G. Cota 238*86e1eff8SEmilio G. Cota #else /* !TCG_TARGET_IMPLEMENTS_DYN_TLB */ 239*86e1eff8SEmilio G. Cota 240*86e1eff8SEmilio G. Cota static inline void tlb_dyn_init(CPUArchState *env) 241*86e1eff8SEmilio G. Cota { 242*86e1eff8SEmilio G. Cota } 243*86e1eff8SEmilio G. Cota 244*86e1eff8SEmilio G. Cota static inline void tlb_table_flush_by_mmuidx(CPUArchState *env, int mmu_idx) 245*86e1eff8SEmilio G. Cota { 246*86e1eff8SEmilio G. Cota memset(env->tlb_table[mmu_idx], -1, sizeof(env->tlb_table[0])); 247*86e1eff8SEmilio G. Cota } 248*86e1eff8SEmilio G. Cota 249*86e1eff8SEmilio G. Cota static inline void tlb_n_used_entries_inc(CPUArchState *env, uintptr_t mmu_idx) 250*86e1eff8SEmilio G. Cota { 251*86e1eff8SEmilio G. Cota } 252*86e1eff8SEmilio G. Cota 253*86e1eff8SEmilio G. Cota static inline void tlb_n_used_entries_dec(CPUArchState *env, uintptr_t mmu_idx) 254*86e1eff8SEmilio G. Cota { 255*86e1eff8SEmilio G. Cota } 256*86e1eff8SEmilio G. Cota #endif /* TCG_TARGET_IMPLEMENTS_DYN_TLB */ 257*86e1eff8SEmilio G. Cota 2585005e253SEmilio G. Cota void tlb_init(CPUState *cpu) 2595005e253SEmilio G. Cota { 26071aec354SEmilio G. Cota CPUArchState *env = cpu->env_ptr; 26171aec354SEmilio G. Cota 26253d28455SRichard Henderson qemu_spin_init(&env->tlb_c.lock); 2633d1523ceSRichard Henderson 2643d1523ceSRichard Henderson /* Ensure that cpu_reset performs a full flush. */ 2653d1523ceSRichard Henderson env->tlb_c.dirty = ALL_MMUIDX_BITS; 266*86e1eff8SEmilio G. Cota 267*86e1eff8SEmilio G. Cota tlb_dyn_init(env); 2685005e253SEmilio G. Cota } 2695005e253SEmilio G. Cota 270d9bb58e5SYang Zhong /* flush_all_helper: run fn across all cpus 271d9bb58e5SYang Zhong * 272d9bb58e5SYang Zhong * If the wait flag is set then the src cpu's helper will be queued as 273d9bb58e5SYang Zhong * "safe" work and the loop exited creating a synchronisation point 274d9bb58e5SYang Zhong * where all queued work will be finished before execution starts 275d9bb58e5SYang Zhong * again. 276d9bb58e5SYang Zhong */ 277d9bb58e5SYang Zhong static void flush_all_helper(CPUState *src, run_on_cpu_func fn, 278d9bb58e5SYang Zhong run_on_cpu_data d) 279d9bb58e5SYang Zhong { 280d9bb58e5SYang Zhong CPUState *cpu; 281d9bb58e5SYang Zhong 282d9bb58e5SYang Zhong CPU_FOREACH(cpu) { 283d9bb58e5SYang Zhong if (cpu != src) { 284d9bb58e5SYang Zhong async_run_on_cpu(cpu, fn, d); 285d9bb58e5SYang Zhong } 286d9bb58e5SYang Zhong } 287d9bb58e5SYang Zhong } 288d9bb58e5SYang Zhong 289e09de0a2SRichard Henderson void tlb_flush_counts(size_t *pfull, size_t *ppart, size_t *pelide) 29083974cf4SEmilio G. Cota { 29183974cf4SEmilio G. Cota CPUState *cpu; 292e09de0a2SRichard Henderson size_t full = 0, part = 0, elide = 0; 29383974cf4SEmilio G. Cota 29483974cf4SEmilio G. Cota CPU_FOREACH(cpu) { 29583974cf4SEmilio G. Cota CPUArchState *env = cpu->env_ptr; 29683974cf4SEmilio G. Cota 297e09de0a2SRichard Henderson full += atomic_read(&env->tlb_c.full_flush_count); 298e09de0a2SRichard Henderson part += atomic_read(&env->tlb_c.part_flush_count); 299e09de0a2SRichard Henderson elide += atomic_read(&env->tlb_c.elide_flush_count); 30083974cf4SEmilio G. Cota } 301e09de0a2SRichard Henderson *pfull = full; 302e09de0a2SRichard Henderson *ppart = part; 303e09de0a2SRichard Henderson *pelide = elide; 30483974cf4SEmilio G. Cota } 305d9bb58e5SYang Zhong 3061308e026SRichard Henderson static void tlb_flush_one_mmuidx_locked(CPUArchState *env, int mmu_idx) 3071308e026SRichard Henderson { 308*86e1eff8SEmilio G. Cota tlb_table_flush_by_mmuidx(env, mmu_idx); 3091308e026SRichard Henderson memset(env->tlb_v_table[mmu_idx], -1, sizeof(env->tlb_v_table[0])); 3101308e026SRichard Henderson env->tlb_d[mmu_idx].large_page_addr = -1; 3111308e026SRichard Henderson env->tlb_d[mmu_idx].large_page_mask = -1; 312d5363e58SRichard Henderson env->tlb_d[mmu_idx].vindex = 0; 3131308e026SRichard Henderson } 3141308e026SRichard Henderson 315d9bb58e5SYang Zhong static void tlb_flush_by_mmuidx_async_work(CPUState *cpu, run_on_cpu_data data) 316d9bb58e5SYang Zhong { 317d9bb58e5SYang Zhong CPUArchState *env = cpu->env_ptr; 3183d1523ceSRichard Henderson uint16_t asked = data.host_int; 3193d1523ceSRichard Henderson uint16_t all_dirty, work, to_clean; 320d9bb58e5SYang Zhong 321d9bb58e5SYang Zhong assert_cpu_is_self(cpu); 322d9bb58e5SYang Zhong 3233d1523ceSRichard Henderson tlb_debug("mmu_idx:0x%04" PRIx16 "\n", asked); 324d9bb58e5SYang Zhong 32553d28455SRichard Henderson qemu_spin_lock(&env->tlb_c.lock); 32660a2ad7dSRichard Henderson 3273d1523ceSRichard Henderson all_dirty = env->tlb_c.dirty; 3283d1523ceSRichard Henderson to_clean = asked & all_dirty; 3293d1523ceSRichard Henderson all_dirty &= ~to_clean; 3303d1523ceSRichard Henderson env->tlb_c.dirty = all_dirty; 3313d1523ceSRichard Henderson 3323d1523ceSRichard Henderson for (work = to_clean; work != 0; work &= work - 1) { 3333d1523ceSRichard Henderson int mmu_idx = ctz32(work); 3341308e026SRichard Henderson tlb_flush_one_mmuidx_locked(env, mmu_idx); 335d9bb58e5SYang Zhong } 3363d1523ceSRichard Henderson 33753d28455SRichard Henderson qemu_spin_unlock(&env->tlb_c.lock); 338d9bb58e5SYang Zhong 339f3ced3c5SEmilio G. Cota cpu_tb_jmp_cache_clear(cpu); 34064f2674bSRichard Henderson 3413d1523ceSRichard Henderson if (to_clean == ALL_MMUIDX_BITS) { 342e09de0a2SRichard Henderson atomic_set(&env->tlb_c.full_flush_count, 343e09de0a2SRichard Henderson env->tlb_c.full_flush_count + 1); 344e09de0a2SRichard Henderson } else { 345e09de0a2SRichard Henderson atomic_set(&env->tlb_c.part_flush_count, 3463d1523ceSRichard Henderson env->tlb_c.part_flush_count + ctpop16(to_clean)); 3473d1523ceSRichard Henderson if (to_clean != asked) { 3483d1523ceSRichard Henderson atomic_set(&env->tlb_c.elide_flush_count, 3493d1523ceSRichard Henderson env->tlb_c.elide_flush_count + 3503d1523ceSRichard Henderson ctpop16(asked & ~to_clean)); 3513d1523ceSRichard Henderson } 35264f2674bSRichard Henderson } 353d9bb58e5SYang Zhong } 354d9bb58e5SYang Zhong 355d9bb58e5SYang Zhong void tlb_flush_by_mmuidx(CPUState *cpu, uint16_t idxmap) 356d9bb58e5SYang Zhong { 357d9bb58e5SYang Zhong tlb_debug("mmu_idx: 0x%" PRIx16 "\n", idxmap); 358d9bb58e5SYang Zhong 35964f2674bSRichard Henderson if (cpu->created && !qemu_cpu_is_self(cpu)) { 360d9bb58e5SYang Zhong async_run_on_cpu(cpu, tlb_flush_by_mmuidx_async_work, 361ab651105SRichard Henderson RUN_ON_CPU_HOST_INT(idxmap)); 362d9bb58e5SYang Zhong } else { 36360a2ad7dSRichard Henderson tlb_flush_by_mmuidx_async_work(cpu, RUN_ON_CPU_HOST_INT(idxmap)); 364d9bb58e5SYang Zhong } 365d9bb58e5SYang Zhong } 366d9bb58e5SYang Zhong 36764f2674bSRichard Henderson void tlb_flush(CPUState *cpu) 36864f2674bSRichard Henderson { 36964f2674bSRichard Henderson tlb_flush_by_mmuidx(cpu, ALL_MMUIDX_BITS); 37064f2674bSRichard Henderson } 37164f2674bSRichard Henderson 372d9bb58e5SYang Zhong void tlb_flush_by_mmuidx_all_cpus(CPUState *src_cpu, uint16_t idxmap) 373d9bb58e5SYang Zhong { 374d9bb58e5SYang Zhong const run_on_cpu_func fn = tlb_flush_by_mmuidx_async_work; 375d9bb58e5SYang Zhong 376d9bb58e5SYang Zhong tlb_debug("mmu_idx: 0x%"PRIx16"\n", idxmap); 377d9bb58e5SYang Zhong 378d9bb58e5SYang Zhong flush_all_helper(src_cpu, fn, RUN_ON_CPU_HOST_INT(idxmap)); 379d9bb58e5SYang Zhong fn(src_cpu, RUN_ON_CPU_HOST_INT(idxmap)); 380d9bb58e5SYang Zhong } 381d9bb58e5SYang Zhong 38264f2674bSRichard Henderson void tlb_flush_all_cpus(CPUState *src_cpu) 38364f2674bSRichard Henderson { 38464f2674bSRichard Henderson tlb_flush_by_mmuidx_all_cpus(src_cpu, ALL_MMUIDX_BITS); 38564f2674bSRichard Henderson } 38664f2674bSRichard Henderson 38764f2674bSRichard Henderson void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *src_cpu, uint16_t idxmap) 388d9bb58e5SYang Zhong { 389d9bb58e5SYang Zhong const run_on_cpu_func fn = tlb_flush_by_mmuidx_async_work; 390d9bb58e5SYang Zhong 391d9bb58e5SYang Zhong tlb_debug("mmu_idx: 0x%"PRIx16"\n", idxmap); 392d9bb58e5SYang Zhong 393d9bb58e5SYang Zhong flush_all_helper(src_cpu, fn, RUN_ON_CPU_HOST_INT(idxmap)); 394d9bb58e5SYang Zhong async_safe_run_on_cpu(src_cpu, fn, RUN_ON_CPU_HOST_INT(idxmap)); 395d9bb58e5SYang Zhong } 396d9bb58e5SYang Zhong 39764f2674bSRichard Henderson void tlb_flush_all_cpus_synced(CPUState *src_cpu) 39864f2674bSRichard Henderson { 39964f2674bSRichard Henderson tlb_flush_by_mmuidx_all_cpus_synced(src_cpu, ALL_MMUIDX_BITS); 40064f2674bSRichard Henderson } 40164f2674bSRichard Henderson 40268fea038SRichard Henderson static inline bool tlb_hit_page_anyprot(CPUTLBEntry *tlb_entry, 40368fea038SRichard Henderson target_ulong page) 404d9bb58e5SYang Zhong { 40568fea038SRichard Henderson return tlb_hit_page(tlb_entry->addr_read, page) || 406403f290cSEmilio G. Cota tlb_hit_page(tlb_addr_write(tlb_entry), page) || 40768fea038SRichard Henderson tlb_hit_page(tlb_entry->addr_code, page); 40868fea038SRichard Henderson } 40968fea038SRichard Henderson 4103cea94bbSEmilio G. Cota /** 4113cea94bbSEmilio G. Cota * tlb_entry_is_empty - return true if the entry is not in use 4123cea94bbSEmilio G. Cota * @te: pointer to CPUTLBEntry 4133cea94bbSEmilio G. Cota */ 4143cea94bbSEmilio G. Cota static inline bool tlb_entry_is_empty(const CPUTLBEntry *te) 4153cea94bbSEmilio G. Cota { 4163cea94bbSEmilio G. Cota return te->addr_read == -1 && te->addr_write == -1 && te->addr_code == -1; 4173cea94bbSEmilio G. Cota } 4183cea94bbSEmilio G. Cota 41953d28455SRichard Henderson /* Called with tlb_c.lock held */ 420*86e1eff8SEmilio G. Cota static inline bool tlb_flush_entry_locked(CPUTLBEntry *tlb_entry, 42171aec354SEmilio G. Cota target_ulong page) 42268fea038SRichard Henderson { 42368fea038SRichard Henderson if (tlb_hit_page_anyprot(tlb_entry, page)) { 424d9bb58e5SYang Zhong memset(tlb_entry, -1, sizeof(*tlb_entry)); 425*86e1eff8SEmilio G. Cota return true; 426d9bb58e5SYang Zhong } 427*86e1eff8SEmilio G. Cota return false; 428d9bb58e5SYang Zhong } 429d9bb58e5SYang Zhong 43053d28455SRichard Henderson /* Called with tlb_c.lock held */ 43171aec354SEmilio G. Cota static inline void tlb_flush_vtlb_page_locked(CPUArchState *env, int mmu_idx, 43268fea038SRichard Henderson target_ulong page) 43368fea038SRichard Henderson { 43468fea038SRichard Henderson int k; 43571aec354SEmilio G. Cota 43671aec354SEmilio G. Cota assert_cpu_is_self(ENV_GET_CPU(env)); 43768fea038SRichard Henderson for (k = 0; k < CPU_VTLB_SIZE; k++) { 438*86e1eff8SEmilio G. Cota if (tlb_flush_entry_locked(&env->tlb_v_table[mmu_idx][k], page)) { 439*86e1eff8SEmilio G. Cota tlb_n_used_entries_dec(env, mmu_idx); 440*86e1eff8SEmilio G. Cota } 44168fea038SRichard Henderson } 44268fea038SRichard Henderson } 44368fea038SRichard Henderson 4441308e026SRichard Henderson static void tlb_flush_page_locked(CPUArchState *env, int midx, 4451308e026SRichard Henderson target_ulong page) 4461308e026SRichard Henderson { 4471308e026SRichard Henderson target_ulong lp_addr = env->tlb_d[midx].large_page_addr; 4481308e026SRichard Henderson target_ulong lp_mask = env->tlb_d[midx].large_page_mask; 4491308e026SRichard Henderson 4501308e026SRichard Henderson /* Check if we need to flush due to large pages. */ 4511308e026SRichard Henderson if ((page & lp_mask) == lp_addr) { 4521308e026SRichard Henderson tlb_debug("forcing full flush midx %d (" 4531308e026SRichard Henderson TARGET_FMT_lx "/" TARGET_FMT_lx ")\n", 4541308e026SRichard Henderson midx, lp_addr, lp_mask); 4551308e026SRichard Henderson tlb_flush_one_mmuidx_locked(env, midx); 4561308e026SRichard Henderson } else { 457*86e1eff8SEmilio G. Cota if (tlb_flush_entry_locked(tlb_entry(env, midx, page), page)) { 458*86e1eff8SEmilio G. Cota tlb_n_used_entries_dec(env, midx); 459*86e1eff8SEmilio G. Cota } 4601308e026SRichard Henderson tlb_flush_vtlb_page_locked(env, midx, page); 4611308e026SRichard Henderson } 4621308e026SRichard Henderson } 4631308e026SRichard Henderson 464d9bb58e5SYang Zhong /* As we are going to hijack the bottom bits of the page address for a 465d9bb58e5SYang Zhong * mmuidx bit mask we need to fail to build if we can't do that 466d9bb58e5SYang Zhong */ 467d9bb58e5SYang Zhong QEMU_BUILD_BUG_ON(NB_MMU_MODES > TARGET_PAGE_BITS_MIN); 468d9bb58e5SYang Zhong 469d9bb58e5SYang Zhong static void tlb_flush_page_by_mmuidx_async_work(CPUState *cpu, 470d9bb58e5SYang Zhong run_on_cpu_data data) 471d9bb58e5SYang Zhong { 472d9bb58e5SYang Zhong CPUArchState *env = cpu->env_ptr; 473d9bb58e5SYang Zhong target_ulong addr_and_mmuidx = (target_ulong) data.target_ptr; 474d9bb58e5SYang Zhong target_ulong addr = addr_and_mmuidx & TARGET_PAGE_MASK; 475d9bb58e5SYang Zhong unsigned long mmu_idx_bitmap = addr_and_mmuidx & ALL_MMUIDX_BITS; 476d9bb58e5SYang Zhong int mmu_idx; 477d9bb58e5SYang Zhong 478d9bb58e5SYang Zhong assert_cpu_is_self(cpu); 479d9bb58e5SYang Zhong 4801308e026SRichard Henderson tlb_debug("page addr:" TARGET_FMT_lx " mmu_map:0x%lx\n", 481383beda9SRichard Henderson addr, mmu_idx_bitmap); 482d9bb58e5SYang Zhong 48353d28455SRichard Henderson qemu_spin_lock(&env->tlb_c.lock); 484d9bb58e5SYang Zhong for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 485d9bb58e5SYang Zhong if (test_bit(mmu_idx, &mmu_idx_bitmap)) { 4861308e026SRichard Henderson tlb_flush_page_locked(env, mmu_idx, addr); 487d9bb58e5SYang Zhong } 488d9bb58e5SYang Zhong } 48953d28455SRichard Henderson qemu_spin_unlock(&env->tlb_c.lock); 490d9bb58e5SYang Zhong 491d9bb58e5SYang Zhong tb_flush_jmp_cache(cpu, addr); 492d9bb58e5SYang Zhong } 493d9bb58e5SYang Zhong 494d9bb58e5SYang Zhong void tlb_flush_page_by_mmuidx(CPUState *cpu, target_ulong addr, uint16_t idxmap) 495d9bb58e5SYang Zhong { 496d9bb58e5SYang Zhong target_ulong addr_and_mmu_idx; 497d9bb58e5SYang Zhong 498d9bb58e5SYang Zhong tlb_debug("addr: "TARGET_FMT_lx" mmu_idx:%" PRIx16 "\n", addr, idxmap); 499d9bb58e5SYang Zhong 500d9bb58e5SYang Zhong /* This should already be page aligned */ 501d9bb58e5SYang Zhong addr_and_mmu_idx = addr & TARGET_PAGE_MASK; 502d9bb58e5SYang Zhong addr_and_mmu_idx |= idxmap; 503d9bb58e5SYang Zhong 504d9bb58e5SYang Zhong if (!qemu_cpu_is_self(cpu)) { 5051308e026SRichard Henderson async_run_on_cpu(cpu, tlb_flush_page_by_mmuidx_async_work, 506d9bb58e5SYang Zhong RUN_ON_CPU_TARGET_PTR(addr_and_mmu_idx)); 507d9bb58e5SYang Zhong } else { 5081308e026SRichard Henderson tlb_flush_page_by_mmuidx_async_work( 509d9bb58e5SYang Zhong cpu, RUN_ON_CPU_TARGET_PTR(addr_and_mmu_idx)); 510d9bb58e5SYang Zhong } 511d9bb58e5SYang Zhong } 512d9bb58e5SYang Zhong 513f8144c6cSRichard Henderson void tlb_flush_page(CPUState *cpu, target_ulong addr) 514f8144c6cSRichard Henderson { 515f8144c6cSRichard Henderson tlb_flush_page_by_mmuidx(cpu, addr, ALL_MMUIDX_BITS); 516f8144c6cSRichard Henderson } 517f8144c6cSRichard Henderson 518d9bb58e5SYang Zhong void tlb_flush_page_by_mmuidx_all_cpus(CPUState *src_cpu, target_ulong addr, 519d9bb58e5SYang Zhong uint16_t idxmap) 520d9bb58e5SYang Zhong { 5211308e026SRichard Henderson const run_on_cpu_func fn = tlb_flush_page_by_mmuidx_async_work; 522d9bb58e5SYang Zhong target_ulong addr_and_mmu_idx; 523d9bb58e5SYang Zhong 524d9bb58e5SYang Zhong tlb_debug("addr: "TARGET_FMT_lx" mmu_idx:%"PRIx16"\n", addr, idxmap); 525d9bb58e5SYang Zhong 526d9bb58e5SYang Zhong /* This should already be page aligned */ 527d9bb58e5SYang Zhong addr_and_mmu_idx = addr & TARGET_PAGE_MASK; 528d9bb58e5SYang Zhong addr_and_mmu_idx |= idxmap; 529d9bb58e5SYang Zhong 530d9bb58e5SYang Zhong flush_all_helper(src_cpu, fn, RUN_ON_CPU_TARGET_PTR(addr_and_mmu_idx)); 531d9bb58e5SYang Zhong fn(src_cpu, RUN_ON_CPU_TARGET_PTR(addr_and_mmu_idx)); 532d9bb58e5SYang Zhong } 533d9bb58e5SYang Zhong 534f8144c6cSRichard Henderson void tlb_flush_page_all_cpus(CPUState *src, target_ulong addr) 535f8144c6cSRichard Henderson { 536f8144c6cSRichard Henderson tlb_flush_page_by_mmuidx_all_cpus(src, addr, ALL_MMUIDX_BITS); 537f8144c6cSRichard Henderson } 538f8144c6cSRichard Henderson 539d9bb58e5SYang Zhong void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *src_cpu, 540d9bb58e5SYang Zhong target_ulong addr, 541d9bb58e5SYang Zhong uint16_t idxmap) 542d9bb58e5SYang Zhong { 5431308e026SRichard Henderson const run_on_cpu_func fn = tlb_flush_page_by_mmuidx_async_work; 544d9bb58e5SYang Zhong target_ulong addr_and_mmu_idx; 545d9bb58e5SYang Zhong 546d9bb58e5SYang Zhong tlb_debug("addr: "TARGET_FMT_lx" mmu_idx:%"PRIx16"\n", addr, idxmap); 547d9bb58e5SYang Zhong 548d9bb58e5SYang Zhong /* This should already be page aligned */ 549d9bb58e5SYang Zhong addr_and_mmu_idx = addr & TARGET_PAGE_MASK; 550d9bb58e5SYang Zhong addr_and_mmu_idx |= idxmap; 551d9bb58e5SYang Zhong 552d9bb58e5SYang Zhong flush_all_helper(src_cpu, fn, RUN_ON_CPU_TARGET_PTR(addr_and_mmu_idx)); 553d9bb58e5SYang Zhong async_safe_run_on_cpu(src_cpu, fn, RUN_ON_CPU_TARGET_PTR(addr_and_mmu_idx)); 554d9bb58e5SYang Zhong } 555d9bb58e5SYang Zhong 556f8144c6cSRichard Henderson void tlb_flush_page_all_cpus_synced(CPUState *src, target_ulong addr) 557d9bb58e5SYang Zhong { 558f8144c6cSRichard Henderson tlb_flush_page_by_mmuidx_all_cpus_synced(src, addr, ALL_MMUIDX_BITS); 559d9bb58e5SYang Zhong } 560d9bb58e5SYang Zhong 561d9bb58e5SYang Zhong /* update the TLBs so that writes to code in the virtual page 'addr' 562d9bb58e5SYang Zhong can be detected */ 563d9bb58e5SYang Zhong void tlb_protect_code(ram_addr_t ram_addr) 564d9bb58e5SYang Zhong { 565d9bb58e5SYang Zhong cpu_physical_memory_test_and_clear_dirty(ram_addr, TARGET_PAGE_SIZE, 566d9bb58e5SYang Zhong DIRTY_MEMORY_CODE); 567d9bb58e5SYang Zhong } 568d9bb58e5SYang Zhong 569d9bb58e5SYang Zhong /* update the TLB so that writes in physical page 'phys_addr' are no longer 570d9bb58e5SYang Zhong tested for self modifying code */ 571d9bb58e5SYang Zhong void tlb_unprotect_code(ram_addr_t ram_addr) 572d9bb58e5SYang Zhong { 573d9bb58e5SYang Zhong cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_CODE); 574d9bb58e5SYang Zhong } 575d9bb58e5SYang Zhong 576d9bb58e5SYang Zhong 577d9bb58e5SYang Zhong /* 578d9bb58e5SYang Zhong * Dirty write flag handling 579d9bb58e5SYang Zhong * 580d9bb58e5SYang Zhong * When the TCG code writes to a location it looks up the address in 581d9bb58e5SYang Zhong * the TLB and uses that data to compute the final address. If any of 582d9bb58e5SYang Zhong * the lower bits of the address are set then the slow path is forced. 583d9bb58e5SYang Zhong * There are a number of reasons to do this but for normal RAM the 584d9bb58e5SYang Zhong * most usual is detecting writes to code regions which may invalidate 585d9bb58e5SYang Zhong * generated code. 586d9bb58e5SYang Zhong * 58771aec354SEmilio G. Cota * Other vCPUs might be reading their TLBs during guest execution, so we update 58871aec354SEmilio G. Cota * te->addr_write with atomic_set. We don't need to worry about this for 58971aec354SEmilio G. Cota * oversized guests as MTTCG is disabled for them. 590d9bb58e5SYang Zhong * 59153d28455SRichard Henderson * Called with tlb_c.lock held. 592d9bb58e5SYang Zhong */ 59371aec354SEmilio G. Cota static void tlb_reset_dirty_range_locked(CPUTLBEntry *tlb_entry, 59471aec354SEmilio G. Cota uintptr_t start, uintptr_t length) 595d9bb58e5SYang Zhong { 596d9bb58e5SYang Zhong uintptr_t addr = tlb_entry->addr_write; 597d9bb58e5SYang Zhong 598d9bb58e5SYang Zhong if ((addr & (TLB_INVALID_MASK | TLB_MMIO | TLB_NOTDIRTY)) == 0) { 599d9bb58e5SYang Zhong addr &= TARGET_PAGE_MASK; 600d9bb58e5SYang Zhong addr += tlb_entry->addend; 601d9bb58e5SYang Zhong if ((addr - start) < length) { 602d9bb58e5SYang Zhong #if TCG_OVERSIZED_GUEST 60371aec354SEmilio G. Cota tlb_entry->addr_write |= TLB_NOTDIRTY; 604d9bb58e5SYang Zhong #else 60571aec354SEmilio G. Cota atomic_set(&tlb_entry->addr_write, 60671aec354SEmilio G. Cota tlb_entry->addr_write | TLB_NOTDIRTY); 607d9bb58e5SYang Zhong #endif 608d9bb58e5SYang Zhong } 60971aec354SEmilio G. Cota } 61071aec354SEmilio G. Cota } 61171aec354SEmilio G. Cota 61271aec354SEmilio G. Cota /* 61353d28455SRichard Henderson * Called with tlb_c.lock held. 61471aec354SEmilio G. Cota * Called only from the vCPU context, i.e. the TLB's owner thread. 61571aec354SEmilio G. Cota */ 61671aec354SEmilio G. Cota static inline void copy_tlb_helper_locked(CPUTLBEntry *d, const CPUTLBEntry *s) 61771aec354SEmilio G. Cota { 61871aec354SEmilio G. Cota *d = *s; 61971aec354SEmilio G. Cota } 620d9bb58e5SYang Zhong 621d9bb58e5SYang Zhong /* This is a cross vCPU call (i.e. another vCPU resetting the flags of 62271aec354SEmilio G. Cota * the target vCPU). 62353d28455SRichard Henderson * We must take tlb_c.lock to avoid racing with another vCPU update. The only 62471aec354SEmilio G. Cota * thing actually updated is the target TLB entry ->addr_write flags. 625d9bb58e5SYang Zhong */ 626d9bb58e5SYang Zhong void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length) 627d9bb58e5SYang Zhong { 628d9bb58e5SYang Zhong CPUArchState *env; 629d9bb58e5SYang Zhong 630d9bb58e5SYang Zhong int mmu_idx; 631d9bb58e5SYang Zhong 632d9bb58e5SYang Zhong env = cpu->env_ptr; 63353d28455SRichard Henderson qemu_spin_lock(&env->tlb_c.lock); 634d9bb58e5SYang Zhong for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 635d9bb58e5SYang Zhong unsigned int i; 636*86e1eff8SEmilio G. Cota unsigned int n = tlb_n_entries(env, mmu_idx); 637d9bb58e5SYang Zhong 638*86e1eff8SEmilio G. Cota for (i = 0; i < n; i++) { 63971aec354SEmilio G. Cota tlb_reset_dirty_range_locked(&env->tlb_table[mmu_idx][i], start1, 64071aec354SEmilio G. Cota length); 641d9bb58e5SYang Zhong } 642d9bb58e5SYang Zhong 643d9bb58e5SYang Zhong for (i = 0; i < CPU_VTLB_SIZE; i++) { 64471aec354SEmilio G. Cota tlb_reset_dirty_range_locked(&env->tlb_v_table[mmu_idx][i], start1, 64571aec354SEmilio G. Cota length); 646d9bb58e5SYang Zhong } 647d9bb58e5SYang Zhong } 64853d28455SRichard Henderson qemu_spin_unlock(&env->tlb_c.lock); 649d9bb58e5SYang Zhong } 650d9bb58e5SYang Zhong 65153d28455SRichard Henderson /* Called with tlb_c.lock held */ 65271aec354SEmilio G. Cota static inline void tlb_set_dirty1_locked(CPUTLBEntry *tlb_entry, 65371aec354SEmilio G. Cota target_ulong vaddr) 654d9bb58e5SYang Zhong { 655d9bb58e5SYang Zhong if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY)) { 656d9bb58e5SYang Zhong tlb_entry->addr_write = vaddr; 657d9bb58e5SYang Zhong } 658d9bb58e5SYang Zhong } 659d9bb58e5SYang Zhong 660d9bb58e5SYang Zhong /* update the TLB corresponding to virtual page vaddr 661d9bb58e5SYang Zhong so that it is no longer dirty */ 662d9bb58e5SYang Zhong void tlb_set_dirty(CPUState *cpu, target_ulong vaddr) 663d9bb58e5SYang Zhong { 664d9bb58e5SYang Zhong CPUArchState *env = cpu->env_ptr; 665d9bb58e5SYang Zhong int mmu_idx; 666d9bb58e5SYang Zhong 667d9bb58e5SYang Zhong assert_cpu_is_self(cpu); 668d9bb58e5SYang Zhong 669d9bb58e5SYang Zhong vaddr &= TARGET_PAGE_MASK; 67053d28455SRichard Henderson qemu_spin_lock(&env->tlb_c.lock); 671d9bb58e5SYang Zhong for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 672383beda9SRichard Henderson tlb_set_dirty1_locked(tlb_entry(env, mmu_idx, vaddr), vaddr); 673d9bb58e5SYang Zhong } 674d9bb58e5SYang Zhong 675d9bb58e5SYang Zhong for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 676d9bb58e5SYang Zhong int k; 677d9bb58e5SYang Zhong for (k = 0; k < CPU_VTLB_SIZE; k++) { 67871aec354SEmilio G. Cota tlb_set_dirty1_locked(&env->tlb_v_table[mmu_idx][k], vaddr); 679d9bb58e5SYang Zhong } 680d9bb58e5SYang Zhong } 68153d28455SRichard Henderson qemu_spin_unlock(&env->tlb_c.lock); 682d9bb58e5SYang Zhong } 683d9bb58e5SYang Zhong 684d9bb58e5SYang Zhong /* Our TLB does not support large pages, so remember the area covered by 685d9bb58e5SYang Zhong large pages and trigger a full TLB flush if these are invalidated. */ 6861308e026SRichard Henderson static void tlb_add_large_page(CPUArchState *env, int mmu_idx, 6871308e026SRichard Henderson target_ulong vaddr, target_ulong size) 688d9bb58e5SYang Zhong { 6891308e026SRichard Henderson target_ulong lp_addr = env->tlb_d[mmu_idx].large_page_addr; 6901308e026SRichard Henderson target_ulong lp_mask = ~(size - 1); 691d9bb58e5SYang Zhong 6921308e026SRichard Henderson if (lp_addr == (target_ulong)-1) { 6931308e026SRichard Henderson /* No previous large page. */ 6941308e026SRichard Henderson lp_addr = vaddr; 6951308e026SRichard Henderson } else { 696d9bb58e5SYang Zhong /* Extend the existing region to include the new page. 6971308e026SRichard Henderson This is a compromise between unnecessary flushes and 6981308e026SRichard Henderson the cost of maintaining a full variable size TLB. */ 6991308e026SRichard Henderson lp_mask &= env->tlb_d[mmu_idx].large_page_mask; 7001308e026SRichard Henderson while (((lp_addr ^ vaddr) & lp_mask) != 0) { 7011308e026SRichard Henderson lp_mask <<= 1; 702d9bb58e5SYang Zhong } 7031308e026SRichard Henderson } 7041308e026SRichard Henderson env->tlb_d[mmu_idx].large_page_addr = lp_addr & lp_mask; 7051308e026SRichard Henderson env->tlb_d[mmu_idx].large_page_mask = lp_mask; 706d9bb58e5SYang Zhong } 707d9bb58e5SYang Zhong 708d9bb58e5SYang Zhong /* Add a new TLB entry. At most one entry for a given virtual address 709d9bb58e5SYang Zhong * is permitted. Only a single TARGET_PAGE_SIZE region is mapped, the 710d9bb58e5SYang Zhong * supplied size is only used by tlb_flush_page. 711d9bb58e5SYang Zhong * 712d9bb58e5SYang Zhong * Called from TCG-generated code, which is under an RCU read-side 713d9bb58e5SYang Zhong * critical section. 714d9bb58e5SYang Zhong */ 715d9bb58e5SYang Zhong void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, 716d9bb58e5SYang Zhong hwaddr paddr, MemTxAttrs attrs, int prot, 717d9bb58e5SYang Zhong int mmu_idx, target_ulong size) 718d9bb58e5SYang Zhong { 719d9bb58e5SYang Zhong CPUArchState *env = cpu->env_ptr; 720d9bb58e5SYang Zhong MemoryRegionSection *section; 721d9bb58e5SYang Zhong unsigned int index; 722d9bb58e5SYang Zhong target_ulong address; 723d9bb58e5SYang Zhong target_ulong code_address; 724d9bb58e5SYang Zhong uintptr_t addend; 72568fea038SRichard Henderson CPUTLBEntry *te, tn; 72655df6fcfSPeter Maydell hwaddr iotlb, xlat, sz, paddr_page; 72755df6fcfSPeter Maydell target_ulong vaddr_page; 728d9bb58e5SYang Zhong int asidx = cpu_asidx_from_attrs(cpu, attrs); 729d9bb58e5SYang Zhong 730d9bb58e5SYang Zhong assert_cpu_is_self(cpu); 73155df6fcfSPeter Maydell 7321308e026SRichard Henderson if (size <= TARGET_PAGE_SIZE) { 73355df6fcfSPeter Maydell sz = TARGET_PAGE_SIZE; 73455df6fcfSPeter Maydell } else { 7351308e026SRichard Henderson tlb_add_large_page(env, mmu_idx, vaddr, size); 736d9bb58e5SYang Zhong sz = size; 73755df6fcfSPeter Maydell } 73855df6fcfSPeter Maydell vaddr_page = vaddr & TARGET_PAGE_MASK; 73955df6fcfSPeter Maydell paddr_page = paddr & TARGET_PAGE_MASK; 74055df6fcfSPeter Maydell 74155df6fcfSPeter Maydell section = address_space_translate_for_iotlb(cpu, asidx, paddr_page, 74255df6fcfSPeter Maydell &xlat, &sz, attrs, &prot); 743d9bb58e5SYang Zhong assert(sz >= TARGET_PAGE_SIZE); 744d9bb58e5SYang Zhong 745d9bb58e5SYang Zhong tlb_debug("vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx 746d9bb58e5SYang Zhong " prot=%x idx=%d\n", 747d9bb58e5SYang Zhong vaddr, paddr, prot, mmu_idx); 748d9bb58e5SYang Zhong 74955df6fcfSPeter Maydell address = vaddr_page; 75055df6fcfSPeter Maydell if (size < TARGET_PAGE_SIZE) { 75155df6fcfSPeter Maydell /* 75255df6fcfSPeter Maydell * Slow-path the TLB entries; we will repeat the MMU check and TLB 75355df6fcfSPeter Maydell * fill on every access. 75455df6fcfSPeter Maydell */ 75555df6fcfSPeter Maydell address |= TLB_RECHECK; 75655df6fcfSPeter Maydell } 75755df6fcfSPeter Maydell if (!memory_region_is_ram(section->mr) && 75855df6fcfSPeter Maydell !memory_region_is_romd(section->mr)) { 759d9bb58e5SYang Zhong /* IO memory case */ 760d9bb58e5SYang Zhong address |= TLB_MMIO; 761d9bb58e5SYang Zhong addend = 0; 762d9bb58e5SYang Zhong } else { 763d9bb58e5SYang Zhong /* TLB_MMIO for rom/romd handled below */ 764d9bb58e5SYang Zhong addend = (uintptr_t)memory_region_get_ram_ptr(section->mr) + xlat; 765d9bb58e5SYang Zhong } 766d9bb58e5SYang Zhong 767d9bb58e5SYang Zhong code_address = address; 76855df6fcfSPeter Maydell iotlb = memory_region_section_get_iotlb(cpu, section, vaddr_page, 76955df6fcfSPeter Maydell paddr_page, xlat, prot, &address); 770d9bb58e5SYang Zhong 771383beda9SRichard Henderson index = tlb_index(env, mmu_idx, vaddr_page); 772383beda9SRichard Henderson te = tlb_entry(env, mmu_idx, vaddr_page); 773d9bb58e5SYang Zhong 77468fea038SRichard Henderson /* 77571aec354SEmilio G. Cota * Hold the TLB lock for the rest of the function. We could acquire/release 77671aec354SEmilio G. Cota * the lock several times in the function, but it is faster to amortize the 77771aec354SEmilio G. Cota * acquisition cost by acquiring it just once. Note that this leads to 77871aec354SEmilio G. Cota * a longer critical section, but this is not a concern since the TLB lock 77971aec354SEmilio G. Cota * is unlikely to be contended. 78071aec354SEmilio G. Cota */ 78153d28455SRichard Henderson qemu_spin_lock(&env->tlb_c.lock); 78271aec354SEmilio G. Cota 7833d1523ceSRichard Henderson /* Note that the tlb is no longer clean. */ 7843d1523ceSRichard Henderson env->tlb_c.dirty |= 1 << mmu_idx; 7853d1523ceSRichard Henderson 78671aec354SEmilio G. Cota /* Make sure there's no cached translation for the new page. */ 78771aec354SEmilio G. Cota tlb_flush_vtlb_page_locked(env, mmu_idx, vaddr_page); 78871aec354SEmilio G. Cota 78971aec354SEmilio G. Cota /* 79068fea038SRichard Henderson * Only evict the old entry to the victim tlb if it's for a 79168fea038SRichard Henderson * different page; otherwise just overwrite the stale data. 79268fea038SRichard Henderson */ 7933cea94bbSEmilio G. Cota if (!tlb_hit_page_anyprot(te, vaddr_page) && !tlb_entry_is_empty(te)) { 794d5363e58SRichard Henderson unsigned vidx = env->tlb_d[mmu_idx].vindex++ % CPU_VTLB_SIZE; 79568fea038SRichard Henderson CPUTLBEntry *tv = &env->tlb_v_table[mmu_idx][vidx]; 79668fea038SRichard Henderson 79768fea038SRichard Henderson /* Evict the old entry into the victim tlb. */ 79871aec354SEmilio G. Cota copy_tlb_helper_locked(tv, te); 799d9bb58e5SYang Zhong env->iotlb_v[mmu_idx][vidx] = env->iotlb[mmu_idx][index]; 800*86e1eff8SEmilio G. Cota tlb_n_used_entries_dec(env, mmu_idx); 80168fea038SRichard Henderson } 802d9bb58e5SYang Zhong 803d9bb58e5SYang Zhong /* refill the tlb */ 804ace41090SPeter Maydell /* 805ace41090SPeter Maydell * At this point iotlb contains a physical section number in the lower 806ace41090SPeter Maydell * TARGET_PAGE_BITS, and either 807ace41090SPeter Maydell * + the ram_addr_t of the page base of the target RAM (if NOTDIRTY or ROM) 808ace41090SPeter Maydell * + the offset within section->mr of the page base (otherwise) 80955df6fcfSPeter Maydell * We subtract the vaddr_page (which is page aligned and thus won't 810ace41090SPeter Maydell * disturb the low bits) to give an offset which can be added to the 811ace41090SPeter Maydell * (non-page-aligned) vaddr of the eventual memory access to get 812ace41090SPeter Maydell * the MemoryRegion offset for the access. Note that the vaddr we 813ace41090SPeter Maydell * subtract here is that of the page base, and not the same as the 814ace41090SPeter Maydell * vaddr we add back in io_readx()/io_writex()/get_page_addr_code(). 815ace41090SPeter Maydell */ 81655df6fcfSPeter Maydell env->iotlb[mmu_idx][index].addr = iotlb - vaddr_page; 817d9bb58e5SYang Zhong env->iotlb[mmu_idx][index].attrs = attrs; 818d9bb58e5SYang Zhong 819d9bb58e5SYang Zhong /* Now calculate the new entry */ 82055df6fcfSPeter Maydell tn.addend = addend - vaddr_page; 821d9bb58e5SYang Zhong if (prot & PAGE_READ) { 822d9bb58e5SYang Zhong tn.addr_read = address; 823d9bb58e5SYang Zhong } else { 824d9bb58e5SYang Zhong tn.addr_read = -1; 825d9bb58e5SYang Zhong } 826d9bb58e5SYang Zhong 827d9bb58e5SYang Zhong if (prot & PAGE_EXEC) { 828d9bb58e5SYang Zhong tn.addr_code = code_address; 829d9bb58e5SYang Zhong } else { 830d9bb58e5SYang Zhong tn.addr_code = -1; 831d9bb58e5SYang Zhong } 832d9bb58e5SYang Zhong 833d9bb58e5SYang Zhong tn.addr_write = -1; 834d9bb58e5SYang Zhong if (prot & PAGE_WRITE) { 835d9bb58e5SYang Zhong if ((memory_region_is_ram(section->mr) && section->readonly) 836d9bb58e5SYang Zhong || memory_region_is_romd(section->mr)) { 837d9bb58e5SYang Zhong /* Write access calls the I/O callback. */ 838d9bb58e5SYang Zhong tn.addr_write = address | TLB_MMIO; 839d9bb58e5SYang Zhong } else if (memory_region_is_ram(section->mr) 840d9bb58e5SYang Zhong && cpu_physical_memory_is_clean( 841d9bb58e5SYang Zhong memory_region_get_ram_addr(section->mr) + xlat)) { 842d9bb58e5SYang Zhong tn.addr_write = address | TLB_NOTDIRTY; 843d9bb58e5SYang Zhong } else { 844d9bb58e5SYang Zhong tn.addr_write = address; 845d9bb58e5SYang Zhong } 846f52bfb12SDavid Hildenbrand if (prot & PAGE_WRITE_INV) { 847f52bfb12SDavid Hildenbrand tn.addr_write |= TLB_INVALID_MASK; 848f52bfb12SDavid Hildenbrand } 849d9bb58e5SYang Zhong } 850d9bb58e5SYang Zhong 85171aec354SEmilio G. Cota copy_tlb_helper_locked(te, &tn); 852*86e1eff8SEmilio G. Cota tlb_n_used_entries_inc(env, mmu_idx); 85353d28455SRichard Henderson qemu_spin_unlock(&env->tlb_c.lock); 854d9bb58e5SYang Zhong } 855d9bb58e5SYang Zhong 856d9bb58e5SYang Zhong /* Add a new TLB entry, but without specifying the memory 857d9bb58e5SYang Zhong * transaction attributes to be used. 858d9bb58e5SYang Zhong */ 859d9bb58e5SYang Zhong void tlb_set_page(CPUState *cpu, target_ulong vaddr, 860d9bb58e5SYang Zhong hwaddr paddr, int prot, 861d9bb58e5SYang Zhong int mmu_idx, target_ulong size) 862d9bb58e5SYang Zhong { 863d9bb58e5SYang Zhong tlb_set_page_with_attrs(cpu, vaddr, paddr, MEMTXATTRS_UNSPECIFIED, 864d9bb58e5SYang Zhong prot, mmu_idx, size); 865d9bb58e5SYang Zhong } 866d9bb58e5SYang Zhong 867d9bb58e5SYang Zhong static inline ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr) 868d9bb58e5SYang Zhong { 869d9bb58e5SYang Zhong ram_addr_t ram_addr; 870d9bb58e5SYang Zhong 871d9bb58e5SYang Zhong ram_addr = qemu_ram_addr_from_host(ptr); 872d9bb58e5SYang Zhong if (ram_addr == RAM_ADDR_INVALID) { 873d9bb58e5SYang Zhong error_report("Bad ram pointer %p", ptr); 874d9bb58e5SYang Zhong abort(); 875d9bb58e5SYang Zhong } 876d9bb58e5SYang Zhong return ram_addr; 877d9bb58e5SYang Zhong } 878d9bb58e5SYang Zhong 879d9bb58e5SYang Zhong static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry, 88004e3aabdSPeter Maydell int mmu_idx, 88155df6fcfSPeter Maydell target_ulong addr, uintptr_t retaddr, 882dbea78a4SPeter Maydell bool recheck, MMUAccessType access_type, int size) 883d9bb58e5SYang Zhong { 884d9bb58e5SYang Zhong CPUState *cpu = ENV_GET_CPU(env); 8852d54f194SPeter Maydell hwaddr mr_offset; 8862d54f194SPeter Maydell MemoryRegionSection *section; 8872d54f194SPeter Maydell MemoryRegion *mr; 888d9bb58e5SYang Zhong uint64_t val; 889d9bb58e5SYang Zhong bool locked = false; 89004e3aabdSPeter Maydell MemTxResult r; 891d9bb58e5SYang Zhong 89255df6fcfSPeter Maydell if (recheck) { 89355df6fcfSPeter Maydell /* 89455df6fcfSPeter Maydell * This is a TLB_RECHECK access, where the MMU protection 89555df6fcfSPeter Maydell * covers a smaller range than a target page, and we must 89655df6fcfSPeter Maydell * repeat the MMU check here. This tlb_fill() call might 89755df6fcfSPeter Maydell * longjump out if this access should cause a guest exception. 89855df6fcfSPeter Maydell */ 899383beda9SRichard Henderson CPUTLBEntry *entry; 90055df6fcfSPeter Maydell target_ulong tlb_addr; 90155df6fcfSPeter Maydell 90255df6fcfSPeter Maydell tlb_fill(cpu, addr, size, MMU_DATA_LOAD, mmu_idx, retaddr); 90355df6fcfSPeter Maydell 904383beda9SRichard Henderson entry = tlb_entry(env, mmu_idx, addr); 905383beda9SRichard Henderson tlb_addr = entry->addr_read; 90655df6fcfSPeter Maydell if (!(tlb_addr & ~(TARGET_PAGE_MASK | TLB_RECHECK))) { 90755df6fcfSPeter Maydell /* RAM access */ 908383beda9SRichard Henderson uintptr_t haddr = addr + entry->addend; 90955df6fcfSPeter Maydell 91055df6fcfSPeter Maydell return ldn_p((void *)haddr, size); 91155df6fcfSPeter Maydell } 91255df6fcfSPeter Maydell /* Fall through for handling IO accesses */ 91355df6fcfSPeter Maydell } 91455df6fcfSPeter Maydell 9152d54f194SPeter Maydell section = iotlb_to_section(cpu, iotlbentry->addr, iotlbentry->attrs); 9162d54f194SPeter Maydell mr = section->mr; 9172d54f194SPeter Maydell mr_offset = (iotlbentry->addr & TARGET_PAGE_MASK) + addr; 918d9bb58e5SYang Zhong cpu->mem_io_pc = retaddr; 919d9bb58e5SYang Zhong if (mr != &io_mem_rom && mr != &io_mem_notdirty && !cpu->can_do_io) { 920d9bb58e5SYang Zhong cpu_io_recompile(cpu, retaddr); 921d9bb58e5SYang Zhong } 922d9bb58e5SYang Zhong 923d9bb58e5SYang Zhong cpu->mem_io_vaddr = addr; 924dbea78a4SPeter Maydell cpu->mem_io_access_type = access_type; 925d9bb58e5SYang Zhong 9268b812533SAlex Bennée if (mr->global_locking && !qemu_mutex_iothread_locked()) { 927d9bb58e5SYang Zhong qemu_mutex_lock_iothread(); 928d9bb58e5SYang Zhong locked = true; 929d9bb58e5SYang Zhong } 9302d54f194SPeter Maydell r = memory_region_dispatch_read(mr, mr_offset, 93104e3aabdSPeter Maydell &val, size, iotlbentry->attrs); 93204e3aabdSPeter Maydell if (r != MEMTX_OK) { 9332d54f194SPeter Maydell hwaddr physaddr = mr_offset + 9342d54f194SPeter Maydell section->offset_within_address_space - 9352d54f194SPeter Maydell section->offset_within_region; 9362d54f194SPeter Maydell 937dbea78a4SPeter Maydell cpu_transaction_failed(cpu, physaddr, addr, size, access_type, 93804e3aabdSPeter Maydell mmu_idx, iotlbentry->attrs, r, retaddr); 93904e3aabdSPeter Maydell } 940d9bb58e5SYang Zhong if (locked) { 941d9bb58e5SYang Zhong qemu_mutex_unlock_iothread(); 942d9bb58e5SYang Zhong } 943d9bb58e5SYang Zhong 944d9bb58e5SYang Zhong return val; 945d9bb58e5SYang Zhong } 946d9bb58e5SYang Zhong 947d9bb58e5SYang Zhong static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry, 94804e3aabdSPeter Maydell int mmu_idx, 949d9bb58e5SYang Zhong uint64_t val, target_ulong addr, 95055df6fcfSPeter Maydell uintptr_t retaddr, bool recheck, int size) 951d9bb58e5SYang Zhong { 952d9bb58e5SYang Zhong CPUState *cpu = ENV_GET_CPU(env); 9532d54f194SPeter Maydell hwaddr mr_offset; 9542d54f194SPeter Maydell MemoryRegionSection *section; 9552d54f194SPeter Maydell MemoryRegion *mr; 956d9bb58e5SYang Zhong bool locked = false; 95704e3aabdSPeter Maydell MemTxResult r; 958d9bb58e5SYang Zhong 95955df6fcfSPeter Maydell if (recheck) { 96055df6fcfSPeter Maydell /* 96155df6fcfSPeter Maydell * This is a TLB_RECHECK access, where the MMU protection 96255df6fcfSPeter Maydell * covers a smaller range than a target page, and we must 96355df6fcfSPeter Maydell * repeat the MMU check here. This tlb_fill() call might 96455df6fcfSPeter Maydell * longjump out if this access should cause a guest exception. 96555df6fcfSPeter Maydell */ 966383beda9SRichard Henderson CPUTLBEntry *entry; 96755df6fcfSPeter Maydell target_ulong tlb_addr; 96855df6fcfSPeter Maydell 96955df6fcfSPeter Maydell tlb_fill(cpu, addr, size, MMU_DATA_STORE, mmu_idx, retaddr); 97055df6fcfSPeter Maydell 971383beda9SRichard Henderson entry = tlb_entry(env, mmu_idx, addr); 972403f290cSEmilio G. Cota tlb_addr = tlb_addr_write(entry); 97355df6fcfSPeter Maydell if (!(tlb_addr & ~(TARGET_PAGE_MASK | TLB_RECHECK))) { 97455df6fcfSPeter Maydell /* RAM access */ 975383beda9SRichard Henderson uintptr_t haddr = addr + entry->addend; 97655df6fcfSPeter Maydell 97755df6fcfSPeter Maydell stn_p((void *)haddr, size, val); 97855df6fcfSPeter Maydell return; 97955df6fcfSPeter Maydell } 98055df6fcfSPeter Maydell /* Fall through for handling IO accesses */ 98155df6fcfSPeter Maydell } 98255df6fcfSPeter Maydell 9832d54f194SPeter Maydell section = iotlb_to_section(cpu, iotlbentry->addr, iotlbentry->attrs); 9842d54f194SPeter Maydell mr = section->mr; 9852d54f194SPeter Maydell mr_offset = (iotlbentry->addr & TARGET_PAGE_MASK) + addr; 986d9bb58e5SYang Zhong if (mr != &io_mem_rom && mr != &io_mem_notdirty && !cpu->can_do_io) { 987d9bb58e5SYang Zhong cpu_io_recompile(cpu, retaddr); 988d9bb58e5SYang Zhong } 989d9bb58e5SYang Zhong cpu->mem_io_vaddr = addr; 990d9bb58e5SYang Zhong cpu->mem_io_pc = retaddr; 991d9bb58e5SYang Zhong 9928b812533SAlex Bennée if (mr->global_locking && !qemu_mutex_iothread_locked()) { 993d9bb58e5SYang Zhong qemu_mutex_lock_iothread(); 994d9bb58e5SYang Zhong locked = true; 995d9bb58e5SYang Zhong } 9962d54f194SPeter Maydell r = memory_region_dispatch_write(mr, mr_offset, 99704e3aabdSPeter Maydell val, size, iotlbentry->attrs); 99804e3aabdSPeter Maydell if (r != MEMTX_OK) { 9992d54f194SPeter Maydell hwaddr physaddr = mr_offset + 10002d54f194SPeter Maydell section->offset_within_address_space - 10012d54f194SPeter Maydell section->offset_within_region; 10022d54f194SPeter Maydell 100304e3aabdSPeter Maydell cpu_transaction_failed(cpu, physaddr, addr, size, MMU_DATA_STORE, 100404e3aabdSPeter Maydell mmu_idx, iotlbentry->attrs, r, retaddr); 100504e3aabdSPeter Maydell } 1006d9bb58e5SYang Zhong if (locked) { 1007d9bb58e5SYang Zhong qemu_mutex_unlock_iothread(); 1008d9bb58e5SYang Zhong } 1009d9bb58e5SYang Zhong } 1010d9bb58e5SYang Zhong 1011d9bb58e5SYang Zhong /* Return true if ADDR is present in the victim tlb, and has been copied 1012d9bb58e5SYang Zhong back to the main tlb. */ 1013d9bb58e5SYang Zhong static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index, 1014d9bb58e5SYang Zhong size_t elt_ofs, target_ulong page) 1015d9bb58e5SYang Zhong { 1016d9bb58e5SYang Zhong size_t vidx; 101771aec354SEmilio G. Cota 101871aec354SEmilio G. Cota assert_cpu_is_self(ENV_GET_CPU(env)); 1019d9bb58e5SYang Zhong for (vidx = 0; vidx < CPU_VTLB_SIZE; ++vidx) { 1020d9bb58e5SYang Zhong CPUTLBEntry *vtlb = &env->tlb_v_table[mmu_idx][vidx]; 1021403f290cSEmilio G. Cota target_ulong cmp; 1022403f290cSEmilio G. Cota 1023403f290cSEmilio G. Cota /* elt_ofs might correspond to .addr_write, so use atomic_read */ 1024403f290cSEmilio G. Cota #if TCG_OVERSIZED_GUEST 1025403f290cSEmilio G. Cota cmp = *(target_ulong *)((uintptr_t)vtlb + elt_ofs); 1026403f290cSEmilio G. Cota #else 1027403f290cSEmilio G. Cota cmp = atomic_read((target_ulong *)((uintptr_t)vtlb + elt_ofs)); 1028403f290cSEmilio G. Cota #endif 1029d9bb58e5SYang Zhong 1030d9bb58e5SYang Zhong if (cmp == page) { 1031d9bb58e5SYang Zhong /* Found entry in victim tlb, swap tlb and iotlb. */ 1032d9bb58e5SYang Zhong CPUTLBEntry tmptlb, *tlb = &env->tlb_table[mmu_idx][index]; 1033d9bb58e5SYang Zhong 103453d28455SRichard Henderson qemu_spin_lock(&env->tlb_c.lock); 103571aec354SEmilio G. Cota copy_tlb_helper_locked(&tmptlb, tlb); 103671aec354SEmilio G. Cota copy_tlb_helper_locked(tlb, vtlb); 103771aec354SEmilio G. Cota copy_tlb_helper_locked(vtlb, &tmptlb); 103853d28455SRichard Henderson qemu_spin_unlock(&env->tlb_c.lock); 1039d9bb58e5SYang Zhong 1040d9bb58e5SYang Zhong CPUIOTLBEntry tmpio, *io = &env->iotlb[mmu_idx][index]; 1041d9bb58e5SYang Zhong CPUIOTLBEntry *vio = &env->iotlb_v[mmu_idx][vidx]; 1042d9bb58e5SYang Zhong tmpio = *io; *io = *vio; *vio = tmpio; 1043d9bb58e5SYang Zhong return true; 1044d9bb58e5SYang Zhong } 1045d9bb58e5SYang Zhong } 1046d9bb58e5SYang Zhong return false; 1047d9bb58e5SYang Zhong } 1048d9bb58e5SYang Zhong 1049d9bb58e5SYang Zhong /* Macro to call the above, with local variables from the use context. */ 1050d9bb58e5SYang Zhong #define VICTIM_TLB_HIT(TY, ADDR) \ 1051d9bb58e5SYang Zhong victim_tlb_hit(env, mmu_idx, index, offsetof(CPUTLBEntry, TY), \ 1052d9bb58e5SYang Zhong (ADDR) & TARGET_PAGE_MASK) 1053d9bb58e5SYang Zhong 1054f2553f04SKONRAD Frederic /* NOTE: this function can trigger an exception */ 1055f2553f04SKONRAD Frederic /* NOTE2: the returned address is not exactly the physical address: it 1056f2553f04SKONRAD Frederic * is actually a ram_addr_t (in system mode; the user mode emulation 1057f2553f04SKONRAD Frederic * version of this function returns a guest virtual address). 1058f2553f04SKONRAD Frederic */ 1059f2553f04SKONRAD Frederic tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr) 1060f2553f04SKONRAD Frederic { 1061383beda9SRichard Henderson uintptr_t mmu_idx = cpu_mmu_index(env, true); 1062383beda9SRichard Henderson uintptr_t index = tlb_index(env, mmu_idx, addr); 1063383beda9SRichard Henderson CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); 1064f2553f04SKONRAD Frederic void *p; 1065f2553f04SKONRAD Frederic 1066383beda9SRichard Henderson if (unlikely(!tlb_hit(entry->addr_code, addr))) { 1067b493ccf1SPeter Maydell if (!VICTIM_TLB_HIT(addr_code, addr)) { 106898670d47SLaurent Vivier tlb_fill(ENV_GET_CPU(env), addr, 0, MMU_INST_FETCH, mmu_idx, 0); 106971b9a453SKONRAD Frederic } 1070383beda9SRichard Henderson assert(tlb_hit(entry->addr_code, addr)); 1071f2553f04SKONRAD Frederic } 107255df6fcfSPeter Maydell 1073383beda9SRichard Henderson if (unlikely(entry->addr_code & (TLB_RECHECK | TLB_MMIO))) { 107455df6fcfSPeter Maydell /* 107555a7cb14SPeter Maydell * Return -1 if we can't translate and execute from an entire 107655a7cb14SPeter Maydell * page of RAM here, which will cause us to execute by loading 107755a7cb14SPeter Maydell * and translating one insn at a time, without caching: 107855a7cb14SPeter Maydell * - TLB_RECHECK: means the MMU protection covers a smaller range 107955a7cb14SPeter Maydell * than a target page, so we must redo the MMU check every insn 108055a7cb14SPeter Maydell * - TLB_MMIO: region is not backed by RAM 108155df6fcfSPeter Maydell */ 108220cb6ae4SPeter Maydell return -1; 108355df6fcfSPeter Maydell } 108455df6fcfSPeter Maydell 1085383beda9SRichard Henderson p = (void *)((uintptr_t)addr + entry->addend); 1086f2553f04SKONRAD Frederic return qemu_ram_addr_from_host_nofail(p); 1087f2553f04SKONRAD Frederic } 1088f2553f04SKONRAD Frederic 1089d9bb58e5SYang Zhong /* Probe for whether the specified guest write access is permitted. 1090d9bb58e5SYang Zhong * If it is not permitted then an exception will be taken in the same 1091d9bb58e5SYang Zhong * way as if this were a real write access (and we will not return). 1092d9bb58e5SYang Zhong * Otherwise the function will return, and there will be a valid 1093d9bb58e5SYang Zhong * entry in the TLB for this access. 1094d9bb58e5SYang Zhong */ 109598670d47SLaurent Vivier void probe_write(CPUArchState *env, target_ulong addr, int size, int mmu_idx, 1096d9bb58e5SYang Zhong uintptr_t retaddr) 1097d9bb58e5SYang Zhong { 1098383beda9SRichard Henderson uintptr_t index = tlb_index(env, mmu_idx, addr); 1099383beda9SRichard Henderson CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); 1100d9bb58e5SYang Zhong 1101403f290cSEmilio G. Cota if (!tlb_hit(tlb_addr_write(entry), addr)) { 1102d9bb58e5SYang Zhong /* TLB entry is for a different page */ 1103d9bb58e5SYang Zhong if (!VICTIM_TLB_HIT(addr_write, addr)) { 110498670d47SLaurent Vivier tlb_fill(ENV_GET_CPU(env), addr, size, MMU_DATA_STORE, 110598670d47SLaurent Vivier mmu_idx, retaddr); 1106d9bb58e5SYang Zhong } 1107d9bb58e5SYang Zhong } 1108d9bb58e5SYang Zhong } 1109d9bb58e5SYang Zhong 1110d9bb58e5SYang Zhong /* Probe for a read-modify-write atomic operation. Do not allow unaligned 1111d9bb58e5SYang Zhong * operations, or io operations to proceed. Return the host address. */ 1112d9bb58e5SYang Zhong static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, 111334d49937SPeter Maydell TCGMemOpIdx oi, uintptr_t retaddr, 111434d49937SPeter Maydell NotDirtyInfo *ndi) 1115d9bb58e5SYang Zhong { 1116d9bb58e5SYang Zhong size_t mmu_idx = get_mmuidx(oi); 1117383beda9SRichard Henderson uintptr_t index = tlb_index(env, mmu_idx, addr); 1118383beda9SRichard Henderson CPUTLBEntry *tlbe = tlb_entry(env, mmu_idx, addr); 1119403f290cSEmilio G. Cota target_ulong tlb_addr = tlb_addr_write(tlbe); 1120d9bb58e5SYang Zhong TCGMemOp mop = get_memop(oi); 1121d9bb58e5SYang Zhong int a_bits = get_alignment_bits(mop); 1122d9bb58e5SYang Zhong int s_bits = mop & MO_SIZE; 112334d49937SPeter Maydell void *hostaddr; 1124d9bb58e5SYang Zhong 1125d9bb58e5SYang Zhong /* Adjust the given return address. */ 1126d9bb58e5SYang Zhong retaddr -= GETPC_ADJ; 1127d9bb58e5SYang Zhong 1128d9bb58e5SYang Zhong /* Enforce guest required alignment. */ 1129d9bb58e5SYang Zhong if (unlikely(a_bits > 0 && (addr & ((1 << a_bits) - 1)))) { 1130d9bb58e5SYang Zhong /* ??? Maybe indicate atomic op to cpu_unaligned_access */ 1131d9bb58e5SYang Zhong cpu_unaligned_access(ENV_GET_CPU(env), addr, MMU_DATA_STORE, 1132d9bb58e5SYang Zhong mmu_idx, retaddr); 1133d9bb58e5SYang Zhong } 1134d9bb58e5SYang Zhong 1135d9bb58e5SYang Zhong /* Enforce qemu required alignment. */ 1136d9bb58e5SYang Zhong if (unlikely(addr & ((1 << s_bits) - 1))) { 1137d9bb58e5SYang Zhong /* We get here if guest alignment was not requested, 1138d9bb58e5SYang Zhong or was not enforced by cpu_unaligned_access above. 1139d9bb58e5SYang Zhong We might widen the access and emulate, but for now 1140d9bb58e5SYang Zhong mark an exception and exit the cpu loop. */ 1141d9bb58e5SYang Zhong goto stop_the_world; 1142d9bb58e5SYang Zhong } 1143d9bb58e5SYang Zhong 1144d9bb58e5SYang Zhong /* Check TLB entry and enforce page permissions. */ 1145334692bcSPeter Maydell if (!tlb_hit(tlb_addr, addr)) { 1146d9bb58e5SYang Zhong if (!VICTIM_TLB_HIT(addr_write, addr)) { 114798670d47SLaurent Vivier tlb_fill(ENV_GET_CPU(env), addr, 1 << s_bits, MMU_DATA_STORE, 114898670d47SLaurent Vivier mmu_idx, retaddr); 1149d9bb58e5SYang Zhong } 1150403f290cSEmilio G. Cota tlb_addr = tlb_addr_write(tlbe) & ~TLB_INVALID_MASK; 1151d9bb58e5SYang Zhong } 1152d9bb58e5SYang Zhong 115355df6fcfSPeter Maydell /* Notice an IO access or a needs-MMU-lookup access */ 115455df6fcfSPeter Maydell if (unlikely(tlb_addr & (TLB_MMIO | TLB_RECHECK))) { 1155d9bb58e5SYang Zhong /* There's really nothing that can be done to 1156d9bb58e5SYang Zhong support this apart from stop-the-world. */ 1157d9bb58e5SYang Zhong goto stop_the_world; 1158d9bb58e5SYang Zhong } 1159d9bb58e5SYang Zhong 1160d9bb58e5SYang Zhong /* Let the guest notice RMW on a write-only page. */ 116134d49937SPeter Maydell if (unlikely(tlbe->addr_read != (tlb_addr & ~TLB_NOTDIRTY))) { 116298670d47SLaurent Vivier tlb_fill(ENV_GET_CPU(env), addr, 1 << s_bits, MMU_DATA_LOAD, 116398670d47SLaurent Vivier mmu_idx, retaddr); 1164d9bb58e5SYang Zhong /* Since we don't support reads and writes to different addresses, 1165d9bb58e5SYang Zhong and we do have the proper page loaded for write, this shouldn't 1166d9bb58e5SYang Zhong ever return. But just in case, handle via stop-the-world. */ 1167d9bb58e5SYang Zhong goto stop_the_world; 1168d9bb58e5SYang Zhong } 1169d9bb58e5SYang Zhong 117034d49937SPeter Maydell hostaddr = (void *)((uintptr_t)addr + tlbe->addend); 117134d49937SPeter Maydell 117234d49937SPeter Maydell ndi->active = false; 117334d49937SPeter Maydell if (unlikely(tlb_addr & TLB_NOTDIRTY)) { 117434d49937SPeter Maydell ndi->active = true; 117534d49937SPeter Maydell memory_notdirty_write_prepare(ndi, ENV_GET_CPU(env), addr, 117634d49937SPeter Maydell qemu_ram_addr_from_host_nofail(hostaddr), 117734d49937SPeter Maydell 1 << s_bits); 117834d49937SPeter Maydell } 117934d49937SPeter Maydell 118034d49937SPeter Maydell return hostaddr; 1181d9bb58e5SYang Zhong 1182d9bb58e5SYang Zhong stop_the_world: 1183d9bb58e5SYang Zhong cpu_loop_exit_atomic(ENV_GET_CPU(env), retaddr); 1184d9bb58e5SYang Zhong } 1185d9bb58e5SYang Zhong 1186d9bb58e5SYang Zhong #ifdef TARGET_WORDS_BIGENDIAN 1187d9bb58e5SYang Zhong # define TGT_BE(X) (X) 1188d9bb58e5SYang Zhong # define TGT_LE(X) BSWAP(X) 1189d9bb58e5SYang Zhong #else 1190d9bb58e5SYang Zhong # define TGT_BE(X) BSWAP(X) 1191d9bb58e5SYang Zhong # define TGT_LE(X) (X) 1192d9bb58e5SYang Zhong #endif 1193d9bb58e5SYang Zhong 1194d9bb58e5SYang Zhong #define MMUSUFFIX _mmu 1195d9bb58e5SYang Zhong 1196d9bb58e5SYang Zhong #define DATA_SIZE 1 1197d9bb58e5SYang Zhong #include "softmmu_template.h" 1198d9bb58e5SYang Zhong 1199d9bb58e5SYang Zhong #define DATA_SIZE 2 1200d9bb58e5SYang Zhong #include "softmmu_template.h" 1201d9bb58e5SYang Zhong 1202d9bb58e5SYang Zhong #define DATA_SIZE 4 1203d9bb58e5SYang Zhong #include "softmmu_template.h" 1204d9bb58e5SYang Zhong 1205d9bb58e5SYang Zhong #define DATA_SIZE 8 1206d9bb58e5SYang Zhong #include "softmmu_template.h" 1207d9bb58e5SYang Zhong 1208d9bb58e5SYang Zhong /* First set of helpers allows passing in of OI and RETADDR. This makes 1209d9bb58e5SYang Zhong them callable from other helpers. */ 1210d9bb58e5SYang Zhong 1211d9bb58e5SYang Zhong #define EXTRA_ARGS , TCGMemOpIdx oi, uintptr_t retaddr 1212d9bb58e5SYang Zhong #define ATOMIC_NAME(X) \ 1213d9bb58e5SYang Zhong HELPER(glue(glue(glue(atomic_ ## X, SUFFIX), END), _mmu)) 121434d49937SPeter Maydell #define ATOMIC_MMU_DECLS NotDirtyInfo ndi 121534d49937SPeter Maydell #define ATOMIC_MMU_LOOKUP atomic_mmu_lookup(env, addr, oi, retaddr, &ndi) 121634d49937SPeter Maydell #define ATOMIC_MMU_CLEANUP \ 121734d49937SPeter Maydell do { \ 121834d49937SPeter Maydell if (unlikely(ndi.active)) { \ 121934d49937SPeter Maydell memory_notdirty_write_complete(&ndi); \ 122034d49937SPeter Maydell } \ 122134d49937SPeter Maydell } while (0) 1222d9bb58e5SYang Zhong 1223d9bb58e5SYang Zhong #define DATA_SIZE 1 1224d9bb58e5SYang Zhong #include "atomic_template.h" 1225d9bb58e5SYang Zhong 1226d9bb58e5SYang Zhong #define DATA_SIZE 2 1227d9bb58e5SYang Zhong #include "atomic_template.h" 1228d9bb58e5SYang Zhong 1229d9bb58e5SYang Zhong #define DATA_SIZE 4 1230d9bb58e5SYang Zhong #include "atomic_template.h" 1231d9bb58e5SYang Zhong 1232d9bb58e5SYang Zhong #ifdef CONFIG_ATOMIC64 1233d9bb58e5SYang Zhong #define DATA_SIZE 8 1234d9bb58e5SYang Zhong #include "atomic_template.h" 1235d9bb58e5SYang Zhong #endif 1236d9bb58e5SYang Zhong 1237e6cd4bb5SRichard Henderson #if HAVE_CMPXCHG128 || HAVE_ATOMIC128 1238d9bb58e5SYang Zhong #define DATA_SIZE 16 1239d9bb58e5SYang Zhong #include "atomic_template.h" 1240d9bb58e5SYang Zhong #endif 1241d9bb58e5SYang Zhong 1242d9bb58e5SYang Zhong /* Second set of helpers are directly callable from TCG as helpers. */ 1243d9bb58e5SYang Zhong 1244d9bb58e5SYang Zhong #undef EXTRA_ARGS 1245d9bb58e5SYang Zhong #undef ATOMIC_NAME 1246d9bb58e5SYang Zhong #undef ATOMIC_MMU_LOOKUP 1247d9bb58e5SYang Zhong #define EXTRA_ARGS , TCGMemOpIdx oi 1248d9bb58e5SYang Zhong #define ATOMIC_NAME(X) HELPER(glue(glue(atomic_ ## X, SUFFIX), END)) 124934d49937SPeter Maydell #define ATOMIC_MMU_LOOKUP atomic_mmu_lookup(env, addr, oi, GETPC(), &ndi) 1250d9bb58e5SYang Zhong 1251d9bb58e5SYang Zhong #define DATA_SIZE 1 1252d9bb58e5SYang Zhong #include "atomic_template.h" 1253d9bb58e5SYang Zhong 1254d9bb58e5SYang Zhong #define DATA_SIZE 2 1255d9bb58e5SYang Zhong #include "atomic_template.h" 1256d9bb58e5SYang Zhong 1257d9bb58e5SYang Zhong #define DATA_SIZE 4 1258d9bb58e5SYang Zhong #include "atomic_template.h" 1259d9bb58e5SYang Zhong 1260d9bb58e5SYang Zhong #ifdef CONFIG_ATOMIC64 1261d9bb58e5SYang Zhong #define DATA_SIZE 8 1262d9bb58e5SYang Zhong #include "atomic_template.h" 1263d9bb58e5SYang Zhong #endif 1264d9bb58e5SYang Zhong 1265d9bb58e5SYang Zhong /* Code access functions. */ 1266d9bb58e5SYang Zhong 1267d9bb58e5SYang Zhong #undef MMUSUFFIX 1268d9bb58e5SYang Zhong #define MMUSUFFIX _cmmu 1269d9bb58e5SYang Zhong #undef GETPC 1270d9bb58e5SYang Zhong #define GETPC() ((uintptr_t)0) 1271d9bb58e5SYang Zhong #define SOFTMMU_CODE_ACCESS 1272d9bb58e5SYang Zhong 1273d9bb58e5SYang Zhong #define DATA_SIZE 1 1274d9bb58e5SYang Zhong #include "softmmu_template.h" 1275d9bb58e5SYang Zhong 1276d9bb58e5SYang Zhong #define DATA_SIZE 2 1277d9bb58e5SYang Zhong #include "softmmu_template.h" 1278d9bb58e5SYang Zhong 1279d9bb58e5SYang Zhong #define DATA_SIZE 4 1280d9bb58e5SYang Zhong #include "softmmu_template.h" 1281d9bb58e5SYang Zhong 1282d9bb58e5SYang Zhong #define DATA_SIZE 8 1283d9bb58e5SYang Zhong #include "softmmu_template.h" 1284