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 9fb0343d5SThomas Huth * version 2.1 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" 2278271684SClaudio Fontana #include "hw/core/tcg-cpu-ops.h" 23d9bb58e5SYang Zhong #include "exec/exec-all.h" 24d9bb58e5SYang Zhong #include "exec/memory.h" 25d9bb58e5SYang Zhong #include "exec/cpu_ldst.h" 26d9bb58e5SYang Zhong #include "exec/cputlb.h" 27d9bb58e5SYang Zhong #include "exec/memory-internal.h" 28d9bb58e5SYang Zhong #include "exec/ram_addr.h" 29d9bb58e5SYang Zhong #include "tcg/tcg.h" 30d9bb58e5SYang Zhong #include "qemu/error-report.h" 31d9bb58e5SYang Zhong #include "exec/log.h" 32d9bb58e5SYang Zhong #include "exec/helper-proto.h" 33d9bb58e5SYang Zhong #include "qemu/atomic.h" 34e6cd4bb5SRichard Henderson #include "qemu/atomic128.h" 353b9bd3f4SPaolo Bonzini #include "exec/translate-all.h" 36243af022SPaolo Bonzini #include "trace/trace-root.h" 37d03f1408SRichard Henderson #include "trace/mem.h" 38e5ceadffSPhilippe Mathieu-Daudé #include "tb-hash.h" 3965269192SPhilippe Mathieu-Daudé #include "internal.h" 40235537faSAlex Bennée #ifdef CONFIG_PLUGIN 41235537faSAlex Bennée #include "qemu/plugin-memory.h" 42235537faSAlex Bennée #endif 43d9bb58e5SYang Zhong 44d9bb58e5SYang Zhong /* DEBUG defines, enable DEBUG_TLB_LOG to log to the CPU_LOG_MMU target */ 45d9bb58e5SYang Zhong /* #define DEBUG_TLB */ 46d9bb58e5SYang Zhong /* #define DEBUG_TLB_LOG */ 47d9bb58e5SYang Zhong 48d9bb58e5SYang Zhong #ifdef DEBUG_TLB 49d9bb58e5SYang Zhong # define DEBUG_TLB_GATE 1 50d9bb58e5SYang Zhong # ifdef DEBUG_TLB_LOG 51d9bb58e5SYang Zhong # define DEBUG_TLB_LOG_GATE 1 52d9bb58e5SYang Zhong # else 53d9bb58e5SYang Zhong # define DEBUG_TLB_LOG_GATE 0 54d9bb58e5SYang Zhong # endif 55d9bb58e5SYang Zhong #else 56d9bb58e5SYang Zhong # define DEBUG_TLB_GATE 0 57d9bb58e5SYang Zhong # define DEBUG_TLB_LOG_GATE 0 58d9bb58e5SYang Zhong #endif 59d9bb58e5SYang Zhong 60d9bb58e5SYang Zhong #define tlb_debug(fmt, ...) do { \ 61d9bb58e5SYang Zhong if (DEBUG_TLB_LOG_GATE) { \ 62d9bb58e5SYang Zhong qemu_log_mask(CPU_LOG_MMU, "%s: " fmt, __func__, \ 63d9bb58e5SYang Zhong ## __VA_ARGS__); \ 64d9bb58e5SYang Zhong } else if (DEBUG_TLB_GATE) { \ 65d9bb58e5SYang Zhong fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); \ 66d9bb58e5SYang Zhong } \ 67d9bb58e5SYang Zhong } while (0) 68d9bb58e5SYang Zhong 69ea9025cbSEmilio G. Cota #define assert_cpu_is_self(cpu) do { \ 70d9bb58e5SYang Zhong if (DEBUG_TLB_GATE) { \ 71ea9025cbSEmilio G. Cota g_assert(!(cpu)->created || qemu_cpu_is_self(cpu)); \ 72d9bb58e5SYang Zhong } \ 73d9bb58e5SYang Zhong } while (0) 74d9bb58e5SYang Zhong 75d9bb58e5SYang Zhong /* run_on_cpu_data.target_ptr should always be big enough for a 76d9bb58e5SYang Zhong * target_ulong even on 32 bit builds */ 77d9bb58e5SYang Zhong QEMU_BUILD_BUG_ON(sizeof(target_ulong) > sizeof(run_on_cpu_data)); 78d9bb58e5SYang Zhong 79d9bb58e5SYang Zhong /* We currently can't handle more than 16 bits in the MMUIDX bitmask. 80d9bb58e5SYang Zhong */ 81d9bb58e5SYang Zhong QEMU_BUILD_BUG_ON(NB_MMU_MODES > 16); 82d9bb58e5SYang Zhong #define ALL_MMUIDX_BITS ((1 << NB_MMU_MODES) - 1) 83d9bb58e5SYang Zhong 84722a1c1eSRichard Henderson static inline size_t tlb_n_entries(CPUTLBDescFast *fast) 857a1efe1bSRichard Henderson { 86722a1c1eSRichard Henderson return (fast->mask >> CPU_TLB_ENTRY_BITS) + 1; 877a1efe1bSRichard Henderson } 887a1efe1bSRichard Henderson 89722a1c1eSRichard Henderson static inline size_t sizeof_tlb(CPUTLBDescFast *fast) 9086e1eff8SEmilio G. Cota { 91722a1c1eSRichard Henderson return fast->mask + (1 << CPU_TLB_ENTRY_BITS); 9286e1eff8SEmilio G. Cota } 9386e1eff8SEmilio G. Cota 9479e42085SRichard Henderson static void tlb_window_reset(CPUTLBDesc *desc, int64_t ns, 9586e1eff8SEmilio G. Cota size_t max_entries) 9686e1eff8SEmilio G. Cota { 9779e42085SRichard Henderson desc->window_begin_ns = ns; 9879e42085SRichard Henderson desc->window_max_entries = max_entries; 9986e1eff8SEmilio G. Cota } 10086e1eff8SEmilio G. Cota 1010f4abea8SRichard Henderson static void tb_jmp_cache_clear_page(CPUState *cpu, target_ulong page_addr) 1020f4abea8SRichard Henderson { 1030f4abea8SRichard Henderson unsigned int i, i0 = tb_jmp_cache_hash_page(page_addr); 1040f4abea8SRichard Henderson 1050f4abea8SRichard Henderson for (i = 0; i < TB_JMP_PAGE_SIZE; i++) { 1060f4abea8SRichard Henderson qatomic_set(&cpu->tb_jmp_cache[i0 + i], NULL); 1070f4abea8SRichard Henderson } 1080f4abea8SRichard Henderson } 1090f4abea8SRichard Henderson 1100f4abea8SRichard Henderson static void tb_flush_jmp_cache(CPUState *cpu, target_ulong addr) 1110f4abea8SRichard Henderson { 1120f4abea8SRichard Henderson /* Discard jump cache entries for any tb which might potentially 1130f4abea8SRichard Henderson overlap the flushed page. */ 1140f4abea8SRichard Henderson tb_jmp_cache_clear_page(cpu, addr - TARGET_PAGE_SIZE); 1150f4abea8SRichard Henderson tb_jmp_cache_clear_page(cpu, addr); 1160f4abea8SRichard Henderson } 1170f4abea8SRichard Henderson 11886e1eff8SEmilio G. Cota /** 11986e1eff8SEmilio G. Cota * tlb_mmu_resize_locked() - perform TLB resize bookkeeping; resize if necessary 12071ccd47bSRichard Henderson * @desc: The CPUTLBDesc portion of the TLB 12171ccd47bSRichard Henderson * @fast: The CPUTLBDescFast portion of the same TLB 12286e1eff8SEmilio G. Cota * 12386e1eff8SEmilio G. Cota * Called with tlb_lock_held. 12486e1eff8SEmilio G. Cota * 12586e1eff8SEmilio G. Cota * We have two main constraints when resizing a TLB: (1) we only resize it 12686e1eff8SEmilio G. Cota * on a TLB flush (otherwise we'd have to take a perf hit by either rehashing 12786e1eff8SEmilio G. Cota * the array or unnecessarily flushing it), which means we do not control how 12886e1eff8SEmilio G. Cota * frequently the resizing can occur; (2) we don't have access to the guest's 12986e1eff8SEmilio G. Cota * future scheduling decisions, and therefore have to decide the magnitude of 13086e1eff8SEmilio G. Cota * the resize based on past observations. 13186e1eff8SEmilio G. Cota * 13286e1eff8SEmilio G. Cota * In general, a memory-hungry process can benefit greatly from an appropriately 13386e1eff8SEmilio G. Cota * sized TLB, since a guest TLB miss is very expensive. This doesn't mean that 13486e1eff8SEmilio G. Cota * we just have to make the TLB as large as possible; while an oversized TLB 13586e1eff8SEmilio G. Cota * results in minimal TLB miss rates, it also takes longer to be flushed 13686e1eff8SEmilio G. Cota * (flushes can be _very_ frequent), and the reduced locality can also hurt 13786e1eff8SEmilio G. Cota * performance. 13886e1eff8SEmilio G. Cota * 13986e1eff8SEmilio G. Cota * To achieve near-optimal performance for all kinds of workloads, we: 14086e1eff8SEmilio G. Cota * 14186e1eff8SEmilio G. Cota * 1. Aggressively increase the size of the TLB when the use rate of the 14286e1eff8SEmilio G. Cota * TLB being flushed is high, since it is likely that in the near future this 14386e1eff8SEmilio G. Cota * memory-hungry process will execute again, and its memory hungriness will 14486e1eff8SEmilio G. Cota * probably be similar. 14586e1eff8SEmilio G. Cota * 14686e1eff8SEmilio G. Cota * 2. Slowly reduce the size of the TLB as the use rate declines over a 14786e1eff8SEmilio G. Cota * reasonably large time window. The rationale is that if in such a time window 14886e1eff8SEmilio G. Cota * we have not observed a high TLB use rate, it is likely that we won't observe 14986e1eff8SEmilio G. Cota * it in the near future. In that case, once a time window expires we downsize 15086e1eff8SEmilio G. Cota * the TLB to match the maximum use rate observed in the window. 15186e1eff8SEmilio G. Cota * 15286e1eff8SEmilio G. Cota * 3. Try to keep the maximum use rate in a time window in the 30-70% range, 15386e1eff8SEmilio G. Cota * since in that range performance is likely near-optimal. Recall that the TLB 15486e1eff8SEmilio G. Cota * is direct mapped, so we want the use rate to be low (or at least not too 15586e1eff8SEmilio G. Cota * high), since otherwise we are likely to have a significant amount of 15686e1eff8SEmilio G. Cota * conflict misses. 15786e1eff8SEmilio G. Cota */ 1583c3959f2SRichard Henderson static void tlb_mmu_resize_locked(CPUTLBDesc *desc, CPUTLBDescFast *fast, 1593c3959f2SRichard Henderson int64_t now) 16086e1eff8SEmilio G. Cota { 16171ccd47bSRichard Henderson size_t old_size = tlb_n_entries(fast); 16286e1eff8SEmilio G. Cota size_t rate; 16386e1eff8SEmilio G. Cota size_t new_size = old_size; 16486e1eff8SEmilio G. Cota int64_t window_len_ms = 100; 16586e1eff8SEmilio G. Cota int64_t window_len_ns = window_len_ms * 1000 * 1000; 16679e42085SRichard Henderson bool window_expired = now > desc->window_begin_ns + window_len_ns; 16786e1eff8SEmilio G. Cota 16879e42085SRichard Henderson if (desc->n_used_entries > desc->window_max_entries) { 16979e42085SRichard Henderson desc->window_max_entries = desc->n_used_entries; 17086e1eff8SEmilio G. Cota } 17179e42085SRichard Henderson rate = desc->window_max_entries * 100 / old_size; 17286e1eff8SEmilio G. Cota 17386e1eff8SEmilio G. Cota if (rate > 70) { 17486e1eff8SEmilio G. Cota new_size = MIN(old_size << 1, 1 << CPU_TLB_DYN_MAX_BITS); 17586e1eff8SEmilio G. Cota } else if (rate < 30 && window_expired) { 17679e42085SRichard Henderson size_t ceil = pow2ceil(desc->window_max_entries); 17779e42085SRichard Henderson size_t expected_rate = desc->window_max_entries * 100 / ceil; 17886e1eff8SEmilio G. Cota 17986e1eff8SEmilio G. Cota /* 18086e1eff8SEmilio G. Cota * Avoid undersizing when the max number of entries seen is just below 18186e1eff8SEmilio G. Cota * a pow2. For instance, if max_entries == 1025, the expected use rate 18286e1eff8SEmilio G. Cota * would be 1025/2048==50%. However, if max_entries == 1023, we'd get 18386e1eff8SEmilio G. Cota * 1023/1024==99.9% use rate, so we'd likely end up doubling the size 18486e1eff8SEmilio G. Cota * later. Thus, make sure that the expected use rate remains below 70%. 18586e1eff8SEmilio G. Cota * (and since we double the size, that means the lowest rate we'd 18686e1eff8SEmilio G. Cota * expect to get is 35%, which is still in the 30-70% range where 18786e1eff8SEmilio G. Cota * we consider that the size is appropriate.) 18886e1eff8SEmilio G. Cota */ 18986e1eff8SEmilio G. Cota if (expected_rate > 70) { 19086e1eff8SEmilio G. Cota ceil *= 2; 19186e1eff8SEmilio G. Cota } 19286e1eff8SEmilio G. Cota new_size = MAX(ceil, 1 << CPU_TLB_DYN_MIN_BITS); 19386e1eff8SEmilio G. Cota } 19486e1eff8SEmilio G. Cota 19586e1eff8SEmilio G. Cota if (new_size == old_size) { 19686e1eff8SEmilio G. Cota if (window_expired) { 19779e42085SRichard Henderson tlb_window_reset(desc, now, desc->n_used_entries); 19886e1eff8SEmilio G. Cota } 19986e1eff8SEmilio G. Cota return; 20086e1eff8SEmilio G. Cota } 20186e1eff8SEmilio G. Cota 20271ccd47bSRichard Henderson g_free(fast->table); 20371ccd47bSRichard Henderson g_free(desc->iotlb); 20486e1eff8SEmilio G. Cota 20579e42085SRichard Henderson tlb_window_reset(desc, now, 0); 20686e1eff8SEmilio G. Cota /* desc->n_used_entries is cleared by the caller */ 20771ccd47bSRichard Henderson fast->mask = (new_size - 1) << CPU_TLB_ENTRY_BITS; 20871ccd47bSRichard Henderson fast->table = g_try_new(CPUTLBEntry, new_size); 20971ccd47bSRichard Henderson desc->iotlb = g_try_new(CPUIOTLBEntry, new_size); 21071ccd47bSRichard Henderson 21186e1eff8SEmilio G. Cota /* 21286e1eff8SEmilio G. Cota * If the allocations fail, try smaller sizes. We just freed some 21386e1eff8SEmilio G. Cota * memory, so going back to half of new_size has a good chance of working. 21486e1eff8SEmilio G. Cota * Increased memory pressure elsewhere in the system might cause the 21586e1eff8SEmilio G. Cota * allocations to fail though, so we progressively reduce the allocation 21686e1eff8SEmilio G. Cota * size, aborting if we cannot even allocate the smallest TLB we support. 21786e1eff8SEmilio G. Cota */ 21871ccd47bSRichard Henderson while (fast->table == NULL || desc->iotlb == NULL) { 21986e1eff8SEmilio G. Cota if (new_size == (1 << CPU_TLB_DYN_MIN_BITS)) { 22086e1eff8SEmilio G. Cota error_report("%s: %s", __func__, strerror(errno)); 22186e1eff8SEmilio G. Cota abort(); 22286e1eff8SEmilio G. Cota } 22386e1eff8SEmilio G. Cota new_size = MAX(new_size >> 1, 1 << CPU_TLB_DYN_MIN_BITS); 22471ccd47bSRichard Henderson fast->mask = (new_size - 1) << CPU_TLB_ENTRY_BITS; 22586e1eff8SEmilio G. Cota 22671ccd47bSRichard Henderson g_free(fast->table); 22771ccd47bSRichard Henderson g_free(desc->iotlb); 22871ccd47bSRichard Henderson fast->table = g_try_new(CPUTLBEntry, new_size); 22971ccd47bSRichard Henderson desc->iotlb = g_try_new(CPUIOTLBEntry, new_size); 23086e1eff8SEmilio G. Cota } 23186e1eff8SEmilio G. Cota } 23286e1eff8SEmilio G. Cota 233bbf021b0SRichard Henderson static void tlb_mmu_flush_locked(CPUTLBDesc *desc, CPUTLBDescFast *fast) 23486e1eff8SEmilio G. Cota { 2355c948e31SRichard Henderson desc->n_used_entries = 0; 2365c948e31SRichard Henderson desc->large_page_addr = -1; 2375c948e31SRichard Henderson desc->large_page_mask = -1; 2385c948e31SRichard Henderson desc->vindex = 0; 2395c948e31SRichard Henderson memset(fast->table, -1, sizeof_tlb(fast)); 2405c948e31SRichard Henderson memset(desc->vtable, -1, sizeof(desc->vtable)); 24186e1eff8SEmilio G. Cota } 24286e1eff8SEmilio G. Cota 2433c3959f2SRichard Henderson static void tlb_flush_one_mmuidx_locked(CPUArchState *env, int mmu_idx, 2443c3959f2SRichard Henderson int64_t now) 245bbf021b0SRichard Henderson { 246bbf021b0SRichard Henderson CPUTLBDesc *desc = &env_tlb(env)->d[mmu_idx]; 247bbf021b0SRichard Henderson CPUTLBDescFast *fast = &env_tlb(env)->f[mmu_idx]; 248bbf021b0SRichard Henderson 2493c3959f2SRichard Henderson tlb_mmu_resize_locked(desc, fast, now); 250bbf021b0SRichard Henderson tlb_mmu_flush_locked(desc, fast); 251bbf021b0SRichard Henderson } 252bbf021b0SRichard Henderson 25356e89f76SRichard Henderson static void tlb_mmu_init(CPUTLBDesc *desc, CPUTLBDescFast *fast, int64_t now) 25456e89f76SRichard Henderson { 25556e89f76SRichard Henderson size_t n_entries = 1 << CPU_TLB_DYN_DEFAULT_BITS; 25656e89f76SRichard Henderson 25756e89f76SRichard Henderson tlb_window_reset(desc, now, 0); 25856e89f76SRichard Henderson desc->n_used_entries = 0; 25956e89f76SRichard Henderson fast->mask = (n_entries - 1) << CPU_TLB_ENTRY_BITS; 26056e89f76SRichard Henderson fast->table = g_new(CPUTLBEntry, n_entries); 26156e89f76SRichard Henderson desc->iotlb = g_new(CPUIOTLBEntry, n_entries); 2623c16304aSRichard Henderson tlb_mmu_flush_locked(desc, fast); 26356e89f76SRichard Henderson } 26456e89f76SRichard Henderson 26586e1eff8SEmilio G. Cota static inline void tlb_n_used_entries_inc(CPUArchState *env, uintptr_t mmu_idx) 26686e1eff8SEmilio G. Cota { 267a40ec84eSRichard Henderson env_tlb(env)->d[mmu_idx].n_used_entries++; 26886e1eff8SEmilio G. Cota } 26986e1eff8SEmilio G. Cota 27086e1eff8SEmilio G. Cota static inline void tlb_n_used_entries_dec(CPUArchState *env, uintptr_t mmu_idx) 27186e1eff8SEmilio G. Cota { 272a40ec84eSRichard Henderson env_tlb(env)->d[mmu_idx].n_used_entries--; 27386e1eff8SEmilio G. Cota } 27486e1eff8SEmilio G. Cota 2755005e253SEmilio G. Cota void tlb_init(CPUState *cpu) 2765005e253SEmilio G. Cota { 27771aec354SEmilio G. Cota CPUArchState *env = cpu->env_ptr; 27856e89f76SRichard Henderson int64_t now = get_clock_realtime(); 27956e89f76SRichard Henderson int i; 28071aec354SEmilio G. Cota 281a40ec84eSRichard Henderson qemu_spin_init(&env_tlb(env)->c.lock); 2823d1523ceSRichard Henderson 2833c16304aSRichard Henderson /* All tlbs are initialized flushed. */ 2843c16304aSRichard Henderson env_tlb(env)->c.dirty = 0; 28586e1eff8SEmilio G. Cota 28656e89f76SRichard Henderson for (i = 0; i < NB_MMU_MODES; i++) { 28756e89f76SRichard Henderson tlb_mmu_init(&env_tlb(env)->d[i], &env_tlb(env)->f[i], now); 28856e89f76SRichard Henderson } 2895005e253SEmilio G. Cota } 2905005e253SEmilio G. Cota 291816d9be5SEmilio G. Cota void tlb_destroy(CPUState *cpu) 292816d9be5SEmilio G. Cota { 293816d9be5SEmilio G. Cota CPUArchState *env = cpu->env_ptr; 294816d9be5SEmilio G. Cota int i; 295816d9be5SEmilio G. Cota 296816d9be5SEmilio G. Cota qemu_spin_destroy(&env_tlb(env)->c.lock); 297816d9be5SEmilio G. Cota for (i = 0; i < NB_MMU_MODES; i++) { 298816d9be5SEmilio G. Cota CPUTLBDesc *desc = &env_tlb(env)->d[i]; 299816d9be5SEmilio G. Cota CPUTLBDescFast *fast = &env_tlb(env)->f[i]; 300816d9be5SEmilio G. Cota 301816d9be5SEmilio G. Cota g_free(fast->table); 302816d9be5SEmilio G. Cota g_free(desc->iotlb); 303816d9be5SEmilio G. Cota } 304816d9be5SEmilio G. Cota } 305816d9be5SEmilio G. Cota 306d9bb58e5SYang Zhong /* flush_all_helper: run fn across all cpus 307d9bb58e5SYang Zhong * 308d9bb58e5SYang Zhong * If the wait flag is set then the src cpu's helper will be queued as 309d9bb58e5SYang Zhong * "safe" work and the loop exited creating a synchronisation point 310d9bb58e5SYang Zhong * where all queued work will be finished before execution starts 311d9bb58e5SYang Zhong * again. 312d9bb58e5SYang Zhong */ 313d9bb58e5SYang Zhong static void flush_all_helper(CPUState *src, run_on_cpu_func fn, 314d9bb58e5SYang Zhong run_on_cpu_data d) 315d9bb58e5SYang Zhong { 316d9bb58e5SYang Zhong CPUState *cpu; 317d9bb58e5SYang Zhong 318d9bb58e5SYang Zhong CPU_FOREACH(cpu) { 319d9bb58e5SYang Zhong if (cpu != src) { 320d9bb58e5SYang Zhong async_run_on_cpu(cpu, fn, d); 321d9bb58e5SYang Zhong } 322d9bb58e5SYang Zhong } 323d9bb58e5SYang Zhong } 324d9bb58e5SYang Zhong 325e09de0a2SRichard Henderson void tlb_flush_counts(size_t *pfull, size_t *ppart, size_t *pelide) 32683974cf4SEmilio G. Cota { 32783974cf4SEmilio G. Cota CPUState *cpu; 328e09de0a2SRichard Henderson size_t full = 0, part = 0, elide = 0; 32983974cf4SEmilio G. Cota 33083974cf4SEmilio G. Cota CPU_FOREACH(cpu) { 33183974cf4SEmilio G. Cota CPUArchState *env = cpu->env_ptr; 33283974cf4SEmilio G. Cota 333d73415a3SStefan Hajnoczi full += qatomic_read(&env_tlb(env)->c.full_flush_count); 334d73415a3SStefan Hajnoczi part += qatomic_read(&env_tlb(env)->c.part_flush_count); 335d73415a3SStefan Hajnoczi elide += qatomic_read(&env_tlb(env)->c.elide_flush_count); 33683974cf4SEmilio G. Cota } 337e09de0a2SRichard Henderson *pfull = full; 338e09de0a2SRichard Henderson *ppart = part; 339e09de0a2SRichard Henderson *pelide = elide; 34083974cf4SEmilio G. Cota } 341d9bb58e5SYang Zhong 342d9bb58e5SYang Zhong static void tlb_flush_by_mmuidx_async_work(CPUState *cpu, run_on_cpu_data data) 343d9bb58e5SYang Zhong { 344d9bb58e5SYang Zhong CPUArchState *env = cpu->env_ptr; 3453d1523ceSRichard Henderson uint16_t asked = data.host_int; 3463d1523ceSRichard Henderson uint16_t all_dirty, work, to_clean; 3473c3959f2SRichard Henderson int64_t now = get_clock_realtime(); 348d9bb58e5SYang Zhong 349d9bb58e5SYang Zhong assert_cpu_is_self(cpu); 350d9bb58e5SYang Zhong 3513d1523ceSRichard Henderson tlb_debug("mmu_idx:0x%04" PRIx16 "\n", asked); 352d9bb58e5SYang Zhong 353a40ec84eSRichard Henderson qemu_spin_lock(&env_tlb(env)->c.lock); 35460a2ad7dSRichard Henderson 355a40ec84eSRichard Henderson all_dirty = env_tlb(env)->c.dirty; 3563d1523ceSRichard Henderson to_clean = asked & all_dirty; 3573d1523ceSRichard Henderson all_dirty &= ~to_clean; 358a40ec84eSRichard Henderson env_tlb(env)->c.dirty = all_dirty; 3593d1523ceSRichard Henderson 3603d1523ceSRichard Henderson for (work = to_clean; work != 0; work &= work - 1) { 3613d1523ceSRichard Henderson int mmu_idx = ctz32(work); 3623c3959f2SRichard Henderson tlb_flush_one_mmuidx_locked(env, mmu_idx, now); 363d9bb58e5SYang Zhong } 3643d1523ceSRichard Henderson 365a40ec84eSRichard Henderson qemu_spin_unlock(&env_tlb(env)->c.lock); 366d9bb58e5SYang Zhong 367f3ced3c5SEmilio G. Cota cpu_tb_jmp_cache_clear(cpu); 36864f2674bSRichard Henderson 3693d1523ceSRichard Henderson if (to_clean == ALL_MMUIDX_BITS) { 370d73415a3SStefan Hajnoczi qatomic_set(&env_tlb(env)->c.full_flush_count, 371a40ec84eSRichard Henderson env_tlb(env)->c.full_flush_count + 1); 372e09de0a2SRichard Henderson } else { 373d73415a3SStefan Hajnoczi qatomic_set(&env_tlb(env)->c.part_flush_count, 374a40ec84eSRichard Henderson env_tlb(env)->c.part_flush_count + ctpop16(to_clean)); 3753d1523ceSRichard Henderson if (to_clean != asked) { 376d73415a3SStefan Hajnoczi qatomic_set(&env_tlb(env)->c.elide_flush_count, 377a40ec84eSRichard Henderson env_tlb(env)->c.elide_flush_count + 3783d1523ceSRichard Henderson ctpop16(asked & ~to_clean)); 3793d1523ceSRichard Henderson } 38064f2674bSRichard Henderson } 381d9bb58e5SYang Zhong } 382d9bb58e5SYang Zhong 383d9bb58e5SYang Zhong void tlb_flush_by_mmuidx(CPUState *cpu, uint16_t idxmap) 384d9bb58e5SYang Zhong { 385d9bb58e5SYang Zhong tlb_debug("mmu_idx: 0x%" PRIx16 "\n", idxmap); 386d9bb58e5SYang Zhong 38764f2674bSRichard Henderson if (cpu->created && !qemu_cpu_is_self(cpu)) { 388d9bb58e5SYang Zhong async_run_on_cpu(cpu, tlb_flush_by_mmuidx_async_work, 389ab651105SRichard Henderson RUN_ON_CPU_HOST_INT(idxmap)); 390d9bb58e5SYang Zhong } else { 39160a2ad7dSRichard Henderson tlb_flush_by_mmuidx_async_work(cpu, RUN_ON_CPU_HOST_INT(idxmap)); 392d9bb58e5SYang Zhong } 393d9bb58e5SYang Zhong } 394d9bb58e5SYang Zhong 39564f2674bSRichard Henderson void tlb_flush(CPUState *cpu) 39664f2674bSRichard Henderson { 39764f2674bSRichard Henderson tlb_flush_by_mmuidx(cpu, ALL_MMUIDX_BITS); 39864f2674bSRichard Henderson } 39964f2674bSRichard Henderson 400d9bb58e5SYang Zhong void tlb_flush_by_mmuidx_all_cpus(CPUState *src_cpu, uint16_t idxmap) 401d9bb58e5SYang Zhong { 402d9bb58e5SYang Zhong const run_on_cpu_func fn = tlb_flush_by_mmuidx_async_work; 403d9bb58e5SYang Zhong 404d9bb58e5SYang Zhong tlb_debug("mmu_idx: 0x%"PRIx16"\n", idxmap); 405d9bb58e5SYang Zhong 406d9bb58e5SYang Zhong flush_all_helper(src_cpu, fn, RUN_ON_CPU_HOST_INT(idxmap)); 407d9bb58e5SYang Zhong fn(src_cpu, RUN_ON_CPU_HOST_INT(idxmap)); 408d9bb58e5SYang Zhong } 409d9bb58e5SYang Zhong 41064f2674bSRichard Henderson void tlb_flush_all_cpus(CPUState *src_cpu) 41164f2674bSRichard Henderson { 41264f2674bSRichard Henderson tlb_flush_by_mmuidx_all_cpus(src_cpu, ALL_MMUIDX_BITS); 41364f2674bSRichard Henderson } 41464f2674bSRichard Henderson 41564f2674bSRichard Henderson void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *src_cpu, uint16_t idxmap) 416d9bb58e5SYang Zhong { 417d9bb58e5SYang Zhong const run_on_cpu_func fn = tlb_flush_by_mmuidx_async_work; 418d9bb58e5SYang Zhong 419d9bb58e5SYang Zhong tlb_debug("mmu_idx: 0x%"PRIx16"\n", idxmap); 420d9bb58e5SYang Zhong 421d9bb58e5SYang Zhong flush_all_helper(src_cpu, fn, RUN_ON_CPU_HOST_INT(idxmap)); 422d9bb58e5SYang Zhong async_safe_run_on_cpu(src_cpu, fn, RUN_ON_CPU_HOST_INT(idxmap)); 423d9bb58e5SYang Zhong } 424d9bb58e5SYang Zhong 42564f2674bSRichard Henderson void tlb_flush_all_cpus_synced(CPUState *src_cpu) 42664f2674bSRichard Henderson { 42764f2674bSRichard Henderson tlb_flush_by_mmuidx_all_cpus_synced(src_cpu, ALL_MMUIDX_BITS); 42864f2674bSRichard Henderson } 42964f2674bSRichard Henderson 4303ab6e68cSRichard Henderson static bool tlb_hit_page_mask_anyprot(CPUTLBEntry *tlb_entry, 4313ab6e68cSRichard Henderson target_ulong page, target_ulong mask) 4323ab6e68cSRichard Henderson { 4333ab6e68cSRichard Henderson page &= mask; 4343ab6e68cSRichard Henderson mask &= TARGET_PAGE_MASK | TLB_INVALID_MASK; 4353ab6e68cSRichard Henderson 4363ab6e68cSRichard Henderson return (page == (tlb_entry->addr_read & mask) || 4373ab6e68cSRichard Henderson page == (tlb_addr_write(tlb_entry) & mask) || 4383ab6e68cSRichard Henderson page == (tlb_entry->addr_code & mask)); 4393ab6e68cSRichard Henderson } 4403ab6e68cSRichard Henderson 44168fea038SRichard Henderson static inline bool tlb_hit_page_anyprot(CPUTLBEntry *tlb_entry, 44268fea038SRichard Henderson target_ulong page) 443d9bb58e5SYang Zhong { 4443ab6e68cSRichard Henderson return tlb_hit_page_mask_anyprot(tlb_entry, page, -1); 44568fea038SRichard Henderson } 44668fea038SRichard Henderson 4473cea94bbSEmilio G. Cota /** 4483cea94bbSEmilio G. Cota * tlb_entry_is_empty - return true if the entry is not in use 4493cea94bbSEmilio G. Cota * @te: pointer to CPUTLBEntry 4503cea94bbSEmilio G. Cota */ 4513cea94bbSEmilio G. Cota static inline bool tlb_entry_is_empty(const CPUTLBEntry *te) 4523cea94bbSEmilio G. Cota { 4533cea94bbSEmilio G. Cota return te->addr_read == -1 && te->addr_write == -1 && te->addr_code == -1; 4543cea94bbSEmilio G. Cota } 4553cea94bbSEmilio G. Cota 45653d28455SRichard Henderson /* Called with tlb_c.lock held */ 4573ab6e68cSRichard Henderson static bool tlb_flush_entry_mask_locked(CPUTLBEntry *tlb_entry, 4583ab6e68cSRichard Henderson target_ulong page, 4593ab6e68cSRichard Henderson target_ulong mask) 46068fea038SRichard Henderson { 4613ab6e68cSRichard Henderson if (tlb_hit_page_mask_anyprot(tlb_entry, page, mask)) { 462d9bb58e5SYang Zhong memset(tlb_entry, -1, sizeof(*tlb_entry)); 46386e1eff8SEmilio G. Cota return true; 464d9bb58e5SYang Zhong } 46586e1eff8SEmilio G. Cota return false; 466d9bb58e5SYang Zhong } 467d9bb58e5SYang Zhong 4683ab6e68cSRichard Henderson static inline bool tlb_flush_entry_locked(CPUTLBEntry *tlb_entry, 46968fea038SRichard Henderson target_ulong page) 47068fea038SRichard Henderson { 4713ab6e68cSRichard Henderson return tlb_flush_entry_mask_locked(tlb_entry, page, -1); 4723ab6e68cSRichard Henderson } 4733ab6e68cSRichard Henderson 4743ab6e68cSRichard Henderson /* Called with tlb_c.lock held */ 4753ab6e68cSRichard Henderson static void tlb_flush_vtlb_page_mask_locked(CPUArchState *env, int mmu_idx, 4763ab6e68cSRichard Henderson target_ulong page, 4773ab6e68cSRichard Henderson target_ulong mask) 4783ab6e68cSRichard Henderson { 479a40ec84eSRichard Henderson CPUTLBDesc *d = &env_tlb(env)->d[mmu_idx]; 48068fea038SRichard Henderson int k; 48171aec354SEmilio G. Cota 48229a0af61SRichard Henderson assert_cpu_is_self(env_cpu(env)); 48368fea038SRichard Henderson for (k = 0; k < CPU_VTLB_SIZE; k++) { 4843ab6e68cSRichard Henderson if (tlb_flush_entry_mask_locked(&d->vtable[k], page, mask)) { 48586e1eff8SEmilio G. Cota tlb_n_used_entries_dec(env, mmu_idx); 48686e1eff8SEmilio G. Cota } 48768fea038SRichard Henderson } 48868fea038SRichard Henderson } 48968fea038SRichard Henderson 4903ab6e68cSRichard Henderson static inline void tlb_flush_vtlb_page_locked(CPUArchState *env, int mmu_idx, 4913ab6e68cSRichard Henderson target_ulong page) 4923ab6e68cSRichard Henderson { 4933ab6e68cSRichard Henderson tlb_flush_vtlb_page_mask_locked(env, mmu_idx, page, -1); 4943ab6e68cSRichard Henderson } 4953ab6e68cSRichard Henderson 4961308e026SRichard Henderson static void tlb_flush_page_locked(CPUArchState *env, int midx, 4971308e026SRichard Henderson target_ulong page) 4981308e026SRichard Henderson { 499a40ec84eSRichard Henderson target_ulong lp_addr = env_tlb(env)->d[midx].large_page_addr; 500a40ec84eSRichard Henderson target_ulong lp_mask = env_tlb(env)->d[midx].large_page_mask; 5011308e026SRichard Henderson 5021308e026SRichard Henderson /* Check if we need to flush due to large pages. */ 5031308e026SRichard Henderson if ((page & lp_mask) == lp_addr) { 5041308e026SRichard Henderson tlb_debug("forcing full flush midx %d (" 5051308e026SRichard Henderson TARGET_FMT_lx "/" TARGET_FMT_lx ")\n", 5061308e026SRichard Henderson midx, lp_addr, lp_mask); 5073c3959f2SRichard Henderson tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime()); 5081308e026SRichard Henderson } else { 50986e1eff8SEmilio G. Cota if (tlb_flush_entry_locked(tlb_entry(env, midx, page), page)) { 51086e1eff8SEmilio G. Cota tlb_n_used_entries_dec(env, midx); 51186e1eff8SEmilio G. Cota } 5121308e026SRichard Henderson tlb_flush_vtlb_page_locked(env, midx, page); 5131308e026SRichard Henderson } 5141308e026SRichard Henderson } 5151308e026SRichard Henderson 5167b7d00e0SRichard Henderson /** 5177b7d00e0SRichard Henderson * tlb_flush_page_by_mmuidx_async_0: 5187b7d00e0SRichard Henderson * @cpu: cpu on which to flush 5197b7d00e0SRichard Henderson * @addr: page of virtual address to flush 5207b7d00e0SRichard Henderson * @idxmap: set of mmu_idx to flush 5217b7d00e0SRichard Henderson * 5227b7d00e0SRichard Henderson * Helper for tlb_flush_page_by_mmuidx and friends, flush one page 5237b7d00e0SRichard Henderson * at @addr from the tlbs indicated by @idxmap from @cpu. 524d9bb58e5SYang Zhong */ 5257b7d00e0SRichard Henderson static void tlb_flush_page_by_mmuidx_async_0(CPUState *cpu, 5267b7d00e0SRichard Henderson target_ulong addr, 5277b7d00e0SRichard Henderson uint16_t idxmap) 528d9bb58e5SYang Zhong { 529d9bb58e5SYang Zhong CPUArchState *env = cpu->env_ptr; 530d9bb58e5SYang Zhong int mmu_idx; 531d9bb58e5SYang Zhong 532d9bb58e5SYang Zhong assert_cpu_is_self(cpu); 533d9bb58e5SYang Zhong 5347b7d00e0SRichard Henderson tlb_debug("page addr:" TARGET_FMT_lx " mmu_map:0x%x\n", addr, idxmap); 535d9bb58e5SYang Zhong 536a40ec84eSRichard Henderson qemu_spin_lock(&env_tlb(env)->c.lock); 537d9bb58e5SYang Zhong for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 5387b7d00e0SRichard Henderson if ((idxmap >> mmu_idx) & 1) { 5391308e026SRichard Henderson tlb_flush_page_locked(env, mmu_idx, addr); 540d9bb58e5SYang Zhong } 541d9bb58e5SYang Zhong } 542a40ec84eSRichard Henderson qemu_spin_unlock(&env_tlb(env)->c.lock); 543d9bb58e5SYang Zhong 544d9bb58e5SYang Zhong tb_flush_jmp_cache(cpu, addr); 545d9bb58e5SYang Zhong } 546d9bb58e5SYang Zhong 5477b7d00e0SRichard Henderson /** 5487b7d00e0SRichard Henderson * tlb_flush_page_by_mmuidx_async_1: 5497b7d00e0SRichard Henderson * @cpu: cpu on which to flush 5507b7d00e0SRichard Henderson * @data: encoded addr + idxmap 5517b7d00e0SRichard Henderson * 5527b7d00e0SRichard Henderson * Helper for tlb_flush_page_by_mmuidx and friends, called through 5537b7d00e0SRichard Henderson * async_run_on_cpu. The idxmap parameter is encoded in the page 5547b7d00e0SRichard Henderson * offset of the target_ptr field. This limits the set of mmu_idx 5557b7d00e0SRichard Henderson * that can be passed via this method. 5567b7d00e0SRichard Henderson */ 5577b7d00e0SRichard Henderson static void tlb_flush_page_by_mmuidx_async_1(CPUState *cpu, 5587b7d00e0SRichard Henderson run_on_cpu_data data) 5597b7d00e0SRichard Henderson { 5607b7d00e0SRichard Henderson target_ulong addr_and_idxmap = (target_ulong) data.target_ptr; 5617b7d00e0SRichard Henderson target_ulong addr = addr_and_idxmap & TARGET_PAGE_MASK; 5627b7d00e0SRichard Henderson uint16_t idxmap = addr_and_idxmap & ~TARGET_PAGE_MASK; 5637b7d00e0SRichard Henderson 5647b7d00e0SRichard Henderson tlb_flush_page_by_mmuidx_async_0(cpu, addr, idxmap); 5657b7d00e0SRichard Henderson } 5667b7d00e0SRichard Henderson 5677b7d00e0SRichard Henderson typedef struct { 5687b7d00e0SRichard Henderson target_ulong addr; 5697b7d00e0SRichard Henderson uint16_t idxmap; 5707b7d00e0SRichard Henderson } TLBFlushPageByMMUIdxData; 5717b7d00e0SRichard Henderson 5727b7d00e0SRichard Henderson /** 5737b7d00e0SRichard Henderson * tlb_flush_page_by_mmuidx_async_2: 5747b7d00e0SRichard Henderson * @cpu: cpu on which to flush 5757b7d00e0SRichard Henderson * @data: allocated addr + idxmap 5767b7d00e0SRichard Henderson * 5777b7d00e0SRichard Henderson * Helper for tlb_flush_page_by_mmuidx and friends, called through 5787b7d00e0SRichard Henderson * async_run_on_cpu. The addr+idxmap parameters are stored in a 5797b7d00e0SRichard Henderson * TLBFlushPageByMMUIdxData structure that has been allocated 5807b7d00e0SRichard Henderson * specifically for this helper. Free the structure when done. 5817b7d00e0SRichard Henderson */ 5827b7d00e0SRichard Henderson static void tlb_flush_page_by_mmuidx_async_2(CPUState *cpu, 5837b7d00e0SRichard Henderson run_on_cpu_data data) 5847b7d00e0SRichard Henderson { 5857b7d00e0SRichard Henderson TLBFlushPageByMMUIdxData *d = data.host_ptr; 5867b7d00e0SRichard Henderson 5877b7d00e0SRichard Henderson tlb_flush_page_by_mmuidx_async_0(cpu, d->addr, d->idxmap); 5887b7d00e0SRichard Henderson g_free(d); 5897b7d00e0SRichard Henderson } 5907b7d00e0SRichard Henderson 591d9bb58e5SYang Zhong void tlb_flush_page_by_mmuidx(CPUState *cpu, target_ulong addr, uint16_t idxmap) 592d9bb58e5SYang Zhong { 593d9bb58e5SYang Zhong tlb_debug("addr: "TARGET_FMT_lx" mmu_idx:%" PRIx16 "\n", addr, idxmap); 594d9bb58e5SYang Zhong 595d9bb58e5SYang Zhong /* This should already be page aligned */ 5967b7d00e0SRichard Henderson addr &= TARGET_PAGE_MASK; 597d9bb58e5SYang Zhong 5987b7d00e0SRichard Henderson if (qemu_cpu_is_self(cpu)) { 5997b7d00e0SRichard Henderson tlb_flush_page_by_mmuidx_async_0(cpu, addr, idxmap); 6007b7d00e0SRichard Henderson } else if (idxmap < TARGET_PAGE_SIZE) { 6017b7d00e0SRichard Henderson /* 6027b7d00e0SRichard Henderson * Most targets have only a few mmu_idx. In the case where 6037b7d00e0SRichard Henderson * we can stuff idxmap into the low TARGET_PAGE_BITS, avoid 6047b7d00e0SRichard Henderson * allocating memory for this operation. 6057b7d00e0SRichard Henderson */ 6067b7d00e0SRichard Henderson async_run_on_cpu(cpu, tlb_flush_page_by_mmuidx_async_1, 6077b7d00e0SRichard Henderson RUN_ON_CPU_TARGET_PTR(addr | idxmap)); 608d9bb58e5SYang Zhong } else { 6097b7d00e0SRichard Henderson TLBFlushPageByMMUIdxData *d = g_new(TLBFlushPageByMMUIdxData, 1); 6107b7d00e0SRichard Henderson 6117b7d00e0SRichard Henderson /* Otherwise allocate a structure, freed by the worker. */ 6127b7d00e0SRichard Henderson d->addr = addr; 6137b7d00e0SRichard Henderson d->idxmap = idxmap; 6147b7d00e0SRichard Henderson async_run_on_cpu(cpu, tlb_flush_page_by_mmuidx_async_2, 6157b7d00e0SRichard Henderson RUN_ON_CPU_HOST_PTR(d)); 616d9bb58e5SYang Zhong } 617d9bb58e5SYang Zhong } 618d9bb58e5SYang Zhong 619f8144c6cSRichard Henderson void tlb_flush_page(CPUState *cpu, target_ulong addr) 620f8144c6cSRichard Henderson { 621f8144c6cSRichard Henderson tlb_flush_page_by_mmuidx(cpu, addr, ALL_MMUIDX_BITS); 622f8144c6cSRichard Henderson } 623f8144c6cSRichard Henderson 624d9bb58e5SYang Zhong void tlb_flush_page_by_mmuidx_all_cpus(CPUState *src_cpu, target_ulong addr, 625d9bb58e5SYang Zhong uint16_t idxmap) 626d9bb58e5SYang Zhong { 627d9bb58e5SYang Zhong tlb_debug("addr: "TARGET_FMT_lx" mmu_idx:%"PRIx16"\n", addr, idxmap); 628d9bb58e5SYang Zhong 629d9bb58e5SYang Zhong /* This should already be page aligned */ 6307b7d00e0SRichard Henderson addr &= TARGET_PAGE_MASK; 631d9bb58e5SYang Zhong 6327b7d00e0SRichard Henderson /* 6337b7d00e0SRichard Henderson * Allocate memory to hold addr+idxmap only when needed. 6347b7d00e0SRichard Henderson * See tlb_flush_page_by_mmuidx for details. 6357b7d00e0SRichard Henderson */ 6367b7d00e0SRichard Henderson if (idxmap < TARGET_PAGE_SIZE) { 6377b7d00e0SRichard Henderson flush_all_helper(src_cpu, tlb_flush_page_by_mmuidx_async_1, 6387b7d00e0SRichard Henderson RUN_ON_CPU_TARGET_PTR(addr | idxmap)); 6397b7d00e0SRichard Henderson } else { 6407b7d00e0SRichard Henderson CPUState *dst_cpu; 6417b7d00e0SRichard Henderson 6427b7d00e0SRichard Henderson /* Allocate a separate data block for each destination cpu. */ 6437b7d00e0SRichard Henderson CPU_FOREACH(dst_cpu) { 6447b7d00e0SRichard Henderson if (dst_cpu != src_cpu) { 6457b7d00e0SRichard Henderson TLBFlushPageByMMUIdxData *d 6467b7d00e0SRichard Henderson = g_new(TLBFlushPageByMMUIdxData, 1); 6477b7d00e0SRichard Henderson 6487b7d00e0SRichard Henderson d->addr = addr; 6497b7d00e0SRichard Henderson d->idxmap = idxmap; 6507b7d00e0SRichard Henderson async_run_on_cpu(dst_cpu, tlb_flush_page_by_mmuidx_async_2, 6517b7d00e0SRichard Henderson RUN_ON_CPU_HOST_PTR(d)); 6527b7d00e0SRichard Henderson } 6537b7d00e0SRichard Henderson } 6547b7d00e0SRichard Henderson } 6557b7d00e0SRichard Henderson 6567b7d00e0SRichard Henderson tlb_flush_page_by_mmuidx_async_0(src_cpu, addr, idxmap); 657d9bb58e5SYang Zhong } 658d9bb58e5SYang Zhong 659f8144c6cSRichard Henderson void tlb_flush_page_all_cpus(CPUState *src, target_ulong addr) 660f8144c6cSRichard Henderson { 661f8144c6cSRichard Henderson tlb_flush_page_by_mmuidx_all_cpus(src, addr, ALL_MMUIDX_BITS); 662f8144c6cSRichard Henderson } 663f8144c6cSRichard Henderson 664d9bb58e5SYang Zhong void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *src_cpu, 665d9bb58e5SYang Zhong target_ulong addr, 666d9bb58e5SYang Zhong uint16_t idxmap) 667d9bb58e5SYang Zhong { 668d9bb58e5SYang Zhong tlb_debug("addr: "TARGET_FMT_lx" mmu_idx:%"PRIx16"\n", addr, idxmap); 669d9bb58e5SYang Zhong 670d9bb58e5SYang Zhong /* This should already be page aligned */ 6717b7d00e0SRichard Henderson addr &= TARGET_PAGE_MASK; 672d9bb58e5SYang Zhong 6737b7d00e0SRichard Henderson /* 6747b7d00e0SRichard Henderson * Allocate memory to hold addr+idxmap only when needed. 6757b7d00e0SRichard Henderson * See tlb_flush_page_by_mmuidx for details. 6767b7d00e0SRichard Henderson */ 6777b7d00e0SRichard Henderson if (idxmap < TARGET_PAGE_SIZE) { 6787b7d00e0SRichard Henderson flush_all_helper(src_cpu, tlb_flush_page_by_mmuidx_async_1, 6797b7d00e0SRichard Henderson RUN_ON_CPU_TARGET_PTR(addr | idxmap)); 6807b7d00e0SRichard Henderson async_safe_run_on_cpu(src_cpu, tlb_flush_page_by_mmuidx_async_1, 6817b7d00e0SRichard Henderson RUN_ON_CPU_TARGET_PTR(addr | idxmap)); 6827b7d00e0SRichard Henderson } else { 6837b7d00e0SRichard Henderson CPUState *dst_cpu; 6847b7d00e0SRichard Henderson TLBFlushPageByMMUIdxData *d; 6857b7d00e0SRichard Henderson 6867b7d00e0SRichard Henderson /* Allocate a separate data block for each destination cpu. */ 6877b7d00e0SRichard Henderson CPU_FOREACH(dst_cpu) { 6887b7d00e0SRichard Henderson if (dst_cpu != src_cpu) { 6897b7d00e0SRichard Henderson d = g_new(TLBFlushPageByMMUIdxData, 1); 6907b7d00e0SRichard Henderson d->addr = addr; 6917b7d00e0SRichard Henderson d->idxmap = idxmap; 6927b7d00e0SRichard Henderson async_run_on_cpu(dst_cpu, tlb_flush_page_by_mmuidx_async_2, 6937b7d00e0SRichard Henderson RUN_ON_CPU_HOST_PTR(d)); 6947b7d00e0SRichard Henderson } 6957b7d00e0SRichard Henderson } 6967b7d00e0SRichard Henderson 6977b7d00e0SRichard Henderson d = g_new(TLBFlushPageByMMUIdxData, 1); 6987b7d00e0SRichard Henderson d->addr = addr; 6997b7d00e0SRichard Henderson d->idxmap = idxmap; 7007b7d00e0SRichard Henderson async_safe_run_on_cpu(src_cpu, tlb_flush_page_by_mmuidx_async_2, 7017b7d00e0SRichard Henderson RUN_ON_CPU_HOST_PTR(d)); 7027b7d00e0SRichard Henderson } 703d9bb58e5SYang Zhong } 704d9bb58e5SYang Zhong 705f8144c6cSRichard Henderson void tlb_flush_page_all_cpus_synced(CPUState *src, target_ulong addr) 706d9bb58e5SYang Zhong { 707f8144c6cSRichard Henderson tlb_flush_page_by_mmuidx_all_cpus_synced(src, addr, ALL_MMUIDX_BITS); 708d9bb58e5SYang Zhong } 709d9bb58e5SYang Zhong 7103c4ddec1SRichard Henderson static void tlb_flush_range_locked(CPUArchState *env, int midx, 7113c4ddec1SRichard Henderson target_ulong addr, target_ulong len, 7123c4ddec1SRichard Henderson unsigned bits) 7133ab6e68cSRichard Henderson { 7143ab6e68cSRichard Henderson CPUTLBDesc *d = &env_tlb(env)->d[midx]; 7153ab6e68cSRichard Henderson CPUTLBDescFast *f = &env_tlb(env)->f[midx]; 7163ab6e68cSRichard Henderson target_ulong mask = MAKE_64BIT_MASK(0, bits); 7173ab6e68cSRichard Henderson 7183ab6e68cSRichard Henderson /* 7193ab6e68cSRichard Henderson * If @bits is smaller than the tlb size, there may be multiple entries 7203ab6e68cSRichard Henderson * within the TLB; otherwise all addresses that match under @mask hit 7213ab6e68cSRichard Henderson * the same TLB entry. 7223ab6e68cSRichard Henderson * TODO: Perhaps allow bits to be a few bits less than the size. 7233ab6e68cSRichard Henderson * For now, just flush the entire TLB. 7243c4ddec1SRichard Henderson * 7253c4ddec1SRichard Henderson * If @len is larger than the tlb size, then it will take longer to 7263c4ddec1SRichard Henderson * test all of the entries in the TLB than it will to flush it all. 7273ab6e68cSRichard Henderson */ 7283c4ddec1SRichard Henderson if (mask < f->mask || len > f->mask) { 7293ab6e68cSRichard Henderson tlb_debug("forcing full flush midx %d (" 7303c4ddec1SRichard Henderson TARGET_FMT_lx "/" TARGET_FMT_lx "+" TARGET_FMT_lx ")\n", 7313c4ddec1SRichard Henderson midx, addr, mask, len); 7323ab6e68cSRichard Henderson tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime()); 7333ab6e68cSRichard Henderson return; 7343ab6e68cSRichard Henderson } 7353ab6e68cSRichard Henderson 7363c4ddec1SRichard Henderson /* 7373c4ddec1SRichard Henderson * Check if we need to flush due to large pages. 7383c4ddec1SRichard Henderson * Because large_page_mask contains all 1's from the msb, 7393c4ddec1SRichard Henderson * we only need to test the end of the range. 7403c4ddec1SRichard Henderson */ 7413c4ddec1SRichard Henderson if (((addr + len - 1) & d->large_page_mask) == d->large_page_addr) { 7423ab6e68cSRichard Henderson tlb_debug("forcing full flush midx %d (" 7433ab6e68cSRichard Henderson TARGET_FMT_lx "/" TARGET_FMT_lx ")\n", 7443ab6e68cSRichard Henderson midx, d->large_page_addr, d->large_page_mask); 7453ab6e68cSRichard Henderson tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime()); 7463ab6e68cSRichard Henderson return; 7473ab6e68cSRichard Henderson } 7483ab6e68cSRichard Henderson 7493c4ddec1SRichard Henderson for (target_ulong i = 0; i < len; i += TARGET_PAGE_SIZE) { 7503c4ddec1SRichard Henderson target_ulong page = addr + i; 7513c4ddec1SRichard Henderson CPUTLBEntry *entry = tlb_entry(env, midx, page); 7523c4ddec1SRichard Henderson 7533c4ddec1SRichard Henderson if (tlb_flush_entry_mask_locked(entry, page, mask)) { 7543ab6e68cSRichard Henderson tlb_n_used_entries_dec(env, midx); 7553ab6e68cSRichard Henderson } 7563ab6e68cSRichard Henderson tlb_flush_vtlb_page_mask_locked(env, midx, page, mask); 7573ab6e68cSRichard Henderson } 7583c4ddec1SRichard Henderson } 7593ab6e68cSRichard Henderson 7603ab6e68cSRichard Henderson typedef struct { 7613ab6e68cSRichard Henderson target_ulong addr; 7623c4ddec1SRichard Henderson target_ulong len; 7633ab6e68cSRichard Henderson uint16_t idxmap; 7643ab6e68cSRichard Henderson uint16_t bits; 7653960a59fSRichard Henderson } TLBFlushRangeData; 7663ab6e68cSRichard Henderson 7676be48e45SRichard Henderson static void tlb_flush_range_by_mmuidx_async_0(CPUState *cpu, 7683960a59fSRichard Henderson TLBFlushRangeData d) 7693ab6e68cSRichard Henderson { 7703ab6e68cSRichard Henderson CPUArchState *env = cpu->env_ptr; 7713ab6e68cSRichard Henderson int mmu_idx; 7723ab6e68cSRichard Henderson 7733ab6e68cSRichard Henderson assert_cpu_is_self(cpu); 7743ab6e68cSRichard Henderson 7753c4ddec1SRichard Henderson tlb_debug("range:" TARGET_FMT_lx "/%u+" TARGET_FMT_lx " mmu_map:0x%x\n", 7763c4ddec1SRichard Henderson d.addr, d.bits, d.len, d.idxmap); 7773ab6e68cSRichard Henderson 7783ab6e68cSRichard Henderson qemu_spin_lock(&env_tlb(env)->c.lock); 7793ab6e68cSRichard Henderson for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 7803ab6e68cSRichard Henderson if ((d.idxmap >> mmu_idx) & 1) { 7813c4ddec1SRichard Henderson tlb_flush_range_locked(env, mmu_idx, d.addr, d.len, d.bits); 7823ab6e68cSRichard Henderson } 7833ab6e68cSRichard Henderson } 7843ab6e68cSRichard Henderson qemu_spin_unlock(&env_tlb(env)->c.lock); 7853ab6e68cSRichard Henderson 7863c4ddec1SRichard Henderson for (target_ulong i = 0; i < d.len; i += TARGET_PAGE_SIZE) { 7873c4ddec1SRichard Henderson tb_flush_jmp_cache(cpu, d.addr + i); 7883c4ddec1SRichard Henderson } 7893ab6e68cSRichard Henderson } 7903ab6e68cSRichard Henderson 791206a583dSRichard Henderson static void tlb_flush_range_by_mmuidx_async_1(CPUState *cpu, 7923ab6e68cSRichard Henderson run_on_cpu_data data) 7933ab6e68cSRichard Henderson { 7943960a59fSRichard Henderson TLBFlushRangeData *d = data.host_ptr; 7956be48e45SRichard Henderson tlb_flush_range_by_mmuidx_async_0(cpu, *d); 7963ab6e68cSRichard Henderson g_free(d); 7973ab6e68cSRichard Henderson } 7983ab6e68cSRichard Henderson 799e5b1921bSRichard Henderson void tlb_flush_range_by_mmuidx(CPUState *cpu, target_ulong addr, 800e5b1921bSRichard Henderson target_ulong len, uint16_t idxmap, 801e5b1921bSRichard Henderson unsigned bits) 8023ab6e68cSRichard Henderson { 8033960a59fSRichard Henderson TLBFlushRangeData d; 8043ab6e68cSRichard Henderson 805e5b1921bSRichard Henderson /* 806e5b1921bSRichard Henderson * If all bits are significant, and len is small, 807e5b1921bSRichard Henderson * this devolves to tlb_flush_page. 808e5b1921bSRichard Henderson */ 809e5b1921bSRichard Henderson if (bits >= TARGET_LONG_BITS && len <= TARGET_PAGE_SIZE) { 8103ab6e68cSRichard Henderson tlb_flush_page_by_mmuidx(cpu, addr, idxmap); 8113ab6e68cSRichard Henderson return; 8123ab6e68cSRichard Henderson } 8133ab6e68cSRichard Henderson /* If no page bits are significant, this devolves to tlb_flush. */ 8143ab6e68cSRichard Henderson if (bits < TARGET_PAGE_BITS) { 8153ab6e68cSRichard Henderson tlb_flush_by_mmuidx(cpu, idxmap); 8163ab6e68cSRichard Henderson return; 8173ab6e68cSRichard Henderson } 8183ab6e68cSRichard Henderson 8193ab6e68cSRichard Henderson /* This should already be page aligned */ 8203ab6e68cSRichard Henderson d.addr = addr & TARGET_PAGE_MASK; 821e5b1921bSRichard Henderson d.len = len; 8223ab6e68cSRichard Henderson d.idxmap = idxmap; 8233ab6e68cSRichard Henderson d.bits = bits; 8243ab6e68cSRichard Henderson 8253ab6e68cSRichard Henderson if (qemu_cpu_is_self(cpu)) { 8266be48e45SRichard Henderson tlb_flush_range_by_mmuidx_async_0(cpu, d); 8273ab6e68cSRichard Henderson } else { 8283ab6e68cSRichard Henderson /* Otherwise allocate a structure, freed by the worker. */ 8293960a59fSRichard Henderson TLBFlushRangeData *p = g_memdup(&d, sizeof(d)); 830206a583dSRichard Henderson async_run_on_cpu(cpu, tlb_flush_range_by_mmuidx_async_1, 8313ab6e68cSRichard Henderson RUN_ON_CPU_HOST_PTR(p)); 8323ab6e68cSRichard Henderson } 8333ab6e68cSRichard Henderson } 8343ab6e68cSRichard Henderson 835e5b1921bSRichard Henderson void tlb_flush_page_bits_by_mmuidx(CPUState *cpu, target_ulong addr, 836e5b1921bSRichard Henderson uint16_t idxmap, unsigned bits) 837e5b1921bSRichard Henderson { 838e5b1921bSRichard Henderson tlb_flush_range_by_mmuidx(cpu, addr, TARGET_PAGE_SIZE, idxmap, bits); 839e5b1921bSRichard Henderson } 840e5b1921bSRichard Henderson 841600b819fSRichard Henderson void tlb_flush_range_by_mmuidx_all_cpus(CPUState *src_cpu, 842600b819fSRichard Henderson target_ulong addr, target_ulong len, 843600b819fSRichard Henderson uint16_t idxmap, unsigned bits) 8443ab6e68cSRichard Henderson { 8453960a59fSRichard Henderson TLBFlushRangeData d; 846d34e4d1aSRichard Henderson CPUState *dst_cpu; 8473ab6e68cSRichard Henderson 848600b819fSRichard Henderson /* 849600b819fSRichard Henderson * If all bits are significant, and len is small, 850600b819fSRichard Henderson * this devolves to tlb_flush_page. 851600b819fSRichard Henderson */ 852600b819fSRichard Henderson if (bits >= TARGET_LONG_BITS && len <= TARGET_PAGE_SIZE) { 8533ab6e68cSRichard Henderson tlb_flush_page_by_mmuidx_all_cpus(src_cpu, addr, idxmap); 8543ab6e68cSRichard Henderson return; 8553ab6e68cSRichard Henderson } 8563ab6e68cSRichard Henderson /* If no page bits are significant, this devolves to tlb_flush. */ 8573ab6e68cSRichard Henderson if (bits < TARGET_PAGE_BITS) { 8583ab6e68cSRichard Henderson tlb_flush_by_mmuidx_all_cpus(src_cpu, idxmap); 8593ab6e68cSRichard Henderson return; 8603ab6e68cSRichard Henderson } 8613ab6e68cSRichard Henderson 8623ab6e68cSRichard Henderson /* This should already be page aligned */ 8633ab6e68cSRichard Henderson d.addr = addr & TARGET_PAGE_MASK; 864600b819fSRichard Henderson d.len = len; 8653ab6e68cSRichard Henderson d.idxmap = idxmap; 8663ab6e68cSRichard Henderson d.bits = bits; 8673ab6e68cSRichard Henderson 8683ab6e68cSRichard Henderson /* Allocate a separate data block for each destination cpu. */ 8693ab6e68cSRichard Henderson CPU_FOREACH(dst_cpu) { 8703ab6e68cSRichard Henderson if (dst_cpu != src_cpu) { 8713960a59fSRichard Henderson TLBFlushRangeData *p = g_memdup(&d, sizeof(d)); 8723ab6e68cSRichard Henderson async_run_on_cpu(dst_cpu, 873206a583dSRichard Henderson tlb_flush_range_by_mmuidx_async_1, 8743ab6e68cSRichard Henderson RUN_ON_CPU_HOST_PTR(p)); 8753ab6e68cSRichard Henderson } 8763ab6e68cSRichard Henderson } 8773ab6e68cSRichard Henderson 8786be48e45SRichard Henderson tlb_flush_range_by_mmuidx_async_0(src_cpu, d); 8793ab6e68cSRichard Henderson } 8803ab6e68cSRichard Henderson 881600b819fSRichard Henderson void tlb_flush_page_bits_by_mmuidx_all_cpus(CPUState *src_cpu, 882600b819fSRichard Henderson target_ulong addr, 883600b819fSRichard Henderson uint16_t idxmap, unsigned bits) 884600b819fSRichard Henderson { 885600b819fSRichard Henderson tlb_flush_range_by_mmuidx_all_cpus(src_cpu, addr, TARGET_PAGE_SIZE, 886600b819fSRichard Henderson idxmap, bits); 887600b819fSRichard Henderson } 888600b819fSRichard Henderson 889c13b27d8SRichard Henderson void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *src_cpu, 8903ab6e68cSRichard Henderson target_ulong addr, 891c13b27d8SRichard Henderson target_ulong len, 8923ab6e68cSRichard Henderson uint16_t idxmap, 8933ab6e68cSRichard Henderson unsigned bits) 8943ab6e68cSRichard Henderson { 895d34e4d1aSRichard Henderson TLBFlushRangeData d, *p; 896d34e4d1aSRichard Henderson CPUState *dst_cpu; 8973ab6e68cSRichard Henderson 898c13b27d8SRichard Henderson /* 899c13b27d8SRichard Henderson * If all bits are significant, and len is small, 900c13b27d8SRichard Henderson * this devolves to tlb_flush_page. 901c13b27d8SRichard Henderson */ 902c13b27d8SRichard Henderson if (bits >= TARGET_LONG_BITS && len <= TARGET_PAGE_SIZE) { 9033ab6e68cSRichard Henderson tlb_flush_page_by_mmuidx_all_cpus_synced(src_cpu, addr, idxmap); 9043ab6e68cSRichard Henderson return; 9053ab6e68cSRichard Henderson } 9063ab6e68cSRichard Henderson /* If no page bits are significant, this devolves to tlb_flush. */ 9073ab6e68cSRichard Henderson if (bits < TARGET_PAGE_BITS) { 9083ab6e68cSRichard Henderson tlb_flush_by_mmuidx_all_cpus_synced(src_cpu, idxmap); 9093ab6e68cSRichard Henderson return; 9103ab6e68cSRichard Henderson } 9113ab6e68cSRichard Henderson 9123ab6e68cSRichard Henderson /* This should already be page aligned */ 9133ab6e68cSRichard Henderson d.addr = addr & TARGET_PAGE_MASK; 914c13b27d8SRichard Henderson d.len = len; 9153ab6e68cSRichard Henderson d.idxmap = idxmap; 9163ab6e68cSRichard Henderson d.bits = bits; 9173ab6e68cSRichard Henderson 9183ab6e68cSRichard Henderson /* Allocate a separate data block for each destination cpu. */ 9193ab6e68cSRichard Henderson CPU_FOREACH(dst_cpu) { 9203ab6e68cSRichard Henderson if (dst_cpu != src_cpu) { 9216d244788SRichard Henderson p = g_memdup(&d, sizeof(d)); 922206a583dSRichard Henderson async_run_on_cpu(dst_cpu, tlb_flush_range_by_mmuidx_async_1, 9233ab6e68cSRichard Henderson RUN_ON_CPU_HOST_PTR(p)); 9243ab6e68cSRichard Henderson } 9253ab6e68cSRichard Henderson } 9263ab6e68cSRichard Henderson 9276d244788SRichard Henderson p = g_memdup(&d, sizeof(d)); 928206a583dSRichard Henderson async_safe_run_on_cpu(src_cpu, tlb_flush_range_by_mmuidx_async_1, 9293ab6e68cSRichard Henderson RUN_ON_CPU_HOST_PTR(p)); 9303ab6e68cSRichard Henderson } 9313ab6e68cSRichard Henderson 932c13b27d8SRichard Henderson void tlb_flush_page_bits_by_mmuidx_all_cpus_synced(CPUState *src_cpu, 933c13b27d8SRichard Henderson target_ulong addr, 934c13b27d8SRichard Henderson uint16_t idxmap, 935c13b27d8SRichard Henderson unsigned bits) 936c13b27d8SRichard Henderson { 937c13b27d8SRichard Henderson tlb_flush_range_by_mmuidx_all_cpus_synced(src_cpu, addr, TARGET_PAGE_SIZE, 938c13b27d8SRichard Henderson idxmap, bits); 939c13b27d8SRichard Henderson } 940c13b27d8SRichard Henderson 941d9bb58e5SYang Zhong /* update the TLBs so that writes to code in the virtual page 'addr' 942d9bb58e5SYang Zhong can be detected */ 943d9bb58e5SYang Zhong void tlb_protect_code(ram_addr_t ram_addr) 944d9bb58e5SYang Zhong { 945d9bb58e5SYang Zhong cpu_physical_memory_test_and_clear_dirty(ram_addr, TARGET_PAGE_SIZE, 946d9bb58e5SYang Zhong DIRTY_MEMORY_CODE); 947d9bb58e5SYang Zhong } 948d9bb58e5SYang Zhong 949d9bb58e5SYang Zhong /* update the TLB so that writes in physical page 'phys_addr' are no longer 950d9bb58e5SYang Zhong tested for self modifying code */ 951d9bb58e5SYang Zhong void tlb_unprotect_code(ram_addr_t ram_addr) 952d9bb58e5SYang Zhong { 953d9bb58e5SYang Zhong cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_CODE); 954d9bb58e5SYang Zhong } 955d9bb58e5SYang Zhong 956d9bb58e5SYang Zhong 957d9bb58e5SYang Zhong /* 958d9bb58e5SYang Zhong * Dirty write flag handling 959d9bb58e5SYang Zhong * 960d9bb58e5SYang Zhong * When the TCG code writes to a location it looks up the address in 961d9bb58e5SYang Zhong * the TLB and uses that data to compute the final address. If any of 962d9bb58e5SYang Zhong * the lower bits of the address are set then the slow path is forced. 963d9bb58e5SYang Zhong * There are a number of reasons to do this but for normal RAM the 964d9bb58e5SYang Zhong * most usual is detecting writes to code regions which may invalidate 965d9bb58e5SYang Zhong * generated code. 966d9bb58e5SYang Zhong * 96771aec354SEmilio G. Cota * Other vCPUs might be reading their TLBs during guest execution, so we update 968d73415a3SStefan Hajnoczi * te->addr_write with qatomic_set. We don't need to worry about this for 96971aec354SEmilio G. Cota * oversized guests as MTTCG is disabled for them. 970d9bb58e5SYang Zhong * 97153d28455SRichard Henderson * Called with tlb_c.lock held. 972d9bb58e5SYang Zhong */ 97371aec354SEmilio G. Cota static void tlb_reset_dirty_range_locked(CPUTLBEntry *tlb_entry, 97471aec354SEmilio G. Cota uintptr_t start, uintptr_t length) 975d9bb58e5SYang Zhong { 976d9bb58e5SYang Zhong uintptr_t addr = tlb_entry->addr_write; 977d9bb58e5SYang Zhong 9787b0d792cSRichard Henderson if ((addr & (TLB_INVALID_MASK | TLB_MMIO | 9797b0d792cSRichard Henderson TLB_DISCARD_WRITE | TLB_NOTDIRTY)) == 0) { 980d9bb58e5SYang Zhong addr &= TARGET_PAGE_MASK; 981d9bb58e5SYang Zhong addr += tlb_entry->addend; 982d9bb58e5SYang Zhong if ((addr - start) < length) { 983d9bb58e5SYang Zhong #if TCG_OVERSIZED_GUEST 98471aec354SEmilio G. Cota tlb_entry->addr_write |= TLB_NOTDIRTY; 985d9bb58e5SYang Zhong #else 986d73415a3SStefan Hajnoczi qatomic_set(&tlb_entry->addr_write, 98771aec354SEmilio G. Cota tlb_entry->addr_write | TLB_NOTDIRTY); 988d9bb58e5SYang Zhong #endif 989d9bb58e5SYang Zhong } 99071aec354SEmilio G. Cota } 99171aec354SEmilio G. Cota } 99271aec354SEmilio G. Cota 99371aec354SEmilio G. Cota /* 99453d28455SRichard Henderson * Called with tlb_c.lock held. 99571aec354SEmilio G. Cota * Called only from the vCPU context, i.e. the TLB's owner thread. 99671aec354SEmilio G. Cota */ 99771aec354SEmilio G. Cota static inline void copy_tlb_helper_locked(CPUTLBEntry *d, const CPUTLBEntry *s) 99871aec354SEmilio G. Cota { 99971aec354SEmilio G. Cota *d = *s; 100071aec354SEmilio G. Cota } 1001d9bb58e5SYang Zhong 1002d9bb58e5SYang Zhong /* This is a cross vCPU call (i.e. another vCPU resetting the flags of 100371aec354SEmilio G. Cota * the target vCPU). 100453d28455SRichard Henderson * We must take tlb_c.lock to avoid racing with another vCPU update. The only 100571aec354SEmilio G. Cota * thing actually updated is the target TLB entry ->addr_write flags. 1006d9bb58e5SYang Zhong */ 1007d9bb58e5SYang Zhong void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length) 1008d9bb58e5SYang Zhong { 1009d9bb58e5SYang Zhong CPUArchState *env; 1010d9bb58e5SYang Zhong 1011d9bb58e5SYang Zhong int mmu_idx; 1012d9bb58e5SYang Zhong 1013d9bb58e5SYang Zhong env = cpu->env_ptr; 1014a40ec84eSRichard Henderson qemu_spin_lock(&env_tlb(env)->c.lock); 1015d9bb58e5SYang Zhong for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 1016d9bb58e5SYang Zhong unsigned int i; 1017722a1c1eSRichard Henderson unsigned int n = tlb_n_entries(&env_tlb(env)->f[mmu_idx]); 1018d9bb58e5SYang Zhong 101986e1eff8SEmilio G. Cota for (i = 0; i < n; i++) { 1020a40ec84eSRichard Henderson tlb_reset_dirty_range_locked(&env_tlb(env)->f[mmu_idx].table[i], 1021a40ec84eSRichard Henderson start1, length); 1022d9bb58e5SYang Zhong } 1023d9bb58e5SYang Zhong 1024d9bb58e5SYang Zhong for (i = 0; i < CPU_VTLB_SIZE; i++) { 1025a40ec84eSRichard Henderson tlb_reset_dirty_range_locked(&env_tlb(env)->d[mmu_idx].vtable[i], 1026a40ec84eSRichard Henderson start1, length); 1027d9bb58e5SYang Zhong } 1028d9bb58e5SYang Zhong } 1029a40ec84eSRichard Henderson qemu_spin_unlock(&env_tlb(env)->c.lock); 1030d9bb58e5SYang Zhong } 1031d9bb58e5SYang Zhong 103253d28455SRichard Henderson /* Called with tlb_c.lock held */ 103371aec354SEmilio G. Cota static inline void tlb_set_dirty1_locked(CPUTLBEntry *tlb_entry, 103471aec354SEmilio G. Cota target_ulong vaddr) 1035d9bb58e5SYang Zhong { 1036d9bb58e5SYang Zhong if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY)) { 1037d9bb58e5SYang Zhong tlb_entry->addr_write = vaddr; 1038d9bb58e5SYang Zhong } 1039d9bb58e5SYang Zhong } 1040d9bb58e5SYang Zhong 1041d9bb58e5SYang Zhong /* update the TLB corresponding to virtual page vaddr 1042d9bb58e5SYang Zhong so that it is no longer dirty */ 1043d9bb58e5SYang Zhong void tlb_set_dirty(CPUState *cpu, target_ulong vaddr) 1044d9bb58e5SYang Zhong { 1045d9bb58e5SYang Zhong CPUArchState *env = cpu->env_ptr; 1046d9bb58e5SYang Zhong int mmu_idx; 1047d9bb58e5SYang Zhong 1048d9bb58e5SYang Zhong assert_cpu_is_self(cpu); 1049d9bb58e5SYang Zhong 1050d9bb58e5SYang Zhong vaddr &= TARGET_PAGE_MASK; 1051a40ec84eSRichard Henderson qemu_spin_lock(&env_tlb(env)->c.lock); 1052d9bb58e5SYang Zhong for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 1053383beda9SRichard Henderson tlb_set_dirty1_locked(tlb_entry(env, mmu_idx, vaddr), vaddr); 1054d9bb58e5SYang Zhong } 1055d9bb58e5SYang Zhong 1056d9bb58e5SYang Zhong for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 1057d9bb58e5SYang Zhong int k; 1058d9bb58e5SYang Zhong for (k = 0; k < CPU_VTLB_SIZE; k++) { 1059a40ec84eSRichard Henderson tlb_set_dirty1_locked(&env_tlb(env)->d[mmu_idx].vtable[k], vaddr); 1060d9bb58e5SYang Zhong } 1061d9bb58e5SYang Zhong } 1062a40ec84eSRichard Henderson qemu_spin_unlock(&env_tlb(env)->c.lock); 1063d9bb58e5SYang Zhong } 1064d9bb58e5SYang Zhong 1065d9bb58e5SYang Zhong /* Our TLB does not support large pages, so remember the area covered by 1066d9bb58e5SYang Zhong large pages and trigger a full TLB flush if these are invalidated. */ 10671308e026SRichard Henderson static void tlb_add_large_page(CPUArchState *env, int mmu_idx, 10681308e026SRichard Henderson target_ulong vaddr, target_ulong size) 1069d9bb58e5SYang Zhong { 1070a40ec84eSRichard Henderson target_ulong lp_addr = env_tlb(env)->d[mmu_idx].large_page_addr; 10711308e026SRichard Henderson target_ulong lp_mask = ~(size - 1); 1072d9bb58e5SYang Zhong 10731308e026SRichard Henderson if (lp_addr == (target_ulong)-1) { 10741308e026SRichard Henderson /* No previous large page. */ 10751308e026SRichard Henderson lp_addr = vaddr; 10761308e026SRichard Henderson } else { 1077d9bb58e5SYang Zhong /* Extend the existing region to include the new page. 10781308e026SRichard Henderson This is a compromise between unnecessary flushes and 10791308e026SRichard Henderson the cost of maintaining a full variable size TLB. */ 1080a40ec84eSRichard Henderson lp_mask &= env_tlb(env)->d[mmu_idx].large_page_mask; 10811308e026SRichard Henderson while (((lp_addr ^ vaddr) & lp_mask) != 0) { 10821308e026SRichard Henderson lp_mask <<= 1; 1083d9bb58e5SYang Zhong } 10841308e026SRichard Henderson } 1085a40ec84eSRichard Henderson env_tlb(env)->d[mmu_idx].large_page_addr = lp_addr & lp_mask; 1086a40ec84eSRichard Henderson env_tlb(env)->d[mmu_idx].large_page_mask = lp_mask; 1087d9bb58e5SYang Zhong } 1088d9bb58e5SYang Zhong 1089d9bb58e5SYang Zhong /* Add a new TLB entry. At most one entry for a given virtual address 1090d9bb58e5SYang Zhong * is permitted. Only a single TARGET_PAGE_SIZE region is mapped, the 1091d9bb58e5SYang Zhong * supplied size is only used by tlb_flush_page. 1092d9bb58e5SYang Zhong * 1093d9bb58e5SYang Zhong * Called from TCG-generated code, which is under an RCU read-side 1094d9bb58e5SYang Zhong * critical section. 1095d9bb58e5SYang Zhong */ 1096d9bb58e5SYang Zhong void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, 1097d9bb58e5SYang Zhong hwaddr paddr, MemTxAttrs attrs, int prot, 1098d9bb58e5SYang Zhong int mmu_idx, target_ulong size) 1099d9bb58e5SYang Zhong { 1100d9bb58e5SYang Zhong CPUArchState *env = cpu->env_ptr; 1101a40ec84eSRichard Henderson CPUTLB *tlb = env_tlb(env); 1102a40ec84eSRichard Henderson CPUTLBDesc *desc = &tlb->d[mmu_idx]; 1103d9bb58e5SYang Zhong MemoryRegionSection *section; 1104d9bb58e5SYang Zhong unsigned int index; 1105d9bb58e5SYang Zhong target_ulong address; 11068f5db641SRichard Henderson target_ulong write_address; 1107d9bb58e5SYang Zhong uintptr_t addend; 110868fea038SRichard Henderson CPUTLBEntry *te, tn; 110955df6fcfSPeter Maydell hwaddr iotlb, xlat, sz, paddr_page; 111055df6fcfSPeter Maydell target_ulong vaddr_page; 1111d9bb58e5SYang Zhong int asidx = cpu_asidx_from_attrs(cpu, attrs); 111250b107c5SRichard Henderson int wp_flags; 11138f5db641SRichard Henderson bool is_ram, is_romd; 1114d9bb58e5SYang Zhong 1115d9bb58e5SYang Zhong assert_cpu_is_self(cpu); 111655df6fcfSPeter Maydell 11171308e026SRichard Henderson if (size <= TARGET_PAGE_SIZE) { 111855df6fcfSPeter Maydell sz = TARGET_PAGE_SIZE; 111955df6fcfSPeter Maydell } else { 11201308e026SRichard Henderson tlb_add_large_page(env, mmu_idx, vaddr, size); 1121d9bb58e5SYang Zhong sz = size; 112255df6fcfSPeter Maydell } 112355df6fcfSPeter Maydell vaddr_page = vaddr & TARGET_PAGE_MASK; 112455df6fcfSPeter Maydell paddr_page = paddr & TARGET_PAGE_MASK; 112555df6fcfSPeter Maydell 112655df6fcfSPeter Maydell section = address_space_translate_for_iotlb(cpu, asidx, paddr_page, 112755df6fcfSPeter Maydell &xlat, &sz, attrs, &prot); 1128d9bb58e5SYang Zhong assert(sz >= TARGET_PAGE_SIZE); 1129d9bb58e5SYang Zhong 1130d9bb58e5SYang Zhong tlb_debug("vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx 1131d9bb58e5SYang Zhong " prot=%x idx=%d\n", 1132d9bb58e5SYang Zhong vaddr, paddr, prot, mmu_idx); 1133d9bb58e5SYang Zhong 113455df6fcfSPeter Maydell address = vaddr_page; 113555df6fcfSPeter Maydell if (size < TARGET_PAGE_SIZE) { 113630d7e098SRichard Henderson /* Repeat the MMU check and TLB fill on every access. */ 113730d7e098SRichard Henderson address |= TLB_INVALID_MASK; 113855df6fcfSPeter Maydell } 1139a26fc6f5STony Nguyen if (attrs.byte_swap) { 11405b87b3e6SRichard Henderson address |= TLB_BSWAP; 1141a26fc6f5STony Nguyen } 11428f5db641SRichard Henderson 11438f5db641SRichard Henderson is_ram = memory_region_is_ram(section->mr); 11448f5db641SRichard Henderson is_romd = memory_region_is_romd(section->mr); 11458f5db641SRichard Henderson 11468f5db641SRichard Henderson if (is_ram || is_romd) { 11478f5db641SRichard Henderson /* RAM and ROMD both have associated host memory. */ 1148d9bb58e5SYang Zhong addend = (uintptr_t)memory_region_get_ram_ptr(section->mr) + xlat; 11498f5db641SRichard Henderson } else { 11508f5db641SRichard Henderson /* I/O does not; force the host address to NULL. */ 11518f5db641SRichard Henderson addend = 0; 1152d9bb58e5SYang Zhong } 1153d9bb58e5SYang Zhong 11548f5db641SRichard Henderson write_address = address; 11558f5db641SRichard Henderson if (is_ram) { 11568f5db641SRichard Henderson iotlb = memory_region_get_ram_addr(section->mr) + xlat; 11578f5db641SRichard Henderson /* 11588f5db641SRichard Henderson * Computing is_clean is expensive; avoid all that unless 11598f5db641SRichard Henderson * the page is actually writable. 11608f5db641SRichard Henderson */ 11618f5db641SRichard Henderson if (prot & PAGE_WRITE) { 11628f5db641SRichard Henderson if (section->readonly) { 11638f5db641SRichard Henderson write_address |= TLB_DISCARD_WRITE; 11648f5db641SRichard Henderson } else if (cpu_physical_memory_is_clean(iotlb)) { 11658f5db641SRichard Henderson write_address |= TLB_NOTDIRTY; 11668f5db641SRichard Henderson } 11678f5db641SRichard Henderson } 11688f5db641SRichard Henderson } else { 11698f5db641SRichard Henderson /* I/O or ROMD */ 11708f5db641SRichard Henderson iotlb = memory_region_section_get_iotlb(cpu, section) + xlat; 11718f5db641SRichard Henderson /* 11728f5db641SRichard Henderson * Writes to romd devices must go through MMIO to enable write. 11738f5db641SRichard Henderson * Reads to romd devices go through the ram_ptr found above, 11748f5db641SRichard Henderson * but of course reads to I/O must go through MMIO. 11758f5db641SRichard Henderson */ 11768f5db641SRichard Henderson write_address |= TLB_MMIO; 11778f5db641SRichard Henderson if (!is_romd) { 11788f5db641SRichard Henderson address = write_address; 11798f5db641SRichard Henderson } 11808f5db641SRichard Henderson } 11818f5db641SRichard Henderson 118250b107c5SRichard Henderson wp_flags = cpu_watchpoint_address_matches(cpu, vaddr_page, 118350b107c5SRichard Henderson TARGET_PAGE_SIZE); 1184d9bb58e5SYang Zhong 1185383beda9SRichard Henderson index = tlb_index(env, mmu_idx, vaddr_page); 1186383beda9SRichard Henderson te = tlb_entry(env, mmu_idx, vaddr_page); 1187d9bb58e5SYang Zhong 118868fea038SRichard Henderson /* 118971aec354SEmilio G. Cota * Hold the TLB lock for the rest of the function. We could acquire/release 119071aec354SEmilio G. Cota * the lock several times in the function, but it is faster to amortize the 119171aec354SEmilio G. Cota * acquisition cost by acquiring it just once. Note that this leads to 119271aec354SEmilio G. Cota * a longer critical section, but this is not a concern since the TLB lock 119371aec354SEmilio G. Cota * is unlikely to be contended. 119471aec354SEmilio G. Cota */ 1195a40ec84eSRichard Henderson qemu_spin_lock(&tlb->c.lock); 119671aec354SEmilio G. Cota 11973d1523ceSRichard Henderson /* Note that the tlb is no longer clean. */ 1198a40ec84eSRichard Henderson tlb->c.dirty |= 1 << mmu_idx; 11993d1523ceSRichard Henderson 120071aec354SEmilio G. Cota /* Make sure there's no cached translation for the new page. */ 120171aec354SEmilio G. Cota tlb_flush_vtlb_page_locked(env, mmu_idx, vaddr_page); 120271aec354SEmilio G. Cota 120371aec354SEmilio G. Cota /* 120468fea038SRichard Henderson * Only evict the old entry to the victim tlb if it's for a 120568fea038SRichard Henderson * different page; otherwise just overwrite the stale data. 120668fea038SRichard Henderson */ 12073cea94bbSEmilio G. Cota if (!tlb_hit_page_anyprot(te, vaddr_page) && !tlb_entry_is_empty(te)) { 1208a40ec84eSRichard Henderson unsigned vidx = desc->vindex++ % CPU_VTLB_SIZE; 1209a40ec84eSRichard Henderson CPUTLBEntry *tv = &desc->vtable[vidx]; 121068fea038SRichard Henderson 121168fea038SRichard Henderson /* Evict the old entry into the victim tlb. */ 121271aec354SEmilio G. Cota copy_tlb_helper_locked(tv, te); 1213a40ec84eSRichard Henderson desc->viotlb[vidx] = desc->iotlb[index]; 121486e1eff8SEmilio G. Cota tlb_n_used_entries_dec(env, mmu_idx); 121568fea038SRichard Henderson } 1216d9bb58e5SYang Zhong 1217d9bb58e5SYang Zhong /* refill the tlb */ 1218ace41090SPeter Maydell /* 1219ace41090SPeter Maydell * At this point iotlb contains a physical section number in the lower 1220ace41090SPeter Maydell * TARGET_PAGE_BITS, and either 12218f5db641SRichard Henderson * + the ram_addr_t of the page base of the target RAM (RAM) 12228f5db641SRichard Henderson * + the offset within section->mr of the page base (I/O, ROMD) 122355df6fcfSPeter Maydell * We subtract the vaddr_page (which is page aligned and thus won't 1224ace41090SPeter Maydell * disturb the low bits) to give an offset which can be added to the 1225ace41090SPeter Maydell * (non-page-aligned) vaddr of the eventual memory access to get 1226ace41090SPeter Maydell * the MemoryRegion offset for the access. Note that the vaddr we 1227ace41090SPeter Maydell * subtract here is that of the page base, and not the same as the 1228ace41090SPeter Maydell * vaddr we add back in io_readx()/io_writex()/get_page_addr_code(). 1229ace41090SPeter Maydell */ 1230a40ec84eSRichard Henderson desc->iotlb[index].addr = iotlb - vaddr_page; 1231a40ec84eSRichard Henderson desc->iotlb[index].attrs = attrs; 1232d9bb58e5SYang Zhong 1233d9bb58e5SYang Zhong /* Now calculate the new entry */ 123455df6fcfSPeter Maydell tn.addend = addend - vaddr_page; 1235d9bb58e5SYang Zhong if (prot & PAGE_READ) { 1236d9bb58e5SYang Zhong tn.addr_read = address; 123750b107c5SRichard Henderson if (wp_flags & BP_MEM_READ) { 123850b107c5SRichard Henderson tn.addr_read |= TLB_WATCHPOINT; 123950b107c5SRichard Henderson } 1240d9bb58e5SYang Zhong } else { 1241d9bb58e5SYang Zhong tn.addr_read = -1; 1242d9bb58e5SYang Zhong } 1243d9bb58e5SYang Zhong 1244d9bb58e5SYang Zhong if (prot & PAGE_EXEC) { 12458f5db641SRichard Henderson tn.addr_code = address; 1246d9bb58e5SYang Zhong } else { 1247d9bb58e5SYang Zhong tn.addr_code = -1; 1248d9bb58e5SYang Zhong } 1249d9bb58e5SYang Zhong 1250d9bb58e5SYang Zhong tn.addr_write = -1; 1251d9bb58e5SYang Zhong if (prot & PAGE_WRITE) { 12528f5db641SRichard Henderson tn.addr_write = write_address; 1253f52bfb12SDavid Hildenbrand if (prot & PAGE_WRITE_INV) { 1254f52bfb12SDavid Hildenbrand tn.addr_write |= TLB_INVALID_MASK; 1255f52bfb12SDavid Hildenbrand } 125650b107c5SRichard Henderson if (wp_flags & BP_MEM_WRITE) { 125750b107c5SRichard Henderson tn.addr_write |= TLB_WATCHPOINT; 125850b107c5SRichard Henderson } 1259d9bb58e5SYang Zhong } 1260d9bb58e5SYang Zhong 126171aec354SEmilio G. Cota copy_tlb_helper_locked(te, &tn); 126286e1eff8SEmilio G. Cota tlb_n_used_entries_inc(env, mmu_idx); 1263a40ec84eSRichard Henderson qemu_spin_unlock(&tlb->c.lock); 1264d9bb58e5SYang Zhong } 1265d9bb58e5SYang Zhong 1266d9bb58e5SYang Zhong /* Add a new TLB entry, but without specifying the memory 1267d9bb58e5SYang Zhong * transaction attributes to be used. 1268d9bb58e5SYang Zhong */ 1269d9bb58e5SYang Zhong void tlb_set_page(CPUState *cpu, target_ulong vaddr, 1270d9bb58e5SYang Zhong hwaddr paddr, int prot, 1271d9bb58e5SYang Zhong int mmu_idx, target_ulong size) 1272d9bb58e5SYang Zhong { 1273d9bb58e5SYang Zhong tlb_set_page_with_attrs(cpu, vaddr, paddr, MEMTXATTRS_UNSPECIFIED, 1274d9bb58e5SYang Zhong prot, mmu_idx, size); 1275d9bb58e5SYang Zhong } 1276d9bb58e5SYang Zhong 1277d9bb58e5SYang Zhong static inline ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr) 1278d9bb58e5SYang Zhong { 1279d9bb58e5SYang Zhong ram_addr_t ram_addr; 1280d9bb58e5SYang Zhong 1281d9bb58e5SYang Zhong ram_addr = qemu_ram_addr_from_host(ptr); 1282d9bb58e5SYang Zhong if (ram_addr == RAM_ADDR_INVALID) { 1283d9bb58e5SYang Zhong error_report("Bad ram pointer %p", ptr); 1284d9bb58e5SYang Zhong abort(); 1285d9bb58e5SYang Zhong } 1286d9bb58e5SYang Zhong return ram_addr; 1287d9bb58e5SYang Zhong } 1288d9bb58e5SYang Zhong 1289c319dc13SRichard Henderson /* 1290c319dc13SRichard Henderson * Note: tlb_fill() can trigger a resize of the TLB. This means that all of the 1291c319dc13SRichard Henderson * caller's prior references to the TLB table (e.g. CPUTLBEntry pointers) must 1292c319dc13SRichard Henderson * be discarded and looked up again (e.g. via tlb_entry()). 1293c319dc13SRichard Henderson */ 1294c319dc13SRichard Henderson static void tlb_fill(CPUState *cpu, target_ulong addr, int size, 1295c319dc13SRichard Henderson MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) 1296c319dc13SRichard Henderson { 1297c319dc13SRichard Henderson CPUClass *cc = CPU_GET_CLASS(cpu); 1298c319dc13SRichard Henderson bool ok; 1299c319dc13SRichard Henderson 1300c319dc13SRichard Henderson /* 1301c319dc13SRichard Henderson * This is not a probe, so only valid return is success; failure 1302c319dc13SRichard Henderson * should result in exception + longjmp to the cpu loop. 1303c319dc13SRichard Henderson */ 130478271684SClaudio Fontana ok = cc->tcg_ops->tlb_fill(cpu, addr, size, 1305e124536fSEduardo Habkost access_type, mmu_idx, false, retaddr); 1306c319dc13SRichard Henderson assert(ok); 1307c319dc13SRichard Henderson } 1308c319dc13SRichard Henderson 130978271684SClaudio Fontana static inline void cpu_unaligned_access(CPUState *cpu, vaddr addr, 131078271684SClaudio Fontana MMUAccessType access_type, 131178271684SClaudio Fontana int mmu_idx, uintptr_t retaddr) 131278271684SClaudio Fontana { 131378271684SClaudio Fontana CPUClass *cc = CPU_GET_CLASS(cpu); 131478271684SClaudio Fontana 131578271684SClaudio Fontana cc->tcg_ops->do_unaligned_access(cpu, addr, access_type, mmu_idx, retaddr); 131678271684SClaudio Fontana } 131778271684SClaudio Fontana 131878271684SClaudio Fontana static inline void cpu_transaction_failed(CPUState *cpu, hwaddr physaddr, 131978271684SClaudio Fontana vaddr addr, unsigned size, 132078271684SClaudio Fontana MMUAccessType access_type, 132178271684SClaudio Fontana int mmu_idx, MemTxAttrs attrs, 132278271684SClaudio Fontana MemTxResult response, 132378271684SClaudio Fontana uintptr_t retaddr) 132478271684SClaudio Fontana { 132578271684SClaudio Fontana CPUClass *cc = CPU_GET_CLASS(cpu); 132678271684SClaudio Fontana 132778271684SClaudio Fontana if (!cpu->ignore_memory_transaction_failures && 132878271684SClaudio Fontana cc->tcg_ops->do_transaction_failed) { 132978271684SClaudio Fontana cc->tcg_ops->do_transaction_failed(cpu, physaddr, addr, size, 133078271684SClaudio Fontana access_type, mmu_idx, attrs, 133178271684SClaudio Fontana response, retaddr); 133278271684SClaudio Fontana } 133378271684SClaudio Fontana } 133478271684SClaudio Fontana 1335d9bb58e5SYang Zhong static uint64_t io_readx(CPUArchState *env, CPUIOTLBEntry *iotlbentry, 1336f1be3696SRichard Henderson int mmu_idx, target_ulong addr, uintptr_t retaddr, 1337be5c4787STony Nguyen MMUAccessType access_type, MemOp op) 1338d9bb58e5SYang Zhong { 133929a0af61SRichard Henderson CPUState *cpu = env_cpu(env); 13402d54f194SPeter Maydell hwaddr mr_offset; 13412d54f194SPeter Maydell MemoryRegionSection *section; 13422d54f194SPeter Maydell MemoryRegion *mr; 1343d9bb58e5SYang Zhong uint64_t val; 1344d9bb58e5SYang Zhong bool locked = false; 134504e3aabdSPeter Maydell MemTxResult r; 1346d9bb58e5SYang Zhong 13472d54f194SPeter Maydell section = iotlb_to_section(cpu, iotlbentry->addr, iotlbentry->attrs); 13482d54f194SPeter Maydell mr = section->mr; 13492d54f194SPeter Maydell mr_offset = (iotlbentry->addr & TARGET_PAGE_MASK) + addr; 1350d9bb58e5SYang Zhong cpu->mem_io_pc = retaddr; 135108565552SRichard Henderson if (!cpu->can_do_io) { 1352d9bb58e5SYang Zhong cpu_io_recompile(cpu, retaddr); 1353d9bb58e5SYang Zhong } 1354d9bb58e5SYang Zhong 135541744954SPhilippe Mathieu-Daudé if (!qemu_mutex_iothread_locked()) { 1356d9bb58e5SYang Zhong qemu_mutex_lock_iothread(); 1357d9bb58e5SYang Zhong locked = true; 1358d9bb58e5SYang Zhong } 1359be5c4787STony Nguyen r = memory_region_dispatch_read(mr, mr_offset, &val, op, iotlbentry->attrs); 136004e3aabdSPeter Maydell if (r != MEMTX_OK) { 13612d54f194SPeter Maydell hwaddr physaddr = mr_offset + 13622d54f194SPeter Maydell section->offset_within_address_space - 13632d54f194SPeter Maydell section->offset_within_region; 13642d54f194SPeter Maydell 1365be5c4787STony Nguyen cpu_transaction_failed(cpu, physaddr, addr, memop_size(op), access_type, 136604e3aabdSPeter Maydell mmu_idx, iotlbentry->attrs, r, retaddr); 136704e3aabdSPeter Maydell } 1368d9bb58e5SYang Zhong if (locked) { 1369d9bb58e5SYang Zhong qemu_mutex_unlock_iothread(); 1370d9bb58e5SYang Zhong } 1371d9bb58e5SYang Zhong 1372d9bb58e5SYang Zhong return val; 1373d9bb58e5SYang Zhong } 1374d9bb58e5SYang Zhong 13752f3a57eeSAlex Bennée /* 13762f3a57eeSAlex Bennée * Save a potentially trashed IOTLB entry for later lookup by plugin. 1377570ef309SAlex Bennée * This is read by tlb_plugin_lookup if the iotlb entry doesn't match 1378570ef309SAlex Bennée * because of the side effect of io_writex changing memory layout. 13792f3a57eeSAlex Bennée */ 13802f3a57eeSAlex Bennée static void save_iotlb_data(CPUState *cs, hwaddr addr, 13812f3a57eeSAlex Bennée MemoryRegionSection *section, hwaddr mr_offset) 13822f3a57eeSAlex Bennée { 13832f3a57eeSAlex Bennée #ifdef CONFIG_PLUGIN 13842f3a57eeSAlex Bennée SavedIOTLB *saved = &cs->saved_iotlb; 13852f3a57eeSAlex Bennée saved->addr = addr; 13862f3a57eeSAlex Bennée saved->section = section; 13872f3a57eeSAlex Bennée saved->mr_offset = mr_offset; 13882f3a57eeSAlex Bennée #endif 13892f3a57eeSAlex Bennée } 13902f3a57eeSAlex Bennée 1391d9bb58e5SYang Zhong static void io_writex(CPUArchState *env, CPUIOTLBEntry *iotlbentry, 1392f1be3696SRichard Henderson int mmu_idx, uint64_t val, target_ulong addr, 1393be5c4787STony Nguyen uintptr_t retaddr, MemOp op) 1394d9bb58e5SYang Zhong { 139529a0af61SRichard Henderson CPUState *cpu = env_cpu(env); 13962d54f194SPeter Maydell hwaddr mr_offset; 13972d54f194SPeter Maydell MemoryRegionSection *section; 13982d54f194SPeter Maydell MemoryRegion *mr; 1399d9bb58e5SYang Zhong bool locked = false; 140004e3aabdSPeter Maydell MemTxResult r; 1401d9bb58e5SYang Zhong 14022d54f194SPeter Maydell section = iotlb_to_section(cpu, iotlbentry->addr, iotlbentry->attrs); 14032d54f194SPeter Maydell mr = section->mr; 14042d54f194SPeter Maydell mr_offset = (iotlbentry->addr & TARGET_PAGE_MASK) + addr; 140508565552SRichard Henderson if (!cpu->can_do_io) { 1406d9bb58e5SYang Zhong cpu_io_recompile(cpu, retaddr); 1407d9bb58e5SYang Zhong } 1408d9bb58e5SYang Zhong cpu->mem_io_pc = retaddr; 1409d9bb58e5SYang Zhong 14102f3a57eeSAlex Bennée /* 14112f3a57eeSAlex Bennée * The memory_region_dispatch may trigger a flush/resize 14122f3a57eeSAlex Bennée * so for plugins we save the iotlb_data just in case. 14132f3a57eeSAlex Bennée */ 14142f3a57eeSAlex Bennée save_iotlb_data(cpu, iotlbentry->addr, section, mr_offset); 14152f3a57eeSAlex Bennée 141641744954SPhilippe Mathieu-Daudé if (!qemu_mutex_iothread_locked()) { 1417d9bb58e5SYang Zhong qemu_mutex_lock_iothread(); 1418d9bb58e5SYang Zhong locked = true; 1419d9bb58e5SYang Zhong } 1420be5c4787STony Nguyen r = memory_region_dispatch_write(mr, mr_offset, val, op, iotlbentry->attrs); 142104e3aabdSPeter Maydell if (r != MEMTX_OK) { 14222d54f194SPeter Maydell hwaddr physaddr = mr_offset + 14232d54f194SPeter Maydell section->offset_within_address_space - 14242d54f194SPeter Maydell section->offset_within_region; 14252d54f194SPeter Maydell 1426be5c4787STony Nguyen cpu_transaction_failed(cpu, physaddr, addr, memop_size(op), 1427be5c4787STony Nguyen MMU_DATA_STORE, mmu_idx, iotlbentry->attrs, r, 1428be5c4787STony Nguyen retaddr); 142904e3aabdSPeter Maydell } 1430d9bb58e5SYang Zhong if (locked) { 1431d9bb58e5SYang Zhong qemu_mutex_unlock_iothread(); 1432d9bb58e5SYang Zhong } 1433d9bb58e5SYang Zhong } 1434d9bb58e5SYang Zhong 14354811e909SRichard Henderson static inline target_ulong tlb_read_ofs(CPUTLBEntry *entry, size_t ofs) 14364811e909SRichard Henderson { 14374811e909SRichard Henderson #if TCG_OVERSIZED_GUEST 14384811e909SRichard Henderson return *(target_ulong *)((uintptr_t)entry + ofs); 14394811e909SRichard Henderson #else 1440d73415a3SStefan Hajnoczi /* ofs might correspond to .addr_write, so use qatomic_read */ 1441d73415a3SStefan Hajnoczi return qatomic_read((target_ulong *)((uintptr_t)entry + ofs)); 14424811e909SRichard Henderson #endif 14434811e909SRichard Henderson } 14444811e909SRichard Henderson 1445d9bb58e5SYang Zhong /* Return true if ADDR is present in the victim tlb, and has been copied 1446d9bb58e5SYang Zhong back to the main tlb. */ 1447d9bb58e5SYang Zhong static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index, 1448d9bb58e5SYang Zhong size_t elt_ofs, target_ulong page) 1449d9bb58e5SYang Zhong { 1450d9bb58e5SYang Zhong size_t vidx; 145171aec354SEmilio G. Cota 145229a0af61SRichard Henderson assert_cpu_is_self(env_cpu(env)); 1453d9bb58e5SYang Zhong for (vidx = 0; vidx < CPU_VTLB_SIZE; ++vidx) { 1454a40ec84eSRichard Henderson CPUTLBEntry *vtlb = &env_tlb(env)->d[mmu_idx].vtable[vidx]; 1455a40ec84eSRichard Henderson target_ulong cmp; 1456a40ec84eSRichard Henderson 1457d73415a3SStefan Hajnoczi /* elt_ofs might correspond to .addr_write, so use qatomic_read */ 1458a40ec84eSRichard Henderson #if TCG_OVERSIZED_GUEST 1459a40ec84eSRichard Henderson cmp = *(target_ulong *)((uintptr_t)vtlb + elt_ofs); 1460a40ec84eSRichard Henderson #else 1461d73415a3SStefan Hajnoczi cmp = qatomic_read((target_ulong *)((uintptr_t)vtlb + elt_ofs)); 1462a40ec84eSRichard Henderson #endif 1463d9bb58e5SYang Zhong 1464d9bb58e5SYang Zhong if (cmp == page) { 1465d9bb58e5SYang Zhong /* Found entry in victim tlb, swap tlb and iotlb. */ 1466a40ec84eSRichard Henderson CPUTLBEntry tmptlb, *tlb = &env_tlb(env)->f[mmu_idx].table[index]; 1467d9bb58e5SYang Zhong 1468a40ec84eSRichard Henderson qemu_spin_lock(&env_tlb(env)->c.lock); 146971aec354SEmilio G. Cota copy_tlb_helper_locked(&tmptlb, tlb); 147071aec354SEmilio G. Cota copy_tlb_helper_locked(tlb, vtlb); 147171aec354SEmilio G. Cota copy_tlb_helper_locked(vtlb, &tmptlb); 1472a40ec84eSRichard Henderson qemu_spin_unlock(&env_tlb(env)->c.lock); 1473d9bb58e5SYang Zhong 1474a40ec84eSRichard Henderson CPUIOTLBEntry tmpio, *io = &env_tlb(env)->d[mmu_idx].iotlb[index]; 1475a40ec84eSRichard Henderson CPUIOTLBEntry *vio = &env_tlb(env)->d[mmu_idx].viotlb[vidx]; 1476d9bb58e5SYang Zhong tmpio = *io; *io = *vio; *vio = tmpio; 1477d9bb58e5SYang Zhong return true; 1478d9bb58e5SYang Zhong } 1479d9bb58e5SYang Zhong } 1480d9bb58e5SYang Zhong return false; 1481d9bb58e5SYang Zhong } 1482d9bb58e5SYang Zhong 1483d9bb58e5SYang Zhong /* Macro to call the above, with local variables from the use context. */ 1484d9bb58e5SYang Zhong #define VICTIM_TLB_HIT(TY, ADDR) \ 1485d9bb58e5SYang Zhong victim_tlb_hit(env, mmu_idx, index, offsetof(CPUTLBEntry, TY), \ 1486d9bb58e5SYang Zhong (ADDR) & TARGET_PAGE_MASK) 1487d9bb58e5SYang Zhong 148830d7e098SRichard Henderson /* 148930d7e098SRichard Henderson * Return a ram_addr_t for the virtual address for execution. 149030d7e098SRichard Henderson * 149130d7e098SRichard Henderson * Return -1 if we can't translate and execute from an entire page 149230d7e098SRichard Henderson * of RAM. This will force us to execute by loading and translating 149330d7e098SRichard Henderson * one insn at a time, without caching. 149430d7e098SRichard Henderson * 149530d7e098SRichard Henderson * NOTE: This function will trigger an exception if the page is 149630d7e098SRichard Henderson * not executable. 1497f2553f04SKONRAD Frederic */ 14984b2190daSEmilio G. Cota tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, target_ulong addr, 14994b2190daSEmilio G. Cota void **hostp) 1500f2553f04SKONRAD Frederic { 1501383beda9SRichard Henderson uintptr_t mmu_idx = cpu_mmu_index(env, true); 1502383beda9SRichard Henderson uintptr_t index = tlb_index(env, mmu_idx, addr); 1503383beda9SRichard Henderson CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); 1504f2553f04SKONRAD Frederic void *p; 1505f2553f04SKONRAD Frederic 1506383beda9SRichard Henderson if (unlikely(!tlb_hit(entry->addr_code, addr))) { 1507b493ccf1SPeter Maydell if (!VICTIM_TLB_HIT(addr_code, addr)) { 150829a0af61SRichard Henderson tlb_fill(env_cpu(env), addr, 0, MMU_INST_FETCH, mmu_idx, 0); 15096d967cb8SEmilio G. Cota index = tlb_index(env, mmu_idx, addr); 15106d967cb8SEmilio G. Cota entry = tlb_entry(env, mmu_idx, addr); 151130d7e098SRichard Henderson 151230d7e098SRichard Henderson if (unlikely(entry->addr_code & TLB_INVALID_MASK)) { 151330d7e098SRichard Henderson /* 151430d7e098SRichard Henderson * The MMU protection covers a smaller range than a target 151530d7e098SRichard Henderson * page, so we must redo the MMU check for every insn. 151630d7e098SRichard Henderson */ 151730d7e098SRichard Henderson return -1; 151830d7e098SRichard Henderson } 151971b9a453SKONRAD Frederic } 1520383beda9SRichard Henderson assert(tlb_hit(entry->addr_code, addr)); 1521f2553f04SKONRAD Frederic } 152255df6fcfSPeter Maydell 152330d7e098SRichard Henderson if (unlikely(entry->addr_code & TLB_MMIO)) { 152430d7e098SRichard Henderson /* The region is not backed by RAM. */ 15254b2190daSEmilio G. Cota if (hostp) { 15264b2190daSEmilio G. Cota *hostp = NULL; 15274b2190daSEmilio G. Cota } 152820cb6ae4SPeter Maydell return -1; 152955df6fcfSPeter Maydell } 153055df6fcfSPeter Maydell 1531383beda9SRichard Henderson p = (void *)((uintptr_t)addr + entry->addend); 15324b2190daSEmilio G. Cota if (hostp) { 15334b2190daSEmilio G. Cota *hostp = p; 15344b2190daSEmilio G. Cota } 1535f2553f04SKONRAD Frederic return qemu_ram_addr_from_host_nofail(p); 1536f2553f04SKONRAD Frederic } 1537f2553f04SKONRAD Frederic 15384b2190daSEmilio G. Cota tb_page_addr_t get_page_addr_code(CPUArchState *env, target_ulong addr) 15394b2190daSEmilio G. Cota { 15404b2190daSEmilio G. Cota return get_page_addr_code_hostp(env, addr, NULL); 15414b2190daSEmilio G. Cota } 15424b2190daSEmilio G. Cota 1543707526adSRichard Henderson static void notdirty_write(CPUState *cpu, vaddr mem_vaddr, unsigned size, 1544707526adSRichard Henderson CPUIOTLBEntry *iotlbentry, uintptr_t retaddr) 1545707526adSRichard Henderson { 1546707526adSRichard Henderson ram_addr_t ram_addr = mem_vaddr + iotlbentry->addr; 1547707526adSRichard Henderson 1548707526adSRichard Henderson trace_memory_notdirty_write_access(mem_vaddr, ram_addr, size); 1549707526adSRichard Henderson 1550707526adSRichard Henderson if (!cpu_physical_memory_get_dirty_flag(ram_addr, DIRTY_MEMORY_CODE)) { 1551707526adSRichard Henderson struct page_collection *pages 1552707526adSRichard Henderson = page_collection_lock(ram_addr, ram_addr + size); 15535a7c27bbSRichard Henderson tb_invalidate_phys_page_fast(pages, ram_addr, size, retaddr); 1554707526adSRichard Henderson page_collection_unlock(pages); 1555707526adSRichard Henderson } 1556707526adSRichard Henderson 1557707526adSRichard Henderson /* 1558707526adSRichard Henderson * Set both VGA and migration bits for simplicity and to remove 1559707526adSRichard Henderson * the notdirty callback faster. 1560707526adSRichard Henderson */ 1561707526adSRichard Henderson cpu_physical_memory_set_dirty_range(ram_addr, size, DIRTY_CLIENTS_NOCODE); 1562707526adSRichard Henderson 1563707526adSRichard Henderson /* We remove the notdirty callback only if the code has been flushed. */ 1564707526adSRichard Henderson if (!cpu_physical_memory_is_clean(ram_addr)) { 1565707526adSRichard Henderson trace_memory_notdirty_set_dirty(mem_vaddr); 1566707526adSRichard Henderson tlb_set_dirty(cpu, mem_vaddr); 1567707526adSRichard Henderson } 1568707526adSRichard Henderson } 1569707526adSRichard Henderson 1570069cfe77SRichard Henderson static int probe_access_internal(CPUArchState *env, target_ulong addr, 1571069cfe77SRichard Henderson int fault_size, MMUAccessType access_type, 1572069cfe77SRichard Henderson int mmu_idx, bool nonfault, 1573069cfe77SRichard Henderson void **phost, uintptr_t retaddr) 1574d9bb58e5SYang Zhong { 1575383beda9SRichard Henderson uintptr_t index = tlb_index(env, mmu_idx, addr); 1576383beda9SRichard Henderson CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); 1577069cfe77SRichard Henderson target_ulong tlb_addr, page_addr; 1578c25c283dSDavid Hildenbrand size_t elt_ofs; 1579069cfe77SRichard Henderson int flags; 1580ca86cf32SDavid Hildenbrand 1581c25c283dSDavid Hildenbrand switch (access_type) { 1582c25c283dSDavid Hildenbrand case MMU_DATA_LOAD: 1583c25c283dSDavid Hildenbrand elt_ofs = offsetof(CPUTLBEntry, addr_read); 1584c25c283dSDavid Hildenbrand break; 1585c25c283dSDavid Hildenbrand case MMU_DATA_STORE: 1586c25c283dSDavid Hildenbrand elt_ofs = offsetof(CPUTLBEntry, addr_write); 1587c25c283dSDavid Hildenbrand break; 1588c25c283dSDavid Hildenbrand case MMU_INST_FETCH: 1589c25c283dSDavid Hildenbrand elt_ofs = offsetof(CPUTLBEntry, addr_code); 1590c25c283dSDavid Hildenbrand break; 1591c25c283dSDavid Hildenbrand default: 1592c25c283dSDavid Hildenbrand g_assert_not_reached(); 1593c25c283dSDavid Hildenbrand } 1594c25c283dSDavid Hildenbrand tlb_addr = tlb_read_ofs(entry, elt_ofs); 1595c25c283dSDavid Hildenbrand 1596069cfe77SRichard Henderson page_addr = addr & TARGET_PAGE_MASK; 1597069cfe77SRichard Henderson if (!tlb_hit_page(tlb_addr, page_addr)) { 1598069cfe77SRichard Henderson if (!victim_tlb_hit(env, mmu_idx, index, elt_ofs, page_addr)) { 1599069cfe77SRichard Henderson CPUState *cs = env_cpu(env); 1600069cfe77SRichard Henderson CPUClass *cc = CPU_GET_CLASS(cs); 1601069cfe77SRichard Henderson 160278271684SClaudio Fontana if (!cc->tcg_ops->tlb_fill(cs, addr, fault_size, access_type, 1603069cfe77SRichard Henderson mmu_idx, nonfault, retaddr)) { 1604069cfe77SRichard Henderson /* Non-faulting page table read failed. */ 1605069cfe77SRichard Henderson *phost = NULL; 1606069cfe77SRichard Henderson return TLB_INVALID_MASK; 1607069cfe77SRichard Henderson } 1608069cfe77SRichard Henderson 160903a98189SDavid Hildenbrand /* TLB resize via tlb_fill may have moved the entry. */ 161003a98189SDavid Hildenbrand entry = tlb_entry(env, mmu_idx, addr); 1611d9bb58e5SYang Zhong } 1612c25c283dSDavid Hildenbrand tlb_addr = tlb_read_ofs(entry, elt_ofs); 161303a98189SDavid Hildenbrand } 1614069cfe77SRichard Henderson flags = tlb_addr & TLB_FLAGS_MASK; 161503a98189SDavid Hildenbrand 1616069cfe77SRichard Henderson /* Fold all "mmio-like" bits into TLB_MMIO. This is not RAM. */ 1617069cfe77SRichard Henderson if (unlikely(flags & ~(TLB_WATCHPOINT | TLB_NOTDIRTY))) { 1618069cfe77SRichard Henderson *phost = NULL; 1619069cfe77SRichard Henderson return TLB_MMIO; 1620fef39ccdSDavid Hildenbrand } 1621fef39ccdSDavid Hildenbrand 1622069cfe77SRichard Henderson /* Everything else is RAM. */ 1623069cfe77SRichard Henderson *phost = (void *)((uintptr_t)addr + entry->addend); 1624069cfe77SRichard Henderson return flags; 1625069cfe77SRichard Henderson } 1626069cfe77SRichard Henderson 1627069cfe77SRichard Henderson int probe_access_flags(CPUArchState *env, target_ulong addr, 1628069cfe77SRichard Henderson MMUAccessType access_type, int mmu_idx, 1629069cfe77SRichard Henderson bool nonfault, void **phost, uintptr_t retaddr) 1630069cfe77SRichard Henderson { 1631069cfe77SRichard Henderson int flags; 1632069cfe77SRichard Henderson 1633069cfe77SRichard Henderson flags = probe_access_internal(env, addr, 0, access_type, mmu_idx, 1634069cfe77SRichard Henderson nonfault, phost, retaddr); 1635069cfe77SRichard Henderson 1636069cfe77SRichard Henderson /* Handle clean RAM pages. */ 1637069cfe77SRichard Henderson if (unlikely(flags & TLB_NOTDIRTY)) { 1638069cfe77SRichard Henderson uintptr_t index = tlb_index(env, mmu_idx, addr); 163973bc0bd4SRichard Henderson CPUIOTLBEntry *iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index]; 164073bc0bd4SRichard Henderson 1641069cfe77SRichard Henderson notdirty_write(env_cpu(env), addr, 1, iotlbentry, retaddr); 1642069cfe77SRichard Henderson flags &= ~TLB_NOTDIRTY; 1643069cfe77SRichard Henderson } 1644069cfe77SRichard Henderson 1645069cfe77SRichard Henderson return flags; 1646069cfe77SRichard Henderson } 1647069cfe77SRichard Henderson 1648069cfe77SRichard Henderson void *probe_access(CPUArchState *env, target_ulong addr, int size, 1649069cfe77SRichard Henderson MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) 1650069cfe77SRichard Henderson { 1651069cfe77SRichard Henderson void *host; 1652069cfe77SRichard Henderson int flags; 1653069cfe77SRichard Henderson 1654069cfe77SRichard Henderson g_assert(-(addr | TARGET_PAGE_MASK) >= size); 1655069cfe77SRichard Henderson 1656069cfe77SRichard Henderson flags = probe_access_internal(env, addr, size, access_type, mmu_idx, 1657069cfe77SRichard Henderson false, &host, retaddr); 1658069cfe77SRichard Henderson 1659069cfe77SRichard Henderson /* Per the interface, size == 0 merely faults the access. */ 1660069cfe77SRichard Henderson if (size == 0) { 166173bc0bd4SRichard Henderson return NULL; 166273bc0bd4SRichard Henderson } 166373bc0bd4SRichard Henderson 1664069cfe77SRichard Henderson if (unlikely(flags & (TLB_NOTDIRTY | TLB_WATCHPOINT))) { 1665069cfe77SRichard Henderson uintptr_t index = tlb_index(env, mmu_idx, addr); 1666069cfe77SRichard Henderson CPUIOTLBEntry *iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index]; 1667069cfe77SRichard Henderson 166803a98189SDavid Hildenbrand /* Handle watchpoints. */ 1669069cfe77SRichard Henderson if (flags & TLB_WATCHPOINT) { 1670069cfe77SRichard Henderson int wp_access = (access_type == MMU_DATA_STORE 1671069cfe77SRichard Henderson ? BP_MEM_WRITE : BP_MEM_READ); 167203a98189SDavid Hildenbrand cpu_check_watchpoint(env_cpu(env), addr, size, 167373bc0bd4SRichard Henderson iotlbentry->attrs, wp_access, retaddr); 1674d9bb58e5SYang Zhong } 1675fef39ccdSDavid Hildenbrand 167673bc0bd4SRichard Henderson /* Handle clean RAM pages. */ 1677069cfe77SRichard Henderson if (flags & TLB_NOTDIRTY) { 1678069cfe77SRichard Henderson notdirty_write(env_cpu(env), addr, 1, iotlbentry, retaddr); 167973bc0bd4SRichard Henderson } 1680fef39ccdSDavid Hildenbrand } 1681fef39ccdSDavid Hildenbrand 1682069cfe77SRichard Henderson return host; 1683d9bb58e5SYang Zhong } 1684d9bb58e5SYang Zhong 16854811e909SRichard Henderson void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr, 16864811e909SRichard Henderson MMUAccessType access_type, int mmu_idx) 16874811e909SRichard Henderson { 1688069cfe77SRichard Henderson void *host; 1689069cfe77SRichard Henderson int flags; 16904811e909SRichard Henderson 1691069cfe77SRichard Henderson flags = probe_access_internal(env, addr, 0, access_type, 1692069cfe77SRichard Henderson mmu_idx, true, &host, 0); 1693069cfe77SRichard Henderson 1694069cfe77SRichard Henderson /* No combination of flags are expected by the caller. */ 1695069cfe77SRichard Henderson return flags ? NULL : host; 16964811e909SRichard Henderson } 16974811e909SRichard Henderson 1698235537faSAlex Bennée #ifdef CONFIG_PLUGIN 1699235537faSAlex Bennée /* 1700235537faSAlex Bennée * Perform a TLB lookup and populate the qemu_plugin_hwaddr structure. 1701235537faSAlex Bennée * This should be a hot path as we will have just looked this path up 1702235537faSAlex Bennée * in the softmmu lookup code (or helper). We don't handle re-fills or 1703235537faSAlex Bennée * checking the victim table. This is purely informational. 1704235537faSAlex Bennée * 17052f3a57eeSAlex Bennée * This almost never fails as the memory access being instrumented 17062f3a57eeSAlex Bennée * should have just filled the TLB. The one corner case is io_writex 17072f3a57eeSAlex Bennée * which can cause TLB flushes and potential resizing of the TLBs 1708570ef309SAlex Bennée * losing the information we need. In those cases we need to recover 1709570ef309SAlex Bennée * data from a copy of the iotlbentry. As long as this always occurs 1710570ef309SAlex Bennée * from the same thread (which a mem callback will be) this is safe. 1711235537faSAlex Bennée */ 1712235537faSAlex Bennée 1713235537faSAlex Bennée bool tlb_plugin_lookup(CPUState *cpu, target_ulong addr, int mmu_idx, 1714235537faSAlex Bennée bool is_store, struct qemu_plugin_hwaddr *data) 1715235537faSAlex Bennée { 1716235537faSAlex Bennée CPUArchState *env = cpu->env_ptr; 1717235537faSAlex Bennée CPUTLBEntry *tlbe = tlb_entry(env, mmu_idx, addr); 1718235537faSAlex Bennée uintptr_t index = tlb_index(env, mmu_idx, addr); 1719235537faSAlex Bennée target_ulong tlb_addr = is_store ? tlb_addr_write(tlbe) : tlbe->addr_read; 1720235537faSAlex Bennée 1721235537faSAlex Bennée if (likely(tlb_hit(tlb_addr, addr))) { 1722235537faSAlex Bennée /* We must have an iotlb entry for MMIO */ 1723235537faSAlex Bennée if (tlb_addr & TLB_MMIO) { 1724235537faSAlex Bennée CPUIOTLBEntry *iotlbentry; 1725235537faSAlex Bennée iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index]; 1726235537faSAlex Bennée data->is_io = true; 1727235537faSAlex Bennée data->v.io.section = iotlb_to_section(cpu, iotlbentry->addr, iotlbentry->attrs); 1728235537faSAlex Bennée data->v.io.offset = (iotlbentry->addr & TARGET_PAGE_MASK) + addr; 1729235537faSAlex Bennée } else { 1730235537faSAlex Bennée data->is_io = false; 1731*2d932039SAlex Bennée data->v.ram.hostaddr = (void *)((uintptr_t)addr + tlbe->addend); 1732235537faSAlex Bennée } 1733235537faSAlex Bennée return true; 17342f3a57eeSAlex Bennée } else { 17352f3a57eeSAlex Bennée SavedIOTLB *saved = &cpu->saved_iotlb; 17362f3a57eeSAlex Bennée data->is_io = true; 17372f3a57eeSAlex Bennée data->v.io.section = saved->section; 17382f3a57eeSAlex Bennée data->v.io.offset = saved->mr_offset; 17392f3a57eeSAlex Bennée return true; 1740235537faSAlex Bennée } 1741235537faSAlex Bennée } 1742235537faSAlex Bennée 1743235537faSAlex Bennée #endif 1744235537faSAlex Bennée 174508dff435SRichard Henderson /* 174608dff435SRichard Henderson * Probe for an atomic operation. Do not allow unaligned operations, 174708dff435SRichard Henderson * or io operations to proceed. Return the host address. 174808dff435SRichard Henderson * 174908dff435SRichard Henderson * @prot may be PAGE_READ, PAGE_WRITE, or PAGE_READ|PAGE_WRITE. 175008dff435SRichard Henderson */ 1751d9bb58e5SYang Zhong static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, 175208dff435SRichard Henderson TCGMemOpIdx oi, int size, int prot, 175308dff435SRichard Henderson uintptr_t retaddr) 1754d9bb58e5SYang Zhong { 1755d9bb58e5SYang Zhong size_t mmu_idx = get_mmuidx(oi); 175614776ab5STony Nguyen MemOp mop = get_memop(oi); 1757d9bb58e5SYang Zhong int a_bits = get_alignment_bits(mop); 175808dff435SRichard Henderson uintptr_t index; 175908dff435SRichard Henderson CPUTLBEntry *tlbe; 176008dff435SRichard Henderson target_ulong tlb_addr; 176134d49937SPeter Maydell void *hostaddr; 1762d9bb58e5SYang Zhong 1763d9bb58e5SYang Zhong /* Adjust the given return address. */ 1764d9bb58e5SYang Zhong retaddr -= GETPC_ADJ; 1765d9bb58e5SYang Zhong 1766d9bb58e5SYang Zhong /* Enforce guest required alignment. */ 1767d9bb58e5SYang Zhong if (unlikely(a_bits > 0 && (addr & ((1 << a_bits) - 1)))) { 1768d9bb58e5SYang Zhong /* ??? Maybe indicate atomic op to cpu_unaligned_access */ 176929a0af61SRichard Henderson cpu_unaligned_access(env_cpu(env), addr, MMU_DATA_STORE, 1770d9bb58e5SYang Zhong mmu_idx, retaddr); 1771d9bb58e5SYang Zhong } 1772d9bb58e5SYang Zhong 1773d9bb58e5SYang Zhong /* Enforce qemu required alignment. */ 177408dff435SRichard Henderson if (unlikely(addr & (size - 1))) { 1775d9bb58e5SYang Zhong /* We get here if guest alignment was not requested, 1776d9bb58e5SYang Zhong or was not enforced by cpu_unaligned_access above. 1777d9bb58e5SYang Zhong We might widen the access and emulate, but for now 1778d9bb58e5SYang Zhong mark an exception and exit the cpu loop. */ 1779d9bb58e5SYang Zhong goto stop_the_world; 1780d9bb58e5SYang Zhong } 1781d9bb58e5SYang Zhong 178208dff435SRichard Henderson index = tlb_index(env, mmu_idx, addr); 178308dff435SRichard Henderson tlbe = tlb_entry(env, mmu_idx, addr); 178408dff435SRichard Henderson 1785d9bb58e5SYang Zhong /* Check TLB entry and enforce page permissions. */ 178608dff435SRichard Henderson if (prot & PAGE_WRITE) { 178708dff435SRichard Henderson tlb_addr = tlb_addr_write(tlbe); 1788334692bcSPeter Maydell if (!tlb_hit(tlb_addr, addr)) { 1789d9bb58e5SYang Zhong if (!VICTIM_TLB_HIT(addr_write, addr)) { 179008dff435SRichard Henderson tlb_fill(env_cpu(env), addr, size, 179108dff435SRichard Henderson MMU_DATA_STORE, mmu_idx, retaddr); 17926d967cb8SEmilio G. Cota index = tlb_index(env, mmu_idx, addr); 17936d967cb8SEmilio G. Cota tlbe = tlb_entry(env, mmu_idx, addr); 1794d9bb58e5SYang Zhong } 1795403f290cSEmilio G. Cota tlb_addr = tlb_addr_write(tlbe) & ~TLB_INVALID_MASK; 1796d9bb58e5SYang Zhong } 1797d9bb58e5SYang Zhong 179808dff435SRichard Henderson /* Let the guest notice RMW on a write-only page. */ 179908dff435SRichard Henderson if ((prot & PAGE_READ) && 180008dff435SRichard Henderson unlikely(tlbe->addr_read != (tlb_addr & ~TLB_NOTDIRTY))) { 180108dff435SRichard Henderson tlb_fill(env_cpu(env), addr, size, 180208dff435SRichard Henderson MMU_DATA_LOAD, mmu_idx, retaddr); 180308dff435SRichard Henderson /* 180408dff435SRichard Henderson * Since we don't support reads and writes to different addresses, 180508dff435SRichard Henderson * and we do have the proper page loaded for write, this shouldn't 180608dff435SRichard Henderson * ever return. But just in case, handle via stop-the-world. 180708dff435SRichard Henderson */ 180808dff435SRichard Henderson goto stop_the_world; 180908dff435SRichard Henderson } 181008dff435SRichard Henderson } else /* if (prot & PAGE_READ) */ { 181108dff435SRichard Henderson tlb_addr = tlbe->addr_read; 181208dff435SRichard Henderson if (!tlb_hit(tlb_addr, addr)) { 181308dff435SRichard Henderson if (!VICTIM_TLB_HIT(addr_write, addr)) { 181408dff435SRichard Henderson tlb_fill(env_cpu(env), addr, size, 181508dff435SRichard Henderson MMU_DATA_LOAD, mmu_idx, retaddr); 181608dff435SRichard Henderson index = tlb_index(env, mmu_idx, addr); 181708dff435SRichard Henderson tlbe = tlb_entry(env, mmu_idx, addr); 181808dff435SRichard Henderson } 181908dff435SRichard Henderson tlb_addr = tlbe->addr_read & ~TLB_INVALID_MASK; 182008dff435SRichard Henderson } 182108dff435SRichard Henderson } 182208dff435SRichard Henderson 182355df6fcfSPeter Maydell /* Notice an IO access or a needs-MMU-lookup access */ 182430d7e098SRichard Henderson if (unlikely(tlb_addr & TLB_MMIO)) { 1825d9bb58e5SYang Zhong /* There's really nothing that can be done to 1826d9bb58e5SYang Zhong support this apart from stop-the-world. */ 1827d9bb58e5SYang Zhong goto stop_the_world; 1828d9bb58e5SYang Zhong } 1829d9bb58e5SYang Zhong 183034d49937SPeter Maydell hostaddr = (void *)((uintptr_t)addr + tlbe->addend); 183134d49937SPeter Maydell 183234d49937SPeter Maydell if (unlikely(tlb_addr & TLB_NOTDIRTY)) { 183308dff435SRichard Henderson notdirty_write(env_cpu(env), addr, size, 1834707526adSRichard Henderson &env_tlb(env)->d[mmu_idx].iotlb[index], retaddr); 183534d49937SPeter Maydell } 183634d49937SPeter Maydell 183734d49937SPeter Maydell return hostaddr; 1838d9bb58e5SYang Zhong 1839d9bb58e5SYang Zhong stop_the_world: 184029a0af61SRichard Henderson cpu_loop_exit_atomic(env_cpu(env), retaddr); 1841d9bb58e5SYang Zhong } 1842d9bb58e5SYang Zhong 1843eed56642SAlex Bennée /* 1844eed56642SAlex Bennée * Load Helpers 1845eed56642SAlex Bennée * 1846eed56642SAlex Bennée * We support two different access types. SOFTMMU_CODE_ACCESS is 1847eed56642SAlex Bennée * specifically for reading instructions from system memory. It is 1848eed56642SAlex Bennée * called by the translation loop and in some helpers where the code 1849eed56642SAlex Bennée * is disassembled. It shouldn't be called directly by guest code. 1850eed56642SAlex Bennée */ 1851d9bb58e5SYang Zhong 18522dd92606SRichard Henderson typedef uint64_t FullLoadHelper(CPUArchState *env, target_ulong addr, 18532dd92606SRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr); 18542dd92606SRichard Henderson 1855c6b716cdSRichard Henderson static inline uint64_t QEMU_ALWAYS_INLINE 185680d9d1c6SRichard Henderson load_memop(const void *haddr, MemOp op) 185780d9d1c6SRichard Henderson { 185880d9d1c6SRichard Henderson switch (op) { 185980d9d1c6SRichard Henderson case MO_UB: 186080d9d1c6SRichard Henderson return ldub_p(haddr); 186180d9d1c6SRichard Henderson case MO_BEUW: 186280d9d1c6SRichard Henderson return lduw_be_p(haddr); 186380d9d1c6SRichard Henderson case MO_LEUW: 186480d9d1c6SRichard Henderson return lduw_le_p(haddr); 186580d9d1c6SRichard Henderson case MO_BEUL: 186680d9d1c6SRichard Henderson return (uint32_t)ldl_be_p(haddr); 186780d9d1c6SRichard Henderson case MO_LEUL: 186880d9d1c6SRichard Henderson return (uint32_t)ldl_le_p(haddr); 186980d9d1c6SRichard Henderson case MO_BEQ: 187080d9d1c6SRichard Henderson return ldq_be_p(haddr); 187180d9d1c6SRichard Henderson case MO_LEQ: 187280d9d1c6SRichard Henderson return ldq_le_p(haddr); 187380d9d1c6SRichard Henderson default: 187480d9d1c6SRichard Henderson qemu_build_not_reached(); 187580d9d1c6SRichard Henderson } 187680d9d1c6SRichard Henderson } 187780d9d1c6SRichard Henderson 187880d9d1c6SRichard Henderson static inline uint64_t QEMU_ALWAYS_INLINE 18792dd92606SRichard Henderson load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, 1880be5c4787STony Nguyen uintptr_t retaddr, MemOp op, bool code_read, 18812dd92606SRichard Henderson FullLoadHelper *full_load) 1882eed56642SAlex Bennée { 1883eed56642SAlex Bennée uintptr_t mmu_idx = get_mmuidx(oi); 1884eed56642SAlex Bennée uintptr_t index = tlb_index(env, mmu_idx, addr); 1885eed56642SAlex Bennée CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); 1886eed56642SAlex Bennée target_ulong tlb_addr = code_read ? entry->addr_code : entry->addr_read; 1887eed56642SAlex Bennée const size_t tlb_off = code_read ? 1888eed56642SAlex Bennée offsetof(CPUTLBEntry, addr_code) : offsetof(CPUTLBEntry, addr_read); 1889f1be3696SRichard Henderson const MMUAccessType access_type = 1890f1be3696SRichard Henderson code_read ? MMU_INST_FETCH : MMU_DATA_LOAD; 1891eed56642SAlex Bennée unsigned a_bits = get_alignment_bits(get_memop(oi)); 1892eed56642SAlex Bennée void *haddr; 1893eed56642SAlex Bennée uint64_t res; 1894be5c4787STony Nguyen size_t size = memop_size(op); 1895d9bb58e5SYang Zhong 1896eed56642SAlex Bennée /* Handle CPU specific unaligned behaviour */ 1897eed56642SAlex Bennée if (addr & ((1 << a_bits) - 1)) { 189829a0af61SRichard Henderson cpu_unaligned_access(env_cpu(env), addr, access_type, 1899eed56642SAlex Bennée mmu_idx, retaddr); 1900eed56642SAlex Bennée } 1901eed56642SAlex Bennée 1902eed56642SAlex Bennée /* If the TLB entry is for a different page, reload and try again. */ 1903eed56642SAlex Bennée if (!tlb_hit(tlb_addr, addr)) { 1904eed56642SAlex Bennée if (!victim_tlb_hit(env, mmu_idx, index, tlb_off, 1905eed56642SAlex Bennée addr & TARGET_PAGE_MASK)) { 190629a0af61SRichard Henderson tlb_fill(env_cpu(env), addr, size, 1907f1be3696SRichard Henderson access_type, mmu_idx, retaddr); 1908eed56642SAlex Bennée index = tlb_index(env, mmu_idx, addr); 1909eed56642SAlex Bennée entry = tlb_entry(env, mmu_idx, addr); 1910eed56642SAlex Bennée } 1911eed56642SAlex Bennée tlb_addr = code_read ? entry->addr_code : entry->addr_read; 191230d7e098SRichard Henderson tlb_addr &= ~TLB_INVALID_MASK; 1913eed56642SAlex Bennée } 1914eed56642SAlex Bennée 191550b107c5SRichard Henderson /* Handle anything that isn't just a straight memory access. */ 1916eed56642SAlex Bennée if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) { 191750b107c5SRichard Henderson CPUIOTLBEntry *iotlbentry; 19185b87b3e6SRichard Henderson bool need_swap; 191950b107c5SRichard Henderson 192050b107c5SRichard Henderson /* For anything that is unaligned, recurse through full_load. */ 1921eed56642SAlex Bennée if ((addr & (size - 1)) != 0) { 1922eed56642SAlex Bennée goto do_unaligned_access; 1923eed56642SAlex Bennée } 192450b107c5SRichard Henderson 192550b107c5SRichard Henderson iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index]; 192650b107c5SRichard Henderson 192750b107c5SRichard Henderson /* Handle watchpoints. */ 192850b107c5SRichard Henderson if (unlikely(tlb_addr & TLB_WATCHPOINT)) { 192950b107c5SRichard Henderson /* On watchpoint hit, this will longjmp out. */ 193050b107c5SRichard Henderson cpu_check_watchpoint(env_cpu(env), addr, size, 193150b107c5SRichard Henderson iotlbentry->attrs, BP_MEM_READ, retaddr); 19325b87b3e6SRichard Henderson } 193350b107c5SRichard Henderson 19345b87b3e6SRichard Henderson need_swap = size > 1 && (tlb_addr & TLB_BSWAP); 193550b107c5SRichard Henderson 193650b107c5SRichard Henderson /* Handle I/O access. */ 19375b87b3e6SRichard Henderson if (likely(tlb_addr & TLB_MMIO)) { 19385b87b3e6SRichard Henderson return io_readx(env, iotlbentry, mmu_idx, addr, retaddr, 19395b87b3e6SRichard Henderson access_type, op ^ (need_swap * MO_BSWAP)); 19405b87b3e6SRichard Henderson } 19415b87b3e6SRichard Henderson 19425b87b3e6SRichard Henderson haddr = (void *)((uintptr_t)addr + entry->addend); 19435b87b3e6SRichard Henderson 19445b87b3e6SRichard Henderson /* 19455b87b3e6SRichard Henderson * Keep these two load_memop separate to ensure that the compiler 19465b87b3e6SRichard Henderson * is able to fold the entire function to a single instruction. 19475b87b3e6SRichard Henderson * There is a build-time assert inside to remind you of this. ;-) 19485b87b3e6SRichard Henderson */ 19495b87b3e6SRichard Henderson if (unlikely(need_swap)) { 19505b87b3e6SRichard Henderson return load_memop(haddr, op ^ MO_BSWAP); 19515b87b3e6SRichard Henderson } 19525b87b3e6SRichard Henderson return load_memop(haddr, op); 1953eed56642SAlex Bennée } 1954eed56642SAlex Bennée 1955eed56642SAlex Bennée /* Handle slow unaligned access (it spans two pages or IO). */ 1956eed56642SAlex Bennée if (size > 1 1957eed56642SAlex Bennée && unlikely((addr & ~TARGET_PAGE_MASK) + size - 1 1958eed56642SAlex Bennée >= TARGET_PAGE_SIZE)) { 1959eed56642SAlex Bennée target_ulong addr1, addr2; 19608c79b288SAlex Bennée uint64_t r1, r2; 1961eed56642SAlex Bennée unsigned shift; 1962eed56642SAlex Bennée do_unaligned_access: 1963ab7a2009SAlex Bennée addr1 = addr & ~((target_ulong)size - 1); 1964eed56642SAlex Bennée addr2 = addr1 + size; 19652dd92606SRichard Henderson r1 = full_load(env, addr1, oi, retaddr); 19662dd92606SRichard Henderson r2 = full_load(env, addr2, oi, retaddr); 1967eed56642SAlex Bennée shift = (addr & (size - 1)) * 8; 1968eed56642SAlex Bennée 1969be5c4787STony Nguyen if (memop_big_endian(op)) { 1970eed56642SAlex Bennée /* Big-endian combine. */ 1971eed56642SAlex Bennée res = (r1 << shift) | (r2 >> ((size * 8) - shift)); 1972eed56642SAlex Bennée } else { 1973eed56642SAlex Bennée /* Little-endian combine. */ 1974eed56642SAlex Bennée res = (r1 >> shift) | (r2 << ((size * 8) - shift)); 1975eed56642SAlex Bennée } 1976eed56642SAlex Bennée return res & MAKE_64BIT_MASK(0, size * 8); 1977eed56642SAlex Bennée } 1978eed56642SAlex Bennée 1979eed56642SAlex Bennée haddr = (void *)((uintptr_t)addr + entry->addend); 198080d9d1c6SRichard Henderson return load_memop(haddr, op); 1981eed56642SAlex Bennée } 1982eed56642SAlex Bennée 1983eed56642SAlex Bennée /* 1984eed56642SAlex Bennée * For the benefit of TCG generated code, we want to avoid the 1985eed56642SAlex Bennée * complication of ABI-specific return type promotion and always 1986eed56642SAlex Bennée * return a value extended to the register size of the host. This is 1987eed56642SAlex Bennée * tcg_target_long, except in the case of a 32-bit host and 64-bit 1988eed56642SAlex Bennée * data, and for that we always have uint64_t. 1989eed56642SAlex Bennée * 1990eed56642SAlex Bennée * We don't bother with this widened value for SOFTMMU_CODE_ACCESS. 1991eed56642SAlex Bennée */ 1992eed56642SAlex Bennée 19932dd92606SRichard Henderson static uint64_t full_ldub_mmu(CPUArchState *env, target_ulong addr, 19942dd92606SRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 19952dd92606SRichard Henderson { 1996be5c4787STony Nguyen return load_helper(env, addr, oi, retaddr, MO_UB, false, full_ldub_mmu); 19972dd92606SRichard Henderson } 19982dd92606SRichard Henderson 1999fc1bc777SRichard Henderson tcg_target_ulong helper_ret_ldub_mmu(CPUArchState *env, target_ulong addr, 2000fc1bc777SRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 2001eed56642SAlex Bennée { 20022dd92606SRichard Henderson return full_ldub_mmu(env, addr, oi, retaddr); 20032dd92606SRichard Henderson } 20042dd92606SRichard Henderson 20052dd92606SRichard Henderson static uint64_t full_le_lduw_mmu(CPUArchState *env, target_ulong addr, 20062dd92606SRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 20072dd92606SRichard Henderson { 2008be5c4787STony Nguyen return load_helper(env, addr, oi, retaddr, MO_LEUW, false, 20092dd92606SRichard Henderson full_le_lduw_mmu); 2010eed56642SAlex Bennée } 2011eed56642SAlex Bennée 2012fc1bc777SRichard Henderson tcg_target_ulong helper_le_lduw_mmu(CPUArchState *env, target_ulong addr, 2013fc1bc777SRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 2014eed56642SAlex Bennée { 20152dd92606SRichard Henderson return full_le_lduw_mmu(env, addr, oi, retaddr); 20162dd92606SRichard Henderson } 20172dd92606SRichard Henderson 20182dd92606SRichard Henderson static uint64_t full_be_lduw_mmu(CPUArchState *env, target_ulong addr, 20192dd92606SRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 20202dd92606SRichard Henderson { 2021be5c4787STony Nguyen return load_helper(env, addr, oi, retaddr, MO_BEUW, false, 20222dd92606SRichard Henderson full_be_lduw_mmu); 2023eed56642SAlex Bennée } 2024eed56642SAlex Bennée 2025fc1bc777SRichard Henderson tcg_target_ulong helper_be_lduw_mmu(CPUArchState *env, target_ulong addr, 2026fc1bc777SRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 2027eed56642SAlex Bennée { 20282dd92606SRichard Henderson return full_be_lduw_mmu(env, addr, oi, retaddr); 20292dd92606SRichard Henderson } 20302dd92606SRichard Henderson 20312dd92606SRichard Henderson static uint64_t full_le_ldul_mmu(CPUArchState *env, target_ulong addr, 20322dd92606SRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 20332dd92606SRichard Henderson { 2034be5c4787STony Nguyen return load_helper(env, addr, oi, retaddr, MO_LEUL, false, 20352dd92606SRichard Henderson full_le_ldul_mmu); 2036eed56642SAlex Bennée } 2037eed56642SAlex Bennée 2038fc1bc777SRichard Henderson tcg_target_ulong helper_le_ldul_mmu(CPUArchState *env, target_ulong addr, 2039fc1bc777SRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 2040eed56642SAlex Bennée { 20412dd92606SRichard Henderson return full_le_ldul_mmu(env, addr, oi, retaddr); 20422dd92606SRichard Henderson } 20432dd92606SRichard Henderson 20442dd92606SRichard Henderson static uint64_t full_be_ldul_mmu(CPUArchState *env, target_ulong addr, 20452dd92606SRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 20462dd92606SRichard Henderson { 2047be5c4787STony Nguyen return load_helper(env, addr, oi, retaddr, MO_BEUL, false, 20482dd92606SRichard Henderson full_be_ldul_mmu); 2049eed56642SAlex Bennée } 2050eed56642SAlex Bennée 2051fc1bc777SRichard Henderson tcg_target_ulong helper_be_ldul_mmu(CPUArchState *env, target_ulong addr, 2052fc1bc777SRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 2053eed56642SAlex Bennée { 20542dd92606SRichard Henderson return full_be_ldul_mmu(env, addr, oi, retaddr); 2055eed56642SAlex Bennée } 2056eed56642SAlex Bennée 2057fc1bc777SRichard Henderson uint64_t helper_le_ldq_mmu(CPUArchState *env, target_ulong addr, 2058fc1bc777SRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 2059eed56642SAlex Bennée { 2060be5c4787STony Nguyen return load_helper(env, addr, oi, retaddr, MO_LEQ, false, 20612dd92606SRichard Henderson helper_le_ldq_mmu); 2062eed56642SAlex Bennée } 2063eed56642SAlex Bennée 2064fc1bc777SRichard Henderson uint64_t helper_be_ldq_mmu(CPUArchState *env, target_ulong addr, 2065fc1bc777SRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 2066eed56642SAlex Bennée { 2067be5c4787STony Nguyen return load_helper(env, addr, oi, retaddr, MO_BEQ, false, 20682dd92606SRichard Henderson helper_be_ldq_mmu); 2069eed56642SAlex Bennée } 2070eed56642SAlex Bennée 2071eed56642SAlex Bennée /* 2072eed56642SAlex Bennée * Provide signed versions of the load routines as well. We can of course 2073eed56642SAlex Bennée * avoid this for 64-bit data, or for 32-bit data on 32-bit host. 2074eed56642SAlex Bennée */ 2075eed56642SAlex Bennée 2076eed56642SAlex Bennée 2077eed56642SAlex Bennée tcg_target_ulong helper_ret_ldsb_mmu(CPUArchState *env, target_ulong addr, 2078eed56642SAlex Bennée TCGMemOpIdx oi, uintptr_t retaddr) 2079eed56642SAlex Bennée { 2080eed56642SAlex Bennée return (int8_t)helper_ret_ldub_mmu(env, addr, oi, retaddr); 2081eed56642SAlex Bennée } 2082eed56642SAlex Bennée 2083eed56642SAlex Bennée tcg_target_ulong helper_le_ldsw_mmu(CPUArchState *env, target_ulong addr, 2084eed56642SAlex Bennée TCGMemOpIdx oi, uintptr_t retaddr) 2085eed56642SAlex Bennée { 2086eed56642SAlex Bennée return (int16_t)helper_le_lduw_mmu(env, addr, oi, retaddr); 2087eed56642SAlex Bennée } 2088eed56642SAlex Bennée 2089eed56642SAlex Bennée tcg_target_ulong helper_be_ldsw_mmu(CPUArchState *env, target_ulong addr, 2090eed56642SAlex Bennée TCGMemOpIdx oi, uintptr_t retaddr) 2091eed56642SAlex Bennée { 2092eed56642SAlex Bennée return (int16_t)helper_be_lduw_mmu(env, addr, oi, retaddr); 2093eed56642SAlex Bennée } 2094eed56642SAlex Bennée 2095eed56642SAlex Bennée tcg_target_ulong helper_le_ldsl_mmu(CPUArchState *env, target_ulong addr, 2096eed56642SAlex Bennée TCGMemOpIdx oi, uintptr_t retaddr) 2097eed56642SAlex Bennée { 2098eed56642SAlex Bennée return (int32_t)helper_le_ldul_mmu(env, addr, oi, retaddr); 2099eed56642SAlex Bennée } 2100eed56642SAlex Bennée 2101eed56642SAlex Bennée tcg_target_ulong helper_be_ldsl_mmu(CPUArchState *env, target_ulong addr, 2102eed56642SAlex Bennée TCGMemOpIdx oi, uintptr_t retaddr) 2103eed56642SAlex Bennée { 2104eed56642SAlex Bennée return (int32_t)helper_be_ldul_mmu(env, addr, oi, retaddr); 2105eed56642SAlex Bennée } 2106eed56642SAlex Bennée 2107eed56642SAlex Bennée /* 2108d03f1408SRichard Henderson * Load helpers for cpu_ldst.h. 2109d03f1408SRichard Henderson */ 2110d03f1408SRichard Henderson 2111d03f1408SRichard Henderson static inline uint64_t cpu_load_helper(CPUArchState *env, abi_ptr addr, 2112d03f1408SRichard Henderson int mmu_idx, uintptr_t retaddr, 2113d03f1408SRichard Henderson MemOp op, FullLoadHelper *full_load) 2114d03f1408SRichard Henderson { 2115d03f1408SRichard Henderson uint16_t meminfo; 2116d03f1408SRichard Henderson TCGMemOpIdx oi; 2117d03f1408SRichard Henderson uint64_t ret; 2118d03f1408SRichard Henderson 2119d03f1408SRichard Henderson meminfo = trace_mem_get_info(op, mmu_idx, false); 2120d03f1408SRichard Henderson trace_guest_mem_before_exec(env_cpu(env), addr, meminfo); 2121d03f1408SRichard Henderson 2122d03f1408SRichard Henderson op &= ~MO_SIGN; 2123d03f1408SRichard Henderson oi = make_memop_idx(op, mmu_idx); 2124d03f1408SRichard Henderson ret = full_load(env, addr, oi, retaddr); 2125d03f1408SRichard Henderson 2126d03f1408SRichard Henderson qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, meminfo); 2127d03f1408SRichard Henderson 2128d03f1408SRichard Henderson return ret; 2129d03f1408SRichard Henderson } 2130d03f1408SRichard Henderson 2131d03f1408SRichard Henderson uint32_t cpu_ldub_mmuidx_ra(CPUArchState *env, abi_ptr addr, 2132d03f1408SRichard Henderson int mmu_idx, uintptr_t ra) 2133d03f1408SRichard Henderson { 2134d03f1408SRichard Henderson return cpu_load_helper(env, addr, mmu_idx, ra, MO_UB, full_ldub_mmu); 2135d03f1408SRichard Henderson } 2136d03f1408SRichard Henderson 2137d03f1408SRichard Henderson int cpu_ldsb_mmuidx_ra(CPUArchState *env, abi_ptr addr, 2138d03f1408SRichard Henderson int mmu_idx, uintptr_t ra) 2139d03f1408SRichard Henderson { 2140d03f1408SRichard Henderson return (int8_t)cpu_load_helper(env, addr, mmu_idx, ra, MO_SB, 2141d03f1408SRichard Henderson full_ldub_mmu); 2142d03f1408SRichard Henderson } 2143d03f1408SRichard Henderson 2144b9e60257SRichard Henderson uint32_t cpu_lduw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, 2145d03f1408SRichard Henderson int mmu_idx, uintptr_t ra) 2146d03f1408SRichard Henderson { 2147b9e60257SRichard Henderson return cpu_load_helper(env, addr, mmu_idx, ra, MO_BEUW, full_be_lduw_mmu); 2148d03f1408SRichard Henderson } 2149d03f1408SRichard Henderson 2150b9e60257SRichard Henderson int cpu_ldsw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, 2151d03f1408SRichard Henderson int mmu_idx, uintptr_t ra) 2152d03f1408SRichard Henderson { 2153b9e60257SRichard Henderson return (int16_t)cpu_load_helper(env, addr, mmu_idx, ra, MO_BESW, 2154b9e60257SRichard Henderson full_be_lduw_mmu); 2155d03f1408SRichard Henderson } 2156d03f1408SRichard Henderson 2157b9e60257SRichard Henderson uint32_t cpu_ldl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, 2158d03f1408SRichard Henderson int mmu_idx, uintptr_t ra) 2159d03f1408SRichard Henderson { 2160b9e60257SRichard Henderson return cpu_load_helper(env, addr, mmu_idx, ra, MO_BEUL, full_be_ldul_mmu); 2161d03f1408SRichard Henderson } 2162d03f1408SRichard Henderson 2163b9e60257SRichard Henderson uint64_t cpu_ldq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, 2164d03f1408SRichard Henderson int mmu_idx, uintptr_t ra) 2165d03f1408SRichard Henderson { 2166b9e60257SRichard Henderson return cpu_load_helper(env, addr, mmu_idx, ra, MO_BEQ, helper_be_ldq_mmu); 2167b9e60257SRichard Henderson } 2168b9e60257SRichard Henderson 2169b9e60257SRichard Henderson uint32_t cpu_lduw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, 2170b9e60257SRichard Henderson int mmu_idx, uintptr_t ra) 2171b9e60257SRichard Henderson { 2172b9e60257SRichard Henderson return cpu_load_helper(env, addr, mmu_idx, ra, MO_LEUW, full_le_lduw_mmu); 2173b9e60257SRichard Henderson } 2174b9e60257SRichard Henderson 2175b9e60257SRichard Henderson int cpu_ldsw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, 2176b9e60257SRichard Henderson int mmu_idx, uintptr_t ra) 2177b9e60257SRichard Henderson { 2178b9e60257SRichard Henderson return (int16_t)cpu_load_helper(env, addr, mmu_idx, ra, MO_LESW, 2179b9e60257SRichard Henderson full_le_lduw_mmu); 2180b9e60257SRichard Henderson } 2181b9e60257SRichard Henderson 2182b9e60257SRichard Henderson uint32_t cpu_ldl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, 2183b9e60257SRichard Henderson int mmu_idx, uintptr_t ra) 2184b9e60257SRichard Henderson { 2185b9e60257SRichard Henderson return cpu_load_helper(env, addr, mmu_idx, ra, MO_LEUL, full_le_ldul_mmu); 2186b9e60257SRichard Henderson } 2187b9e60257SRichard Henderson 2188b9e60257SRichard Henderson uint64_t cpu_ldq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, 2189b9e60257SRichard Henderson int mmu_idx, uintptr_t ra) 2190b9e60257SRichard Henderson { 2191b9e60257SRichard Henderson return cpu_load_helper(env, addr, mmu_idx, ra, MO_LEQ, helper_le_ldq_mmu); 2192d03f1408SRichard Henderson } 2193d03f1408SRichard Henderson 2194cfe04a4bSRichard Henderson uint32_t cpu_ldub_data_ra(CPUArchState *env, target_ulong ptr, 2195cfe04a4bSRichard Henderson uintptr_t retaddr) 2196cfe04a4bSRichard Henderson { 2197cfe04a4bSRichard Henderson return cpu_ldub_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); 2198cfe04a4bSRichard Henderson } 2199cfe04a4bSRichard Henderson 2200cfe04a4bSRichard Henderson int cpu_ldsb_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr) 2201cfe04a4bSRichard Henderson { 2202cfe04a4bSRichard Henderson return cpu_ldsb_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); 2203cfe04a4bSRichard Henderson } 2204cfe04a4bSRichard Henderson 2205b9e60257SRichard Henderson uint32_t cpu_lduw_be_data_ra(CPUArchState *env, target_ulong ptr, 2206cfe04a4bSRichard Henderson uintptr_t retaddr) 2207cfe04a4bSRichard Henderson { 2208b9e60257SRichard Henderson return cpu_lduw_be_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); 2209cfe04a4bSRichard Henderson } 2210cfe04a4bSRichard Henderson 2211b9e60257SRichard Henderson int cpu_ldsw_be_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr) 2212cfe04a4bSRichard Henderson { 2213b9e60257SRichard Henderson return cpu_ldsw_be_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); 2214cfe04a4bSRichard Henderson } 2215cfe04a4bSRichard Henderson 2216b9e60257SRichard Henderson uint32_t cpu_ldl_be_data_ra(CPUArchState *env, target_ulong ptr, 2217b9e60257SRichard Henderson uintptr_t retaddr) 2218cfe04a4bSRichard Henderson { 2219b9e60257SRichard Henderson return cpu_ldl_be_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); 2220cfe04a4bSRichard Henderson } 2221cfe04a4bSRichard Henderson 2222b9e60257SRichard Henderson uint64_t cpu_ldq_be_data_ra(CPUArchState *env, target_ulong ptr, 2223b9e60257SRichard Henderson uintptr_t retaddr) 2224cfe04a4bSRichard Henderson { 2225b9e60257SRichard Henderson return cpu_ldq_be_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); 2226b9e60257SRichard Henderson } 2227b9e60257SRichard Henderson 2228b9e60257SRichard Henderson uint32_t cpu_lduw_le_data_ra(CPUArchState *env, target_ulong ptr, 2229b9e60257SRichard Henderson uintptr_t retaddr) 2230b9e60257SRichard Henderson { 2231b9e60257SRichard Henderson return cpu_lduw_le_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); 2232b9e60257SRichard Henderson } 2233b9e60257SRichard Henderson 2234b9e60257SRichard Henderson int cpu_ldsw_le_data_ra(CPUArchState *env, target_ulong ptr, uintptr_t retaddr) 2235b9e60257SRichard Henderson { 2236b9e60257SRichard Henderson return cpu_ldsw_le_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); 2237b9e60257SRichard Henderson } 2238b9e60257SRichard Henderson 2239b9e60257SRichard Henderson uint32_t cpu_ldl_le_data_ra(CPUArchState *env, target_ulong ptr, 2240b9e60257SRichard Henderson uintptr_t retaddr) 2241b9e60257SRichard Henderson { 2242b9e60257SRichard Henderson return cpu_ldl_le_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); 2243b9e60257SRichard Henderson } 2244b9e60257SRichard Henderson 2245b9e60257SRichard Henderson uint64_t cpu_ldq_le_data_ra(CPUArchState *env, target_ulong ptr, 2246b9e60257SRichard Henderson uintptr_t retaddr) 2247b9e60257SRichard Henderson { 2248b9e60257SRichard Henderson return cpu_ldq_le_mmuidx_ra(env, ptr, cpu_mmu_index(env, false), retaddr); 2249cfe04a4bSRichard Henderson } 2250cfe04a4bSRichard Henderson 2251cfe04a4bSRichard Henderson uint32_t cpu_ldub_data(CPUArchState *env, target_ulong ptr) 2252cfe04a4bSRichard Henderson { 2253cfe04a4bSRichard Henderson return cpu_ldub_data_ra(env, ptr, 0); 2254cfe04a4bSRichard Henderson } 2255cfe04a4bSRichard Henderson 2256cfe04a4bSRichard Henderson int cpu_ldsb_data(CPUArchState *env, target_ulong ptr) 2257cfe04a4bSRichard Henderson { 2258cfe04a4bSRichard Henderson return cpu_ldsb_data_ra(env, ptr, 0); 2259cfe04a4bSRichard Henderson } 2260cfe04a4bSRichard Henderson 2261b9e60257SRichard Henderson uint32_t cpu_lduw_be_data(CPUArchState *env, target_ulong ptr) 2262cfe04a4bSRichard Henderson { 2263b9e60257SRichard Henderson return cpu_lduw_be_data_ra(env, ptr, 0); 2264cfe04a4bSRichard Henderson } 2265cfe04a4bSRichard Henderson 2266b9e60257SRichard Henderson int cpu_ldsw_be_data(CPUArchState *env, target_ulong ptr) 2267cfe04a4bSRichard Henderson { 2268b9e60257SRichard Henderson return cpu_ldsw_be_data_ra(env, ptr, 0); 2269cfe04a4bSRichard Henderson } 2270cfe04a4bSRichard Henderson 2271b9e60257SRichard Henderson uint32_t cpu_ldl_be_data(CPUArchState *env, target_ulong ptr) 2272cfe04a4bSRichard Henderson { 2273b9e60257SRichard Henderson return cpu_ldl_be_data_ra(env, ptr, 0); 2274cfe04a4bSRichard Henderson } 2275cfe04a4bSRichard Henderson 2276b9e60257SRichard Henderson uint64_t cpu_ldq_be_data(CPUArchState *env, target_ulong ptr) 2277cfe04a4bSRichard Henderson { 2278b9e60257SRichard Henderson return cpu_ldq_be_data_ra(env, ptr, 0); 2279b9e60257SRichard Henderson } 2280b9e60257SRichard Henderson 2281b9e60257SRichard Henderson uint32_t cpu_lduw_le_data(CPUArchState *env, target_ulong ptr) 2282b9e60257SRichard Henderson { 2283b9e60257SRichard Henderson return cpu_lduw_le_data_ra(env, ptr, 0); 2284b9e60257SRichard Henderson } 2285b9e60257SRichard Henderson 2286b9e60257SRichard Henderson int cpu_ldsw_le_data(CPUArchState *env, target_ulong ptr) 2287b9e60257SRichard Henderson { 2288b9e60257SRichard Henderson return cpu_ldsw_le_data_ra(env, ptr, 0); 2289b9e60257SRichard Henderson } 2290b9e60257SRichard Henderson 2291b9e60257SRichard Henderson uint32_t cpu_ldl_le_data(CPUArchState *env, target_ulong ptr) 2292b9e60257SRichard Henderson { 2293b9e60257SRichard Henderson return cpu_ldl_le_data_ra(env, ptr, 0); 2294b9e60257SRichard Henderson } 2295b9e60257SRichard Henderson 2296b9e60257SRichard Henderson uint64_t cpu_ldq_le_data(CPUArchState *env, target_ulong ptr) 2297b9e60257SRichard Henderson { 2298b9e60257SRichard Henderson return cpu_ldq_le_data_ra(env, ptr, 0); 2299cfe04a4bSRichard Henderson } 2300cfe04a4bSRichard Henderson 2301d03f1408SRichard Henderson /* 2302eed56642SAlex Bennée * Store Helpers 2303eed56642SAlex Bennée */ 2304eed56642SAlex Bennée 2305c6b716cdSRichard Henderson static inline void QEMU_ALWAYS_INLINE 230680d9d1c6SRichard Henderson store_memop(void *haddr, uint64_t val, MemOp op) 230780d9d1c6SRichard Henderson { 230880d9d1c6SRichard Henderson switch (op) { 230980d9d1c6SRichard Henderson case MO_UB: 231080d9d1c6SRichard Henderson stb_p(haddr, val); 231180d9d1c6SRichard Henderson break; 231280d9d1c6SRichard Henderson case MO_BEUW: 231380d9d1c6SRichard Henderson stw_be_p(haddr, val); 231480d9d1c6SRichard Henderson break; 231580d9d1c6SRichard Henderson case MO_LEUW: 231680d9d1c6SRichard Henderson stw_le_p(haddr, val); 231780d9d1c6SRichard Henderson break; 231880d9d1c6SRichard Henderson case MO_BEUL: 231980d9d1c6SRichard Henderson stl_be_p(haddr, val); 232080d9d1c6SRichard Henderson break; 232180d9d1c6SRichard Henderson case MO_LEUL: 232280d9d1c6SRichard Henderson stl_le_p(haddr, val); 232380d9d1c6SRichard Henderson break; 232480d9d1c6SRichard Henderson case MO_BEQ: 232580d9d1c6SRichard Henderson stq_be_p(haddr, val); 232680d9d1c6SRichard Henderson break; 232780d9d1c6SRichard Henderson case MO_LEQ: 232880d9d1c6SRichard Henderson stq_le_p(haddr, val); 232980d9d1c6SRichard Henderson break; 233080d9d1c6SRichard Henderson default: 233180d9d1c6SRichard Henderson qemu_build_not_reached(); 233280d9d1c6SRichard Henderson } 233380d9d1c6SRichard Henderson } 233480d9d1c6SRichard Henderson 23356b8b622eSRichard Henderson static void __attribute__((noinline)) 23366b8b622eSRichard Henderson store_helper_unaligned(CPUArchState *env, target_ulong addr, uint64_t val, 23376b8b622eSRichard Henderson uintptr_t retaddr, size_t size, uintptr_t mmu_idx, 23386b8b622eSRichard Henderson bool big_endian) 23396b8b622eSRichard Henderson { 23406b8b622eSRichard Henderson const size_t tlb_off = offsetof(CPUTLBEntry, addr_write); 23416b8b622eSRichard Henderson uintptr_t index, index2; 23426b8b622eSRichard Henderson CPUTLBEntry *entry, *entry2; 23436b8b622eSRichard Henderson target_ulong page2, tlb_addr, tlb_addr2; 23446b8b622eSRichard Henderson TCGMemOpIdx oi; 23456b8b622eSRichard Henderson size_t size2; 23466b8b622eSRichard Henderson int i; 23476b8b622eSRichard Henderson 23486b8b622eSRichard Henderson /* 23496b8b622eSRichard Henderson * Ensure the second page is in the TLB. Note that the first page 23506b8b622eSRichard Henderson * is already guaranteed to be filled, and that the second page 23516b8b622eSRichard Henderson * cannot evict the first. 23526b8b622eSRichard Henderson */ 23536b8b622eSRichard Henderson page2 = (addr + size) & TARGET_PAGE_MASK; 23546b8b622eSRichard Henderson size2 = (addr + size) & ~TARGET_PAGE_MASK; 23556b8b622eSRichard Henderson index2 = tlb_index(env, mmu_idx, page2); 23566b8b622eSRichard Henderson entry2 = tlb_entry(env, mmu_idx, page2); 23576b8b622eSRichard Henderson 23586b8b622eSRichard Henderson tlb_addr2 = tlb_addr_write(entry2); 23596b8b622eSRichard Henderson if (!tlb_hit_page(tlb_addr2, page2)) { 23606b8b622eSRichard Henderson if (!victim_tlb_hit(env, mmu_idx, index2, tlb_off, page2)) { 23616b8b622eSRichard Henderson tlb_fill(env_cpu(env), page2, size2, MMU_DATA_STORE, 23626b8b622eSRichard Henderson mmu_idx, retaddr); 23636b8b622eSRichard Henderson index2 = tlb_index(env, mmu_idx, page2); 23646b8b622eSRichard Henderson entry2 = tlb_entry(env, mmu_idx, page2); 23656b8b622eSRichard Henderson } 23666b8b622eSRichard Henderson tlb_addr2 = tlb_addr_write(entry2); 23676b8b622eSRichard Henderson } 23686b8b622eSRichard Henderson 23696b8b622eSRichard Henderson index = tlb_index(env, mmu_idx, addr); 23706b8b622eSRichard Henderson entry = tlb_entry(env, mmu_idx, addr); 23716b8b622eSRichard Henderson tlb_addr = tlb_addr_write(entry); 23726b8b622eSRichard Henderson 23736b8b622eSRichard Henderson /* 23746b8b622eSRichard Henderson * Handle watchpoints. Since this may trap, all checks 23756b8b622eSRichard Henderson * must happen before any store. 23766b8b622eSRichard Henderson */ 23776b8b622eSRichard Henderson if (unlikely(tlb_addr & TLB_WATCHPOINT)) { 23786b8b622eSRichard Henderson cpu_check_watchpoint(env_cpu(env), addr, size - size2, 23796b8b622eSRichard Henderson env_tlb(env)->d[mmu_idx].iotlb[index].attrs, 23806b8b622eSRichard Henderson BP_MEM_WRITE, retaddr); 23816b8b622eSRichard Henderson } 23826b8b622eSRichard Henderson if (unlikely(tlb_addr2 & TLB_WATCHPOINT)) { 23836b8b622eSRichard Henderson cpu_check_watchpoint(env_cpu(env), page2, size2, 23846b8b622eSRichard Henderson env_tlb(env)->d[mmu_idx].iotlb[index2].attrs, 23856b8b622eSRichard Henderson BP_MEM_WRITE, retaddr); 23866b8b622eSRichard Henderson } 23876b8b622eSRichard Henderson 23886b8b622eSRichard Henderson /* 23896b8b622eSRichard Henderson * XXX: not efficient, but simple. 23906b8b622eSRichard Henderson * This loop must go in the forward direction to avoid issues 23916b8b622eSRichard Henderson * with self-modifying code in Windows 64-bit. 23926b8b622eSRichard Henderson */ 23936b8b622eSRichard Henderson oi = make_memop_idx(MO_UB, mmu_idx); 23946b8b622eSRichard Henderson if (big_endian) { 23956b8b622eSRichard Henderson for (i = 0; i < size; ++i) { 23966b8b622eSRichard Henderson /* Big-endian extract. */ 23976b8b622eSRichard Henderson uint8_t val8 = val >> (((size - 1) * 8) - (i * 8)); 23986b8b622eSRichard Henderson helper_ret_stb_mmu(env, addr + i, val8, oi, retaddr); 23996b8b622eSRichard Henderson } 24006b8b622eSRichard Henderson } else { 24016b8b622eSRichard Henderson for (i = 0; i < size; ++i) { 24026b8b622eSRichard Henderson /* Little-endian extract. */ 24036b8b622eSRichard Henderson uint8_t val8 = val >> (i * 8); 24046b8b622eSRichard Henderson helper_ret_stb_mmu(env, addr + i, val8, oi, retaddr); 24056b8b622eSRichard Henderson } 24066b8b622eSRichard Henderson } 24076b8b622eSRichard Henderson } 24086b8b622eSRichard Henderson 240980d9d1c6SRichard Henderson static inline void QEMU_ALWAYS_INLINE 24104601f8d1SRichard Henderson store_helper(CPUArchState *env, target_ulong addr, uint64_t val, 2411be5c4787STony Nguyen TCGMemOpIdx oi, uintptr_t retaddr, MemOp op) 2412eed56642SAlex Bennée { 2413eed56642SAlex Bennée uintptr_t mmu_idx = get_mmuidx(oi); 2414eed56642SAlex Bennée uintptr_t index = tlb_index(env, mmu_idx, addr); 2415eed56642SAlex Bennée CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); 2416eed56642SAlex Bennée target_ulong tlb_addr = tlb_addr_write(entry); 2417eed56642SAlex Bennée const size_t tlb_off = offsetof(CPUTLBEntry, addr_write); 2418eed56642SAlex Bennée unsigned a_bits = get_alignment_bits(get_memop(oi)); 2419eed56642SAlex Bennée void *haddr; 2420be5c4787STony Nguyen size_t size = memop_size(op); 2421eed56642SAlex Bennée 2422eed56642SAlex Bennée /* Handle CPU specific unaligned behaviour */ 2423eed56642SAlex Bennée if (addr & ((1 << a_bits) - 1)) { 242429a0af61SRichard Henderson cpu_unaligned_access(env_cpu(env), addr, MMU_DATA_STORE, 2425eed56642SAlex Bennée mmu_idx, retaddr); 2426eed56642SAlex Bennée } 2427eed56642SAlex Bennée 2428eed56642SAlex Bennée /* If the TLB entry is for a different page, reload and try again. */ 2429eed56642SAlex Bennée if (!tlb_hit(tlb_addr, addr)) { 2430eed56642SAlex Bennée if (!victim_tlb_hit(env, mmu_idx, index, tlb_off, 2431eed56642SAlex Bennée addr & TARGET_PAGE_MASK)) { 243229a0af61SRichard Henderson tlb_fill(env_cpu(env), addr, size, MMU_DATA_STORE, 2433eed56642SAlex Bennée mmu_idx, retaddr); 2434eed56642SAlex Bennée index = tlb_index(env, mmu_idx, addr); 2435eed56642SAlex Bennée entry = tlb_entry(env, mmu_idx, addr); 2436eed56642SAlex Bennée } 2437eed56642SAlex Bennée tlb_addr = tlb_addr_write(entry) & ~TLB_INVALID_MASK; 2438eed56642SAlex Bennée } 2439eed56642SAlex Bennée 244050b107c5SRichard Henderson /* Handle anything that isn't just a straight memory access. */ 2441eed56642SAlex Bennée if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) { 244250b107c5SRichard Henderson CPUIOTLBEntry *iotlbentry; 24435b87b3e6SRichard Henderson bool need_swap; 244450b107c5SRichard Henderson 244550b107c5SRichard Henderson /* For anything that is unaligned, recurse through byte stores. */ 2446eed56642SAlex Bennée if ((addr & (size - 1)) != 0) { 2447eed56642SAlex Bennée goto do_unaligned_access; 2448eed56642SAlex Bennée } 244950b107c5SRichard Henderson 245050b107c5SRichard Henderson iotlbentry = &env_tlb(env)->d[mmu_idx].iotlb[index]; 245150b107c5SRichard Henderson 245250b107c5SRichard Henderson /* Handle watchpoints. */ 245350b107c5SRichard Henderson if (unlikely(tlb_addr & TLB_WATCHPOINT)) { 245450b107c5SRichard Henderson /* On watchpoint hit, this will longjmp out. */ 245550b107c5SRichard Henderson cpu_check_watchpoint(env_cpu(env), addr, size, 245650b107c5SRichard Henderson iotlbentry->attrs, BP_MEM_WRITE, retaddr); 24575b87b3e6SRichard Henderson } 245850b107c5SRichard Henderson 24595b87b3e6SRichard Henderson need_swap = size > 1 && (tlb_addr & TLB_BSWAP); 246050b107c5SRichard Henderson 246150b107c5SRichard Henderson /* Handle I/O access. */ 246208565552SRichard Henderson if (tlb_addr & TLB_MMIO) { 24635b87b3e6SRichard Henderson io_writex(env, iotlbentry, mmu_idx, val, addr, retaddr, 24645b87b3e6SRichard Henderson op ^ (need_swap * MO_BSWAP)); 24655b87b3e6SRichard Henderson return; 24665b87b3e6SRichard Henderson } 24675b87b3e6SRichard Henderson 24687b0d792cSRichard Henderson /* Ignore writes to ROM. */ 24697b0d792cSRichard Henderson if (unlikely(tlb_addr & TLB_DISCARD_WRITE)) { 24707b0d792cSRichard Henderson return; 24717b0d792cSRichard Henderson } 24727b0d792cSRichard Henderson 247308565552SRichard Henderson /* Handle clean RAM pages. */ 247408565552SRichard Henderson if (tlb_addr & TLB_NOTDIRTY) { 2475707526adSRichard Henderson notdirty_write(env_cpu(env), addr, size, iotlbentry, retaddr); 247608565552SRichard Henderson } 247708565552SRichard Henderson 2478707526adSRichard Henderson haddr = (void *)((uintptr_t)addr + entry->addend); 247908565552SRichard Henderson 24805b87b3e6SRichard Henderson /* 24815b87b3e6SRichard Henderson * Keep these two store_memop separate to ensure that the compiler 24825b87b3e6SRichard Henderson * is able to fold the entire function to a single instruction. 24835b87b3e6SRichard Henderson * There is a build-time assert inside to remind you of this. ;-) 24845b87b3e6SRichard Henderson */ 24855b87b3e6SRichard Henderson if (unlikely(need_swap)) { 24865b87b3e6SRichard Henderson store_memop(haddr, val, op ^ MO_BSWAP); 24875b87b3e6SRichard Henderson } else { 24885b87b3e6SRichard Henderson store_memop(haddr, val, op); 24895b87b3e6SRichard Henderson } 2490eed56642SAlex Bennée return; 2491eed56642SAlex Bennée } 2492eed56642SAlex Bennée 2493eed56642SAlex Bennée /* Handle slow unaligned access (it spans two pages or IO). */ 2494eed56642SAlex Bennée if (size > 1 2495eed56642SAlex Bennée && unlikely((addr & ~TARGET_PAGE_MASK) + size - 1 2496eed56642SAlex Bennée >= TARGET_PAGE_SIZE)) { 2497eed56642SAlex Bennée do_unaligned_access: 24986b8b622eSRichard Henderson store_helper_unaligned(env, addr, val, retaddr, size, 24996b8b622eSRichard Henderson mmu_idx, memop_big_endian(op)); 2500eed56642SAlex Bennée return; 2501eed56642SAlex Bennée } 2502eed56642SAlex Bennée 2503eed56642SAlex Bennée haddr = (void *)((uintptr_t)addr + entry->addend); 250480d9d1c6SRichard Henderson store_memop(haddr, val, op); 2505eed56642SAlex Bennée } 2506eed56642SAlex Bennée 25076b8b622eSRichard Henderson void __attribute__((noinline)) 25086b8b622eSRichard Henderson helper_ret_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val, 2509eed56642SAlex Bennée TCGMemOpIdx oi, uintptr_t retaddr) 2510eed56642SAlex Bennée { 2511be5c4787STony Nguyen store_helper(env, addr, val, oi, retaddr, MO_UB); 2512eed56642SAlex Bennée } 2513eed56642SAlex Bennée 2514fc1bc777SRichard Henderson void helper_le_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val, 2515eed56642SAlex Bennée TCGMemOpIdx oi, uintptr_t retaddr) 2516eed56642SAlex Bennée { 2517be5c4787STony Nguyen store_helper(env, addr, val, oi, retaddr, MO_LEUW); 2518eed56642SAlex Bennée } 2519eed56642SAlex Bennée 2520fc1bc777SRichard Henderson void helper_be_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val, 2521eed56642SAlex Bennée TCGMemOpIdx oi, uintptr_t retaddr) 2522eed56642SAlex Bennée { 2523be5c4787STony Nguyen store_helper(env, addr, val, oi, retaddr, MO_BEUW); 2524eed56642SAlex Bennée } 2525eed56642SAlex Bennée 2526fc1bc777SRichard Henderson void helper_le_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val, 2527eed56642SAlex Bennée TCGMemOpIdx oi, uintptr_t retaddr) 2528eed56642SAlex Bennée { 2529be5c4787STony Nguyen store_helper(env, addr, val, oi, retaddr, MO_LEUL); 2530eed56642SAlex Bennée } 2531eed56642SAlex Bennée 2532fc1bc777SRichard Henderson void helper_be_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val, 2533eed56642SAlex Bennée TCGMemOpIdx oi, uintptr_t retaddr) 2534eed56642SAlex Bennée { 2535be5c4787STony Nguyen store_helper(env, addr, val, oi, retaddr, MO_BEUL); 2536eed56642SAlex Bennée } 2537eed56642SAlex Bennée 2538fc1bc777SRichard Henderson void helper_le_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val, 2539eed56642SAlex Bennée TCGMemOpIdx oi, uintptr_t retaddr) 2540eed56642SAlex Bennée { 2541be5c4787STony Nguyen store_helper(env, addr, val, oi, retaddr, MO_LEQ); 2542eed56642SAlex Bennée } 2543eed56642SAlex Bennée 2544fc1bc777SRichard Henderson void helper_be_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val, 2545eed56642SAlex Bennée TCGMemOpIdx oi, uintptr_t retaddr) 2546eed56642SAlex Bennée { 2547be5c4787STony Nguyen store_helper(env, addr, val, oi, retaddr, MO_BEQ); 2548eed56642SAlex Bennée } 2549d9bb58e5SYang Zhong 2550d03f1408SRichard Henderson /* 2551d03f1408SRichard Henderson * Store Helpers for cpu_ldst.h 2552d03f1408SRichard Henderson */ 2553d03f1408SRichard Henderson 2554d03f1408SRichard Henderson static inline void QEMU_ALWAYS_INLINE 2555d03f1408SRichard Henderson cpu_store_helper(CPUArchState *env, target_ulong addr, uint64_t val, 2556d03f1408SRichard Henderson int mmu_idx, uintptr_t retaddr, MemOp op) 2557d03f1408SRichard Henderson { 2558d03f1408SRichard Henderson TCGMemOpIdx oi; 2559d03f1408SRichard Henderson uint16_t meminfo; 2560d03f1408SRichard Henderson 2561d03f1408SRichard Henderson meminfo = trace_mem_get_info(op, mmu_idx, true); 2562d03f1408SRichard Henderson trace_guest_mem_before_exec(env_cpu(env), addr, meminfo); 2563d03f1408SRichard Henderson 2564d03f1408SRichard Henderson oi = make_memop_idx(op, mmu_idx); 2565d03f1408SRichard Henderson store_helper(env, addr, val, oi, retaddr, op); 2566d03f1408SRichard Henderson 2567d03f1408SRichard Henderson qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, meminfo); 2568d03f1408SRichard Henderson } 2569d03f1408SRichard Henderson 2570d03f1408SRichard Henderson void cpu_stb_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val, 2571d03f1408SRichard Henderson int mmu_idx, uintptr_t retaddr) 2572d03f1408SRichard Henderson { 2573d03f1408SRichard Henderson cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_UB); 2574d03f1408SRichard Henderson } 2575d03f1408SRichard Henderson 2576b9e60257SRichard Henderson void cpu_stw_be_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val, 2577d03f1408SRichard Henderson int mmu_idx, uintptr_t retaddr) 2578d03f1408SRichard Henderson { 2579b9e60257SRichard Henderson cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_BEUW); 2580d03f1408SRichard Henderson } 2581d03f1408SRichard Henderson 2582b9e60257SRichard Henderson void cpu_stl_be_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val, 2583d03f1408SRichard Henderson int mmu_idx, uintptr_t retaddr) 2584d03f1408SRichard Henderson { 2585b9e60257SRichard Henderson cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_BEUL); 2586d03f1408SRichard Henderson } 2587d03f1408SRichard Henderson 2588b9e60257SRichard Henderson void cpu_stq_be_mmuidx_ra(CPUArchState *env, target_ulong addr, uint64_t val, 2589d03f1408SRichard Henderson int mmu_idx, uintptr_t retaddr) 2590d03f1408SRichard Henderson { 2591b9e60257SRichard Henderson cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_BEQ); 2592b9e60257SRichard Henderson } 2593b9e60257SRichard Henderson 2594b9e60257SRichard Henderson void cpu_stw_le_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val, 2595b9e60257SRichard Henderson int mmu_idx, uintptr_t retaddr) 2596b9e60257SRichard Henderson { 2597b9e60257SRichard Henderson cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_LEUW); 2598b9e60257SRichard Henderson } 2599b9e60257SRichard Henderson 2600b9e60257SRichard Henderson void cpu_stl_le_mmuidx_ra(CPUArchState *env, target_ulong addr, uint32_t val, 2601b9e60257SRichard Henderson int mmu_idx, uintptr_t retaddr) 2602b9e60257SRichard Henderson { 2603b9e60257SRichard Henderson cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_LEUL); 2604b9e60257SRichard Henderson } 2605b9e60257SRichard Henderson 2606b9e60257SRichard Henderson void cpu_stq_le_mmuidx_ra(CPUArchState *env, target_ulong addr, uint64_t val, 2607b9e60257SRichard Henderson int mmu_idx, uintptr_t retaddr) 2608b9e60257SRichard Henderson { 2609b9e60257SRichard Henderson cpu_store_helper(env, addr, val, mmu_idx, retaddr, MO_LEQ); 2610d03f1408SRichard Henderson } 2611d03f1408SRichard Henderson 2612cfe04a4bSRichard Henderson void cpu_stb_data_ra(CPUArchState *env, target_ulong ptr, 2613cfe04a4bSRichard Henderson uint32_t val, uintptr_t retaddr) 2614cfe04a4bSRichard Henderson { 2615cfe04a4bSRichard Henderson cpu_stb_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr); 2616cfe04a4bSRichard Henderson } 2617cfe04a4bSRichard Henderson 2618b9e60257SRichard Henderson void cpu_stw_be_data_ra(CPUArchState *env, target_ulong ptr, 2619cfe04a4bSRichard Henderson uint32_t val, uintptr_t retaddr) 2620cfe04a4bSRichard Henderson { 2621b9e60257SRichard Henderson cpu_stw_be_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr); 2622cfe04a4bSRichard Henderson } 2623cfe04a4bSRichard Henderson 2624b9e60257SRichard Henderson void cpu_stl_be_data_ra(CPUArchState *env, target_ulong ptr, 2625cfe04a4bSRichard Henderson uint32_t val, uintptr_t retaddr) 2626cfe04a4bSRichard Henderson { 2627b9e60257SRichard Henderson cpu_stl_be_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr); 2628cfe04a4bSRichard Henderson } 2629cfe04a4bSRichard Henderson 2630b9e60257SRichard Henderson void cpu_stq_be_data_ra(CPUArchState *env, target_ulong ptr, 2631cfe04a4bSRichard Henderson uint64_t val, uintptr_t retaddr) 2632cfe04a4bSRichard Henderson { 2633b9e60257SRichard Henderson cpu_stq_be_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr); 2634b9e60257SRichard Henderson } 2635b9e60257SRichard Henderson 2636b9e60257SRichard Henderson void cpu_stw_le_data_ra(CPUArchState *env, target_ulong ptr, 2637b9e60257SRichard Henderson uint32_t val, uintptr_t retaddr) 2638b9e60257SRichard Henderson { 2639b9e60257SRichard Henderson cpu_stw_le_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr); 2640b9e60257SRichard Henderson } 2641b9e60257SRichard Henderson 2642b9e60257SRichard Henderson void cpu_stl_le_data_ra(CPUArchState *env, target_ulong ptr, 2643b9e60257SRichard Henderson uint32_t val, uintptr_t retaddr) 2644b9e60257SRichard Henderson { 2645b9e60257SRichard Henderson cpu_stl_le_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr); 2646b9e60257SRichard Henderson } 2647b9e60257SRichard Henderson 2648b9e60257SRichard Henderson void cpu_stq_le_data_ra(CPUArchState *env, target_ulong ptr, 2649b9e60257SRichard Henderson uint64_t val, uintptr_t retaddr) 2650b9e60257SRichard Henderson { 2651b9e60257SRichard Henderson cpu_stq_le_mmuidx_ra(env, ptr, val, cpu_mmu_index(env, false), retaddr); 2652cfe04a4bSRichard Henderson } 2653cfe04a4bSRichard Henderson 2654cfe04a4bSRichard Henderson void cpu_stb_data(CPUArchState *env, target_ulong ptr, uint32_t val) 2655cfe04a4bSRichard Henderson { 2656cfe04a4bSRichard Henderson cpu_stb_data_ra(env, ptr, val, 0); 2657cfe04a4bSRichard Henderson } 2658cfe04a4bSRichard Henderson 2659b9e60257SRichard Henderson void cpu_stw_be_data(CPUArchState *env, target_ulong ptr, uint32_t val) 2660cfe04a4bSRichard Henderson { 2661b9e60257SRichard Henderson cpu_stw_be_data_ra(env, ptr, val, 0); 2662cfe04a4bSRichard Henderson } 2663cfe04a4bSRichard Henderson 2664b9e60257SRichard Henderson void cpu_stl_be_data(CPUArchState *env, target_ulong ptr, uint32_t val) 2665cfe04a4bSRichard Henderson { 2666b9e60257SRichard Henderson cpu_stl_be_data_ra(env, ptr, val, 0); 2667cfe04a4bSRichard Henderson } 2668cfe04a4bSRichard Henderson 2669b9e60257SRichard Henderson void cpu_stq_be_data(CPUArchState *env, target_ulong ptr, uint64_t val) 2670cfe04a4bSRichard Henderson { 2671b9e60257SRichard Henderson cpu_stq_be_data_ra(env, ptr, val, 0); 2672b9e60257SRichard Henderson } 2673b9e60257SRichard Henderson 2674b9e60257SRichard Henderson void cpu_stw_le_data(CPUArchState *env, target_ulong ptr, uint32_t val) 2675b9e60257SRichard Henderson { 2676b9e60257SRichard Henderson cpu_stw_le_data_ra(env, ptr, val, 0); 2677b9e60257SRichard Henderson } 2678b9e60257SRichard Henderson 2679b9e60257SRichard Henderson void cpu_stl_le_data(CPUArchState *env, target_ulong ptr, uint32_t val) 2680b9e60257SRichard Henderson { 2681b9e60257SRichard Henderson cpu_stl_le_data_ra(env, ptr, val, 0); 2682b9e60257SRichard Henderson } 2683b9e60257SRichard Henderson 2684b9e60257SRichard Henderson void cpu_stq_le_data(CPUArchState *env, target_ulong ptr, uint64_t val) 2685b9e60257SRichard Henderson { 2686b9e60257SRichard Henderson cpu_stq_le_data_ra(env, ptr, val, 0); 2687cfe04a4bSRichard Henderson } 2688cfe04a4bSRichard Henderson 2689d9bb58e5SYang Zhong /* First set of helpers allows passing in of OI and RETADDR. This makes 2690d9bb58e5SYang Zhong them callable from other helpers. */ 2691d9bb58e5SYang Zhong 2692d9bb58e5SYang Zhong #define EXTRA_ARGS , TCGMemOpIdx oi, uintptr_t retaddr 2693d9bb58e5SYang Zhong #define ATOMIC_NAME(X) \ 2694d9bb58e5SYang Zhong HELPER(glue(glue(glue(atomic_ ## X, SUFFIX), END), _mmu)) 2695707526adSRichard Henderson #define ATOMIC_MMU_DECLS 269608dff435SRichard Henderson #define ATOMIC_MMU_LOOKUP_RW \ 269708dff435SRichard Henderson atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_READ | PAGE_WRITE, retaddr) 269808dff435SRichard Henderson #define ATOMIC_MMU_LOOKUP_R \ 269908dff435SRichard Henderson atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_READ, retaddr) 270008dff435SRichard Henderson #define ATOMIC_MMU_LOOKUP_W \ 270108dff435SRichard Henderson atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_WRITE, retaddr) 2702707526adSRichard Henderson #define ATOMIC_MMU_CLEANUP 2703504f73f7SAlex Bennée #define ATOMIC_MMU_IDX get_mmuidx(oi) 2704d9bb58e5SYang Zhong 2705139c1837SPaolo Bonzini #include "atomic_common.c.inc" 2706d9bb58e5SYang Zhong 2707d9bb58e5SYang Zhong #define DATA_SIZE 1 2708d9bb58e5SYang Zhong #include "atomic_template.h" 2709d9bb58e5SYang Zhong 2710d9bb58e5SYang Zhong #define DATA_SIZE 2 2711d9bb58e5SYang Zhong #include "atomic_template.h" 2712d9bb58e5SYang Zhong 2713d9bb58e5SYang Zhong #define DATA_SIZE 4 2714d9bb58e5SYang Zhong #include "atomic_template.h" 2715d9bb58e5SYang Zhong 2716d9bb58e5SYang Zhong #ifdef CONFIG_ATOMIC64 2717d9bb58e5SYang Zhong #define DATA_SIZE 8 2718d9bb58e5SYang Zhong #include "atomic_template.h" 2719d9bb58e5SYang Zhong #endif 2720d9bb58e5SYang Zhong 2721e6cd4bb5SRichard Henderson #if HAVE_CMPXCHG128 || HAVE_ATOMIC128 2722d9bb58e5SYang Zhong #define DATA_SIZE 16 2723d9bb58e5SYang Zhong #include "atomic_template.h" 2724d9bb58e5SYang Zhong #endif 2725d9bb58e5SYang Zhong 2726d9bb58e5SYang Zhong /* Second set of helpers are directly callable from TCG as helpers. */ 2727d9bb58e5SYang Zhong 2728d9bb58e5SYang Zhong #undef EXTRA_ARGS 2729d9bb58e5SYang Zhong #undef ATOMIC_NAME 273008dff435SRichard Henderson #undef ATOMIC_MMU_LOOKUP_RW 273108dff435SRichard Henderson #undef ATOMIC_MMU_LOOKUP_R 273208dff435SRichard Henderson #undef ATOMIC_MMU_LOOKUP_W 273308dff435SRichard Henderson 2734d9bb58e5SYang Zhong #define EXTRA_ARGS , TCGMemOpIdx oi 2735d9bb58e5SYang Zhong #define ATOMIC_NAME(X) HELPER(glue(glue(atomic_ ## X, SUFFIX), END)) 273608dff435SRichard Henderson #define ATOMIC_MMU_LOOKUP_RW \ 273708dff435SRichard Henderson atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_READ | PAGE_WRITE, GETPC()) 273808dff435SRichard Henderson #define ATOMIC_MMU_LOOKUP_R \ 273908dff435SRichard Henderson atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_READ, GETPC()) 274008dff435SRichard Henderson #define ATOMIC_MMU_LOOKUP_W \ 274108dff435SRichard Henderson atomic_mmu_lookup(env, addr, oi, DATA_SIZE, PAGE_WRITE, GETPC()) 2742d9bb58e5SYang Zhong 2743d9bb58e5SYang Zhong #define DATA_SIZE 1 2744d9bb58e5SYang Zhong #include "atomic_template.h" 2745d9bb58e5SYang Zhong 2746d9bb58e5SYang Zhong #define DATA_SIZE 2 2747d9bb58e5SYang Zhong #include "atomic_template.h" 2748d9bb58e5SYang Zhong 2749d9bb58e5SYang Zhong #define DATA_SIZE 4 2750d9bb58e5SYang Zhong #include "atomic_template.h" 2751d9bb58e5SYang Zhong 2752d9bb58e5SYang Zhong #ifdef CONFIG_ATOMIC64 2753d9bb58e5SYang Zhong #define DATA_SIZE 8 2754d9bb58e5SYang Zhong #include "atomic_template.h" 2755d9bb58e5SYang Zhong #endif 2756504f73f7SAlex Bennée #undef ATOMIC_MMU_IDX 2757d9bb58e5SYang Zhong 2758d9bb58e5SYang Zhong /* Code access functions. */ 2759d9bb58e5SYang Zhong 2760fc4120a3SRichard Henderson static uint64_t full_ldub_code(CPUArchState *env, target_ulong addr, 27612dd92606SRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 27622dd92606SRichard Henderson { 2763fc4120a3SRichard Henderson return load_helper(env, addr, oi, retaddr, MO_8, true, full_ldub_code); 27642dd92606SRichard Henderson } 27652dd92606SRichard Henderson 2766fc4120a3SRichard Henderson uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr addr) 2767eed56642SAlex Bennée { 2768fc4120a3SRichard Henderson TCGMemOpIdx oi = make_memop_idx(MO_UB, cpu_mmu_index(env, true)); 2769fc4120a3SRichard Henderson return full_ldub_code(env, addr, oi, 0); 27702dd92606SRichard Henderson } 27712dd92606SRichard Henderson 2772fc4120a3SRichard Henderson static uint64_t full_lduw_code(CPUArchState *env, target_ulong addr, 27734cef72d0SAlex Bennée TCGMemOpIdx oi, uintptr_t retaddr) 27744cef72d0SAlex Bennée { 2775fc4120a3SRichard Henderson return load_helper(env, addr, oi, retaddr, MO_TEUW, true, full_lduw_code); 27764cef72d0SAlex Bennée } 27774cef72d0SAlex Bennée 2778fc4120a3SRichard Henderson uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr addr) 27792dd92606SRichard Henderson { 2780fc4120a3SRichard Henderson TCGMemOpIdx oi = make_memop_idx(MO_TEUW, cpu_mmu_index(env, true)); 2781fc4120a3SRichard Henderson return full_lduw_code(env, addr, oi, 0); 2782eed56642SAlex Bennée } 2783d9bb58e5SYang Zhong 2784fc4120a3SRichard Henderson static uint64_t full_ldl_code(CPUArchState *env, target_ulong addr, 2785fc1bc777SRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 2786eed56642SAlex Bennée { 2787fc4120a3SRichard Henderson return load_helper(env, addr, oi, retaddr, MO_TEUL, true, full_ldl_code); 27882dd92606SRichard Henderson } 27892dd92606SRichard Henderson 2790fc4120a3SRichard Henderson uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr addr) 27914cef72d0SAlex Bennée { 2792fc4120a3SRichard Henderson TCGMemOpIdx oi = make_memop_idx(MO_TEUL, cpu_mmu_index(env, true)); 2793fc4120a3SRichard Henderson return full_ldl_code(env, addr, oi, 0); 27944cef72d0SAlex Bennée } 27954cef72d0SAlex Bennée 2796fc4120a3SRichard Henderson static uint64_t full_ldq_code(CPUArchState *env, target_ulong addr, 27972dd92606SRichard Henderson TCGMemOpIdx oi, uintptr_t retaddr) 27982dd92606SRichard Henderson { 2799fc4120a3SRichard Henderson return load_helper(env, addr, oi, retaddr, MO_TEQ, true, full_ldq_code); 2800eed56642SAlex Bennée } 2801d9bb58e5SYang Zhong 2802fc4120a3SRichard Henderson uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr addr) 2803eed56642SAlex Bennée { 2804fc4120a3SRichard Henderson TCGMemOpIdx oi = make_memop_idx(MO_TEQ, cpu_mmu_index(env, true)); 2805fc4120a3SRichard Henderson return full_ldq_code(env, addr, oi, 0); 2806eed56642SAlex Bennée } 2807