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" 32c213ee2dSRichard Henderson #include "exec/helper-proto-common.h" 33d9bb58e5SYang Zhong #include "qemu/atomic.h" 34e6cd4bb5SRichard Henderson #include "qemu/atomic128.h" 353b9bd3f4SPaolo Bonzini #include "exec/translate-all.h" 3651807763SPhilippe Mathieu-Daudé #include "trace.h" 37e5ceadffSPhilippe Mathieu-Daudé #include "tb-hash.h" 3865269192SPhilippe Mathieu-Daudé #include "internal.h" 39235537faSAlex Bennée #ifdef CONFIG_PLUGIN 40235537faSAlex Bennée #include "qemu/plugin-memory.h" 41235537faSAlex Bennée #endif 42d2ba8026SRichard Henderson #include "tcg/tcg-ldst.h" 4370f168f8SRichard Henderson #include "tcg/oversized-guest.h" 44d9bb58e5SYang Zhong 45d9bb58e5SYang Zhong /* DEBUG defines, enable DEBUG_TLB_LOG to log to the CPU_LOG_MMU target */ 46d9bb58e5SYang Zhong /* #define DEBUG_TLB */ 47d9bb58e5SYang Zhong /* #define DEBUG_TLB_LOG */ 48d9bb58e5SYang Zhong 49d9bb58e5SYang Zhong #ifdef DEBUG_TLB 50d9bb58e5SYang Zhong # define DEBUG_TLB_GATE 1 51d9bb58e5SYang Zhong # ifdef DEBUG_TLB_LOG 52d9bb58e5SYang Zhong # define DEBUG_TLB_LOG_GATE 1 53d9bb58e5SYang Zhong # else 54d9bb58e5SYang Zhong # define DEBUG_TLB_LOG_GATE 0 55d9bb58e5SYang Zhong # endif 56d9bb58e5SYang Zhong #else 57d9bb58e5SYang Zhong # define DEBUG_TLB_GATE 0 58d9bb58e5SYang Zhong # define DEBUG_TLB_LOG_GATE 0 59d9bb58e5SYang Zhong #endif 60d9bb58e5SYang Zhong 61d9bb58e5SYang Zhong #define tlb_debug(fmt, ...) do { \ 62d9bb58e5SYang Zhong if (DEBUG_TLB_LOG_GATE) { \ 63d9bb58e5SYang Zhong qemu_log_mask(CPU_LOG_MMU, "%s: " fmt, __func__, \ 64d9bb58e5SYang Zhong ## __VA_ARGS__); \ 65d9bb58e5SYang Zhong } else if (DEBUG_TLB_GATE) { \ 66d9bb58e5SYang Zhong fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); \ 67d9bb58e5SYang Zhong } \ 68d9bb58e5SYang Zhong } while (0) 69d9bb58e5SYang Zhong 70ea9025cbSEmilio G. Cota #define assert_cpu_is_self(cpu) do { \ 71d9bb58e5SYang Zhong if (DEBUG_TLB_GATE) { \ 72ea9025cbSEmilio G. Cota g_assert(!(cpu)->created || qemu_cpu_is_self(cpu)); \ 73d9bb58e5SYang Zhong } \ 74d9bb58e5SYang Zhong } while (0) 75d9bb58e5SYang Zhong 76d9bb58e5SYang Zhong /* run_on_cpu_data.target_ptr should always be big enough for a 77d9bb58e5SYang Zhong * target_ulong even on 32 bit builds */ 78d9bb58e5SYang Zhong QEMU_BUILD_BUG_ON(sizeof(target_ulong) > sizeof(run_on_cpu_data)); 79d9bb58e5SYang Zhong 80d9bb58e5SYang Zhong /* We currently can't handle more than 16 bits in the MMUIDX bitmask. 81d9bb58e5SYang Zhong */ 82d9bb58e5SYang Zhong QEMU_BUILD_BUG_ON(NB_MMU_MODES > 16); 83d9bb58e5SYang Zhong #define ALL_MMUIDX_BITS ((1 << NB_MMU_MODES) - 1) 84d9bb58e5SYang Zhong 85722a1c1eSRichard Henderson static inline size_t tlb_n_entries(CPUTLBDescFast *fast) 867a1efe1bSRichard Henderson { 87722a1c1eSRichard Henderson return (fast->mask >> CPU_TLB_ENTRY_BITS) + 1; 887a1efe1bSRichard Henderson } 897a1efe1bSRichard Henderson 90722a1c1eSRichard Henderson static inline size_t sizeof_tlb(CPUTLBDescFast *fast) 9186e1eff8SEmilio G. Cota { 92722a1c1eSRichard Henderson return fast->mask + (1 << CPU_TLB_ENTRY_BITS); 9386e1eff8SEmilio G. Cota } 9486e1eff8SEmilio G. Cota 9579e42085SRichard Henderson static void tlb_window_reset(CPUTLBDesc *desc, int64_t ns, 9686e1eff8SEmilio G. Cota size_t max_entries) 9786e1eff8SEmilio G. Cota { 9879e42085SRichard Henderson desc->window_begin_ns = ns; 9979e42085SRichard Henderson desc->window_max_entries = max_entries; 10086e1eff8SEmilio G. Cota } 10186e1eff8SEmilio G. Cota 10206f3831cSAnton Johansson static void tb_jmp_cache_clear_page(CPUState *cpu, vaddr page_addr) 1030f4abea8SRichard Henderson { 104a976a99aSRichard Henderson CPUJumpCache *jc = cpu->tb_jmp_cache; 10599ab4d50SEric Auger int i, i0; 1060f4abea8SRichard Henderson 10799ab4d50SEric Auger if (unlikely(!jc)) { 10899ab4d50SEric Auger return; 10999ab4d50SEric Auger } 11099ab4d50SEric Auger 11199ab4d50SEric Auger i0 = tb_jmp_cache_hash_page(page_addr); 1120f4abea8SRichard Henderson for (i = 0; i < TB_JMP_PAGE_SIZE; i++) { 113a976a99aSRichard Henderson qatomic_set(&jc->array[i0 + i].tb, NULL); 1140f4abea8SRichard Henderson } 1150f4abea8SRichard Henderson } 1160f4abea8SRichard Henderson 11786e1eff8SEmilio G. Cota /** 11886e1eff8SEmilio G. Cota * tlb_mmu_resize_locked() - perform TLB resize bookkeeping; resize if necessary 11971ccd47bSRichard Henderson * @desc: The CPUTLBDesc portion of the TLB 12071ccd47bSRichard Henderson * @fast: The CPUTLBDescFast portion of the same TLB 12186e1eff8SEmilio G. Cota * 12286e1eff8SEmilio G. Cota * Called with tlb_lock_held. 12386e1eff8SEmilio G. Cota * 12486e1eff8SEmilio G. Cota * We have two main constraints when resizing a TLB: (1) we only resize it 12586e1eff8SEmilio G. Cota * on a TLB flush (otherwise we'd have to take a perf hit by either rehashing 12686e1eff8SEmilio G. Cota * the array or unnecessarily flushing it), which means we do not control how 12786e1eff8SEmilio G. Cota * frequently the resizing can occur; (2) we don't have access to the guest's 12886e1eff8SEmilio G. Cota * future scheduling decisions, and therefore have to decide the magnitude of 12986e1eff8SEmilio G. Cota * the resize based on past observations. 13086e1eff8SEmilio G. Cota * 13186e1eff8SEmilio G. Cota * In general, a memory-hungry process can benefit greatly from an appropriately 13286e1eff8SEmilio G. Cota * sized TLB, since a guest TLB miss is very expensive. This doesn't mean that 13386e1eff8SEmilio G. Cota * we just have to make the TLB as large as possible; while an oversized TLB 13486e1eff8SEmilio G. Cota * results in minimal TLB miss rates, it also takes longer to be flushed 13586e1eff8SEmilio G. Cota * (flushes can be _very_ frequent), and the reduced locality can also hurt 13686e1eff8SEmilio G. Cota * performance. 13786e1eff8SEmilio G. Cota * 13886e1eff8SEmilio G. Cota * To achieve near-optimal performance for all kinds of workloads, we: 13986e1eff8SEmilio G. Cota * 14086e1eff8SEmilio G. Cota * 1. Aggressively increase the size of the TLB when the use rate of the 14186e1eff8SEmilio G. Cota * TLB being flushed is high, since it is likely that in the near future this 14286e1eff8SEmilio G. Cota * memory-hungry process will execute again, and its memory hungriness will 14386e1eff8SEmilio G. Cota * probably be similar. 14486e1eff8SEmilio G. Cota * 14586e1eff8SEmilio G. Cota * 2. Slowly reduce the size of the TLB as the use rate declines over a 14686e1eff8SEmilio G. Cota * reasonably large time window. The rationale is that if in such a time window 14786e1eff8SEmilio G. Cota * we have not observed a high TLB use rate, it is likely that we won't observe 14886e1eff8SEmilio G. Cota * it in the near future. In that case, once a time window expires we downsize 14986e1eff8SEmilio G. Cota * the TLB to match the maximum use rate observed in the window. 15086e1eff8SEmilio G. Cota * 15186e1eff8SEmilio G. Cota * 3. Try to keep the maximum use rate in a time window in the 30-70% range, 15286e1eff8SEmilio G. Cota * since in that range performance is likely near-optimal. Recall that the TLB 15386e1eff8SEmilio G. Cota * is direct mapped, so we want the use rate to be low (or at least not too 15486e1eff8SEmilio G. Cota * high), since otherwise we are likely to have a significant amount of 15586e1eff8SEmilio G. Cota * conflict misses. 15686e1eff8SEmilio G. Cota */ 1573c3959f2SRichard Henderson static void tlb_mmu_resize_locked(CPUTLBDesc *desc, CPUTLBDescFast *fast, 1583c3959f2SRichard Henderson int64_t now) 15986e1eff8SEmilio G. Cota { 16071ccd47bSRichard Henderson size_t old_size = tlb_n_entries(fast); 16186e1eff8SEmilio G. Cota size_t rate; 16286e1eff8SEmilio G. Cota size_t new_size = old_size; 16386e1eff8SEmilio G. Cota int64_t window_len_ms = 100; 16486e1eff8SEmilio G. Cota int64_t window_len_ns = window_len_ms * 1000 * 1000; 16579e42085SRichard Henderson bool window_expired = now > desc->window_begin_ns + window_len_ns; 16686e1eff8SEmilio G. Cota 16779e42085SRichard Henderson if (desc->n_used_entries > desc->window_max_entries) { 16879e42085SRichard Henderson desc->window_max_entries = desc->n_used_entries; 16986e1eff8SEmilio G. Cota } 17079e42085SRichard Henderson rate = desc->window_max_entries * 100 / old_size; 17186e1eff8SEmilio G. Cota 17286e1eff8SEmilio G. Cota if (rate > 70) { 17386e1eff8SEmilio G. Cota new_size = MIN(old_size << 1, 1 << CPU_TLB_DYN_MAX_BITS); 17486e1eff8SEmilio G. Cota } else if (rate < 30 && window_expired) { 17579e42085SRichard Henderson size_t ceil = pow2ceil(desc->window_max_entries); 17679e42085SRichard Henderson size_t expected_rate = desc->window_max_entries * 100 / ceil; 17786e1eff8SEmilio G. Cota 17886e1eff8SEmilio G. Cota /* 17986e1eff8SEmilio G. Cota * Avoid undersizing when the max number of entries seen is just below 18086e1eff8SEmilio G. Cota * a pow2. For instance, if max_entries == 1025, the expected use rate 18186e1eff8SEmilio G. Cota * would be 1025/2048==50%. However, if max_entries == 1023, we'd get 18286e1eff8SEmilio G. Cota * 1023/1024==99.9% use rate, so we'd likely end up doubling the size 18386e1eff8SEmilio G. Cota * later. Thus, make sure that the expected use rate remains below 70%. 18486e1eff8SEmilio G. Cota * (and since we double the size, that means the lowest rate we'd 18586e1eff8SEmilio G. Cota * expect to get is 35%, which is still in the 30-70% range where 18686e1eff8SEmilio G. Cota * we consider that the size is appropriate.) 18786e1eff8SEmilio G. Cota */ 18886e1eff8SEmilio G. Cota if (expected_rate > 70) { 18986e1eff8SEmilio G. Cota ceil *= 2; 19086e1eff8SEmilio G. Cota } 19186e1eff8SEmilio G. Cota new_size = MAX(ceil, 1 << CPU_TLB_DYN_MIN_BITS); 19286e1eff8SEmilio G. Cota } 19386e1eff8SEmilio G. Cota 19486e1eff8SEmilio G. Cota if (new_size == old_size) { 19586e1eff8SEmilio G. Cota if (window_expired) { 19679e42085SRichard Henderson tlb_window_reset(desc, now, desc->n_used_entries); 19786e1eff8SEmilio G. Cota } 19886e1eff8SEmilio G. Cota return; 19986e1eff8SEmilio G. Cota } 20086e1eff8SEmilio G. Cota 20171ccd47bSRichard Henderson g_free(fast->table); 20225d3ec58SRichard Henderson g_free(desc->fulltlb); 20386e1eff8SEmilio G. Cota 20479e42085SRichard Henderson tlb_window_reset(desc, now, 0); 20586e1eff8SEmilio G. Cota /* desc->n_used_entries is cleared by the caller */ 20671ccd47bSRichard Henderson fast->mask = (new_size - 1) << CPU_TLB_ENTRY_BITS; 20771ccd47bSRichard Henderson fast->table = g_try_new(CPUTLBEntry, new_size); 20825d3ec58SRichard Henderson desc->fulltlb = g_try_new(CPUTLBEntryFull, new_size); 20971ccd47bSRichard Henderson 21086e1eff8SEmilio G. Cota /* 21186e1eff8SEmilio G. Cota * If the allocations fail, try smaller sizes. We just freed some 21286e1eff8SEmilio G. Cota * memory, so going back to half of new_size has a good chance of working. 21386e1eff8SEmilio G. Cota * Increased memory pressure elsewhere in the system might cause the 21486e1eff8SEmilio G. Cota * allocations to fail though, so we progressively reduce the allocation 21586e1eff8SEmilio G. Cota * size, aborting if we cannot even allocate the smallest TLB we support. 21686e1eff8SEmilio G. Cota */ 21725d3ec58SRichard Henderson while (fast->table == NULL || desc->fulltlb == NULL) { 21886e1eff8SEmilio G. Cota if (new_size == (1 << CPU_TLB_DYN_MIN_BITS)) { 21986e1eff8SEmilio G. Cota error_report("%s: %s", __func__, strerror(errno)); 22086e1eff8SEmilio G. Cota abort(); 22186e1eff8SEmilio G. Cota } 22286e1eff8SEmilio G. Cota new_size = MAX(new_size >> 1, 1 << CPU_TLB_DYN_MIN_BITS); 22371ccd47bSRichard Henderson fast->mask = (new_size - 1) << CPU_TLB_ENTRY_BITS; 22486e1eff8SEmilio G. Cota 22571ccd47bSRichard Henderson g_free(fast->table); 22625d3ec58SRichard Henderson g_free(desc->fulltlb); 22771ccd47bSRichard Henderson fast->table = g_try_new(CPUTLBEntry, new_size); 22825d3ec58SRichard Henderson desc->fulltlb = g_try_new(CPUTLBEntryFull, new_size); 22986e1eff8SEmilio G. Cota } 23086e1eff8SEmilio G. Cota } 23186e1eff8SEmilio G. Cota 232bbf021b0SRichard Henderson static void tlb_mmu_flush_locked(CPUTLBDesc *desc, CPUTLBDescFast *fast) 23386e1eff8SEmilio G. Cota { 2345c948e31SRichard Henderson desc->n_used_entries = 0; 2355c948e31SRichard Henderson desc->large_page_addr = -1; 2365c948e31SRichard Henderson desc->large_page_mask = -1; 2375c948e31SRichard Henderson desc->vindex = 0; 2385c948e31SRichard Henderson memset(fast->table, -1, sizeof_tlb(fast)); 2395c948e31SRichard Henderson memset(desc->vtable, -1, sizeof(desc->vtable)); 24086e1eff8SEmilio G. Cota } 24186e1eff8SEmilio G. Cota 2423c3959f2SRichard Henderson static void tlb_flush_one_mmuidx_locked(CPUArchState *env, int mmu_idx, 2433c3959f2SRichard Henderson int64_t now) 244bbf021b0SRichard Henderson { 245bbf021b0SRichard Henderson CPUTLBDesc *desc = &env_tlb(env)->d[mmu_idx]; 246bbf021b0SRichard Henderson CPUTLBDescFast *fast = &env_tlb(env)->f[mmu_idx]; 247bbf021b0SRichard Henderson 2483c3959f2SRichard Henderson tlb_mmu_resize_locked(desc, fast, now); 249bbf021b0SRichard Henderson tlb_mmu_flush_locked(desc, fast); 250bbf021b0SRichard Henderson } 251bbf021b0SRichard Henderson 25256e89f76SRichard Henderson static void tlb_mmu_init(CPUTLBDesc *desc, CPUTLBDescFast *fast, int64_t now) 25356e89f76SRichard Henderson { 25456e89f76SRichard Henderson size_t n_entries = 1 << CPU_TLB_DYN_DEFAULT_BITS; 25556e89f76SRichard Henderson 25656e89f76SRichard Henderson tlb_window_reset(desc, now, 0); 25756e89f76SRichard Henderson desc->n_used_entries = 0; 25856e89f76SRichard Henderson fast->mask = (n_entries - 1) << CPU_TLB_ENTRY_BITS; 25956e89f76SRichard Henderson fast->table = g_new(CPUTLBEntry, n_entries); 26025d3ec58SRichard Henderson desc->fulltlb = g_new(CPUTLBEntryFull, n_entries); 2613c16304aSRichard Henderson tlb_mmu_flush_locked(desc, fast); 26256e89f76SRichard Henderson } 26356e89f76SRichard Henderson 26486e1eff8SEmilio G. Cota static inline void tlb_n_used_entries_inc(CPUArchState *env, uintptr_t mmu_idx) 26586e1eff8SEmilio G. Cota { 266a40ec84eSRichard Henderson env_tlb(env)->d[mmu_idx].n_used_entries++; 26786e1eff8SEmilio G. Cota } 26886e1eff8SEmilio G. Cota 26986e1eff8SEmilio G. Cota static inline void tlb_n_used_entries_dec(CPUArchState *env, uintptr_t mmu_idx) 27086e1eff8SEmilio G. Cota { 271a40ec84eSRichard Henderson env_tlb(env)->d[mmu_idx].n_used_entries--; 27286e1eff8SEmilio G. Cota } 27386e1eff8SEmilio G. Cota 2745005e253SEmilio G. Cota void tlb_init(CPUState *cpu) 2755005e253SEmilio G. Cota { 27671aec354SEmilio G. Cota CPUArchState *env = cpu->env_ptr; 27756e89f76SRichard Henderson int64_t now = get_clock_realtime(); 27856e89f76SRichard Henderson int i; 27971aec354SEmilio G. Cota 280a40ec84eSRichard Henderson qemu_spin_init(&env_tlb(env)->c.lock); 2813d1523ceSRichard Henderson 2823c16304aSRichard Henderson /* All tlbs are initialized flushed. */ 2833c16304aSRichard Henderson env_tlb(env)->c.dirty = 0; 28486e1eff8SEmilio G. Cota 28556e89f76SRichard Henderson for (i = 0; i < NB_MMU_MODES; i++) { 28656e89f76SRichard Henderson tlb_mmu_init(&env_tlb(env)->d[i], &env_tlb(env)->f[i], now); 28756e89f76SRichard Henderson } 2885005e253SEmilio G. Cota } 2895005e253SEmilio G. Cota 290816d9be5SEmilio G. Cota void tlb_destroy(CPUState *cpu) 291816d9be5SEmilio G. Cota { 292816d9be5SEmilio G. Cota CPUArchState *env = cpu->env_ptr; 293816d9be5SEmilio G. Cota int i; 294816d9be5SEmilio G. Cota 295816d9be5SEmilio G. Cota qemu_spin_destroy(&env_tlb(env)->c.lock); 296816d9be5SEmilio G. Cota for (i = 0; i < NB_MMU_MODES; i++) { 297816d9be5SEmilio G. Cota CPUTLBDesc *desc = &env_tlb(env)->d[i]; 298816d9be5SEmilio G. Cota CPUTLBDescFast *fast = &env_tlb(env)->f[i]; 299816d9be5SEmilio G. Cota 300816d9be5SEmilio G. Cota g_free(fast->table); 30125d3ec58SRichard Henderson g_free(desc->fulltlb); 302816d9be5SEmilio G. Cota } 303816d9be5SEmilio G. Cota } 304816d9be5SEmilio G. Cota 305d9bb58e5SYang Zhong /* flush_all_helper: run fn across all cpus 306d9bb58e5SYang Zhong * 307d9bb58e5SYang Zhong * If the wait flag is set then the src cpu's helper will be queued as 308d9bb58e5SYang Zhong * "safe" work and the loop exited creating a synchronisation point 309d9bb58e5SYang Zhong * where all queued work will be finished before execution starts 310d9bb58e5SYang Zhong * again. 311d9bb58e5SYang Zhong */ 312d9bb58e5SYang Zhong static void flush_all_helper(CPUState *src, run_on_cpu_func fn, 313d9bb58e5SYang Zhong run_on_cpu_data d) 314d9bb58e5SYang Zhong { 315d9bb58e5SYang Zhong CPUState *cpu; 316d9bb58e5SYang Zhong 317d9bb58e5SYang Zhong CPU_FOREACH(cpu) { 318d9bb58e5SYang Zhong if (cpu != src) { 319d9bb58e5SYang Zhong async_run_on_cpu(cpu, fn, d); 320d9bb58e5SYang Zhong } 321d9bb58e5SYang Zhong } 322d9bb58e5SYang Zhong } 323d9bb58e5SYang Zhong 324e09de0a2SRichard Henderson void tlb_flush_counts(size_t *pfull, size_t *ppart, size_t *pelide) 32583974cf4SEmilio G. Cota { 32683974cf4SEmilio G. Cota CPUState *cpu; 327e09de0a2SRichard Henderson size_t full = 0, part = 0, elide = 0; 32883974cf4SEmilio G. Cota 32983974cf4SEmilio G. Cota CPU_FOREACH(cpu) { 33083974cf4SEmilio G. Cota CPUArchState *env = cpu->env_ptr; 33183974cf4SEmilio G. Cota 332d73415a3SStefan Hajnoczi full += qatomic_read(&env_tlb(env)->c.full_flush_count); 333d73415a3SStefan Hajnoczi part += qatomic_read(&env_tlb(env)->c.part_flush_count); 334d73415a3SStefan Hajnoczi elide += qatomic_read(&env_tlb(env)->c.elide_flush_count); 33583974cf4SEmilio G. Cota } 336e09de0a2SRichard Henderson *pfull = full; 337e09de0a2SRichard Henderson *ppart = part; 338e09de0a2SRichard Henderson *pelide = elide; 33983974cf4SEmilio G. Cota } 340d9bb58e5SYang Zhong 341d9bb58e5SYang Zhong static void tlb_flush_by_mmuidx_async_work(CPUState *cpu, run_on_cpu_data data) 342d9bb58e5SYang Zhong { 343d9bb58e5SYang Zhong CPUArchState *env = cpu->env_ptr; 3443d1523ceSRichard Henderson uint16_t asked = data.host_int; 3453d1523ceSRichard Henderson uint16_t all_dirty, work, to_clean; 3463c3959f2SRichard Henderson int64_t now = get_clock_realtime(); 347d9bb58e5SYang Zhong 348d9bb58e5SYang Zhong assert_cpu_is_self(cpu); 349d9bb58e5SYang Zhong 3503d1523ceSRichard Henderson tlb_debug("mmu_idx:0x%04" PRIx16 "\n", asked); 351d9bb58e5SYang Zhong 352a40ec84eSRichard Henderson qemu_spin_lock(&env_tlb(env)->c.lock); 35360a2ad7dSRichard Henderson 354a40ec84eSRichard Henderson all_dirty = env_tlb(env)->c.dirty; 3553d1523ceSRichard Henderson to_clean = asked & all_dirty; 3563d1523ceSRichard Henderson all_dirty &= ~to_clean; 357a40ec84eSRichard Henderson env_tlb(env)->c.dirty = all_dirty; 3583d1523ceSRichard Henderson 3593d1523ceSRichard Henderson for (work = to_clean; work != 0; work &= work - 1) { 3603d1523ceSRichard Henderson int mmu_idx = ctz32(work); 3613c3959f2SRichard Henderson tlb_flush_one_mmuidx_locked(env, mmu_idx, now); 362d9bb58e5SYang Zhong } 3633d1523ceSRichard Henderson 364a40ec84eSRichard Henderson qemu_spin_unlock(&env_tlb(env)->c.lock); 365d9bb58e5SYang Zhong 366a976a99aSRichard Henderson tcg_flush_jmp_cache(cpu); 36764f2674bSRichard Henderson 3683d1523ceSRichard Henderson if (to_clean == ALL_MMUIDX_BITS) { 369d73415a3SStefan Hajnoczi qatomic_set(&env_tlb(env)->c.full_flush_count, 370a40ec84eSRichard Henderson env_tlb(env)->c.full_flush_count + 1); 371e09de0a2SRichard Henderson } else { 372d73415a3SStefan Hajnoczi qatomic_set(&env_tlb(env)->c.part_flush_count, 373a40ec84eSRichard Henderson env_tlb(env)->c.part_flush_count + ctpop16(to_clean)); 3743d1523ceSRichard Henderson if (to_clean != asked) { 375d73415a3SStefan Hajnoczi qatomic_set(&env_tlb(env)->c.elide_flush_count, 376a40ec84eSRichard Henderson env_tlb(env)->c.elide_flush_count + 3773d1523ceSRichard Henderson ctpop16(asked & ~to_clean)); 3783d1523ceSRichard Henderson } 37964f2674bSRichard Henderson } 380d9bb58e5SYang Zhong } 381d9bb58e5SYang Zhong 382d9bb58e5SYang Zhong void tlb_flush_by_mmuidx(CPUState *cpu, uint16_t idxmap) 383d9bb58e5SYang Zhong { 384d9bb58e5SYang Zhong tlb_debug("mmu_idx: 0x%" PRIx16 "\n", idxmap); 385d9bb58e5SYang Zhong 38664f2674bSRichard Henderson if (cpu->created && !qemu_cpu_is_self(cpu)) { 387d9bb58e5SYang Zhong async_run_on_cpu(cpu, tlb_flush_by_mmuidx_async_work, 388ab651105SRichard Henderson RUN_ON_CPU_HOST_INT(idxmap)); 389d9bb58e5SYang Zhong } else { 39060a2ad7dSRichard Henderson tlb_flush_by_mmuidx_async_work(cpu, RUN_ON_CPU_HOST_INT(idxmap)); 391d9bb58e5SYang Zhong } 392d9bb58e5SYang Zhong } 393d9bb58e5SYang Zhong 39464f2674bSRichard Henderson void tlb_flush(CPUState *cpu) 39564f2674bSRichard Henderson { 39664f2674bSRichard Henderson tlb_flush_by_mmuidx(cpu, ALL_MMUIDX_BITS); 39764f2674bSRichard Henderson } 39864f2674bSRichard Henderson 399d9bb58e5SYang Zhong void tlb_flush_by_mmuidx_all_cpus(CPUState *src_cpu, uint16_t idxmap) 400d9bb58e5SYang Zhong { 401d9bb58e5SYang Zhong const run_on_cpu_func fn = tlb_flush_by_mmuidx_async_work; 402d9bb58e5SYang Zhong 403d9bb58e5SYang Zhong tlb_debug("mmu_idx: 0x%"PRIx16"\n", idxmap); 404d9bb58e5SYang Zhong 405d9bb58e5SYang Zhong flush_all_helper(src_cpu, fn, RUN_ON_CPU_HOST_INT(idxmap)); 406d9bb58e5SYang Zhong fn(src_cpu, RUN_ON_CPU_HOST_INT(idxmap)); 407d9bb58e5SYang Zhong } 408d9bb58e5SYang Zhong 40964f2674bSRichard Henderson void tlb_flush_all_cpus(CPUState *src_cpu) 41064f2674bSRichard Henderson { 41164f2674bSRichard Henderson tlb_flush_by_mmuidx_all_cpus(src_cpu, ALL_MMUIDX_BITS); 41264f2674bSRichard Henderson } 41364f2674bSRichard Henderson 41464f2674bSRichard Henderson void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *src_cpu, uint16_t idxmap) 415d9bb58e5SYang Zhong { 416d9bb58e5SYang Zhong const run_on_cpu_func fn = tlb_flush_by_mmuidx_async_work; 417d9bb58e5SYang Zhong 418d9bb58e5SYang Zhong tlb_debug("mmu_idx: 0x%"PRIx16"\n", idxmap); 419d9bb58e5SYang Zhong 420d9bb58e5SYang Zhong flush_all_helper(src_cpu, fn, RUN_ON_CPU_HOST_INT(idxmap)); 421d9bb58e5SYang Zhong async_safe_run_on_cpu(src_cpu, fn, RUN_ON_CPU_HOST_INT(idxmap)); 422d9bb58e5SYang Zhong } 423d9bb58e5SYang Zhong 42464f2674bSRichard Henderson void tlb_flush_all_cpus_synced(CPUState *src_cpu) 42564f2674bSRichard Henderson { 42664f2674bSRichard Henderson tlb_flush_by_mmuidx_all_cpus_synced(src_cpu, ALL_MMUIDX_BITS); 42764f2674bSRichard Henderson } 42864f2674bSRichard Henderson 4293ab6e68cSRichard Henderson static bool tlb_hit_page_mask_anyprot(CPUTLBEntry *tlb_entry, 430732d5487SAnton Johansson vaddr page, vaddr mask) 4313ab6e68cSRichard Henderson { 4323ab6e68cSRichard Henderson page &= mask; 4333ab6e68cSRichard Henderson mask &= TARGET_PAGE_MASK | TLB_INVALID_MASK; 4343ab6e68cSRichard Henderson 4353ab6e68cSRichard Henderson return (page == (tlb_entry->addr_read & mask) || 4363ab6e68cSRichard Henderson page == (tlb_addr_write(tlb_entry) & mask) || 4373ab6e68cSRichard Henderson page == (tlb_entry->addr_code & mask)); 4383ab6e68cSRichard Henderson } 4393ab6e68cSRichard Henderson 440732d5487SAnton Johansson static inline bool tlb_hit_page_anyprot(CPUTLBEntry *tlb_entry, vaddr page) 441d9bb58e5SYang Zhong { 4423ab6e68cSRichard Henderson return tlb_hit_page_mask_anyprot(tlb_entry, page, -1); 44368fea038SRichard Henderson } 44468fea038SRichard Henderson 4453cea94bbSEmilio G. Cota /** 4463cea94bbSEmilio G. Cota * tlb_entry_is_empty - return true if the entry is not in use 4473cea94bbSEmilio G. Cota * @te: pointer to CPUTLBEntry 4483cea94bbSEmilio G. Cota */ 4493cea94bbSEmilio G. Cota static inline bool tlb_entry_is_empty(const CPUTLBEntry *te) 4503cea94bbSEmilio G. Cota { 4513cea94bbSEmilio G. Cota return te->addr_read == -1 && te->addr_write == -1 && te->addr_code == -1; 4523cea94bbSEmilio G. Cota } 4533cea94bbSEmilio G. Cota 45453d28455SRichard Henderson /* Called with tlb_c.lock held */ 4553ab6e68cSRichard Henderson static bool tlb_flush_entry_mask_locked(CPUTLBEntry *tlb_entry, 456732d5487SAnton Johansson vaddr page, 457732d5487SAnton Johansson vaddr mask) 45868fea038SRichard Henderson { 4593ab6e68cSRichard Henderson if (tlb_hit_page_mask_anyprot(tlb_entry, page, mask)) { 460d9bb58e5SYang Zhong memset(tlb_entry, -1, sizeof(*tlb_entry)); 46186e1eff8SEmilio G. Cota return true; 462d9bb58e5SYang Zhong } 46386e1eff8SEmilio G. Cota return false; 464d9bb58e5SYang Zhong } 465d9bb58e5SYang Zhong 466732d5487SAnton Johansson static inline bool tlb_flush_entry_locked(CPUTLBEntry *tlb_entry, vaddr page) 46768fea038SRichard Henderson { 4683ab6e68cSRichard Henderson return tlb_flush_entry_mask_locked(tlb_entry, page, -1); 4693ab6e68cSRichard Henderson } 4703ab6e68cSRichard Henderson 4713ab6e68cSRichard Henderson /* Called with tlb_c.lock held */ 4723ab6e68cSRichard Henderson static void tlb_flush_vtlb_page_mask_locked(CPUArchState *env, int mmu_idx, 473732d5487SAnton Johansson vaddr page, 474732d5487SAnton Johansson vaddr mask) 4753ab6e68cSRichard Henderson { 476a40ec84eSRichard Henderson CPUTLBDesc *d = &env_tlb(env)->d[mmu_idx]; 47768fea038SRichard Henderson int k; 47871aec354SEmilio G. Cota 47929a0af61SRichard Henderson assert_cpu_is_self(env_cpu(env)); 48068fea038SRichard Henderson for (k = 0; k < CPU_VTLB_SIZE; k++) { 4813ab6e68cSRichard Henderson if (tlb_flush_entry_mask_locked(&d->vtable[k], page, mask)) { 48286e1eff8SEmilio G. Cota tlb_n_used_entries_dec(env, mmu_idx); 48386e1eff8SEmilio G. Cota } 48468fea038SRichard Henderson } 48568fea038SRichard Henderson } 48668fea038SRichard Henderson 4873ab6e68cSRichard Henderson static inline void tlb_flush_vtlb_page_locked(CPUArchState *env, int mmu_idx, 488732d5487SAnton Johansson vaddr page) 4893ab6e68cSRichard Henderson { 4903ab6e68cSRichard Henderson tlb_flush_vtlb_page_mask_locked(env, mmu_idx, page, -1); 4913ab6e68cSRichard Henderson } 4923ab6e68cSRichard Henderson 493732d5487SAnton Johansson static void tlb_flush_page_locked(CPUArchState *env, int midx, vaddr page) 4941308e026SRichard Henderson { 495732d5487SAnton Johansson vaddr lp_addr = env_tlb(env)->d[midx].large_page_addr; 496732d5487SAnton Johansson vaddr lp_mask = env_tlb(env)->d[midx].large_page_mask; 4971308e026SRichard Henderson 4981308e026SRichard Henderson /* Check if we need to flush due to large pages. */ 4991308e026SRichard Henderson if ((page & lp_mask) == lp_addr) { 500732d5487SAnton Johansson tlb_debug("forcing full flush midx %d (%" 501732d5487SAnton Johansson VADDR_PRIx "/%" VADDR_PRIx ")\n", 5021308e026SRichard Henderson midx, lp_addr, lp_mask); 5033c3959f2SRichard Henderson tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime()); 5041308e026SRichard Henderson } else { 50586e1eff8SEmilio G. Cota if (tlb_flush_entry_locked(tlb_entry(env, midx, page), page)) { 50686e1eff8SEmilio G. Cota tlb_n_used_entries_dec(env, midx); 50786e1eff8SEmilio G. Cota } 5081308e026SRichard Henderson tlb_flush_vtlb_page_locked(env, midx, page); 5091308e026SRichard Henderson } 5101308e026SRichard Henderson } 5111308e026SRichard Henderson 5127b7d00e0SRichard Henderson /** 5137b7d00e0SRichard Henderson * tlb_flush_page_by_mmuidx_async_0: 5147b7d00e0SRichard Henderson * @cpu: cpu on which to flush 5157b7d00e0SRichard Henderson * @addr: page of virtual address to flush 5167b7d00e0SRichard Henderson * @idxmap: set of mmu_idx to flush 5177b7d00e0SRichard Henderson * 5187b7d00e0SRichard Henderson * Helper for tlb_flush_page_by_mmuidx and friends, flush one page 5197b7d00e0SRichard Henderson * at @addr from the tlbs indicated by @idxmap from @cpu. 520d9bb58e5SYang Zhong */ 5217b7d00e0SRichard Henderson static void tlb_flush_page_by_mmuidx_async_0(CPUState *cpu, 522732d5487SAnton Johansson vaddr addr, 5237b7d00e0SRichard Henderson uint16_t idxmap) 524d9bb58e5SYang Zhong { 525d9bb58e5SYang Zhong CPUArchState *env = cpu->env_ptr; 526d9bb58e5SYang Zhong int mmu_idx; 527d9bb58e5SYang Zhong 528d9bb58e5SYang Zhong assert_cpu_is_self(cpu); 529d9bb58e5SYang Zhong 530732d5487SAnton Johansson tlb_debug("page addr: %" VADDR_PRIx " mmu_map:0x%x\n", addr, idxmap); 531d9bb58e5SYang Zhong 532a40ec84eSRichard Henderson qemu_spin_lock(&env_tlb(env)->c.lock); 533d9bb58e5SYang Zhong for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 5347b7d00e0SRichard Henderson if ((idxmap >> mmu_idx) & 1) { 5351308e026SRichard Henderson tlb_flush_page_locked(env, mmu_idx, addr); 536d9bb58e5SYang Zhong } 537d9bb58e5SYang Zhong } 538a40ec84eSRichard Henderson qemu_spin_unlock(&env_tlb(env)->c.lock); 539d9bb58e5SYang Zhong 5401d41a79bSRichard Henderson /* 5411d41a79bSRichard Henderson * Discard jump cache entries for any tb which might potentially 5421d41a79bSRichard Henderson * overlap the flushed page, which includes the previous. 5431d41a79bSRichard Henderson */ 5441d41a79bSRichard Henderson tb_jmp_cache_clear_page(cpu, addr - TARGET_PAGE_SIZE); 5451d41a79bSRichard Henderson tb_jmp_cache_clear_page(cpu, addr); 546d9bb58e5SYang Zhong } 547d9bb58e5SYang Zhong 5487b7d00e0SRichard Henderson /** 5497b7d00e0SRichard Henderson * tlb_flush_page_by_mmuidx_async_1: 5507b7d00e0SRichard Henderson * @cpu: cpu on which to flush 5517b7d00e0SRichard Henderson * @data: encoded addr + idxmap 5527b7d00e0SRichard Henderson * 5537b7d00e0SRichard Henderson * Helper for tlb_flush_page_by_mmuidx and friends, called through 5547b7d00e0SRichard Henderson * async_run_on_cpu. The idxmap parameter is encoded in the page 5557b7d00e0SRichard Henderson * offset of the target_ptr field. This limits the set of mmu_idx 5567b7d00e0SRichard Henderson * that can be passed via this method. 5577b7d00e0SRichard Henderson */ 5587b7d00e0SRichard Henderson static void tlb_flush_page_by_mmuidx_async_1(CPUState *cpu, 5597b7d00e0SRichard Henderson run_on_cpu_data data) 5607b7d00e0SRichard Henderson { 561732d5487SAnton Johansson vaddr addr_and_idxmap = data.target_ptr; 562732d5487SAnton Johansson vaddr addr = addr_and_idxmap & TARGET_PAGE_MASK; 5637b7d00e0SRichard Henderson uint16_t idxmap = addr_and_idxmap & ~TARGET_PAGE_MASK; 5647b7d00e0SRichard Henderson 5657b7d00e0SRichard Henderson tlb_flush_page_by_mmuidx_async_0(cpu, addr, idxmap); 5667b7d00e0SRichard Henderson } 5677b7d00e0SRichard Henderson 5687b7d00e0SRichard Henderson typedef struct { 569732d5487SAnton Johansson vaddr addr; 5707b7d00e0SRichard Henderson uint16_t idxmap; 5717b7d00e0SRichard Henderson } TLBFlushPageByMMUIdxData; 5727b7d00e0SRichard Henderson 5737b7d00e0SRichard Henderson /** 5747b7d00e0SRichard Henderson * tlb_flush_page_by_mmuidx_async_2: 5757b7d00e0SRichard Henderson * @cpu: cpu on which to flush 5767b7d00e0SRichard Henderson * @data: allocated addr + idxmap 5777b7d00e0SRichard Henderson * 5787b7d00e0SRichard Henderson * Helper for tlb_flush_page_by_mmuidx and friends, called through 5797b7d00e0SRichard Henderson * async_run_on_cpu. The addr+idxmap parameters are stored in a 5807b7d00e0SRichard Henderson * TLBFlushPageByMMUIdxData structure that has been allocated 5817b7d00e0SRichard Henderson * specifically for this helper. Free the structure when done. 5827b7d00e0SRichard Henderson */ 5837b7d00e0SRichard Henderson static void tlb_flush_page_by_mmuidx_async_2(CPUState *cpu, 5847b7d00e0SRichard Henderson run_on_cpu_data data) 5857b7d00e0SRichard Henderson { 5867b7d00e0SRichard Henderson TLBFlushPageByMMUIdxData *d = data.host_ptr; 5877b7d00e0SRichard Henderson 5887b7d00e0SRichard Henderson tlb_flush_page_by_mmuidx_async_0(cpu, d->addr, d->idxmap); 5897b7d00e0SRichard Henderson g_free(d); 5907b7d00e0SRichard Henderson } 5917b7d00e0SRichard Henderson 592732d5487SAnton Johansson void tlb_flush_page_by_mmuidx(CPUState *cpu, vaddr addr, uint16_t idxmap) 593d9bb58e5SYang Zhong { 594732d5487SAnton Johansson tlb_debug("addr: %" VADDR_PRIx " mmu_idx:%" PRIx16 "\n", addr, idxmap); 595d9bb58e5SYang Zhong 596d9bb58e5SYang Zhong /* This should already be page aligned */ 5977b7d00e0SRichard Henderson addr &= TARGET_PAGE_MASK; 598d9bb58e5SYang Zhong 5997b7d00e0SRichard Henderson if (qemu_cpu_is_self(cpu)) { 6007b7d00e0SRichard Henderson tlb_flush_page_by_mmuidx_async_0(cpu, addr, idxmap); 6017b7d00e0SRichard Henderson } else if (idxmap < TARGET_PAGE_SIZE) { 6027b7d00e0SRichard Henderson /* 6037b7d00e0SRichard Henderson * Most targets have only a few mmu_idx. In the case where 6047b7d00e0SRichard Henderson * we can stuff idxmap into the low TARGET_PAGE_BITS, avoid 6057b7d00e0SRichard Henderson * allocating memory for this operation. 6067b7d00e0SRichard Henderson */ 6077b7d00e0SRichard Henderson async_run_on_cpu(cpu, tlb_flush_page_by_mmuidx_async_1, 6087b7d00e0SRichard Henderson RUN_ON_CPU_TARGET_PTR(addr | idxmap)); 609d9bb58e5SYang Zhong } else { 6107b7d00e0SRichard Henderson TLBFlushPageByMMUIdxData *d = g_new(TLBFlushPageByMMUIdxData, 1); 6117b7d00e0SRichard Henderson 6127b7d00e0SRichard Henderson /* Otherwise allocate a structure, freed by the worker. */ 6137b7d00e0SRichard Henderson d->addr = addr; 6147b7d00e0SRichard Henderson d->idxmap = idxmap; 6157b7d00e0SRichard Henderson async_run_on_cpu(cpu, tlb_flush_page_by_mmuidx_async_2, 6167b7d00e0SRichard Henderson RUN_ON_CPU_HOST_PTR(d)); 617d9bb58e5SYang Zhong } 618d9bb58e5SYang Zhong } 619d9bb58e5SYang Zhong 620732d5487SAnton Johansson void tlb_flush_page(CPUState *cpu, vaddr addr) 621f8144c6cSRichard Henderson { 622f8144c6cSRichard Henderson tlb_flush_page_by_mmuidx(cpu, addr, ALL_MMUIDX_BITS); 623f8144c6cSRichard Henderson } 624f8144c6cSRichard Henderson 625732d5487SAnton Johansson void tlb_flush_page_by_mmuidx_all_cpus(CPUState *src_cpu, vaddr addr, 626d9bb58e5SYang Zhong uint16_t idxmap) 627d9bb58e5SYang Zhong { 628732d5487SAnton Johansson tlb_debug("addr: %" VADDR_PRIx " mmu_idx:%"PRIx16"\n", addr, idxmap); 629d9bb58e5SYang Zhong 630d9bb58e5SYang Zhong /* This should already be page aligned */ 6317b7d00e0SRichard Henderson addr &= TARGET_PAGE_MASK; 632d9bb58e5SYang Zhong 6337b7d00e0SRichard Henderson /* 6347b7d00e0SRichard Henderson * Allocate memory to hold addr+idxmap only when needed. 6357b7d00e0SRichard Henderson * See tlb_flush_page_by_mmuidx for details. 6367b7d00e0SRichard Henderson */ 6377b7d00e0SRichard Henderson if (idxmap < TARGET_PAGE_SIZE) { 6387b7d00e0SRichard Henderson flush_all_helper(src_cpu, tlb_flush_page_by_mmuidx_async_1, 6397b7d00e0SRichard Henderson RUN_ON_CPU_TARGET_PTR(addr | idxmap)); 6407b7d00e0SRichard Henderson } else { 6417b7d00e0SRichard Henderson CPUState *dst_cpu; 6427b7d00e0SRichard Henderson 6437b7d00e0SRichard Henderson /* Allocate a separate data block for each destination cpu. */ 6447b7d00e0SRichard Henderson CPU_FOREACH(dst_cpu) { 6457b7d00e0SRichard Henderson if (dst_cpu != src_cpu) { 6467b7d00e0SRichard Henderson TLBFlushPageByMMUIdxData *d 6477b7d00e0SRichard Henderson = g_new(TLBFlushPageByMMUIdxData, 1); 6487b7d00e0SRichard Henderson 6497b7d00e0SRichard Henderson d->addr = addr; 6507b7d00e0SRichard Henderson d->idxmap = idxmap; 6517b7d00e0SRichard Henderson async_run_on_cpu(dst_cpu, tlb_flush_page_by_mmuidx_async_2, 6527b7d00e0SRichard Henderson RUN_ON_CPU_HOST_PTR(d)); 6537b7d00e0SRichard Henderson } 6547b7d00e0SRichard Henderson } 6557b7d00e0SRichard Henderson } 6567b7d00e0SRichard Henderson 6577b7d00e0SRichard Henderson tlb_flush_page_by_mmuidx_async_0(src_cpu, addr, idxmap); 658d9bb58e5SYang Zhong } 659d9bb58e5SYang Zhong 660732d5487SAnton Johansson void tlb_flush_page_all_cpus(CPUState *src, vaddr addr) 661f8144c6cSRichard Henderson { 662f8144c6cSRichard Henderson tlb_flush_page_by_mmuidx_all_cpus(src, addr, ALL_MMUIDX_BITS); 663f8144c6cSRichard Henderson } 664f8144c6cSRichard Henderson 665d9bb58e5SYang Zhong void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *src_cpu, 666732d5487SAnton Johansson vaddr addr, 667d9bb58e5SYang Zhong uint16_t idxmap) 668d9bb58e5SYang Zhong { 669732d5487SAnton Johansson tlb_debug("addr: %" VADDR_PRIx " mmu_idx:%"PRIx16"\n", addr, idxmap); 670d9bb58e5SYang Zhong 671d9bb58e5SYang Zhong /* This should already be page aligned */ 6727b7d00e0SRichard Henderson addr &= TARGET_PAGE_MASK; 673d9bb58e5SYang Zhong 6747b7d00e0SRichard Henderson /* 6757b7d00e0SRichard Henderson * Allocate memory to hold addr+idxmap only when needed. 6767b7d00e0SRichard Henderson * See tlb_flush_page_by_mmuidx for details. 6777b7d00e0SRichard Henderson */ 6787b7d00e0SRichard Henderson if (idxmap < TARGET_PAGE_SIZE) { 6797b7d00e0SRichard Henderson flush_all_helper(src_cpu, tlb_flush_page_by_mmuidx_async_1, 6807b7d00e0SRichard Henderson RUN_ON_CPU_TARGET_PTR(addr | idxmap)); 6817b7d00e0SRichard Henderson async_safe_run_on_cpu(src_cpu, tlb_flush_page_by_mmuidx_async_1, 6827b7d00e0SRichard Henderson RUN_ON_CPU_TARGET_PTR(addr | idxmap)); 6837b7d00e0SRichard Henderson } else { 6847b7d00e0SRichard Henderson CPUState *dst_cpu; 6857b7d00e0SRichard Henderson TLBFlushPageByMMUIdxData *d; 6867b7d00e0SRichard Henderson 6877b7d00e0SRichard Henderson /* Allocate a separate data block for each destination cpu. */ 6887b7d00e0SRichard Henderson CPU_FOREACH(dst_cpu) { 6897b7d00e0SRichard Henderson if (dst_cpu != src_cpu) { 6907b7d00e0SRichard Henderson d = g_new(TLBFlushPageByMMUIdxData, 1); 6917b7d00e0SRichard Henderson d->addr = addr; 6927b7d00e0SRichard Henderson d->idxmap = idxmap; 6937b7d00e0SRichard Henderson async_run_on_cpu(dst_cpu, tlb_flush_page_by_mmuidx_async_2, 6947b7d00e0SRichard Henderson RUN_ON_CPU_HOST_PTR(d)); 6957b7d00e0SRichard Henderson } 6967b7d00e0SRichard Henderson } 6977b7d00e0SRichard Henderson 6987b7d00e0SRichard Henderson d = g_new(TLBFlushPageByMMUIdxData, 1); 6997b7d00e0SRichard Henderson d->addr = addr; 7007b7d00e0SRichard Henderson d->idxmap = idxmap; 7017b7d00e0SRichard Henderson async_safe_run_on_cpu(src_cpu, tlb_flush_page_by_mmuidx_async_2, 7027b7d00e0SRichard Henderson RUN_ON_CPU_HOST_PTR(d)); 7037b7d00e0SRichard Henderson } 704d9bb58e5SYang Zhong } 705d9bb58e5SYang Zhong 706732d5487SAnton Johansson void tlb_flush_page_all_cpus_synced(CPUState *src, vaddr addr) 707d9bb58e5SYang Zhong { 708f8144c6cSRichard Henderson tlb_flush_page_by_mmuidx_all_cpus_synced(src, addr, ALL_MMUIDX_BITS); 709d9bb58e5SYang Zhong } 710d9bb58e5SYang Zhong 7113c4ddec1SRichard Henderson static void tlb_flush_range_locked(CPUArchState *env, int midx, 712732d5487SAnton Johansson vaddr addr, vaddr len, 7133c4ddec1SRichard Henderson unsigned bits) 7143ab6e68cSRichard Henderson { 7153ab6e68cSRichard Henderson CPUTLBDesc *d = &env_tlb(env)->d[midx]; 7163ab6e68cSRichard Henderson CPUTLBDescFast *f = &env_tlb(env)->f[midx]; 717732d5487SAnton Johansson vaddr mask = MAKE_64BIT_MASK(0, bits); 7183ab6e68cSRichard Henderson 7193ab6e68cSRichard Henderson /* 7203ab6e68cSRichard Henderson * If @bits is smaller than the tlb size, there may be multiple entries 7213ab6e68cSRichard Henderson * within the TLB; otherwise all addresses that match under @mask hit 7223ab6e68cSRichard Henderson * the same TLB entry. 7233ab6e68cSRichard Henderson * TODO: Perhaps allow bits to be a few bits less than the size. 7243ab6e68cSRichard Henderson * For now, just flush the entire TLB. 7253c4ddec1SRichard Henderson * 7263c4ddec1SRichard Henderson * If @len is larger than the tlb size, then it will take longer to 7273c4ddec1SRichard Henderson * test all of the entries in the TLB than it will to flush it all. 7283ab6e68cSRichard Henderson */ 7293c4ddec1SRichard Henderson if (mask < f->mask || len > f->mask) { 7303ab6e68cSRichard Henderson tlb_debug("forcing full flush midx %d (" 731732d5487SAnton Johansson "%" VADDR_PRIx "/%" VADDR_PRIx "+%" VADDR_PRIx ")\n", 7323c4ddec1SRichard Henderson midx, addr, mask, len); 7333ab6e68cSRichard Henderson tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime()); 7343ab6e68cSRichard Henderson return; 7353ab6e68cSRichard Henderson } 7363ab6e68cSRichard Henderson 7373c4ddec1SRichard Henderson /* 7383c4ddec1SRichard Henderson * Check if we need to flush due to large pages. 7393c4ddec1SRichard Henderson * Because large_page_mask contains all 1's from the msb, 7403c4ddec1SRichard Henderson * we only need to test the end of the range. 7413c4ddec1SRichard Henderson */ 7423c4ddec1SRichard Henderson if (((addr + len - 1) & d->large_page_mask) == d->large_page_addr) { 7433ab6e68cSRichard Henderson tlb_debug("forcing full flush midx %d (" 744732d5487SAnton Johansson "%" VADDR_PRIx "/%" VADDR_PRIx ")\n", 7453ab6e68cSRichard Henderson midx, d->large_page_addr, d->large_page_mask); 7463ab6e68cSRichard Henderson tlb_flush_one_mmuidx_locked(env, midx, get_clock_realtime()); 7473ab6e68cSRichard Henderson return; 7483ab6e68cSRichard Henderson } 7493ab6e68cSRichard Henderson 750732d5487SAnton Johansson for (vaddr i = 0; i < len; i += TARGET_PAGE_SIZE) { 751732d5487SAnton Johansson vaddr page = addr + i; 7523c4ddec1SRichard Henderson CPUTLBEntry *entry = tlb_entry(env, midx, page); 7533c4ddec1SRichard Henderson 7543c4ddec1SRichard Henderson if (tlb_flush_entry_mask_locked(entry, page, mask)) { 7553ab6e68cSRichard Henderson tlb_n_used_entries_dec(env, midx); 7563ab6e68cSRichard Henderson } 7573ab6e68cSRichard Henderson tlb_flush_vtlb_page_mask_locked(env, midx, page, mask); 7583ab6e68cSRichard Henderson } 7593c4ddec1SRichard Henderson } 7603ab6e68cSRichard Henderson 7613ab6e68cSRichard Henderson typedef struct { 762732d5487SAnton Johansson vaddr addr; 763732d5487SAnton Johansson vaddr len; 7643ab6e68cSRichard Henderson uint16_t idxmap; 7653ab6e68cSRichard Henderson uint16_t bits; 7663960a59fSRichard Henderson } TLBFlushRangeData; 7673ab6e68cSRichard Henderson 7686be48e45SRichard Henderson static void tlb_flush_range_by_mmuidx_async_0(CPUState *cpu, 7693960a59fSRichard Henderson TLBFlushRangeData d) 7703ab6e68cSRichard Henderson { 7713ab6e68cSRichard Henderson CPUArchState *env = cpu->env_ptr; 7723ab6e68cSRichard Henderson int mmu_idx; 7733ab6e68cSRichard Henderson 7743ab6e68cSRichard Henderson assert_cpu_is_self(cpu); 7753ab6e68cSRichard Henderson 776732d5487SAnton Johansson tlb_debug("range: %" VADDR_PRIx "/%u+%" VADDR_PRIx " mmu_map:0x%x\n", 7773c4ddec1SRichard Henderson d.addr, d.bits, d.len, d.idxmap); 7783ab6e68cSRichard Henderson 7793ab6e68cSRichard Henderson qemu_spin_lock(&env_tlb(env)->c.lock); 7803ab6e68cSRichard Henderson for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 7813ab6e68cSRichard Henderson if ((d.idxmap >> mmu_idx) & 1) { 7823c4ddec1SRichard Henderson tlb_flush_range_locked(env, mmu_idx, d.addr, d.len, d.bits); 7833ab6e68cSRichard Henderson } 7843ab6e68cSRichard Henderson } 7853ab6e68cSRichard Henderson qemu_spin_unlock(&env_tlb(env)->c.lock); 7863ab6e68cSRichard Henderson 787cfc2a2d6SIdan Horowitz /* 788cfc2a2d6SIdan Horowitz * If the length is larger than the jump cache size, then it will take 789cfc2a2d6SIdan Horowitz * longer to clear each entry individually than it will to clear it all. 790cfc2a2d6SIdan Horowitz */ 791cfc2a2d6SIdan Horowitz if (d.len >= (TARGET_PAGE_SIZE * TB_JMP_CACHE_SIZE)) { 792a976a99aSRichard Henderson tcg_flush_jmp_cache(cpu); 793cfc2a2d6SIdan Horowitz return; 794cfc2a2d6SIdan Horowitz } 795cfc2a2d6SIdan Horowitz 7961d41a79bSRichard Henderson /* 7971d41a79bSRichard Henderson * Discard jump cache entries for any tb which might potentially 7981d41a79bSRichard Henderson * overlap the flushed pages, which includes the previous. 7991d41a79bSRichard Henderson */ 8001d41a79bSRichard Henderson d.addr -= TARGET_PAGE_SIZE; 801732d5487SAnton Johansson for (vaddr i = 0, n = d.len / TARGET_PAGE_SIZE + 1; i < n; i++) { 8021d41a79bSRichard Henderson tb_jmp_cache_clear_page(cpu, d.addr); 8031d41a79bSRichard Henderson d.addr += TARGET_PAGE_SIZE; 8043c4ddec1SRichard Henderson } 8053ab6e68cSRichard Henderson } 8063ab6e68cSRichard Henderson 807206a583dSRichard Henderson static void tlb_flush_range_by_mmuidx_async_1(CPUState *cpu, 8083ab6e68cSRichard Henderson run_on_cpu_data data) 8093ab6e68cSRichard Henderson { 8103960a59fSRichard Henderson TLBFlushRangeData *d = data.host_ptr; 8116be48e45SRichard Henderson tlb_flush_range_by_mmuidx_async_0(cpu, *d); 8123ab6e68cSRichard Henderson g_free(d); 8133ab6e68cSRichard Henderson } 8143ab6e68cSRichard Henderson 815732d5487SAnton Johansson void tlb_flush_range_by_mmuidx(CPUState *cpu, vaddr addr, 816732d5487SAnton Johansson vaddr len, uint16_t idxmap, 817e5b1921bSRichard Henderson unsigned bits) 8183ab6e68cSRichard Henderson { 8193960a59fSRichard Henderson TLBFlushRangeData d; 8203ab6e68cSRichard Henderson 821e5b1921bSRichard Henderson /* 822e5b1921bSRichard Henderson * If all bits are significant, and len is small, 823e5b1921bSRichard Henderson * this devolves to tlb_flush_page. 824e5b1921bSRichard Henderson */ 825e5b1921bSRichard Henderson if (bits >= TARGET_LONG_BITS && len <= TARGET_PAGE_SIZE) { 8263ab6e68cSRichard Henderson tlb_flush_page_by_mmuidx(cpu, addr, idxmap); 8273ab6e68cSRichard Henderson return; 8283ab6e68cSRichard Henderson } 8293ab6e68cSRichard Henderson /* If no page bits are significant, this devolves to tlb_flush. */ 8303ab6e68cSRichard Henderson if (bits < TARGET_PAGE_BITS) { 8313ab6e68cSRichard Henderson tlb_flush_by_mmuidx(cpu, idxmap); 8323ab6e68cSRichard Henderson return; 8333ab6e68cSRichard Henderson } 8343ab6e68cSRichard Henderson 8353ab6e68cSRichard Henderson /* This should already be page aligned */ 8363ab6e68cSRichard Henderson d.addr = addr & TARGET_PAGE_MASK; 837e5b1921bSRichard Henderson d.len = len; 8383ab6e68cSRichard Henderson d.idxmap = idxmap; 8393ab6e68cSRichard Henderson d.bits = bits; 8403ab6e68cSRichard Henderson 8413ab6e68cSRichard Henderson if (qemu_cpu_is_self(cpu)) { 8426be48e45SRichard Henderson tlb_flush_range_by_mmuidx_async_0(cpu, d); 8433ab6e68cSRichard Henderson } else { 8443ab6e68cSRichard Henderson /* Otherwise allocate a structure, freed by the worker. */ 8453960a59fSRichard Henderson TLBFlushRangeData *p = g_memdup(&d, sizeof(d)); 846206a583dSRichard Henderson async_run_on_cpu(cpu, tlb_flush_range_by_mmuidx_async_1, 8473ab6e68cSRichard Henderson RUN_ON_CPU_HOST_PTR(p)); 8483ab6e68cSRichard Henderson } 8493ab6e68cSRichard Henderson } 8503ab6e68cSRichard Henderson 851732d5487SAnton Johansson void tlb_flush_page_bits_by_mmuidx(CPUState *cpu, vaddr addr, 852e5b1921bSRichard Henderson uint16_t idxmap, unsigned bits) 853e5b1921bSRichard Henderson { 854e5b1921bSRichard Henderson tlb_flush_range_by_mmuidx(cpu, addr, TARGET_PAGE_SIZE, idxmap, bits); 855e5b1921bSRichard Henderson } 856e5b1921bSRichard Henderson 857600b819fSRichard Henderson void tlb_flush_range_by_mmuidx_all_cpus(CPUState *src_cpu, 858732d5487SAnton Johansson vaddr addr, vaddr len, 859600b819fSRichard Henderson uint16_t idxmap, unsigned bits) 8603ab6e68cSRichard Henderson { 8613960a59fSRichard Henderson TLBFlushRangeData d; 862d34e4d1aSRichard Henderson CPUState *dst_cpu; 8633ab6e68cSRichard Henderson 864600b819fSRichard Henderson /* 865600b819fSRichard Henderson * If all bits are significant, and len is small, 866600b819fSRichard Henderson * this devolves to tlb_flush_page. 867600b819fSRichard Henderson */ 868600b819fSRichard Henderson if (bits >= TARGET_LONG_BITS && len <= TARGET_PAGE_SIZE) { 8693ab6e68cSRichard Henderson tlb_flush_page_by_mmuidx_all_cpus(src_cpu, addr, idxmap); 8703ab6e68cSRichard Henderson return; 8713ab6e68cSRichard Henderson } 8723ab6e68cSRichard Henderson /* If no page bits are significant, this devolves to tlb_flush. */ 8733ab6e68cSRichard Henderson if (bits < TARGET_PAGE_BITS) { 8743ab6e68cSRichard Henderson tlb_flush_by_mmuidx_all_cpus(src_cpu, idxmap); 8753ab6e68cSRichard Henderson return; 8763ab6e68cSRichard Henderson } 8773ab6e68cSRichard Henderson 8783ab6e68cSRichard Henderson /* This should already be page aligned */ 8793ab6e68cSRichard Henderson d.addr = addr & TARGET_PAGE_MASK; 880600b819fSRichard Henderson d.len = len; 8813ab6e68cSRichard Henderson d.idxmap = idxmap; 8823ab6e68cSRichard Henderson d.bits = bits; 8833ab6e68cSRichard Henderson 8843ab6e68cSRichard Henderson /* Allocate a separate data block for each destination cpu. */ 8853ab6e68cSRichard Henderson CPU_FOREACH(dst_cpu) { 8863ab6e68cSRichard Henderson if (dst_cpu != src_cpu) { 8873960a59fSRichard Henderson TLBFlushRangeData *p = g_memdup(&d, sizeof(d)); 8883ab6e68cSRichard Henderson async_run_on_cpu(dst_cpu, 889206a583dSRichard Henderson tlb_flush_range_by_mmuidx_async_1, 8903ab6e68cSRichard Henderson RUN_ON_CPU_HOST_PTR(p)); 8913ab6e68cSRichard Henderson } 8923ab6e68cSRichard Henderson } 8933ab6e68cSRichard Henderson 8946be48e45SRichard Henderson tlb_flush_range_by_mmuidx_async_0(src_cpu, d); 8953ab6e68cSRichard Henderson } 8963ab6e68cSRichard Henderson 897600b819fSRichard Henderson void tlb_flush_page_bits_by_mmuidx_all_cpus(CPUState *src_cpu, 898732d5487SAnton Johansson vaddr addr, uint16_t idxmap, 899732d5487SAnton Johansson unsigned bits) 900600b819fSRichard Henderson { 901600b819fSRichard Henderson tlb_flush_range_by_mmuidx_all_cpus(src_cpu, addr, TARGET_PAGE_SIZE, 902600b819fSRichard Henderson idxmap, bits); 903600b819fSRichard Henderson } 904600b819fSRichard Henderson 905c13b27d8SRichard Henderson void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *src_cpu, 906732d5487SAnton Johansson vaddr addr, 907732d5487SAnton Johansson vaddr len, 9083ab6e68cSRichard Henderson uint16_t idxmap, 9093ab6e68cSRichard Henderson unsigned bits) 9103ab6e68cSRichard Henderson { 911d34e4d1aSRichard Henderson TLBFlushRangeData d, *p; 912d34e4d1aSRichard Henderson CPUState *dst_cpu; 9133ab6e68cSRichard Henderson 914c13b27d8SRichard Henderson /* 915c13b27d8SRichard Henderson * If all bits are significant, and len is small, 916c13b27d8SRichard Henderson * this devolves to tlb_flush_page. 917c13b27d8SRichard Henderson */ 918c13b27d8SRichard Henderson if (bits >= TARGET_LONG_BITS && len <= TARGET_PAGE_SIZE) { 9193ab6e68cSRichard Henderson tlb_flush_page_by_mmuidx_all_cpus_synced(src_cpu, addr, idxmap); 9203ab6e68cSRichard Henderson return; 9213ab6e68cSRichard Henderson } 9223ab6e68cSRichard Henderson /* If no page bits are significant, this devolves to tlb_flush. */ 9233ab6e68cSRichard Henderson if (bits < TARGET_PAGE_BITS) { 9243ab6e68cSRichard Henderson tlb_flush_by_mmuidx_all_cpus_synced(src_cpu, idxmap); 9253ab6e68cSRichard Henderson return; 9263ab6e68cSRichard Henderson } 9273ab6e68cSRichard Henderson 9283ab6e68cSRichard Henderson /* This should already be page aligned */ 9293ab6e68cSRichard Henderson d.addr = addr & TARGET_PAGE_MASK; 930c13b27d8SRichard Henderson d.len = len; 9313ab6e68cSRichard Henderson d.idxmap = idxmap; 9323ab6e68cSRichard Henderson d.bits = bits; 9333ab6e68cSRichard Henderson 9343ab6e68cSRichard Henderson /* Allocate a separate data block for each destination cpu. */ 9353ab6e68cSRichard Henderson CPU_FOREACH(dst_cpu) { 9363ab6e68cSRichard Henderson if (dst_cpu != src_cpu) { 9376d244788SRichard Henderson p = g_memdup(&d, sizeof(d)); 938206a583dSRichard Henderson async_run_on_cpu(dst_cpu, tlb_flush_range_by_mmuidx_async_1, 9393ab6e68cSRichard Henderson RUN_ON_CPU_HOST_PTR(p)); 9403ab6e68cSRichard Henderson } 9413ab6e68cSRichard Henderson } 9423ab6e68cSRichard Henderson 9436d244788SRichard Henderson p = g_memdup(&d, sizeof(d)); 944206a583dSRichard Henderson async_safe_run_on_cpu(src_cpu, tlb_flush_range_by_mmuidx_async_1, 9453ab6e68cSRichard Henderson RUN_ON_CPU_HOST_PTR(p)); 9463ab6e68cSRichard Henderson } 9473ab6e68cSRichard Henderson 948c13b27d8SRichard Henderson void tlb_flush_page_bits_by_mmuidx_all_cpus_synced(CPUState *src_cpu, 949732d5487SAnton Johansson vaddr addr, 950c13b27d8SRichard Henderson uint16_t idxmap, 951c13b27d8SRichard Henderson unsigned bits) 952c13b27d8SRichard Henderson { 953c13b27d8SRichard Henderson tlb_flush_range_by_mmuidx_all_cpus_synced(src_cpu, addr, TARGET_PAGE_SIZE, 954c13b27d8SRichard Henderson idxmap, bits); 955c13b27d8SRichard Henderson } 956c13b27d8SRichard Henderson 957d9bb58e5SYang Zhong /* update the TLBs so that writes to code in the virtual page 'addr' 958d9bb58e5SYang Zhong can be detected */ 959d9bb58e5SYang Zhong void tlb_protect_code(ram_addr_t ram_addr) 960d9bb58e5SYang Zhong { 96193b99616SRichard Henderson cpu_physical_memory_test_and_clear_dirty(ram_addr & TARGET_PAGE_MASK, 96293b99616SRichard Henderson TARGET_PAGE_SIZE, 963d9bb58e5SYang Zhong DIRTY_MEMORY_CODE); 964d9bb58e5SYang Zhong } 965d9bb58e5SYang Zhong 966d9bb58e5SYang Zhong /* update the TLB so that writes in physical page 'phys_addr' are no longer 967d9bb58e5SYang Zhong tested for self modifying code */ 968d9bb58e5SYang Zhong void tlb_unprotect_code(ram_addr_t ram_addr) 969d9bb58e5SYang Zhong { 970d9bb58e5SYang Zhong cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_CODE); 971d9bb58e5SYang Zhong } 972d9bb58e5SYang Zhong 973d9bb58e5SYang Zhong 974d9bb58e5SYang Zhong /* 975d9bb58e5SYang Zhong * Dirty write flag handling 976d9bb58e5SYang Zhong * 977d9bb58e5SYang Zhong * When the TCG code writes to a location it looks up the address in 978d9bb58e5SYang Zhong * the TLB and uses that data to compute the final address. If any of 979d9bb58e5SYang Zhong * the lower bits of the address are set then the slow path is forced. 980d9bb58e5SYang Zhong * There are a number of reasons to do this but for normal RAM the 981d9bb58e5SYang Zhong * most usual is detecting writes to code regions which may invalidate 982d9bb58e5SYang Zhong * generated code. 983d9bb58e5SYang Zhong * 98471aec354SEmilio G. Cota * Other vCPUs might be reading their TLBs during guest execution, so we update 985d73415a3SStefan Hajnoczi * te->addr_write with qatomic_set. We don't need to worry about this for 98671aec354SEmilio G. Cota * oversized guests as MTTCG is disabled for them. 987d9bb58e5SYang Zhong * 98853d28455SRichard Henderson * Called with tlb_c.lock held. 989d9bb58e5SYang Zhong */ 99071aec354SEmilio G. Cota static void tlb_reset_dirty_range_locked(CPUTLBEntry *tlb_entry, 99171aec354SEmilio G. Cota uintptr_t start, uintptr_t length) 992d9bb58e5SYang Zhong { 993d9bb58e5SYang Zhong uintptr_t addr = tlb_entry->addr_write; 994d9bb58e5SYang Zhong 9957b0d792cSRichard Henderson if ((addr & (TLB_INVALID_MASK | TLB_MMIO | 9967b0d792cSRichard Henderson TLB_DISCARD_WRITE | TLB_NOTDIRTY)) == 0) { 997d9bb58e5SYang Zhong addr &= TARGET_PAGE_MASK; 998d9bb58e5SYang Zhong addr += tlb_entry->addend; 999d9bb58e5SYang Zhong if ((addr - start) < length) { 1000238f4380SRichard Henderson #if TARGET_LONG_BITS == 32 1001238f4380SRichard Henderson uint32_t *ptr_write = (uint32_t *)&tlb_entry->addr_write; 1002238f4380SRichard Henderson ptr_write += HOST_BIG_ENDIAN; 1003238f4380SRichard Henderson qatomic_set(ptr_write, *ptr_write | TLB_NOTDIRTY); 1004238f4380SRichard Henderson #elif TCG_OVERSIZED_GUEST 100571aec354SEmilio G. Cota tlb_entry->addr_write |= TLB_NOTDIRTY; 1006d9bb58e5SYang Zhong #else 1007d73415a3SStefan Hajnoczi qatomic_set(&tlb_entry->addr_write, 100871aec354SEmilio G. Cota tlb_entry->addr_write | TLB_NOTDIRTY); 1009d9bb58e5SYang Zhong #endif 1010d9bb58e5SYang Zhong } 101171aec354SEmilio G. Cota } 101271aec354SEmilio G. Cota } 101371aec354SEmilio G. Cota 101471aec354SEmilio G. Cota /* 101553d28455SRichard Henderson * Called with tlb_c.lock held. 101671aec354SEmilio G. Cota * Called only from the vCPU context, i.e. the TLB's owner thread. 101771aec354SEmilio G. Cota */ 101871aec354SEmilio G. Cota static inline void copy_tlb_helper_locked(CPUTLBEntry *d, const CPUTLBEntry *s) 101971aec354SEmilio G. Cota { 102071aec354SEmilio G. Cota *d = *s; 102171aec354SEmilio G. Cota } 1022d9bb58e5SYang Zhong 1023d9bb58e5SYang Zhong /* This is a cross vCPU call (i.e. another vCPU resetting the flags of 102471aec354SEmilio G. Cota * the target vCPU). 102553d28455SRichard Henderson * We must take tlb_c.lock to avoid racing with another vCPU update. The only 102671aec354SEmilio G. Cota * thing actually updated is the target TLB entry ->addr_write flags. 1027d9bb58e5SYang Zhong */ 1028d9bb58e5SYang Zhong void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length) 1029d9bb58e5SYang Zhong { 1030d9bb58e5SYang Zhong CPUArchState *env; 1031d9bb58e5SYang Zhong 1032d9bb58e5SYang Zhong int mmu_idx; 1033d9bb58e5SYang Zhong 1034d9bb58e5SYang Zhong env = cpu->env_ptr; 1035a40ec84eSRichard Henderson qemu_spin_lock(&env_tlb(env)->c.lock); 1036d9bb58e5SYang Zhong for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 1037d9bb58e5SYang Zhong unsigned int i; 1038722a1c1eSRichard Henderson unsigned int n = tlb_n_entries(&env_tlb(env)->f[mmu_idx]); 1039d9bb58e5SYang Zhong 104086e1eff8SEmilio G. Cota for (i = 0; i < n; i++) { 1041a40ec84eSRichard Henderson tlb_reset_dirty_range_locked(&env_tlb(env)->f[mmu_idx].table[i], 1042a40ec84eSRichard Henderson start1, length); 1043d9bb58e5SYang Zhong } 1044d9bb58e5SYang Zhong 1045d9bb58e5SYang Zhong for (i = 0; i < CPU_VTLB_SIZE; i++) { 1046a40ec84eSRichard Henderson tlb_reset_dirty_range_locked(&env_tlb(env)->d[mmu_idx].vtable[i], 1047a40ec84eSRichard Henderson start1, length); 1048d9bb58e5SYang Zhong } 1049d9bb58e5SYang Zhong } 1050a40ec84eSRichard Henderson qemu_spin_unlock(&env_tlb(env)->c.lock); 1051d9bb58e5SYang Zhong } 1052d9bb58e5SYang Zhong 105353d28455SRichard Henderson /* Called with tlb_c.lock held */ 105471aec354SEmilio G. Cota static inline void tlb_set_dirty1_locked(CPUTLBEntry *tlb_entry, 1055732d5487SAnton Johansson vaddr addr) 1056d9bb58e5SYang Zhong { 1057732d5487SAnton Johansson if (tlb_entry->addr_write == (addr | TLB_NOTDIRTY)) { 1058732d5487SAnton Johansson tlb_entry->addr_write = addr; 1059d9bb58e5SYang Zhong } 1060d9bb58e5SYang Zhong } 1061d9bb58e5SYang Zhong 1062d9bb58e5SYang Zhong /* update the TLB corresponding to virtual page vaddr 1063d9bb58e5SYang Zhong so that it is no longer dirty */ 1064732d5487SAnton Johansson void tlb_set_dirty(CPUState *cpu, vaddr addr) 1065d9bb58e5SYang Zhong { 1066d9bb58e5SYang Zhong CPUArchState *env = cpu->env_ptr; 1067d9bb58e5SYang Zhong int mmu_idx; 1068d9bb58e5SYang Zhong 1069d9bb58e5SYang Zhong assert_cpu_is_self(cpu); 1070d9bb58e5SYang Zhong 1071732d5487SAnton Johansson addr &= TARGET_PAGE_MASK; 1072a40ec84eSRichard Henderson qemu_spin_lock(&env_tlb(env)->c.lock); 1073d9bb58e5SYang Zhong for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 1074732d5487SAnton Johansson tlb_set_dirty1_locked(tlb_entry(env, mmu_idx, addr), addr); 1075d9bb58e5SYang Zhong } 1076d9bb58e5SYang Zhong 1077d9bb58e5SYang Zhong for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 1078d9bb58e5SYang Zhong int k; 1079d9bb58e5SYang Zhong for (k = 0; k < CPU_VTLB_SIZE; k++) { 1080732d5487SAnton Johansson tlb_set_dirty1_locked(&env_tlb(env)->d[mmu_idx].vtable[k], addr); 1081d9bb58e5SYang Zhong } 1082d9bb58e5SYang Zhong } 1083a40ec84eSRichard Henderson qemu_spin_unlock(&env_tlb(env)->c.lock); 1084d9bb58e5SYang Zhong } 1085d9bb58e5SYang Zhong 1086d9bb58e5SYang Zhong /* Our TLB does not support large pages, so remember the area covered by 1087d9bb58e5SYang Zhong large pages and trigger a full TLB flush if these are invalidated. */ 10881308e026SRichard Henderson static void tlb_add_large_page(CPUArchState *env, int mmu_idx, 1089732d5487SAnton Johansson vaddr addr, uint64_t size) 1090d9bb58e5SYang Zhong { 1091732d5487SAnton Johansson vaddr lp_addr = env_tlb(env)->d[mmu_idx].large_page_addr; 1092732d5487SAnton Johansson vaddr lp_mask = ~(size - 1); 1093d9bb58e5SYang Zhong 1094732d5487SAnton Johansson if (lp_addr == (vaddr)-1) { 10951308e026SRichard Henderson /* No previous large page. */ 1096732d5487SAnton Johansson lp_addr = addr; 10971308e026SRichard Henderson } else { 1098d9bb58e5SYang Zhong /* Extend the existing region to include the new page. 10991308e026SRichard Henderson This is a compromise between unnecessary flushes and 11001308e026SRichard Henderson the cost of maintaining a full variable size TLB. */ 1101a40ec84eSRichard Henderson lp_mask &= env_tlb(env)->d[mmu_idx].large_page_mask; 1102732d5487SAnton Johansson while (((lp_addr ^ addr) & lp_mask) != 0) { 11031308e026SRichard Henderson lp_mask <<= 1; 1104d9bb58e5SYang Zhong } 11051308e026SRichard Henderson } 1106a40ec84eSRichard Henderson env_tlb(env)->d[mmu_idx].large_page_addr = lp_addr & lp_mask; 1107a40ec84eSRichard Henderson env_tlb(env)->d[mmu_idx].large_page_mask = lp_mask; 1108d9bb58e5SYang Zhong } 1109d9bb58e5SYang Zhong 111040473689SRichard Henderson /* 111140473689SRichard Henderson * Add a new TLB entry. At most one entry for a given virtual address 1112d9bb58e5SYang Zhong * is permitted. Only a single TARGET_PAGE_SIZE region is mapped, the 1113d9bb58e5SYang Zhong * supplied size is only used by tlb_flush_page. 1114d9bb58e5SYang Zhong * 1115d9bb58e5SYang Zhong * Called from TCG-generated code, which is under an RCU read-side 1116d9bb58e5SYang Zhong * critical section. 1117d9bb58e5SYang Zhong */ 111840473689SRichard Henderson void tlb_set_page_full(CPUState *cpu, int mmu_idx, 1119732d5487SAnton Johansson vaddr addr, CPUTLBEntryFull *full) 1120d9bb58e5SYang Zhong { 1121d9bb58e5SYang Zhong CPUArchState *env = cpu->env_ptr; 1122a40ec84eSRichard Henderson CPUTLB *tlb = env_tlb(env); 1123a40ec84eSRichard Henderson CPUTLBDesc *desc = &tlb->d[mmu_idx]; 1124d9bb58e5SYang Zhong MemoryRegionSection *section; 1125d9bb58e5SYang Zhong unsigned int index; 1126732d5487SAnton Johansson vaddr address; 1127732d5487SAnton Johansson vaddr write_address; 1128d9bb58e5SYang Zhong uintptr_t addend; 112968fea038SRichard Henderson CPUTLBEntry *te, tn; 113055df6fcfSPeter Maydell hwaddr iotlb, xlat, sz, paddr_page; 1131732d5487SAnton Johansson vaddr addr_page; 113240473689SRichard Henderson int asidx, wp_flags, prot; 11338f5db641SRichard Henderson bool is_ram, is_romd; 1134d9bb58e5SYang Zhong 1135d9bb58e5SYang Zhong assert_cpu_is_self(cpu); 113655df6fcfSPeter Maydell 113740473689SRichard Henderson if (full->lg_page_size <= TARGET_PAGE_BITS) { 113855df6fcfSPeter Maydell sz = TARGET_PAGE_SIZE; 113955df6fcfSPeter Maydell } else { 114040473689SRichard Henderson sz = (hwaddr)1 << full->lg_page_size; 1141732d5487SAnton Johansson tlb_add_large_page(env, mmu_idx, addr, sz); 114255df6fcfSPeter Maydell } 1143732d5487SAnton Johansson addr_page = addr & TARGET_PAGE_MASK; 114440473689SRichard Henderson paddr_page = full->phys_addr & TARGET_PAGE_MASK; 114555df6fcfSPeter Maydell 114640473689SRichard Henderson prot = full->prot; 114740473689SRichard Henderson asidx = cpu_asidx_from_attrs(cpu, full->attrs); 114855df6fcfSPeter Maydell section = address_space_translate_for_iotlb(cpu, asidx, paddr_page, 114940473689SRichard Henderson &xlat, &sz, full->attrs, &prot); 1150d9bb58e5SYang Zhong assert(sz >= TARGET_PAGE_SIZE); 1151d9bb58e5SYang Zhong 1152732d5487SAnton Johansson tlb_debug("vaddr=%" VADDR_PRIx " paddr=0x" HWADDR_FMT_plx 1153d9bb58e5SYang Zhong " prot=%x idx=%d\n", 1154732d5487SAnton Johansson addr, full->phys_addr, prot, mmu_idx); 1155d9bb58e5SYang Zhong 1156732d5487SAnton Johansson address = addr_page; 115740473689SRichard Henderson if (full->lg_page_size < TARGET_PAGE_BITS) { 115830d7e098SRichard Henderson /* Repeat the MMU check and TLB fill on every access. */ 115930d7e098SRichard Henderson address |= TLB_INVALID_MASK; 116055df6fcfSPeter Maydell } 116140473689SRichard Henderson if (full->attrs.byte_swap) { 11625b87b3e6SRichard Henderson address |= TLB_BSWAP; 1163a26fc6f5STony Nguyen } 11648f5db641SRichard Henderson 11658f5db641SRichard Henderson is_ram = memory_region_is_ram(section->mr); 11668f5db641SRichard Henderson is_romd = memory_region_is_romd(section->mr); 11678f5db641SRichard Henderson 11688f5db641SRichard Henderson if (is_ram || is_romd) { 11698f5db641SRichard Henderson /* RAM and ROMD both have associated host memory. */ 1170d9bb58e5SYang Zhong addend = (uintptr_t)memory_region_get_ram_ptr(section->mr) + xlat; 11718f5db641SRichard Henderson } else { 11728f5db641SRichard Henderson /* I/O does not; force the host address to NULL. */ 11738f5db641SRichard Henderson addend = 0; 1174d9bb58e5SYang Zhong } 1175d9bb58e5SYang Zhong 11768f5db641SRichard Henderson write_address = address; 11778f5db641SRichard Henderson if (is_ram) { 11788f5db641SRichard Henderson iotlb = memory_region_get_ram_addr(section->mr) + xlat; 11798f5db641SRichard Henderson /* 11808f5db641SRichard Henderson * Computing is_clean is expensive; avoid all that unless 11818f5db641SRichard Henderson * the page is actually writable. 11828f5db641SRichard Henderson */ 11838f5db641SRichard Henderson if (prot & PAGE_WRITE) { 11848f5db641SRichard Henderson if (section->readonly) { 11858f5db641SRichard Henderson write_address |= TLB_DISCARD_WRITE; 11868f5db641SRichard Henderson } else if (cpu_physical_memory_is_clean(iotlb)) { 11878f5db641SRichard Henderson write_address |= TLB_NOTDIRTY; 11888f5db641SRichard Henderson } 11898f5db641SRichard Henderson } 11908f5db641SRichard Henderson } else { 11918f5db641SRichard Henderson /* I/O or ROMD */ 11928f5db641SRichard Henderson iotlb = memory_region_section_get_iotlb(cpu, section) + xlat; 11938f5db641SRichard Henderson /* 11948f5db641SRichard Henderson * Writes to romd devices must go through MMIO to enable write. 11958f5db641SRichard Henderson * Reads to romd devices go through the ram_ptr found above, 11968f5db641SRichard Henderson * but of course reads to I/O must go through MMIO. 11978f5db641SRichard Henderson */ 11988f5db641SRichard Henderson write_address |= TLB_MMIO; 11998f5db641SRichard Henderson if (!is_romd) { 12008f5db641SRichard Henderson address = write_address; 12018f5db641SRichard Henderson } 12028f5db641SRichard Henderson } 12038f5db641SRichard Henderson 1204732d5487SAnton Johansson wp_flags = cpu_watchpoint_address_matches(cpu, addr_page, 120550b107c5SRichard Henderson TARGET_PAGE_SIZE); 1206d9bb58e5SYang Zhong 1207732d5487SAnton Johansson index = tlb_index(env, mmu_idx, addr_page); 1208732d5487SAnton Johansson te = tlb_entry(env, mmu_idx, addr_page); 1209d9bb58e5SYang Zhong 121068fea038SRichard Henderson /* 121171aec354SEmilio G. Cota * Hold the TLB lock for the rest of the function. We could acquire/release 121271aec354SEmilio G. Cota * the lock several times in the function, but it is faster to amortize the 121371aec354SEmilio G. Cota * acquisition cost by acquiring it just once. Note that this leads to 121471aec354SEmilio G. Cota * a longer critical section, but this is not a concern since the TLB lock 121571aec354SEmilio G. Cota * is unlikely to be contended. 121671aec354SEmilio G. Cota */ 1217a40ec84eSRichard Henderson qemu_spin_lock(&tlb->c.lock); 121871aec354SEmilio G. Cota 12193d1523ceSRichard Henderson /* Note that the tlb is no longer clean. */ 1220a40ec84eSRichard Henderson tlb->c.dirty |= 1 << mmu_idx; 12213d1523ceSRichard Henderson 122271aec354SEmilio G. Cota /* Make sure there's no cached translation for the new page. */ 1223732d5487SAnton Johansson tlb_flush_vtlb_page_locked(env, mmu_idx, addr_page); 122471aec354SEmilio G. Cota 122571aec354SEmilio G. Cota /* 122668fea038SRichard Henderson * Only evict the old entry to the victim tlb if it's for a 122768fea038SRichard Henderson * different page; otherwise just overwrite the stale data. 122868fea038SRichard Henderson */ 1229732d5487SAnton Johansson if (!tlb_hit_page_anyprot(te, addr_page) && !tlb_entry_is_empty(te)) { 1230a40ec84eSRichard Henderson unsigned vidx = desc->vindex++ % CPU_VTLB_SIZE; 1231a40ec84eSRichard Henderson CPUTLBEntry *tv = &desc->vtable[vidx]; 123268fea038SRichard Henderson 123368fea038SRichard Henderson /* Evict the old entry into the victim tlb. */ 123471aec354SEmilio G. Cota copy_tlb_helper_locked(tv, te); 123525d3ec58SRichard Henderson desc->vfulltlb[vidx] = desc->fulltlb[index]; 123686e1eff8SEmilio G. Cota tlb_n_used_entries_dec(env, mmu_idx); 123768fea038SRichard Henderson } 1238d9bb58e5SYang Zhong 1239d9bb58e5SYang Zhong /* refill the tlb */ 1240ace41090SPeter Maydell /* 1241ace41090SPeter Maydell * At this point iotlb contains a physical section number in the lower 1242ace41090SPeter Maydell * TARGET_PAGE_BITS, and either 12438f5db641SRichard Henderson * + the ram_addr_t of the page base of the target RAM (RAM) 12448f5db641SRichard Henderson * + the offset within section->mr of the page base (I/O, ROMD) 124555df6fcfSPeter Maydell * We subtract the vaddr_page (which is page aligned and thus won't 1246ace41090SPeter Maydell * disturb the low bits) to give an offset which can be added to the 1247ace41090SPeter Maydell * (non-page-aligned) vaddr of the eventual memory access to get 1248ace41090SPeter Maydell * the MemoryRegion offset for the access. Note that the vaddr we 1249ace41090SPeter Maydell * subtract here is that of the page base, and not the same as the 1250ace41090SPeter Maydell * vaddr we add back in io_readx()/io_writex()/get_page_addr_code(). 1251ace41090SPeter Maydell */ 125240473689SRichard Henderson desc->fulltlb[index] = *full; 1253732d5487SAnton Johansson desc->fulltlb[index].xlat_section = iotlb - addr_page; 125440473689SRichard Henderson desc->fulltlb[index].phys_addr = paddr_page; 1255d9bb58e5SYang Zhong 1256d9bb58e5SYang Zhong /* Now calculate the new entry */ 1257732d5487SAnton Johansson tn.addend = addend - addr_page; 1258d9bb58e5SYang Zhong if (prot & PAGE_READ) { 1259d9bb58e5SYang Zhong tn.addr_read = address; 126050b107c5SRichard Henderson if (wp_flags & BP_MEM_READ) { 126150b107c5SRichard Henderson tn.addr_read |= TLB_WATCHPOINT; 126250b107c5SRichard Henderson } 1263d9bb58e5SYang Zhong } else { 1264d9bb58e5SYang Zhong tn.addr_read = -1; 1265d9bb58e5SYang Zhong } 1266d9bb58e5SYang Zhong 1267d9bb58e5SYang Zhong if (prot & PAGE_EXEC) { 12688f5db641SRichard Henderson tn.addr_code = address; 1269d9bb58e5SYang Zhong } else { 1270d9bb58e5SYang Zhong tn.addr_code = -1; 1271d9bb58e5SYang Zhong } 1272d9bb58e5SYang Zhong 1273d9bb58e5SYang Zhong tn.addr_write = -1; 1274d9bb58e5SYang Zhong if (prot & PAGE_WRITE) { 12758f5db641SRichard Henderson tn.addr_write = write_address; 1276f52bfb12SDavid Hildenbrand if (prot & PAGE_WRITE_INV) { 1277f52bfb12SDavid Hildenbrand tn.addr_write |= TLB_INVALID_MASK; 1278f52bfb12SDavid Hildenbrand } 127950b107c5SRichard Henderson if (wp_flags & BP_MEM_WRITE) { 128050b107c5SRichard Henderson tn.addr_write |= TLB_WATCHPOINT; 128150b107c5SRichard Henderson } 1282d9bb58e5SYang Zhong } 1283d9bb58e5SYang Zhong 128471aec354SEmilio G. Cota copy_tlb_helper_locked(te, &tn); 128586e1eff8SEmilio G. Cota tlb_n_used_entries_inc(env, mmu_idx); 1286a40ec84eSRichard Henderson qemu_spin_unlock(&tlb->c.lock); 1287d9bb58e5SYang Zhong } 1288d9bb58e5SYang Zhong 1289732d5487SAnton Johansson void tlb_set_page_with_attrs(CPUState *cpu, vaddr addr, 129040473689SRichard Henderson hwaddr paddr, MemTxAttrs attrs, int prot, 1291732d5487SAnton Johansson int mmu_idx, uint64_t size) 129240473689SRichard Henderson { 129340473689SRichard Henderson CPUTLBEntryFull full = { 129440473689SRichard Henderson .phys_addr = paddr, 129540473689SRichard Henderson .attrs = attrs, 129640473689SRichard Henderson .prot = prot, 129740473689SRichard Henderson .lg_page_size = ctz64(size) 129840473689SRichard Henderson }; 129940473689SRichard Henderson 130040473689SRichard Henderson assert(is_power_of_2(size)); 1301732d5487SAnton Johansson tlb_set_page_full(cpu, mmu_idx, addr, &full); 130240473689SRichard Henderson } 130340473689SRichard Henderson 1304732d5487SAnton Johansson void tlb_set_page(CPUState *cpu, vaddr addr, 1305d9bb58e5SYang Zhong hwaddr paddr, int prot, 1306732d5487SAnton Johansson int mmu_idx, uint64_t size) 1307d9bb58e5SYang Zhong { 1308732d5487SAnton Johansson tlb_set_page_with_attrs(cpu, addr, paddr, MEMTXATTRS_UNSPECIFIED, 1309d9bb58e5SYang Zhong prot, mmu_idx, size); 1310d9bb58e5SYang Zhong } 1311d9bb58e5SYang Zhong 1312c319dc13SRichard Henderson /* 1313c319dc13SRichard Henderson * Note: tlb_fill() can trigger a resize of the TLB. This means that all of the 1314c319dc13SRichard Henderson * caller's prior references to the TLB table (e.g. CPUTLBEntry pointers) must 1315c319dc13SRichard Henderson * be discarded and looked up again (e.g. via tlb_entry()). 1316c319dc13SRichard Henderson */ 1317732d5487SAnton Johansson static void tlb_fill(CPUState *cpu, vaddr addr, int size, 1318c319dc13SRichard Henderson MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) 1319c319dc13SRichard Henderson { 1320c319dc13SRichard Henderson bool ok; 1321c319dc13SRichard Henderson 1322c319dc13SRichard Henderson /* 1323c319dc13SRichard Henderson * This is not a probe, so only valid return is success; failure 1324c319dc13SRichard Henderson * should result in exception + longjmp to the cpu loop. 1325c319dc13SRichard Henderson */ 13268810ee2aSAlex Bennée ok = cpu->cc->tcg_ops->tlb_fill(cpu, addr, size, 1327e124536fSEduardo Habkost access_type, mmu_idx, false, retaddr); 1328c319dc13SRichard Henderson assert(ok); 1329c319dc13SRichard Henderson } 1330c319dc13SRichard Henderson 133178271684SClaudio Fontana static inline void cpu_unaligned_access(CPUState *cpu, vaddr addr, 133278271684SClaudio Fontana MMUAccessType access_type, 133378271684SClaudio Fontana int mmu_idx, uintptr_t retaddr) 133478271684SClaudio Fontana { 13358810ee2aSAlex Bennée cpu->cc->tcg_ops->do_unaligned_access(cpu, addr, access_type, 13368810ee2aSAlex Bennée mmu_idx, retaddr); 133778271684SClaudio Fontana } 133878271684SClaudio Fontana 133978271684SClaudio Fontana static inline void cpu_transaction_failed(CPUState *cpu, hwaddr physaddr, 134078271684SClaudio Fontana vaddr addr, unsigned size, 134178271684SClaudio Fontana MMUAccessType access_type, 134278271684SClaudio Fontana int mmu_idx, MemTxAttrs attrs, 134378271684SClaudio Fontana MemTxResult response, 134478271684SClaudio Fontana uintptr_t retaddr) 134578271684SClaudio Fontana { 134678271684SClaudio Fontana CPUClass *cc = CPU_GET_CLASS(cpu); 134778271684SClaudio Fontana 134878271684SClaudio Fontana if (!cpu->ignore_memory_transaction_failures && 134978271684SClaudio Fontana cc->tcg_ops->do_transaction_failed) { 135078271684SClaudio Fontana cc->tcg_ops->do_transaction_failed(cpu, physaddr, addr, size, 135178271684SClaudio Fontana access_type, mmu_idx, attrs, 135278271684SClaudio Fontana response, retaddr); 135378271684SClaudio Fontana } 135478271684SClaudio Fontana } 135578271684SClaudio Fontana 135625d3ec58SRichard Henderson static uint64_t io_readx(CPUArchState *env, CPUTLBEntryFull *full, 1357732d5487SAnton Johansson int mmu_idx, vaddr addr, uintptr_t retaddr, 1358be5c4787STony Nguyen MMUAccessType access_type, MemOp op) 1359d9bb58e5SYang Zhong { 136029a0af61SRichard Henderson CPUState *cpu = env_cpu(env); 13612d54f194SPeter Maydell hwaddr mr_offset; 13622d54f194SPeter Maydell MemoryRegionSection *section; 13632d54f194SPeter Maydell MemoryRegion *mr; 1364d9bb58e5SYang Zhong uint64_t val; 136504e3aabdSPeter Maydell MemTxResult r; 1366d9bb58e5SYang Zhong 136725d3ec58SRichard Henderson section = iotlb_to_section(cpu, full->xlat_section, full->attrs); 13682d54f194SPeter Maydell mr = section->mr; 136925d3ec58SRichard Henderson mr_offset = (full->xlat_section & TARGET_PAGE_MASK) + addr; 1370d9bb58e5SYang Zhong cpu->mem_io_pc = retaddr; 137108565552SRichard Henderson if (!cpu->can_do_io) { 1372d9bb58e5SYang Zhong cpu_io_recompile(cpu, retaddr); 1373d9bb58e5SYang Zhong } 1374d9bb58e5SYang Zhong 137561b59fb2SRichard Henderson { 137661b59fb2SRichard Henderson QEMU_IOTHREAD_LOCK_GUARD(); 137725d3ec58SRichard Henderson r = memory_region_dispatch_read(mr, mr_offset, &val, op, full->attrs); 137861b59fb2SRichard Henderson } 137961b59fb2SRichard Henderson 138004e3aabdSPeter Maydell if (r != MEMTX_OK) { 13812d54f194SPeter Maydell hwaddr physaddr = mr_offset + 13822d54f194SPeter Maydell section->offset_within_address_space - 13832d54f194SPeter Maydell section->offset_within_region; 13842d54f194SPeter Maydell 1385be5c4787STony Nguyen cpu_transaction_failed(cpu, physaddr, addr, memop_size(op), access_type, 138625d3ec58SRichard Henderson mmu_idx, full->attrs, r, retaddr); 138704e3aabdSPeter Maydell } 1388d9bb58e5SYang Zhong return val; 1389d9bb58e5SYang Zhong } 1390d9bb58e5SYang Zhong 13912f3a57eeSAlex Bennée /* 139225d3ec58SRichard Henderson * Save a potentially trashed CPUTLBEntryFull for later lookup by plugin. 139325d3ec58SRichard Henderson * This is read by tlb_plugin_lookup if the fulltlb entry doesn't match 1394570ef309SAlex Bennée * because of the side effect of io_writex changing memory layout. 13952f3a57eeSAlex Bennée */ 139637523ff7SRichard Henderson static void save_iotlb_data(CPUState *cs, MemoryRegionSection *section, 139737523ff7SRichard Henderson hwaddr mr_offset) 13982f3a57eeSAlex Bennée { 13992f3a57eeSAlex Bennée #ifdef CONFIG_PLUGIN 14002f3a57eeSAlex Bennée SavedIOTLB *saved = &cs->saved_iotlb; 14012f3a57eeSAlex Bennée saved->section = section; 14022f3a57eeSAlex Bennée saved->mr_offset = mr_offset; 14032f3a57eeSAlex Bennée #endif 14042f3a57eeSAlex Bennée } 14052f3a57eeSAlex Bennée 140625d3ec58SRichard Henderson static void io_writex(CPUArchState *env, CPUTLBEntryFull *full, 1407732d5487SAnton Johansson int mmu_idx, uint64_t val, vaddr addr, 1408be5c4787STony Nguyen uintptr_t retaddr, MemOp op) 1409d9bb58e5SYang Zhong { 141029a0af61SRichard Henderson CPUState *cpu = env_cpu(env); 14112d54f194SPeter Maydell hwaddr mr_offset; 14122d54f194SPeter Maydell MemoryRegionSection *section; 14132d54f194SPeter Maydell MemoryRegion *mr; 141404e3aabdSPeter Maydell MemTxResult r; 1415d9bb58e5SYang Zhong 141625d3ec58SRichard Henderson section = iotlb_to_section(cpu, full->xlat_section, full->attrs); 14172d54f194SPeter Maydell mr = section->mr; 141825d3ec58SRichard Henderson mr_offset = (full->xlat_section & TARGET_PAGE_MASK) + addr; 141908565552SRichard Henderson if (!cpu->can_do_io) { 1420d9bb58e5SYang Zhong cpu_io_recompile(cpu, retaddr); 1421d9bb58e5SYang Zhong } 1422d9bb58e5SYang Zhong cpu->mem_io_pc = retaddr; 1423d9bb58e5SYang Zhong 14242f3a57eeSAlex Bennée /* 14252f3a57eeSAlex Bennée * The memory_region_dispatch may trigger a flush/resize 14262f3a57eeSAlex Bennée * so for plugins we save the iotlb_data just in case. 14272f3a57eeSAlex Bennée */ 142837523ff7SRichard Henderson save_iotlb_data(cpu, section, mr_offset); 14292f3a57eeSAlex Bennée 143061b59fb2SRichard Henderson { 143161b59fb2SRichard Henderson QEMU_IOTHREAD_LOCK_GUARD(); 143225d3ec58SRichard Henderson r = memory_region_dispatch_write(mr, mr_offset, val, op, full->attrs); 143361b59fb2SRichard Henderson } 143461b59fb2SRichard Henderson 143504e3aabdSPeter Maydell if (r != MEMTX_OK) { 14362d54f194SPeter Maydell hwaddr physaddr = mr_offset + 14372d54f194SPeter Maydell section->offset_within_address_space - 14382d54f194SPeter Maydell section->offset_within_region; 14392d54f194SPeter Maydell 1440be5c4787STony Nguyen cpu_transaction_failed(cpu, physaddr, addr, memop_size(op), 144125d3ec58SRichard Henderson MMU_DATA_STORE, mmu_idx, full->attrs, r, 1442be5c4787STony Nguyen retaddr); 144304e3aabdSPeter Maydell } 1444d9bb58e5SYang Zhong } 1445d9bb58e5SYang Zhong 1446d9bb58e5SYang Zhong /* Return true if ADDR is present in the victim tlb, and has been copied 1447d9bb58e5SYang Zhong back to the main tlb. */ 1448d9bb58e5SYang Zhong static bool victim_tlb_hit(CPUArchState *env, size_t mmu_idx, size_t index, 1449732d5487SAnton Johansson MMUAccessType access_type, vaddr page) 1450d9bb58e5SYang Zhong { 1451d9bb58e5SYang Zhong size_t vidx; 145271aec354SEmilio G. Cota 145329a0af61SRichard Henderson assert_cpu_is_self(env_cpu(env)); 1454d9bb58e5SYang Zhong for (vidx = 0; vidx < CPU_VTLB_SIZE; ++vidx) { 1455a40ec84eSRichard Henderson CPUTLBEntry *vtlb = &env_tlb(env)->d[mmu_idx].vtable[vidx]; 14569e39de98SAnton Johansson uint64_t cmp = tlb_read_idx(vtlb, access_type); 1457d9bb58e5SYang Zhong 1458d9bb58e5SYang Zhong if (cmp == page) { 1459d9bb58e5SYang Zhong /* Found entry in victim tlb, swap tlb and iotlb. */ 1460a40ec84eSRichard Henderson CPUTLBEntry tmptlb, *tlb = &env_tlb(env)->f[mmu_idx].table[index]; 1461d9bb58e5SYang Zhong 1462a40ec84eSRichard Henderson qemu_spin_lock(&env_tlb(env)->c.lock); 146371aec354SEmilio G. Cota copy_tlb_helper_locked(&tmptlb, tlb); 146471aec354SEmilio G. Cota copy_tlb_helper_locked(tlb, vtlb); 146571aec354SEmilio G. Cota copy_tlb_helper_locked(vtlb, &tmptlb); 1466a40ec84eSRichard Henderson qemu_spin_unlock(&env_tlb(env)->c.lock); 1467d9bb58e5SYang Zhong 146825d3ec58SRichard Henderson CPUTLBEntryFull *f1 = &env_tlb(env)->d[mmu_idx].fulltlb[index]; 146925d3ec58SRichard Henderson CPUTLBEntryFull *f2 = &env_tlb(env)->d[mmu_idx].vfulltlb[vidx]; 147025d3ec58SRichard Henderson CPUTLBEntryFull tmpf; 147125d3ec58SRichard Henderson tmpf = *f1; *f1 = *f2; *f2 = tmpf; 1472d9bb58e5SYang Zhong return true; 1473d9bb58e5SYang Zhong } 1474d9bb58e5SYang Zhong } 1475d9bb58e5SYang Zhong return false; 1476d9bb58e5SYang Zhong } 1477d9bb58e5SYang Zhong 1478707526adSRichard Henderson static void notdirty_write(CPUState *cpu, vaddr mem_vaddr, unsigned size, 147925d3ec58SRichard Henderson CPUTLBEntryFull *full, uintptr_t retaddr) 1480707526adSRichard Henderson { 148125d3ec58SRichard Henderson ram_addr_t ram_addr = mem_vaddr + full->xlat_section; 1482707526adSRichard Henderson 1483707526adSRichard Henderson trace_memory_notdirty_write_access(mem_vaddr, ram_addr, size); 1484707526adSRichard Henderson 1485707526adSRichard Henderson if (!cpu_physical_memory_get_dirty_flag(ram_addr, DIRTY_MEMORY_CODE)) { 1486f349e92eSPhilippe Mathieu-Daudé tb_invalidate_phys_range_fast(ram_addr, size, retaddr); 1487707526adSRichard Henderson } 1488707526adSRichard Henderson 1489707526adSRichard Henderson /* 1490707526adSRichard Henderson * Set both VGA and migration bits for simplicity and to remove 1491707526adSRichard Henderson * the notdirty callback faster. 1492707526adSRichard Henderson */ 1493707526adSRichard Henderson cpu_physical_memory_set_dirty_range(ram_addr, size, DIRTY_CLIENTS_NOCODE); 1494707526adSRichard Henderson 1495707526adSRichard Henderson /* We remove the notdirty callback only if the code has been flushed. */ 1496707526adSRichard Henderson if (!cpu_physical_memory_is_clean(ram_addr)) { 1497707526adSRichard Henderson trace_memory_notdirty_set_dirty(mem_vaddr); 1498707526adSRichard Henderson tlb_set_dirty(cpu, mem_vaddr); 1499707526adSRichard Henderson } 1500707526adSRichard Henderson } 1501707526adSRichard Henderson 15024f8f4127SAnton Johansson static int probe_access_internal(CPUArchState *env, vaddr addr, 1503069cfe77SRichard Henderson int fault_size, MMUAccessType access_type, 1504069cfe77SRichard Henderson int mmu_idx, bool nonfault, 1505af803a4fSRichard Henderson void **phost, CPUTLBEntryFull **pfull, 1506af803a4fSRichard Henderson uintptr_t retaddr) 1507d9bb58e5SYang Zhong { 1508383beda9SRichard Henderson uintptr_t index = tlb_index(env, mmu_idx, addr); 1509383beda9SRichard Henderson CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); 15109e39de98SAnton Johansson uint64_t tlb_addr = tlb_read_idx(entry, access_type); 15114f8f4127SAnton Johansson vaddr page_addr = addr & TARGET_PAGE_MASK; 15120b3c75adSRichard Henderson int flags = TLB_FLAGS_MASK; 1513ca86cf32SDavid Hildenbrand 1514069cfe77SRichard Henderson if (!tlb_hit_page(tlb_addr, page_addr)) { 15150b3c75adSRichard Henderson if (!victim_tlb_hit(env, mmu_idx, index, access_type, page_addr)) { 1516069cfe77SRichard Henderson CPUState *cs = env_cpu(env); 1517069cfe77SRichard Henderson 15188810ee2aSAlex Bennée if (!cs->cc->tcg_ops->tlb_fill(cs, addr, fault_size, access_type, 1519069cfe77SRichard Henderson mmu_idx, nonfault, retaddr)) { 1520069cfe77SRichard Henderson /* Non-faulting page table read failed. */ 1521069cfe77SRichard Henderson *phost = NULL; 1522af803a4fSRichard Henderson *pfull = NULL; 1523069cfe77SRichard Henderson return TLB_INVALID_MASK; 1524069cfe77SRichard Henderson } 1525069cfe77SRichard Henderson 152603a98189SDavid Hildenbrand /* TLB resize via tlb_fill may have moved the entry. */ 1527af803a4fSRichard Henderson index = tlb_index(env, mmu_idx, addr); 152803a98189SDavid Hildenbrand entry = tlb_entry(env, mmu_idx, addr); 1529c3c8bf57SRichard Henderson 1530c3c8bf57SRichard Henderson /* 1531c3c8bf57SRichard Henderson * With PAGE_WRITE_INV, we set TLB_INVALID_MASK immediately, 1532c3c8bf57SRichard Henderson * to force the next access through tlb_fill. We've just 1533c3c8bf57SRichard Henderson * called tlb_fill, so we know that this entry *is* valid. 1534c3c8bf57SRichard Henderson */ 1535c3c8bf57SRichard Henderson flags &= ~TLB_INVALID_MASK; 1536d9bb58e5SYang Zhong } 15370b3c75adSRichard Henderson tlb_addr = tlb_read_idx(entry, access_type); 153803a98189SDavid Hildenbrand } 1539c3c8bf57SRichard Henderson flags &= tlb_addr; 154003a98189SDavid Hildenbrand 1541af803a4fSRichard Henderson *pfull = &env_tlb(env)->d[mmu_idx].fulltlb[index]; 1542af803a4fSRichard Henderson 1543069cfe77SRichard Henderson /* Fold all "mmio-like" bits into TLB_MMIO. This is not RAM. */ 1544069cfe77SRichard Henderson if (unlikely(flags & ~(TLB_WATCHPOINT | TLB_NOTDIRTY))) { 1545069cfe77SRichard Henderson *phost = NULL; 1546069cfe77SRichard Henderson return TLB_MMIO; 1547fef39ccdSDavid Hildenbrand } 1548fef39ccdSDavid Hildenbrand 1549069cfe77SRichard Henderson /* Everything else is RAM. */ 1550069cfe77SRichard Henderson *phost = (void *)((uintptr_t)addr + entry->addend); 1551069cfe77SRichard Henderson return flags; 1552069cfe77SRichard Henderson } 1553069cfe77SRichard Henderson 15544f8f4127SAnton Johansson int probe_access_full(CPUArchState *env, vaddr addr, int size, 1555069cfe77SRichard Henderson MMUAccessType access_type, int mmu_idx, 1556af803a4fSRichard Henderson bool nonfault, void **phost, CPUTLBEntryFull **pfull, 1557af803a4fSRichard Henderson uintptr_t retaddr) 1558069cfe77SRichard Henderson { 1559d507e6c5SRichard Henderson int flags = probe_access_internal(env, addr, size, access_type, mmu_idx, 1560af803a4fSRichard Henderson nonfault, phost, pfull, retaddr); 1561069cfe77SRichard Henderson 1562069cfe77SRichard Henderson /* Handle clean RAM pages. */ 1563069cfe77SRichard Henderson if (unlikely(flags & TLB_NOTDIRTY)) { 1564af803a4fSRichard Henderson notdirty_write(env_cpu(env), addr, 1, *pfull, retaddr); 1565069cfe77SRichard Henderson flags &= ~TLB_NOTDIRTY; 1566069cfe77SRichard Henderson } 1567069cfe77SRichard Henderson 1568069cfe77SRichard Henderson return flags; 1569069cfe77SRichard Henderson } 1570069cfe77SRichard Henderson 15714f8f4127SAnton Johansson int probe_access_flags(CPUArchState *env, vaddr addr, int size, 1572af803a4fSRichard Henderson MMUAccessType access_type, int mmu_idx, 1573af803a4fSRichard Henderson bool nonfault, void **phost, uintptr_t retaddr) 1574af803a4fSRichard Henderson { 1575af803a4fSRichard Henderson CPUTLBEntryFull *full; 15761770b2f2SDaniel Henrique Barboza int flags; 1577af803a4fSRichard Henderson 15781770b2f2SDaniel Henrique Barboza g_assert(-(addr | TARGET_PAGE_MASK) >= size); 15791770b2f2SDaniel Henrique Barboza 15801770b2f2SDaniel Henrique Barboza flags = probe_access_internal(env, addr, size, access_type, mmu_idx, 1581af803a4fSRichard Henderson nonfault, phost, &full, retaddr); 15821770b2f2SDaniel Henrique Barboza 15831770b2f2SDaniel Henrique Barboza /* Handle clean RAM pages. */ 15841770b2f2SDaniel Henrique Barboza if (unlikely(flags & TLB_NOTDIRTY)) { 15851770b2f2SDaniel Henrique Barboza notdirty_write(env_cpu(env), addr, 1, full, retaddr); 15861770b2f2SDaniel Henrique Barboza flags &= ~TLB_NOTDIRTY; 15871770b2f2SDaniel Henrique Barboza } 15881770b2f2SDaniel Henrique Barboza 15891770b2f2SDaniel Henrique Barboza return flags; 1590af803a4fSRichard Henderson } 1591af803a4fSRichard Henderson 15924f8f4127SAnton Johansson void *probe_access(CPUArchState *env, vaddr addr, int size, 1593069cfe77SRichard Henderson MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) 1594069cfe77SRichard Henderson { 1595af803a4fSRichard Henderson CPUTLBEntryFull *full; 1596069cfe77SRichard Henderson void *host; 1597069cfe77SRichard Henderson int flags; 1598069cfe77SRichard Henderson 1599069cfe77SRichard Henderson g_assert(-(addr | TARGET_PAGE_MASK) >= size); 1600069cfe77SRichard Henderson 1601069cfe77SRichard Henderson flags = probe_access_internal(env, addr, size, access_type, mmu_idx, 1602af803a4fSRichard Henderson false, &host, &full, retaddr); 1603069cfe77SRichard Henderson 1604069cfe77SRichard Henderson /* Per the interface, size == 0 merely faults the access. */ 1605069cfe77SRichard Henderson if (size == 0) { 160673bc0bd4SRichard Henderson return NULL; 160773bc0bd4SRichard Henderson } 160873bc0bd4SRichard Henderson 1609069cfe77SRichard Henderson if (unlikely(flags & (TLB_NOTDIRTY | TLB_WATCHPOINT))) { 161003a98189SDavid Hildenbrand /* Handle watchpoints. */ 1611069cfe77SRichard Henderson if (flags & TLB_WATCHPOINT) { 1612069cfe77SRichard Henderson int wp_access = (access_type == MMU_DATA_STORE 1613069cfe77SRichard Henderson ? BP_MEM_WRITE : BP_MEM_READ); 161403a98189SDavid Hildenbrand cpu_check_watchpoint(env_cpu(env), addr, size, 161525d3ec58SRichard Henderson full->attrs, wp_access, retaddr); 1616d9bb58e5SYang Zhong } 1617fef39ccdSDavid Hildenbrand 161873bc0bd4SRichard Henderson /* Handle clean RAM pages. */ 1619069cfe77SRichard Henderson if (flags & TLB_NOTDIRTY) { 162025d3ec58SRichard Henderson notdirty_write(env_cpu(env), addr, 1, full, retaddr); 162173bc0bd4SRichard Henderson } 1622fef39ccdSDavid Hildenbrand } 1623fef39ccdSDavid Hildenbrand 1624069cfe77SRichard Henderson return host; 1625d9bb58e5SYang Zhong } 1626d9bb58e5SYang Zhong 16274811e909SRichard Henderson void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr, 16284811e909SRichard Henderson MMUAccessType access_type, int mmu_idx) 16294811e909SRichard Henderson { 1630af803a4fSRichard Henderson CPUTLBEntryFull *full; 1631069cfe77SRichard Henderson void *host; 1632069cfe77SRichard Henderson int flags; 16334811e909SRichard Henderson 1634069cfe77SRichard Henderson flags = probe_access_internal(env, addr, 0, access_type, 1635af803a4fSRichard Henderson mmu_idx, true, &host, &full, 0); 1636069cfe77SRichard Henderson 1637069cfe77SRichard Henderson /* No combination of flags are expected by the caller. */ 1638069cfe77SRichard Henderson return flags ? NULL : host; 16394811e909SRichard Henderson } 16404811e909SRichard Henderson 16417e0d9973SRichard Henderson /* 16427e0d9973SRichard Henderson * Return a ram_addr_t for the virtual address for execution. 16437e0d9973SRichard Henderson * 16447e0d9973SRichard Henderson * Return -1 if we can't translate and execute from an entire page 16457e0d9973SRichard Henderson * of RAM. This will force us to execute by loading and translating 16467e0d9973SRichard Henderson * one insn at a time, without caching. 16477e0d9973SRichard Henderson * 16487e0d9973SRichard Henderson * NOTE: This function will trigger an exception if the page is 16497e0d9973SRichard Henderson * not executable. 16507e0d9973SRichard Henderson */ 16514f8f4127SAnton Johansson tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, vaddr addr, 16527e0d9973SRichard Henderson void **hostp) 16537e0d9973SRichard Henderson { 1654af803a4fSRichard Henderson CPUTLBEntryFull *full; 16557e0d9973SRichard Henderson void *p; 16567e0d9973SRichard Henderson 16577e0d9973SRichard Henderson (void)probe_access_internal(env, addr, 1, MMU_INST_FETCH, 1658af803a4fSRichard Henderson cpu_mmu_index(env, true), false, &p, &full, 0); 16597e0d9973SRichard Henderson if (p == NULL) { 16607e0d9973SRichard Henderson return -1; 16617e0d9973SRichard Henderson } 1662ac01ec6fSWeiwei Li 1663ac01ec6fSWeiwei Li if (full->lg_page_size < TARGET_PAGE_BITS) { 1664ac01ec6fSWeiwei Li return -1; 1665ac01ec6fSWeiwei Li } 1666ac01ec6fSWeiwei Li 16677e0d9973SRichard Henderson if (hostp) { 16687e0d9973SRichard Henderson *hostp = p; 16697e0d9973SRichard Henderson } 16707e0d9973SRichard Henderson return qemu_ram_addr_from_host_nofail(p); 16717e0d9973SRichard Henderson } 16727e0d9973SRichard Henderson 1673cdfac37bSRichard Henderson /* Load/store with atomicity primitives. */ 1674cdfac37bSRichard Henderson #include "ldst_atomicity.c.inc" 1675cdfac37bSRichard Henderson 1676235537faSAlex Bennée #ifdef CONFIG_PLUGIN 1677235537faSAlex Bennée /* 1678235537faSAlex Bennée * Perform a TLB lookup and populate the qemu_plugin_hwaddr structure. 1679235537faSAlex Bennée * This should be a hot path as we will have just looked this path up 1680235537faSAlex Bennée * in the softmmu lookup code (or helper). We don't handle re-fills or 1681235537faSAlex Bennée * checking the victim table. This is purely informational. 1682235537faSAlex Bennée * 16832f3a57eeSAlex Bennée * This almost never fails as the memory access being instrumented 16842f3a57eeSAlex Bennée * should have just filled the TLB. The one corner case is io_writex 16852f3a57eeSAlex Bennée * which can cause TLB flushes and potential resizing of the TLBs 1686570ef309SAlex Bennée * losing the information we need. In those cases we need to recover 168725d3ec58SRichard Henderson * data from a copy of the CPUTLBEntryFull. As long as this always occurs 1688570ef309SAlex Bennée * from the same thread (which a mem callback will be) this is safe. 1689235537faSAlex Bennée */ 1690235537faSAlex Bennée 1691732d5487SAnton Johansson bool tlb_plugin_lookup(CPUState *cpu, vaddr addr, int mmu_idx, 1692235537faSAlex Bennée bool is_store, struct qemu_plugin_hwaddr *data) 1693235537faSAlex Bennée { 1694235537faSAlex Bennée CPUArchState *env = cpu->env_ptr; 1695235537faSAlex Bennée CPUTLBEntry *tlbe = tlb_entry(env, mmu_idx, addr); 1696235537faSAlex Bennée uintptr_t index = tlb_index(env, mmu_idx, addr); 16979e39de98SAnton Johansson uint64_t tlb_addr = is_store ? tlb_addr_write(tlbe) : tlbe->addr_read; 1698235537faSAlex Bennée 1699235537faSAlex Bennée if (likely(tlb_hit(tlb_addr, addr))) { 1700235537faSAlex Bennée /* We must have an iotlb entry for MMIO */ 1701235537faSAlex Bennée if (tlb_addr & TLB_MMIO) { 170225d3ec58SRichard Henderson CPUTLBEntryFull *full; 170325d3ec58SRichard Henderson full = &env_tlb(env)->d[mmu_idx].fulltlb[index]; 1704235537faSAlex Bennée data->is_io = true; 170525d3ec58SRichard Henderson data->v.io.section = 170625d3ec58SRichard Henderson iotlb_to_section(cpu, full->xlat_section, full->attrs); 170725d3ec58SRichard Henderson data->v.io.offset = (full->xlat_section & TARGET_PAGE_MASK) + addr; 1708235537faSAlex Bennée } else { 1709235537faSAlex Bennée data->is_io = false; 17102d932039SAlex Bennée data->v.ram.hostaddr = (void *)((uintptr_t)addr + tlbe->addend); 1711235537faSAlex Bennée } 1712235537faSAlex Bennée return true; 17132f3a57eeSAlex Bennée } else { 17142f3a57eeSAlex Bennée SavedIOTLB *saved = &cpu->saved_iotlb; 17152f3a57eeSAlex Bennée data->is_io = true; 17162f3a57eeSAlex Bennée data->v.io.section = saved->section; 17172f3a57eeSAlex Bennée data->v.io.offset = saved->mr_offset; 17182f3a57eeSAlex Bennée return true; 1719235537faSAlex Bennée } 1720235537faSAlex Bennée } 1721235537faSAlex Bennée 1722235537faSAlex Bennée #endif 1723235537faSAlex Bennée 172408dff435SRichard Henderson /* 17258cfdacaaSRichard Henderson * Probe for a load/store operation. 17268cfdacaaSRichard Henderson * Return the host address and into @flags. 17278cfdacaaSRichard Henderson */ 17288cfdacaaSRichard Henderson 17298cfdacaaSRichard Henderson typedef struct MMULookupPageData { 17308cfdacaaSRichard Henderson CPUTLBEntryFull *full; 17318cfdacaaSRichard Henderson void *haddr; 1732fb2c53cbSAnton Johansson vaddr addr; 17338cfdacaaSRichard Henderson int flags; 17348cfdacaaSRichard Henderson int size; 17358cfdacaaSRichard Henderson } MMULookupPageData; 17368cfdacaaSRichard Henderson 17378cfdacaaSRichard Henderson typedef struct MMULookupLocals { 17388cfdacaaSRichard Henderson MMULookupPageData page[2]; 17398cfdacaaSRichard Henderson MemOp memop; 17408cfdacaaSRichard Henderson int mmu_idx; 17418cfdacaaSRichard Henderson } MMULookupLocals; 17428cfdacaaSRichard Henderson 17438cfdacaaSRichard Henderson /** 17448cfdacaaSRichard Henderson * mmu_lookup1: translate one page 17458cfdacaaSRichard Henderson * @env: cpu context 17468cfdacaaSRichard Henderson * @data: lookup parameters 17478cfdacaaSRichard Henderson * @mmu_idx: virtual address context 17488cfdacaaSRichard Henderson * @access_type: load/store/code 17498cfdacaaSRichard Henderson * @ra: return address into tcg generated code, or 0 17508cfdacaaSRichard Henderson * 17518cfdacaaSRichard Henderson * Resolve the translation for the one page at @data.addr, filling in 17528cfdacaaSRichard Henderson * the rest of @data with the results. If the translation fails, 17538cfdacaaSRichard Henderson * tlb_fill will longjmp out. Return true if the softmmu tlb for 17548cfdacaaSRichard Henderson * @mmu_idx may have resized. 17558cfdacaaSRichard Henderson */ 17568cfdacaaSRichard Henderson static bool mmu_lookup1(CPUArchState *env, MMULookupPageData *data, 17578cfdacaaSRichard Henderson int mmu_idx, MMUAccessType access_type, uintptr_t ra) 17588cfdacaaSRichard Henderson { 1759fb2c53cbSAnton Johansson vaddr addr = data->addr; 17608cfdacaaSRichard Henderson uintptr_t index = tlb_index(env, mmu_idx, addr); 17618cfdacaaSRichard Henderson CPUTLBEntry *entry = tlb_entry(env, mmu_idx, addr); 17629e39de98SAnton Johansson uint64_t tlb_addr = tlb_read_idx(entry, access_type); 17638cfdacaaSRichard Henderson bool maybe_resized = false; 17648cfdacaaSRichard Henderson 17658cfdacaaSRichard Henderson /* If the TLB entry is for a different page, reload and try again. */ 17668cfdacaaSRichard Henderson if (!tlb_hit(tlb_addr, addr)) { 17678cfdacaaSRichard Henderson if (!victim_tlb_hit(env, mmu_idx, index, access_type, 17688cfdacaaSRichard Henderson addr & TARGET_PAGE_MASK)) { 17698cfdacaaSRichard Henderson tlb_fill(env_cpu(env), addr, data->size, access_type, mmu_idx, ra); 17708cfdacaaSRichard Henderson maybe_resized = true; 17718cfdacaaSRichard Henderson index = tlb_index(env, mmu_idx, addr); 17728cfdacaaSRichard Henderson entry = tlb_entry(env, mmu_idx, addr); 17738cfdacaaSRichard Henderson } 17748cfdacaaSRichard Henderson tlb_addr = tlb_read_idx(entry, access_type) & ~TLB_INVALID_MASK; 17758cfdacaaSRichard Henderson } 17768cfdacaaSRichard Henderson 17778cfdacaaSRichard Henderson data->flags = tlb_addr & TLB_FLAGS_MASK; 17788cfdacaaSRichard Henderson data->full = &env_tlb(env)->d[mmu_idx].fulltlb[index]; 17798cfdacaaSRichard Henderson /* Compute haddr speculatively; depending on flags it might be invalid. */ 17808cfdacaaSRichard Henderson data->haddr = (void *)((uintptr_t)addr + entry->addend); 17818cfdacaaSRichard Henderson 17828cfdacaaSRichard Henderson return maybe_resized; 17838cfdacaaSRichard Henderson } 17848cfdacaaSRichard Henderson 17858cfdacaaSRichard Henderson /** 17868cfdacaaSRichard Henderson * mmu_watch_or_dirty 17878cfdacaaSRichard Henderson * @env: cpu context 17888cfdacaaSRichard Henderson * @data: lookup parameters 17898cfdacaaSRichard Henderson * @access_type: load/store/code 17908cfdacaaSRichard Henderson * @ra: return address into tcg generated code, or 0 17918cfdacaaSRichard Henderson * 17928cfdacaaSRichard Henderson * Trigger watchpoints for @data.addr:@data.size; 17938cfdacaaSRichard Henderson * record writes to protected clean pages. 17948cfdacaaSRichard Henderson */ 17958cfdacaaSRichard Henderson static void mmu_watch_or_dirty(CPUArchState *env, MMULookupPageData *data, 17968cfdacaaSRichard Henderson MMUAccessType access_type, uintptr_t ra) 17978cfdacaaSRichard Henderson { 17988cfdacaaSRichard Henderson CPUTLBEntryFull *full = data->full; 1799fb2c53cbSAnton Johansson vaddr addr = data->addr; 18008cfdacaaSRichard Henderson int flags = data->flags; 18018cfdacaaSRichard Henderson int size = data->size; 18028cfdacaaSRichard Henderson 18038cfdacaaSRichard Henderson /* On watchpoint hit, this will longjmp out. */ 18048cfdacaaSRichard Henderson if (flags & TLB_WATCHPOINT) { 18058cfdacaaSRichard Henderson int wp = access_type == MMU_DATA_STORE ? BP_MEM_WRITE : BP_MEM_READ; 18068cfdacaaSRichard Henderson cpu_check_watchpoint(env_cpu(env), addr, size, full->attrs, wp, ra); 18078cfdacaaSRichard Henderson flags &= ~TLB_WATCHPOINT; 18088cfdacaaSRichard Henderson } 18098cfdacaaSRichard Henderson 18108cfdacaaSRichard Henderson /* Note that notdirty is only set for writes. */ 18118cfdacaaSRichard Henderson if (flags & TLB_NOTDIRTY) { 18128cfdacaaSRichard Henderson notdirty_write(env_cpu(env), addr, size, full, ra); 18138cfdacaaSRichard Henderson flags &= ~TLB_NOTDIRTY; 18148cfdacaaSRichard Henderson } 18158cfdacaaSRichard Henderson data->flags = flags; 18168cfdacaaSRichard Henderson } 18178cfdacaaSRichard Henderson 18188cfdacaaSRichard Henderson /** 18198cfdacaaSRichard Henderson * mmu_lookup: translate page(s) 18208cfdacaaSRichard Henderson * @env: cpu context 18218cfdacaaSRichard Henderson * @addr: virtual address 18228cfdacaaSRichard Henderson * @oi: combined mmu_idx and MemOp 18238cfdacaaSRichard Henderson * @ra: return address into tcg generated code, or 0 18248cfdacaaSRichard Henderson * @access_type: load/store/code 18258cfdacaaSRichard Henderson * @l: output result 18268cfdacaaSRichard Henderson * 18278cfdacaaSRichard Henderson * Resolve the translation for the page(s) beginning at @addr, for MemOp.size 18288cfdacaaSRichard Henderson * bytes. Return true if the lookup crosses a page boundary. 18298cfdacaaSRichard Henderson */ 1830fb2c53cbSAnton Johansson static bool mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, 18318cfdacaaSRichard Henderson uintptr_t ra, MMUAccessType type, MMULookupLocals *l) 18328cfdacaaSRichard Henderson { 18338cfdacaaSRichard Henderson unsigned a_bits; 18348cfdacaaSRichard Henderson bool crosspage; 18358cfdacaaSRichard Henderson int flags; 18368cfdacaaSRichard Henderson 18378cfdacaaSRichard Henderson l->memop = get_memop(oi); 18388cfdacaaSRichard Henderson l->mmu_idx = get_mmuidx(oi); 18398cfdacaaSRichard Henderson 18408cfdacaaSRichard Henderson tcg_debug_assert(l->mmu_idx < NB_MMU_MODES); 18418cfdacaaSRichard Henderson 18428cfdacaaSRichard Henderson /* Handle CPU specific unaligned behaviour */ 18438cfdacaaSRichard Henderson a_bits = get_alignment_bits(l->memop); 18448cfdacaaSRichard Henderson if (addr & ((1 << a_bits) - 1)) { 18458cfdacaaSRichard Henderson cpu_unaligned_access(env_cpu(env), addr, type, l->mmu_idx, ra); 18468cfdacaaSRichard Henderson } 18478cfdacaaSRichard Henderson 18488cfdacaaSRichard Henderson l->page[0].addr = addr; 18498cfdacaaSRichard Henderson l->page[0].size = memop_size(l->memop); 18508cfdacaaSRichard Henderson l->page[1].addr = (addr + l->page[0].size - 1) & TARGET_PAGE_MASK; 18518cfdacaaSRichard Henderson l->page[1].size = 0; 18528cfdacaaSRichard Henderson crosspage = (addr ^ l->page[1].addr) & TARGET_PAGE_MASK; 18538cfdacaaSRichard Henderson 18548cfdacaaSRichard Henderson if (likely(!crosspage)) { 18558cfdacaaSRichard Henderson mmu_lookup1(env, &l->page[0], l->mmu_idx, type, ra); 18568cfdacaaSRichard Henderson 18578cfdacaaSRichard Henderson flags = l->page[0].flags; 18588cfdacaaSRichard Henderson if (unlikely(flags & (TLB_WATCHPOINT | TLB_NOTDIRTY))) { 18598cfdacaaSRichard Henderson mmu_watch_or_dirty(env, &l->page[0], type, ra); 18608cfdacaaSRichard Henderson } 18618cfdacaaSRichard Henderson if (unlikely(flags & TLB_BSWAP)) { 18628cfdacaaSRichard Henderson l->memop ^= MO_BSWAP; 18638cfdacaaSRichard Henderson } 18648cfdacaaSRichard Henderson } else { 18658cfdacaaSRichard Henderson /* Finish compute of page crossing. */ 18668cfdacaaSRichard Henderson int size0 = l->page[1].addr - addr; 18678cfdacaaSRichard Henderson l->page[1].size = l->page[0].size - size0; 18688cfdacaaSRichard Henderson l->page[0].size = size0; 18698cfdacaaSRichard Henderson 18708cfdacaaSRichard Henderson /* 18718cfdacaaSRichard Henderson * Lookup both pages, recognizing exceptions from either. If the 18728cfdacaaSRichard Henderson * second lookup potentially resized, refresh first CPUTLBEntryFull. 18738cfdacaaSRichard Henderson */ 18748cfdacaaSRichard Henderson mmu_lookup1(env, &l->page[0], l->mmu_idx, type, ra); 18758cfdacaaSRichard Henderson if (mmu_lookup1(env, &l->page[1], l->mmu_idx, type, ra)) { 18768cfdacaaSRichard Henderson uintptr_t index = tlb_index(env, l->mmu_idx, addr); 18778cfdacaaSRichard Henderson l->page[0].full = &env_tlb(env)->d[l->mmu_idx].fulltlb[index]; 18788cfdacaaSRichard Henderson } 18798cfdacaaSRichard Henderson 18808cfdacaaSRichard Henderson flags = l->page[0].flags | l->page[1].flags; 18818cfdacaaSRichard Henderson if (unlikely(flags & (TLB_WATCHPOINT | TLB_NOTDIRTY))) { 18828cfdacaaSRichard Henderson mmu_watch_or_dirty(env, &l->page[0], type, ra); 18838cfdacaaSRichard Henderson mmu_watch_or_dirty(env, &l->page[1], type, ra); 18848cfdacaaSRichard Henderson } 18858cfdacaaSRichard Henderson 18868cfdacaaSRichard Henderson /* 18878cfdacaaSRichard Henderson * Since target/sparc is the only user of TLB_BSWAP, and all 18888cfdacaaSRichard Henderson * Sparc accesses are aligned, any treatment across two pages 18898cfdacaaSRichard Henderson * would be arbitrary. Refuse it until there's a use. 18908cfdacaaSRichard Henderson */ 18918cfdacaaSRichard Henderson tcg_debug_assert((flags & TLB_BSWAP) == 0); 18928cfdacaaSRichard Henderson } 18938cfdacaaSRichard Henderson 18948cfdacaaSRichard Henderson return crosspage; 18958cfdacaaSRichard Henderson } 18968cfdacaaSRichard Henderson 18978cfdacaaSRichard Henderson /* 189808dff435SRichard Henderson * Probe for an atomic operation. Do not allow unaligned operations, 189908dff435SRichard Henderson * or io operations to proceed. Return the host address. 190008dff435SRichard Henderson */ 1901*b0326eb9SAnton Johansson static void *atomic_mmu_lookup(CPUArchState *env, vaddr addr, MemOpIdx oi, 1902*b0326eb9SAnton Johansson int size, uintptr_t retaddr) 1903d9bb58e5SYang Zhong { 1904b826044fSRichard Henderson uintptr_t mmu_idx = get_mmuidx(oi); 190514776ab5STony Nguyen MemOp mop = get_memop(oi); 1906d9bb58e5SYang Zhong int a_bits = get_alignment_bits(mop); 190708dff435SRichard Henderson uintptr_t index; 190808dff435SRichard Henderson CPUTLBEntry *tlbe; 1909*b0326eb9SAnton Johansson vaddr tlb_addr; 191034d49937SPeter Maydell void *hostaddr; 1911417aeaffSRichard Henderson CPUTLBEntryFull *full; 1912d9bb58e5SYang Zhong 1913b826044fSRichard Henderson tcg_debug_assert(mmu_idx < NB_MMU_MODES); 1914b826044fSRichard Henderson 1915d9bb58e5SYang Zhong /* Adjust the given return address. */ 1916d9bb58e5SYang Zhong retaddr -= GETPC_ADJ; 1917d9bb58e5SYang Zhong 1918d9bb58e5SYang Zhong /* Enforce guest required alignment. */ 1919d9bb58e5SYang Zhong if (unlikely(a_bits > 0 && (addr & ((1 << a_bits) - 1)))) { 1920d9bb58e5SYang Zhong /* ??? Maybe indicate atomic op to cpu_unaligned_access */ 192129a0af61SRichard Henderson cpu_unaligned_access(env_cpu(env), addr, MMU_DATA_STORE, 1922d9bb58e5SYang Zhong mmu_idx, retaddr); 1923d9bb58e5SYang Zhong } 1924d9bb58e5SYang Zhong 1925d9bb58e5SYang Zhong /* Enforce qemu required alignment. */ 192608dff435SRichard Henderson if (unlikely(addr & (size - 1))) { 1927d9bb58e5SYang Zhong /* We get here if guest alignment was not requested, 1928d9bb58e5SYang Zhong or was not enforced by cpu_unaligned_access above. 1929d9bb58e5SYang Zhong We might widen the access and emulate, but for now 1930d9bb58e5SYang Zhong mark an exception and exit the cpu loop. */ 1931d9bb58e5SYang Zhong goto stop_the_world; 1932d9bb58e5SYang Zhong } 1933d9bb58e5SYang Zhong 193408dff435SRichard Henderson index = tlb_index(env, mmu_idx, addr); 193508dff435SRichard Henderson tlbe = tlb_entry(env, mmu_idx, addr); 193608dff435SRichard Henderson 1937d9bb58e5SYang Zhong /* Check TLB entry and enforce page permissions. */ 193808dff435SRichard Henderson tlb_addr = tlb_addr_write(tlbe); 1939334692bcSPeter Maydell if (!tlb_hit(tlb_addr, addr)) { 19400b3c75adSRichard Henderson if (!victim_tlb_hit(env, mmu_idx, index, MMU_DATA_STORE, 19410b3c75adSRichard Henderson addr & TARGET_PAGE_MASK)) { 194208dff435SRichard Henderson tlb_fill(env_cpu(env), addr, size, 194308dff435SRichard Henderson MMU_DATA_STORE, mmu_idx, retaddr); 19446d967cb8SEmilio G. Cota index = tlb_index(env, mmu_idx, addr); 19456d967cb8SEmilio G. Cota tlbe = tlb_entry(env, mmu_idx, addr); 1946d9bb58e5SYang Zhong } 1947403f290cSEmilio G. Cota tlb_addr = tlb_addr_write(tlbe) & ~TLB_INVALID_MASK; 1948d9bb58e5SYang Zhong } 1949d9bb58e5SYang Zhong 1950417aeaffSRichard Henderson /* 1951417aeaffSRichard Henderson * Let the guest notice RMW on a write-only page. 1952417aeaffSRichard Henderson * We have just verified that the page is writable. 1953417aeaffSRichard Henderson * Subpage lookups may have left TLB_INVALID_MASK set, 1954417aeaffSRichard Henderson * but addr_read will only be -1 if PAGE_READ was unset. 1955417aeaffSRichard Henderson */ 1956417aeaffSRichard Henderson if (unlikely(tlbe->addr_read == -1)) { 19577bedee32SRichard Henderson tlb_fill(env_cpu(env), addr, size, MMU_DATA_LOAD, mmu_idx, retaddr); 195808dff435SRichard Henderson /* 1959417aeaffSRichard Henderson * Since we don't support reads and writes to different 1960417aeaffSRichard Henderson * addresses, and we do have the proper page loaded for 1961417aeaffSRichard Henderson * write, this shouldn't ever return. But just in case, 1962417aeaffSRichard Henderson * handle via stop-the-world. 196308dff435SRichard Henderson */ 196408dff435SRichard Henderson goto stop_the_world; 196508dff435SRichard Henderson } 1966417aeaffSRichard Henderson /* Collect TLB_WATCHPOINT for read. */ 1967417aeaffSRichard Henderson tlb_addr |= tlbe->addr_read; 196808dff435SRichard Henderson 196955df6fcfSPeter Maydell /* Notice an IO access or a needs-MMU-lookup access */ 19700953674eSRichard Henderson if (unlikely(tlb_addr & (TLB_MMIO | TLB_DISCARD_WRITE))) { 1971d9bb58e5SYang Zhong /* There's really nothing that can be done to 1972d9bb58e5SYang Zhong support this apart from stop-the-world. */ 1973d9bb58e5SYang Zhong goto stop_the_world; 1974d9bb58e5SYang Zhong } 1975d9bb58e5SYang Zhong 197634d49937SPeter Maydell hostaddr = (void *)((uintptr_t)addr + tlbe->addend); 1977417aeaffSRichard Henderson full = &env_tlb(env)->d[mmu_idx].fulltlb[index]; 197834d49937SPeter Maydell 197934d49937SPeter Maydell if (unlikely(tlb_addr & TLB_NOTDIRTY)) { 1980417aeaffSRichard Henderson notdirty_write(env_cpu(env), addr, size, full, retaddr); 1981417aeaffSRichard Henderson } 1982417aeaffSRichard Henderson 1983417aeaffSRichard Henderson if (unlikely(tlb_addr & TLB_WATCHPOINT)) { 19847bedee32SRichard Henderson cpu_check_watchpoint(env_cpu(env), addr, size, full->attrs, 19857bedee32SRichard Henderson BP_MEM_READ | BP_MEM_WRITE, retaddr); 198634d49937SPeter Maydell } 198734d49937SPeter Maydell 198834d49937SPeter Maydell return hostaddr; 1989d9bb58e5SYang Zhong 1990d9bb58e5SYang Zhong stop_the_world: 199129a0af61SRichard Henderson cpu_loop_exit_atomic(env_cpu(env), retaddr); 1992d9bb58e5SYang Zhong } 1993d9bb58e5SYang Zhong 1994eed56642SAlex Bennée /* 1995eed56642SAlex Bennée * Load Helpers 1996eed56642SAlex Bennée * 1997eed56642SAlex Bennée * We support two different access types. SOFTMMU_CODE_ACCESS is 1998eed56642SAlex Bennée * specifically for reading instructions from system memory. It is 1999eed56642SAlex Bennée * called by the translation loop and in some helpers where the code 2000eed56642SAlex Bennée * is disassembled. It shouldn't be called directly by guest code. 2001cdfac37bSRichard Henderson * 2002eed56642SAlex Bennée * For the benefit of TCG generated code, we want to avoid the 2003eed56642SAlex Bennée * complication of ABI-specific return type promotion and always 2004eed56642SAlex Bennée * return a value extended to the register size of the host. This is 2005eed56642SAlex Bennée * tcg_target_long, except in the case of a 32-bit host and 64-bit 2006eed56642SAlex Bennée * data, and for that we always have uint64_t. 2007eed56642SAlex Bennée * 2008eed56642SAlex Bennée * We don't bother with this widened value for SOFTMMU_CODE_ACCESS. 2009eed56642SAlex Bennée */ 2010eed56642SAlex Bennée 20118cfdacaaSRichard Henderson /** 20128cfdacaaSRichard Henderson * do_ld_mmio_beN: 20138cfdacaaSRichard Henderson * @env: cpu context 20148cfdacaaSRichard Henderson * @p: translation parameters 20158cfdacaaSRichard Henderson * @ret_be: accumulated data 20168cfdacaaSRichard Henderson * @mmu_idx: virtual address context 20178cfdacaaSRichard Henderson * @ra: return address into tcg generated code, or 0 20188cfdacaaSRichard Henderson * 20198cfdacaaSRichard Henderson * Load @p->size bytes from @p->addr, which is memory-mapped i/o. 20208cfdacaaSRichard Henderson * The bytes are concatenated in big-endian order with @ret_be. 20218cfdacaaSRichard Henderson */ 20228cfdacaaSRichard Henderson static uint64_t do_ld_mmio_beN(CPUArchState *env, MMULookupPageData *p, 20238cfdacaaSRichard Henderson uint64_t ret_be, int mmu_idx, 20248cfdacaaSRichard Henderson MMUAccessType type, uintptr_t ra) 20252dd92606SRichard Henderson { 20268cfdacaaSRichard Henderson CPUTLBEntryFull *full = p->full; 2027fb2c53cbSAnton Johansson vaddr addr = p->addr; 20288cfdacaaSRichard Henderson int i, size = p->size; 20298cfdacaaSRichard Henderson 20308cfdacaaSRichard Henderson QEMU_IOTHREAD_LOCK_GUARD(); 20318cfdacaaSRichard Henderson for (i = 0; i < size; i++) { 20328cfdacaaSRichard Henderson uint8_t x = io_readx(env, full, mmu_idx, addr + i, ra, type, MO_UB); 20338cfdacaaSRichard Henderson ret_be = (ret_be << 8) | x; 20348cfdacaaSRichard Henderson } 20358cfdacaaSRichard Henderson return ret_be; 20368cfdacaaSRichard Henderson } 20378cfdacaaSRichard Henderson 20388cfdacaaSRichard Henderson /** 20398cfdacaaSRichard Henderson * do_ld_bytes_beN 20408cfdacaaSRichard Henderson * @p: translation parameters 20418cfdacaaSRichard Henderson * @ret_be: accumulated data 20428cfdacaaSRichard Henderson * 20438cfdacaaSRichard Henderson * Load @p->size bytes from @p->haddr, which is RAM. 20448cfdacaaSRichard Henderson * The bytes to concatenated in big-endian order with @ret_be. 20458cfdacaaSRichard Henderson */ 20468cfdacaaSRichard Henderson static uint64_t do_ld_bytes_beN(MMULookupPageData *p, uint64_t ret_be) 20478cfdacaaSRichard Henderson { 20488cfdacaaSRichard Henderson uint8_t *haddr = p->haddr; 20498cfdacaaSRichard Henderson int i, size = p->size; 20508cfdacaaSRichard Henderson 20518cfdacaaSRichard Henderson for (i = 0; i < size; i++) { 20528cfdacaaSRichard Henderson ret_be = (ret_be << 8) | haddr[i]; 20538cfdacaaSRichard Henderson } 20548cfdacaaSRichard Henderson return ret_be; 20558cfdacaaSRichard Henderson } 20568cfdacaaSRichard Henderson 2057cdfac37bSRichard Henderson /** 2058cdfac37bSRichard Henderson * do_ld_parts_beN 2059cdfac37bSRichard Henderson * @p: translation parameters 2060cdfac37bSRichard Henderson * @ret_be: accumulated data 2061cdfac37bSRichard Henderson * 2062cdfac37bSRichard Henderson * As do_ld_bytes_beN, but atomically on each aligned part. 2063cdfac37bSRichard Henderson */ 2064cdfac37bSRichard Henderson static uint64_t do_ld_parts_beN(MMULookupPageData *p, uint64_t ret_be) 2065cdfac37bSRichard Henderson { 2066cdfac37bSRichard Henderson void *haddr = p->haddr; 2067cdfac37bSRichard Henderson int size = p->size; 2068cdfac37bSRichard Henderson 2069cdfac37bSRichard Henderson do { 2070cdfac37bSRichard Henderson uint64_t x; 2071cdfac37bSRichard Henderson int n; 2072cdfac37bSRichard Henderson 2073cdfac37bSRichard Henderson /* 2074cdfac37bSRichard Henderson * Find minimum of alignment and size. 2075cdfac37bSRichard Henderson * This is slightly stronger than required by MO_ATOM_SUBALIGN, which 2076cdfac37bSRichard Henderson * would have only checked the low bits of addr|size once at the start, 2077cdfac37bSRichard Henderson * but is just as easy. 2078cdfac37bSRichard Henderson */ 2079cdfac37bSRichard Henderson switch (((uintptr_t)haddr | size) & 7) { 2080cdfac37bSRichard Henderson case 4: 2081cdfac37bSRichard Henderson x = cpu_to_be32(load_atomic4(haddr)); 2082cdfac37bSRichard Henderson ret_be = (ret_be << 32) | x; 2083cdfac37bSRichard Henderson n = 4; 2084cdfac37bSRichard Henderson break; 2085cdfac37bSRichard Henderson case 2: 2086cdfac37bSRichard Henderson case 6: 2087cdfac37bSRichard Henderson x = cpu_to_be16(load_atomic2(haddr)); 2088cdfac37bSRichard Henderson ret_be = (ret_be << 16) | x; 2089cdfac37bSRichard Henderson n = 2; 2090cdfac37bSRichard Henderson break; 2091cdfac37bSRichard Henderson default: 2092cdfac37bSRichard Henderson x = *(uint8_t *)haddr; 2093cdfac37bSRichard Henderson ret_be = (ret_be << 8) | x; 2094cdfac37bSRichard Henderson n = 1; 2095cdfac37bSRichard Henderson break; 2096cdfac37bSRichard Henderson case 0: 2097cdfac37bSRichard Henderson g_assert_not_reached(); 2098cdfac37bSRichard Henderson } 2099cdfac37bSRichard Henderson haddr += n; 2100cdfac37bSRichard Henderson size -= n; 2101cdfac37bSRichard Henderson } while (size != 0); 2102cdfac37bSRichard Henderson return ret_be; 2103cdfac37bSRichard Henderson } 2104cdfac37bSRichard Henderson 2105cdfac37bSRichard Henderson /** 2106cdfac37bSRichard Henderson * do_ld_parts_be4 2107cdfac37bSRichard Henderson * @p: translation parameters 2108cdfac37bSRichard Henderson * @ret_be: accumulated data 2109cdfac37bSRichard Henderson * 2110cdfac37bSRichard Henderson * As do_ld_bytes_beN, but with one atomic load. 2111cdfac37bSRichard Henderson * Four aligned bytes are guaranteed to cover the load. 2112cdfac37bSRichard Henderson */ 2113cdfac37bSRichard Henderson static uint64_t do_ld_whole_be4(MMULookupPageData *p, uint64_t ret_be) 2114cdfac37bSRichard Henderson { 2115cdfac37bSRichard Henderson int o = p->addr & 3; 2116cdfac37bSRichard Henderson uint32_t x = load_atomic4(p->haddr - o); 2117cdfac37bSRichard Henderson 2118cdfac37bSRichard Henderson x = cpu_to_be32(x); 2119cdfac37bSRichard Henderson x <<= o * 8; 2120cdfac37bSRichard Henderson x >>= (4 - p->size) * 8; 2121cdfac37bSRichard Henderson return (ret_be << (p->size * 8)) | x; 2122cdfac37bSRichard Henderson } 2123cdfac37bSRichard Henderson 2124cdfac37bSRichard Henderson /** 2125cdfac37bSRichard Henderson * do_ld_parts_be8 2126cdfac37bSRichard Henderson * @p: translation parameters 2127cdfac37bSRichard Henderson * @ret_be: accumulated data 2128cdfac37bSRichard Henderson * 2129cdfac37bSRichard Henderson * As do_ld_bytes_beN, but with one atomic load. 2130cdfac37bSRichard Henderson * Eight aligned bytes are guaranteed to cover the load. 2131cdfac37bSRichard Henderson */ 2132cdfac37bSRichard Henderson static uint64_t do_ld_whole_be8(CPUArchState *env, uintptr_t ra, 2133cdfac37bSRichard Henderson MMULookupPageData *p, uint64_t ret_be) 2134cdfac37bSRichard Henderson { 2135cdfac37bSRichard Henderson int o = p->addr & 7; 2136cdfac37bSRichard Henderson uint64_t x = load_atomic8_or_exit(env, ra, p->haddr - o); 2137cdfac37bSRichard Henderson 2138cdfac37bSRichard Henderson x = cpu_to_be64(x); 2139cdfac37bSRichard Henderson x <<= o * 8; 2140cdfac37bSRichard Henderson x >>= (8 - p->size) * 8; 2141cdfac37bSRichard Henderson return (ret_be << (p->size * 8)) | x; 2142cdfac37bSRichard Henderson } 2143cdfac37bSRichard Henderson 214435c653c4SRichard Henderson /** 214535c653c4SRichard Henderson * do_ld_parts_be16 214635c653c4SRichard Henderson * @p: translation parameters 214735c653c4SRichard Henderson * @ret_be: accumulated data 214835c653c4SRichard Henderson * 214935c653c4SRichard Henderson * As do_ld_bytes_beN, but with one atomic load. 215035c653c4SRichard Henderson * 16 aligned bytes are guaranteed to cover the load. 215135c653c4SRichard Henderson */ 215235c653c4SRichard Henderson static Int128 do_ld_whole_be16(CPUArchState *env, uintptr_t ra, 215335c653c4SRichard Henderson MMULookupPageData *p, uint64_t ret_be) 215435c653c4SRichard Henderson { 215535c653c4SRichard Henderson int o = p->addr & 15; 215635c653c4SRichard Henderson Int128 x, y = load_atomic16_or_exit(env, ra, p->haddr - o); 215735c653c4SRichard Henderson int size = p->size; 215835c653c4SRichard Henderson 215935c653c4SRichard Henderson if (!HOST_BIG_ENDIAN) { 216035c653c4SRichard Henderson y = bswap128(y); 216135c653c4SRichard Henderson } 216235c653c4SRichard Henderson y = int128_lshift(y, o * 8); 216335c653c4SRichard Henderson y = int128_urshift(y, (16 - size) * 8); 216435c653c4SRichard Henderson x = int128_make64(ret_be); 216535c653c4SRichard Henderson x = int128_lshift(x, size * 8); 216635c653c4SRichard Henderson return int128_or(x, y); 216735c653c4SRichard Henderson } 216835c653c4SRichard Henderson 21698cfdacaaSRichard Henderson /* 21708cfdacaaSRichard Henderson * Wrapper for the above. 21718cfdacaaSRichard Henderson */ 21728cfdacaaSRichard Henderson static uint64_t do_ld_beN(CPUArchState *env, MMULookupPageData *p, 2173cdfac37bSRichard Henderson uint64_t ret_be, int mmu_idx, MMUAccessType type, 2174cdfac37bSRichard Henderson MemOp mop, uintptr_t ra) 21758cfdacaaSRichard Henderson { 2176cdfac37bSRichard Henderson MemOp atom; 2177cdfac37bSRichard Henderson unsigned tmp, half_size; 2178cdfac37bSRichard Henderson 21798cfdacaaSRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 21808cfdacaaSRichard Henderson return do_ld_mmio_beN(env, p, ret_be, mmu_idx, type, ra); 2181cdfac37bSRichard Henderson } 2182cdfac37bSRichard Henderson 2183cdfac37bSRichard Henderson /* 2184cdfac37bSRichard Henderson * It is a given that we cross a page and therefore there is no 2185cdfac37bSRichard Henderson * atomicity for the load as a whole, but subobjects may need attention. 2186cdfac37bSRichard Henderson */ 2187cdfac37bSRichard Henderson atom = mop & MO_ATOM_MASK; 2188cdfac37bSRichard Henderson switch (atom) { 2189cdfac37bSRichard Henderson case MO_ATOM_SUBALIGN: 2190cdfac37bSRichard Henderson return do_ld_parts_beN(p, ret_be); 2191cdfac37bSRichard Henderson 2192cdfac37bSRichard Henderson case MO_ATOM_IFALIGN_PAIR: 2193cdfac37bSRichard Henderson case MO_ATOM_WITHIN16_PAIR: 2194cdfac37bSRichard Henderson tmp = mop & MO_SIZE; 2195cdfac37bSRichard Henderson tmp = tmp ? tmp - 1 : 0; 2196cdfac37bSRichard Henderson half_size = 1 << tmp; 2197cdfac37bSRichard Henderson if (atom == MO_ATOM_IFALIGN_PAIR 2198cdfac37bSRichard Henderson ? p->size == half_size 2199cdfac37bSRichard Henderson : p->size >= half_size) { 2200cdfac37bSRichard Henderson if (!HAVE_al8_fast && p->size < 4) { 2201cdfac37bSRichard Henderson return do_ld_whole_be4(p, ret_be); 22028cfdacaaSRichard Henderson } else { 2203cdfac37bSRichard Henderson return do_ld_whole_be8(env, ra, p, ret_be); 2204cdfac37bSRichard Henderson } 2205cdfac37bSRichard Henderson } 2206cdfac37bSRichard Henderson /* fall through */ 2207cdfac37bSRichard Henderson 2208cdfac37bSRichard Henderson case MO_ATOM_IFALIGN: 2209cdfac37bSRichard Henderson case MO_ATOM_WITHIN16: 2210cdfac37bSRichard Henderson case MO_ATOM_NONE: 22118cfdacaaSRichard Henderson return do_ld_bytes_beN(p, ret_be); 2212cdfac37bSRichard Henderson 2213cdfac37bSRichard Henderson default: 2214cdfac37bSRichard Henderson g_assert_not_reached(); 22158cfdacaaSRichard Henderson } 22168cfdacaaSRichard Henderson } 22178cfdacaaSRichard Henderson 221835c653c4SRichard Henderson /* 221935c653c4SRichard Henderson * Wrapper for the above, for 8 < size < 16. 222035c653c4SRichard Henderson */ 222135c653c4SRichard Henderson static Int128 do_ld16_beN(CPUArchState *env, MMULookupPageData *p, 222235c653c4SRichard Henderson uint64_t a, int mmu_idx, MemOp mop, uintptr_t ra) 222335c653c4SRichard Henderson { 222435c653c4SRichard Henderson int size = p->size; 222535c653c4SRichard Henderson uint64_t b; 222635c653c4SRichard Henderson MemOp atom; 222735c653c4SRichard Henderson 222835c653c4SRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 222935c653c4SRichard Henderson p->size = size - 8; 223035c653c4SRichard Henderson a = do_ld_mmio_beN(env, p, a, mmu_idx, MMU_DATA_LOAD, ra); 223135c653c4SRichard Henderson p->addr += p->size; 223235c653c4SRichard Henderson p->size = 8; 223335c653c4SRichard Henderson b = do_ld_mmio_beN(env, p, 0, mmu_idx, MMU_DATA_LOAD, ra); 223435c653c4SRichard Henderson return int128_make128(b, a); 223535c653c4SRichard Henderson } 223635c653c4SRichard Henderson 223735c653c4SRichard Henderson /* 223835c653c4SRichard Henderson * It is a given that we cross a page and therefore there is no 223935c653c4SRichard Henderson * atomicity for the load as a whole, but subobjects may need attention. 224035c653c4SRichard Henderson */ 224135c653c4SRichard Henderson atom = mop & MO_ATOM_MASK; 224235c653c4SRichard Henderson switch (atom) { 224335c653c4SRichard Henderson case MO_ATOM_SUBALIGN: 224435c653c4SRichard Henderson p->size = size - 8; 224535c653c4SRichard Henderson a = do_ld_parts_beN(p, a); 224635c653c4SRichard Henderson p->haddr += size - 8; 224735c653c4SRichard Henderson p->size = 8; 224835c653c4SRichard Henderson b = do_ld_parts_beN(p, 0); 224935c653c4SRichard Henderson break; 225035c653c4SRichard Henderson 225135c653c4SRichard Henderson case MO_ATOM_WITHIN16_PAIR: 225235c653c4SRichard Henderson /* Since size > 8, this is the half that must be atomic. */ 225335c653c4SRichard Henderson return do_ld_whole_be16(env, ra, p, a); 225435c653c4SRichard Henderson 225535c653c4SRichard Henderson case MO_ATOM_IFALIGN_PAIR: 225635c653c4SRichard Henderson /* 225735c653c4SRichard Henderson * Since size > 8, both halves are misaligned, 225835c653c4SRichard Henderson * and so neither is atomic. 225935c653c4SRichard Henderson */ 226035c653c4SRichard Henderson case MO_ATOM_IFALIGN: 226135c653c4SRichard Henderson case MO_ATOM_WITHIN16: 226235c653c4SRichard Henderson case MO_ATOM_NONE: 226335c653c4SRichard Henderson p->size = size - 8; 226435c653c4SRichard Henderson a = do_ld_bytes_beN(p, a); 226535c653c4SRichard Henderson b = ldq_be_p(p->haddr + size - 8); 226635c653c4SRichard Henderson break; 226735c653c4SRichard Henderson 226835c653c4SRichard Henderson default: 226935c653c4SRichard Henderson g_assert_not_reached(); 227035c653c4SRichard Henderson } 227135c653c4SRichard Henderson 227235c653c4SRichard Henderson return int128_make128(b, a); 227335c653c4SRichard Henderson } 227435c653c4SRichard Henderson 22758cfdacaaSRichard Henderson static uint8_t do_ld_1(CPUArchState *env, MMULookupPageData *p, int mmu_idx, 22768cfdacaaSRichard Henderson MMUAccessType type, uintptr_t ra) 22778cfdacaaSRichard Henderson { 22788cfdacaaSRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 22798cfdacaaSRichard Henderson return io_readx(env, p->full, mmu_idx, p->addr, ra, type, MO_UB); 22808cfdacaaSRichard Henderson } else { 22818cfdacaaSRichard Henderson return *(uint8_t *)p->haddr; 22828cfdacaaSRichard Henderson } 22838cfdacaaSRichard Henderson } 22848cfdacaaSRichard Henderson 22858cfdacaaSRichard Henderson static uint16_t do_ld_2(CPUArchState *env, MMULookupPageData *p, int mmu_idx, 22868cfdacaaSRichard Henderson MMUAccessType type, MemOp memop, uintptr_t ra) 22878cfdacaaSRichard Henderson { 22888cfdacaaSRichard Henderson uint64_t ret; 22898cfdacaaSRichard Henderson 22908cfdacaaSRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 22918cfdacaaSRichard Henderson return io_readx(env, p->full, mmu_idx, p->addr, ra, type, memop); 22928cfdacaaSRichard Henderson } 22938cfdacaaSRichard Henderson 22948cfdacaaSRichard Henderson /* Perform the load host endian, then swap if necessary. */ 2295cdfac37bSRichard Henderson ret = load_atom_2(env, ra, p->haddr, memop); 22968cfdacaaSRichard Henderson if (memop & MO_BSWAP) { 22978cfdacaaSRichard Henderson ret = bswap16(ret); 22988cfdacaaSRichard Henderson } 22998cfdacaaSRichard Henderson return ret; 23008cfdacaaSRichard Henderson } 23018cfdacaaSRichard Henderson 23028cfdacaaSRichard Henderson static uint32_t do_ld_4(CPUArchState *env, MMULookupPageData *p, int mmu_idx, 23038cfdacaaSRichard Henderson MMUAccessType type, MemOp memop, uintptr_t ra) 23048cfdacaaSRichard Henderson { 23058cfdacaaSRichard Henderson uint32_t ret; 23068cfdacaaSRichard Henderson 23078cfdacaaSRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 23088cfdacaaSRichard Henderson return io_readx(env, p->full, mmu_idx, p->addr, ra, type, memop); 23098cfdacaaSRichard Henderson } 23108cfdacaaSRichard Henderson 23118cfdacaaSRichard Henderson /* Perform the load host endian. */ 2312cdfac37bSRichard Henderson ret = load_atom_4(env, ra, p->haddr, memop); 23138cfdacaaSRichard Henderson if (memop & MO_BSWAP) { 23148cfdacaaSRichard Henderson ret = bswap32(ret); 23158cfdacaaSRichard Henderson } 23168cfdacaaSRichard Henderson return ret; 23178cfdacaaSRichard Henderson } 23188cfdacaaSRichard Henderson 23198cfdacaaSRichard Henderson static uint64_t do_ld_8(CPUArchState *env, MMULookupPageData *p, int mmu_idx, 23208cfdacaaSRichard Henderson MMUAccessType type, MemOp memop, uintptr_t ra) 23218cfdacaaSRichard Henderson { 23228cfdacaaSRichard Henderson uint64_t ret; 23238cfdacaaSRichard Henderson 23248cfdacaaSRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 23258cfdacaaSRichard Henderson return io_readx(env, p->full, mmu_idx, p->addr, ra, type, memop); 23268cfdacaaSRichard Henderson } 23278cfdacaaSRichard Henderson 23288cfdacaaSRichard Henderson /* Perform the load host endian. */ 2329cdfac37bSRichard Henderson ret = load_atom_8(env, ra, p->haddr, memop); 23308cfdacaaSRichard Henderson if (memop & MO_BSWAP) { 23318cfdacaaSRichard Henderson ret = bswap64(ret); 23328cfdacaaSRichard Henderson } 23338cfdacaaSRichard Henderson return ret; 23348cfdacaaSRichard Henderson } 23358cfdacaaSRichard Henderson 2336fb2c53cbSAnton Johansson static uint8_t do_ld1_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, 23378cfdacaaSRichard Henderson uintptr_t ra, MMUAccessType access_type) 23388cfdacaaSRichard Henderson { 23398cfdacaaSRichard Henderson MMULookupLocals l; 23408cfdacaaSRichard Henderson bool crosspage; 23418cfdacaaSRichard Henderson 23428cfdacaaSRichard Henderson crosspage = mmu_lookup(env, addr, oi, ra, access_type, &l); 23438cfdacaaSRichard Henderson tcg_debug_assert(!crosspage); 23448cfdacaaSRichard Henderson 23458cfdacaaSRichard Henderson return do_ld_1(env, &l.page[0], l.mmu_idx, access_type, ra); 23462dd92606SRichard Henderson } 23472dd92606SRichard Henderson 234824e46e6cSRichard Henderson tcg_target_ulong helper_ldub_mmu(CPUArchState *env, uint64_t addr, 23499002ffcbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 2350eed56642SAlex Bennée { 23510cadc1edSRichard Henderson tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); 23528cfdacaaSRichard Henderson return do_ld1_mmu(env, addr, oi, retaddr, MMU_DATA_LOAD); 23532dd92606SRichard Henderson } 23542dd92606SRichard Henderson 2355fb2c53cbSAnton Johansson static uint16_t do_ld2_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, 23568cfdacaaSRichard Henderson uintptr_t ra, MMUAccessType access_type) 23572dd92606SRichard Henderson { 23588cfdacaaSRichard Henderson MMULookupLocals l; 23598cfdacaaSRichard Henderson bool crosspage; 23608cfdacaaSRichard Henderson uint16_t ret; 23618cfdacaaSRichard Henderson uint8_t a, b; 23628cfdacaaSRichard Henderson 23638cfdacaaSRichard Henderson crosspage = mmu_lookup(env, addr, oi, ra, access_type, &l); 23648cfdacaaSRichard Henderson if (likely(!crosspage)) { 23658cfdacaaSRichard Henderson return do_ld_2(env, &l.page[0], l.mmu_idx, access_type, l.memop, ra); 23668cfdacaaSRichard Henderson } 23678cfdacaaSRichard Henderson 23688cfdacaaSRichard Henderson a = do_ld_1(env, &l.page[0], l.mmu_idx, access_type, ra); 23698cfdacaaSRichard Henderson b = do_ld_1(env, &l.page[1], l.mmu_idx, access_type, ra); 23708cfdacaaSRichard Henderson 23718cfdacaaSRichard Henderson if ((l.memop & MO_BSWAP) == MO_LE) { 23728cfdacaaSRichard Henderson ret = a | (b << 8); 23738cfdacaaSRichard Henderson } else { 23748cfdacaaSRichard Henderson ret = b | (a << 8); 23758cfdacaaSRichard Henderson } 23768cfdacaaSRichard Henderson return ret; 2377eed56642SAlex Bennée } 2378eed56642SAlex Bennée 237924e46e6cSRichard Henderson tcg_target_ulong helper_lduw_mmu(CPUArchState *env, uint64_t addr, 23809002ffcbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 2381eed56642SAlex Bennée { 23820cadc1edSRichard Henderson tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); 23838cfdacaaSRichard Henderson return do_ld2_mmu(env, addr, oi, retaddr, MMU_DATA_LOAD); 23842dd92606SRichard Henderson } 23852dd92606SRichard Henderson 2386fb2c53cbSAnton Johansson static uint32_t do_ld4_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, 23878cfdacaaSRichard Henderson uintptr_t ra, MMUAccessType access_type) 23882dd92606SRichard Henderson { 23898cfdacaaSRichard Henderson MMULookupLocals l; 23908cfdacaaSRichard Henderson bool crosspage; 23918cfdacaaSRichard Henderson uint32_t ret; 23928cfdacaaSRichard Henderson 23938cfdacaaSRichard Henderson crosspage = mmu_lookup(env, addr, oi, ra, access_type, &l); 23948cfdacaaSRichard Henderson if (likely(!crosspage)) { 23958cfdacaaSRichard Henderson return do_ld_4(env, &l.page[0], l.mmu_idx, access_type, l.memop, ra); 23968cfdacaaSRichard Henderson } 23978cfdacaaSRichard Henderson 2398cdfac37bSRichard Henderson ret = do_ld_beN(env, &l.page[0], 0, l.mmu_idx, access_type, l.memop, ra); 2399cdfac37bSRichard Henderson ret = do_ld_beN(env, &l.page[1], ret, l.mmu_idx, access_type, l.memop, ra); 24008cfdacaaSRichard Henderson if ((l.memop & MO_BSWAP) == MO_LE) { 24018cfdacaaSRichard Henderson ret = bswap32(ret); 24028cfdacaaSRichard Henderson } 24038cfdacaaSRichard Henderson return ret; 2404eed56642SAlex Bennée } 2405eed56642SAlex Bennée 240624e46e6cSRichard Henderson tcg_target_ulong helper_ldul_mmu(CPUArchState *env, uint64_t addr, 24079002ffcbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 2408eed56642SAlex Bennée { 24090cadc1edSRichard Henderson tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); 24108cfdacaaSRichard Henderson return do_ld4_mmu(env, addr, oi, retaddr, MMU_DATA_LOAD); 24118cfdacaaSRichard Henderson } 24128cfdacaaSRichard Henderson 2413fb2c53cbSAnton Johansson static uint64_t do_ld8_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, 24148cfdacaaSRichard Henderson uintptr_t ra, MMUAccessType access_type) 24158cfdacaaSRichard Henderson { 24168cfdacaaSRichard Henderson MMULookupLocals l; 24178cfdacaaSRichard Henderson bool crosspage; 24188cfdacaaSRichard Henderson uint64_t ret; 24198cfdacaaSRichard Henderson 24208cfdacaaSRichard Henderson crosspage = mmu_lookup(env, addr, oi, ra, access_type, &l); 24218cfdacaaSRichard Henderson if (likely(!crosspage)) { 24228cfdacaaSRichard Henderson return do_ld_8(env, &l.page[0], l.mmu_idx, access_type, l.memop, ra); 24238cfdacaaSRichard Henderson } 24248cfdacaaSRichard Henderson 2425cdfac37bSRichard Henderson ret = do_ld_beN(env, &l.page[0], 0, l.mmu_idx, access_type, l.memop, ra); 2426cdfac37bSRichard Henderson ret = do_ld_beN(env, &l.page[1], ret, l.mmu_idx, access_type, l.memop, ra); 24278cfdacaaSRichard Henderson if ((l.memop & MO_BSWAP) == MO_LE) { 24288cfdacaaSRichard Henderson ret = bswap64(ret); 24298cfdacaaSRichard Henderson } 24308cfdacaaSRichard Henderson return ret; 2431eed56642SAlex Bennée } 2432eed56642SAlex Bennée 243324e46e6cSRichard Henderson uint64_t helper_ldq_mmu(CPUArchState *env, uint64_t addr, 24349002ffcbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 2435eed56642SAlex Bennée { 24360cadc1edSRichard Henderson tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); 24378cfdacaaSRichard Henderson return do_ld8_mmu(env, addr, oi, retaddr, MMU_DATA_LOAD); 2438eed56642SAlex Bennée } 2439eed56642SAlex Bennée 2440eed56642SAlex Bennée /* 2441eed56642SAlex Bennée * Provide signed versions of the load routines as well. We can of course 2442eed56642SAlex Bennée * avoid this for 64-bit data, or for 32-bit data on 32-bit host. 2443eed56642SAlex Bennée */ 2444eed56642SAlex Bennée 244524e46e6cSRichard Henderson tcg_target_ulong helper_ldsb_mmu(CPUArchState *env, uint64_t addr, 24469002ffcbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 2447eed56642SAlex Bennée { 24480cadc1edSRichard Henderson return (int8_t)helper_ldub_mmu(env, addr, oi, retaddr); 2449eed56642SAlex Bennée } 2450eed56642SAlex Bennée 245124e46e6cSRichard Henderson tcg_target_ulong helper_ldsw_mmu(CPUArchState *env, uint64_t addr, 24529002ffcbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 2453eed56642SAlex Bennée { 24540cadc1edSRichard Henderson return (int16_t)helper_lduw_mmu(env, addr, oi, retaddr); 2455eed56642SAlex Bennée } 2456eed56642SAlex Bennée 245724e46e6cSRichard Henderson tcg_target_ulong helper_ldsl_mmu(CPUArchState *env, uint64_t addr, 24589002ffcbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 2459eed56642SAlex Bennée { 24600cadc1edSRichard Henderson return (int32_t)helper_ldul_mmu(env, addr, oi, retaddr); 2461eed56642SAlex Bennée } 2462eed56642SAlex Bennée 2463fb2c53cbSAnton Johansson static Int128 do_ld16_mmu(CPUArchState *env, vaddr addr, 246435c653c4SRichard Henderson MemOpIdx oi, uintptr_t ra) 246535c653c4SRichard Henderson { 246635c653c4SRichard Henderson MMULookupLocals l; 246735c653c4SRichard Henderson bool crosspage; 246835c653c4SRichard Henderson uint64_t a, b; 246935c653c4SRichard Henderson Int128 ret; 247035c653c4SRichard Henderson int first; 247135c653c4SRichard Henderson 247235c653c4SRichard Henderson crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD, &l); 247335c653c4SRichard Henderson if (likely(!crosspage)) { 247435c653c4SRichard Henderson /* Perform the load host endian. */ 247535c653c4SRichard Henderson if (unlikely(l.page[0].flags & TLB_MMIO)) { 247635c653c4SRichard Henderson QEMU_IOTHREAD_LOCK_GUARD(); 247735c653c4SRichard Henderson a = io_readx(env, l.page[0].full, l.mmu_idx, addr, 247835c653c4SRichard Henderson ra, MMU_DATA_LOAD, MO_64); 247935c653c4SRichard Henderson b = io_readx(env, l.page[0].full, l.mmu_idx, addr + 8, 248035c653c4SRichard Henderson ra, MMU_DATA_LOAD, MO_64); 248135c653c4SRichard Henderson ret = int128_make128(HOST_BIG_ENDIAN ? b : a, 248235c653c4SRichard Henderson HOST_BIG_ENDIAN ? a : b); 248335c653c4SRichard Henderson } else { 248435c653c4SRichard Henderson ret = load_atom_16(env, ra, l.page[0].haddr, l.memop); 248535c653c4SRichard Henderson } 248635c653c4SRichard Henderson if (l.memop & MO_BSWAP) { 248735c653c4SRichard Henderson ret = bswap128(ret); 248835c653c4SRichard Henderson } 248935c653c4SRichard Henderson return ret; 249035c653c4SRichard Henderson } 249135c653c4SRichard Henderson 249235c653c4SRichard Henderson first = l.page[0].size; 249335c653c4SRichard Henderson if (first == 8) { 249435c653c4SRichard Henderson MemOp mop8 = (l.memop & ~MO_SIZE) | MO_64; 249535c653c4SRichard Henderson 249635c653c4SRichard Henderson a = do_ld_8(env, &l.page[0], l.mmu_idx, MMU_DATA_LOAD, mop8, ra); 249735c653c4SRichard Henderson b = do_ld_8(env, &l.page[1], l.mmu_idx, MMU_DATA_LOAD, mop8, ra); 249835c653c4SRichard Henderson if ((mop8 & MO_BSWAP) == MO_LE) { 249935c653c4SRichard Henderson ret = int128_make128(a, b); 250035c653c4SRichard Henderson } else { 250135c653c4SRichard Henderson ret = int128_make128(b, a); 250235c653c4SRichard Henderson } 250335c653c4SRichard Henderson return ret; 250435c653c4SRichard Henderson } 250535c653c4SRichard Henderson 250635c653c4SRichard Henderson if (first < 8) { 250735c653c4SRichard Henderson a = do_ld_beN(env, &l.page[0], 0, l.mmu_idx, 250835c653c4SRichard Henderson MMU_DATA_LOAD, l.memop, ra); 250935c653c4SRichard Henderson ret = do_ld16_beN(env, &l.page[1], a, l.mmu_idx, l.memop, ra); 251035c653c4SRichard Henderson } else { 251135c653c4SRichard Henderson ret = do_ld16_beN(env, &l.page[0], 0, l.mmu_idx, l.memop, ra); 251235c653c4SRichard Henderson b = int128_getlo(ret); 251335c653c4SRichard Henderson ret = int128_lshift(ret, l.page[1].size * 8); 251435c653c4SRichard Henderson a = int128_gethi(ret); 251535c653c4SRichard Henderson b = do_ld_beN(env, &l.page[1], b, l.mmu_idx, 251635c653c4SRichard Henderson MMU_DATA_LOAD, l.memop, ra); 251735c653c4SRichard Henderson ret = int128_make128(b, a); 251835c653c4SRichard Henderson } 251935c653c4SRichard Henderson if ((l.memop & MO_BSWAP) == MO_LE) { 252035c653c4SRichard Henderson ret = bswap128(ret); 252135c653c4SRichard Henderson } 252235c653c4SRichard Henderson return ret; 252335c653c4SRichard Henderson } 252435c653c4SRichard Henderson 252524e46e6cSRichard Henderson Int128 helper_ld16_mmu(CPUArchState *env, uint64_t addr, 252635c653c4SRichard Henderson uint32_t oi, uintptr_t retaddr) 252735c653c4SRichard Henderson { 252835c653c4SRichard Henderson tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); 252935c653c4SRichard Henderson return do_ld16_mmu(env, addr, oi, retaddr); 253035c653c4SRichard Henderson } 253135c653c4SRichard Henderson 2532e570597aSRichard Henderson Int128 helper_ld_i128(CPUArchState *env, uint64_t addr, uint32_t oi) 253335c653c4SRichard Henderson { 253435c653c4SRichard Henderson return helper_ld16_mmu(env, addr, oi, GETPC()); 253535c653c4SRichard Henderson } 253635c653c4SRichard Henderson 2537eed56642SAlex Bennée /* 2538d03f1408SRichard Henderson * Load helpers for cpu_ldst.h. 2539d03f1408SRichard Henderson */ 2540d03f1408SRichard Henderson 25418cfdacaaSRichard Henderson static void plugin_load_cb(CPUArchState *env, abi_ptr addr, MemOpIdx oi) 2542d03f1408SRichard Henderson { 254337aff087SRichard Henderson qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); 2544d03f1408SRichard Henderson } 2545d03f1408SRichard Henderson 2546f83bcecbSRichard Henderson uint8_t cpu_ldb_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra) 2547d03f1408SRichard Henderson { 25488cfdacaaSRichard Henderson uint8_t ret; 25498cfdacaaSRichard Henderson 25500cadc1edSRichard Henderson tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_UB); 25518cfdacaaSRichard Henderson ret = do_ld1_mmu(env, addr, oi, ra, MMU_DATA_LOAD); 25528cfdacaaSRichard Henderson plugin_load_cb(env, addr, oi); 25538cfdacaaSRichard Henderson return ret; 2554d03f1408SRichard Henderson } 2555d03f1408SRichard Henderson 2556fbea7a40SRichard Henderson uint16_t cpu_ldw_mmu(CPUArchState *env, abi_ptr addr, 2557f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t ra) 2558d03f1408SRichard Henderson { 25598cfdacaaSRichard Henderson uint16_t ret; 25608cfdacaaSRichard Henderson 2561fbea7a40SRichard Henderson tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); 25628cfdacaaSRichard Henderson ret = do_ld2_mmu(env, addr, oi, ra, MMU_DATA_LOAD); 25638cfdacaaSRichard Henderson plugin_load_cb(env, addr, oi); 25648cfdacaaSRichard Henderson return ret; 2565d03f1408SRichard Henderson } 2566d03f1408SRichard Henderson 2567fbea7a40SRichard Henderson uint32_t cpu_ldl_mmu(CPUArchState *env, abi_ptr addr, 2568f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t ra) 2569d03f1408SRichard Henderson { 25708cfdacaaSRichard Henderson uint32_t ret; 25718cfdacaaSRichard Henderson 2572fbea7a40SRichard Henderson tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); 25738cfdacaaSRichard Henderson ret = do_ld4_mmu(env, addr, oi, ra, MMU_DATA_LOAD); 25748cfdacaaSRichard Henderson plugin_load_cb(env, addr, oi); 25758cfdacaaSRichard Henderson return ret; 2576d03f1408SRichard Henderson } 2577d03f1408SRichard Henderson 2578fbea7a40SRichard Henderson uint64_t cpu_ldq_mmu(CPUArchState *env, abi_ptr addr, 2579f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t ra) 2580d03f1408SRichard Henderson { 25818cfdacaaSRichard Henderson uint64_t ret; 25828cfdacaaSRichard Henderson 2583fbea7a40SRichard Henderson tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); 25848cfdacaaSRichard Henderson ret = do_ld8_mmu(env, addr, oi, ra, MMU_DATA_LOAD); 25858cfdacaaSRichard Henderson plugin_load_cb(env, addr, oi); 25868cfdacaaSRichard Henderson return ret; 2587d03f1408SRichard Henderson } 2588d03f1408SRichard Henderson 2589fbea7a40SRichard Henderson Int128 cpu_ld16_mmu(CPUArchState *env, abi_ptr addr, 2590cb48f365SRichard Henderson MemOpIdx oi, uintptr_t ra) 2591cb48f365SRichard Henderson { 259235c653c4SRichard Henderson Int128 ret; 2593cb48f365SRichard Henderson 2594fbea7a40SRichard Henderson tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); 259535c653c4SRichard Henderson ret = do_ld16_mmu(env, addr, oi, ra); 259635c653c4SRichard Henderson plugin_load_cb(env, addr, oi); 259735c653c4SRichard Henderson return ret; 2598cb48f365SRichard Henderson } 2599cb48f365SRichard Henderson 2600d03f1408SRichard Henderson /* 2601eed56642SAlex Bennée * Store Helpers 2602eed56642SAlex Bennée */ 2603eed56642SAlex Bennée 260459213461SRichard Henderson /** 260559213461SRichard Henderson * do_st_mmio_leN: 260659213461SRichard Henderson * @env: cpu context 260759213461SRichard Henderson * @p: translation parameters 260859213461SRichard Henderson * @val_le: data to store 260959213461SRichard Henderson * @mmu_idx: virtual address context 261059213461SRichard Henderson * @ra: return address into tcg generated code, or 0 261159213461SRichard Henderson * 261259213461SRichard Henderson * Store @p->size bytes at @p->addr, which is memory-mapped i/o. 261359213461SRichard Henderson * The bytes to store are extracted in little-endian order from @val_le; 261459213461SRichard Henderson * return the bytes of @val_le beyond @p->size that have not been stored. 261559213461SRichard Henderson */ 261659213461SRichard Henderson static uint64_t do_st_mmio_leN(CPUArchState *env, MMULookupPageData *p, 261759213461SRichard Henderson uint64_t val_le, int mmu_idx, uintptr_t ra) 26186b8b622eSRichard Henderson { 261959213461SRichard Henderson CPUTLBEntryFull *full = p->full; 2620fb2c53cbSAnton Johansson vaddr addr = p->addr; 262159213461SRichard Henderson int i, size = p->size; 26226b8b622eSRichard Henderson 262359213461SRichard Henderson QEMU_IOTHREAD_LOCK_GUARD(); 262459213461SRichard Henderson for (i = 0; i < size; i++, val_le >>= 8) { 262559213461SRichard Henderson io_writex(env, full, mmu_idx, val_le, addr + i, ra, MO_UB); 262659213461SRichard Henderson } 262759213461SRichard Henderson return val_le; 262859213461SRichard Henderson } 262959213461SRichard Henderson 26306b8b622eSRichard Henderson /* 263159213461SRichard Henderson * Wrapper for the above. 26326b8b622eSRichard Henderson */ 263359213461SRichard Henderson static uint64_t do_st_leN(CPUArchState *env, MMULookupPageData *p, 26345b36f268SRichard Henderson uint64_t val_le, int mmu_idx, 26355b36f268SRichard Henderson MemOp mop, uintptr_t ra) 263659213461SRichard Henderson { 26375b36f268SRichard Henderson MemOp atom; 26385b36f268SRichard Henderson unsigned tmp, half_size; 26395b36f268SRichard Henderson 264059213461SRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 264159213461SRichard Henderson return do_st_mmio_leN(env, p, val_le, mmu_idx, ra); 264259213461SRichard Henderson } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { 264359213461SRichard Henderson return val_le >> (p->size * 8); 26445b36f268SRichard Henderson } 26455b36f268SRichard Henderson 26465b36f268SRichard Henderson /* 26475b36f268SRichard Henderson * It is a given that we cross a page and therefore there is no atomicity 26485b36f268SRichard Henderson * for the store as a whole, but subobjects may need attention. 26495b36f268SRichard Henderson */ 26505b36f268SRichard Henderson atom = mop & MO_ATOM_MASK; 26515b36f268SRichard Henderson switch (atom) { 26525b36f268SRichard Henderson case MO_ATOM_SUBALIGN: 26535b36f268SRichard Henderson return store_parts_leN(p->haddr, p->size, val_le); 26545b36f268SRichard Henderson 26555b36f268SRichard Henderson case MO_ATOM_IFALIGN_PAIR: 26565b36f268SRichard Henderson case MO_ATOM_WITHIN16_PAIR: 26575b36f268SRichard Henderson tmp = mop & MO_SIZE; 26585b36f268SRichard Henderson tmp = tmp ? tmp - 1 : 0; 26595b36f268SRichard Henderson half_size = 1 << tmp; 26605b36f268SRichard Henderson if (atom == MO_ATOM_IFALIGN_PAIR 26615b36f268SRichard Henderson ? p->size == half_size 26625b36f268SRichard Henderson : p->size >= half_size) { 26635b36f268SRichard Henderson if (!HAVE_al8_fast && p->size <= 4) { 26645b36f268SRichard Henderson return store_whole_le4(p->haddr, p->size, val_le); 26655b36f268SRichard Henderson } else if (HAVE_al8) { 26665b36f268SRichard Henderson return store_whole_le8(p->haddr, p->size, val_le); 26676b8b622eSRichard Henderson } else { 26685b36f268SRichard Henderson cpu_loop_exit_atomic(env_cpu(env), ra); 26695b36f268SRichard Henderson } 26705b36f268SRichard Henderson } 26715b36f268SRichard Henderson /* fall through */ 26725b36f268SRichard Henderson 26735b36f268SRichard Henderson case MO_ATOM_IFALIGN: 26745b36f268SRichard Henderson case MO_ATOM_WITHIN16: 26755b36f268SRichard Henderson case MO_ATOM_NONE: 26765b36f268SRichard Henderson return store_bytes_leN(p->haddr, p->size, val_le); 26775b36f268SRichard Henderson 26785b36f268SRichard Henderson default: 26795b36f268SRichard Henderson g_assert_not_reached(); 26806b8b622eSRichard Henderson } 26816b8b622eSRichard Henderson } 26826b8b622eSRichard Henderson 268335c653c4SRichard Henderson /* 268435c653c4SRichard Henderson * Wrapper for the above, for 8 < size < 16. 268535c653c4SRichard Henderson */ 268635c653c4SRichard Henderson static uint64_t do_st16_leN(CPUArchState *env, MMULookupPageData *p, 268735c653c4SRichard Henderson Int128 val_le, int mmu_idx, 268835c653c4SRichard Henderson MemOp mop, uintptr_t ra) 268935c653c4SRichard Henderson { 269035c653c4SRichard Henderson int size = p->size; 269135c653c4SRichard Henderson MemOp atom; 269235c653c4SRichard Henderson 269335c653c4SRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 269435c653c4SRichard Henderson p->size = 8; 269535c653c4SRichard Henderson do_st_mmio_leN(env, p, int128_getlo(val_le), mmu_idx, ra); 269635c653c4SRichard Henderson p->size = size - 8; 269735c653c4SRichard Henderson p->addr += 8; 269835c653c4SRichard Henderson return do_st_mmio_leN(env, p, int128_gethi(val_le), mmu_idx, ra); 269935c653c4SRichard Henderson } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { 270035c653c4SRichard Henderson return int128_gethi(val_le) >> ((size - 8) * 8); 270135c653c4SRichard Henderson } 270235c653c4SRichard Henderson 270335c653c4SRichard Henderson /* 270435c653c4SRichard Henderson * It is a given that we cross a page and therefore there is no atomicity 270535c653c4SRichard Henderson * for the store as a whole, but subobjects may need attention. 270635c653c4SRichard Henderson */ 270735c653c4SRichard Henderson atom = mop & MO_ATOM_MASK; 270835c653c4SRichard Henderson switch (atom) { 270935c653c4SRichard Henderson case MO_ATOM_SUBALIGN: 271035c653c4SRichard Henderson store_parts_leN(p->haddr, 8, int128_getlo(val_le)); 271135c653c4SRichard Henderson return store_parts_leN(p->haddr + 8, p->size - 8, 271235c653c4SRichard Henderson int128_gethi(val_le)); 271335c653c4SRichard Henderson 271435c653c4SRichard Henderson case MO_ATOM_WITHIN16_PAIR: 271535c653c4SRichard Henderson /* Since size > 8, this is the half that must be atomic. */ 27168dc24ff4SRichard Henderson if (!HAVE_ATOMIC128_RW) { 271735c653c4SRichard Henderson cpu_loop_exit_atomic(env_cpu(env), ra); 271835c653c4SRichard Henderson } 271935c653c4SRichard Henderson return store_whole_le16(p->haddr, p->size, val_le); 272035c653c4SRichard Henderson 272135c653c4SRichard Henderson case MO_ATOM_IFALIGN_PAIR: 272235c653c4SRichard Henderson /* 272335c653c4SRichard Henderson * Since size > 8, both halves are misaligned, 272435c653c4SRichard Henderson * and so neither is atomic. 272535c653c4SRichard Henderson */ 272635c653c4SRichard Henderson case MO_ATOM_IFALIGN: 27272be6a486SRichard Henderson case MO_ATOM_WITHIN16: 272835c653c4SRichard Henderson case MO_ATOM_NONE: 272935c653c4SRichard Henderson stq_le_p(p->haddr, int128_getlo(val_le)); 273035c653c4SRichard Henderson return store_bytes_leN(p->haddr + 8, p->size - 8, 273135c653c4SRichard Henderson int128_gethi(val_le)); 273235c653c4SRichard Henderson 273335c653c4SRichard Henderson default: 273435c653c4SRichard Henderson g_assert_not_reached(); 273535c653c4SRichard Henderson } 273635c653c4SRichard Henderson } 273735c653c4SRichard Henderson 273859213461SRichard Henderson static void do_st_1(CPUArchState *env, MMULookupPageData *p, uint8_t val, 273959213461SRichard Henderson int mmu_idx, uintptr_t ra) 2740eed56642SAlex Bennée { 274159213461SRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 274259213461SRichard Henderson io_writex(env, p->full, mmu_idx, val, p->addr, ra, MO_UB); 274359213461SRichard Henderson } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { 274459213461SRichard Henderson /* nothing */ 27455b87b3e6SRichard Henderson } else { 274659213461SRichard Henderson *(uint8_t *)p->haddr = val; 27475b87b3e6SRichard Henderson } 2748eed56642SAlex Bennée } 2749eed56642SAlex Bennée 275059213461SRichard Henderson static void do_st_2(CPUArchState *env, MMULookupPageData *p, uint16_t val, 275159213461SRichard Henderson int mmu_idx, MemOp memop, uintptr_t ra) 2752eed56642SAlex Bennée { 275359213461SRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 275459213461SRichard Henderson io_writex(env, p->full, mmu_idx, val, p->addr, ra, memop); 275559213461SRichard Henderson } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { 275659213461SRichard Henderson /* nothing */ 275759213461SRichard Henderson } else { 275859213461SRichard Henderson /* Swap to host endian if necessary, then store. */ 275959213461SRichard Henderson if (memop & MO_BSWAP) { 276059213461SRichard Henderson val = bswap16(val); 276159213461SRichard Henderson } 27625b36f268SRichard Henderson store_atom_2(env, ra, p->haddr, memop, val); 276359213461SRichard Henderson } 276459213461SRichard Henderson } 276559213461SRichard Henderson 276659213461SRichard Henderson static void do_st_4(CPUArchState *env, MMULookupPageData *p, uint32_t val, 276759213461SRichard Henderson int mmu_idx, MemOp memop, uintptr_t ra) 276859213461SRichard Henderson { 276959213461SRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 277059213461SRichard Henderson io_writex(env, p->full, mmu_idx, val, p->addr, ra, memop); 277159213461SRichard Henderson } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { 277259213461SRichard Henderson /* nothing */ 277359213461SRichard Henderson } else { 277459213461SRichard Henderson /* Swap to host endian if necessary, then store. */ 277559213461SRichard Henderson if (memop & MO_BSWAP) { 277659213461SRichard Henderson val = bswap32(val); 277759213461SRichard Henderson } 27785b36f268SRichard Henderson store_atom_4(env, ra, p->haddr, memop, val); 277959213461SRichard Henderson } 278059213461SRichard Henderson } 278159213461SRichard Henderson 278259213461SRichard Henderson static void do_st_8(CPUArchState *env, MMULookupPageData *p, uint64_t val, 278359213461SRichard Henderson int mmu_idx, MemOp memop, uintptr_t ra) 278459213461SRichard Henderson { 278559213461SRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 278659213461SRichard Henderson io_writex(env, p->full, mmu_idx, val, p->addr, ra, memop); 278759213461SRichard Henderson } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { 278859213461SRichard Henderson /* nothing */ 278959213461SRichard Henderson } else { 279059213461SRichard Henderson /* Swap to host endian if necessary, then store. */ 279159213461SRichard Henderson if (memop & MO_BSWAP) { 279259213461SRichard Henderson val = bswap64(val); 279359213461SRichard Henderson } 27945b36f268SRichard Henderson store_atom_8(env, ra, p->haddr, memop, val); 279559213461SRichard Henderson } 2796eed56642SAlex Bennée } 2797eed56642SAlex Bennée 279824e46e6cSRichard Henderson void helper_stb_mmu(CPUArchState *env, uint64_t addr, uint32_t val, 279959213461SRichard Henderson MemOpIdx oi, uintptr_t ra) 2800f83bcecbSRichard Henderson { 280159213461SRichard Henderson MMULookupLocals l; 280259213461SRichard Henderson bool crosspage; 280359213461SRichard Henderson 28040cadc1edSRichard Henderson tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_8); 280559213461SRichard Henderson crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE, &l); 280659213461SRichard Henderson tcg_debug_assert(!crosspage); 280759213461SRichard Henderson 280859213461SRichard Henderson do_st_1(env, &l.page[0], val, l.mmu_idx, ra); 2809f83bcecbSRichard Henderson } 2810f83bcecbSRichard Henderson 2811fb2c53cbSAnton Johansson static void do_st2_mmu(CPUArchState *env, vaddr addr, uint16_t val, 281259213461SRichard Henderson MemOpIdx oi, uintptr_t ra) 2813f83bcecbSRichard Henderson { 281459213461SRichard Henderson MMULookupLocals l; 281559213461SRichard Henderson bool crosspage; 281659213461SRichard Henderson uint8_t a, b; 281759213461SRichard Henderson 281859213461SRichard Henderson crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE, &l); 281959213461SRichard Henderson if (likely(!crosspage)) { 282059213461SRichard Henderson do_st_2(env, &l.page[0], val, l.mmu_idx, l.memop, ra); 282159213461SRichard Henderson return; 282259213461SRichard Henderson } 282359213461SRichard Henderson 282459213461SRichard Henderson if ((l.memop & MO_BSWAP) == MO_LE) { 282559213461SRichard Henderson a = val, b = val >> 8; 282659213461SRichard Henderson } else { 282759213461SRichard Henderson b = val, a = val >> 8; 282859213461SRichard Henderson } 282959213461SRichard Henderson do_st_1(env, &l.page[0], a, l.mmu_idx, ra); 283059213461SRichard Henderson do_st_1(env, &l.page[1], b, l.mmu_idx, ra); 2831f83bcecbSRichard Henderson } 2832f83bcecbSRichard Henderson 283324e46e6cSRichard Henderson void helper_stw_mmu(CPUArchState *env, uint64_t addr, uint32_t val, 28349002ffcbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 2835eed56642SAlex Bennée { 28360cadc1edSRichard Henderson tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); 283759213461SRichard Henderson do_st2_mmu(env, addr, val, oi, retaddr); 2838f83bcecbSRichard Henderson } 2839f83bcecbSRichard Henderson 2840fb2c53cbSAnton Johansson static void do_st4_mmu(CPUArchState *env, vaddr addr, uint32_t val, 284159213461SRichard Henderson MemOpIdx oi, uintptr_t ra) 2842f83bcecbSRichard Henderson { 284359213461SRichard Henderson MMULookupLocals l; 284459213461SRichard Henderson bool crosspage; 284559213461SRichard Henderson 284659213461SRichard Henderson crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE, &l); 284759213461SRichard Henderson if (likely(!crosspage)) { 284859213461SRichard Henderson do_st_4(env, &l.page[0], val, l.mmu_idx, l.memop, ra); 284959213461SRichard Henderson return; 285059213461SRichard Henderson } 285159213461SRichard Henderson 285259213461SRichard Henderson /* Swap to little endian for simplicity, then store by bytes. */ 285359213461SRichard Henderson if ((l.memop & MO_BSWAP) != MO_LE) { 285459213461SRichard Henderson val = bswap32(val); 285559213461SRichard Henderson } 28565b36f268SRichard Henderson val = do_st_leN(env, &l.page[0], val, l.mmu_idx, l.memop, ra); 28575b36f268SRichard Henderson (void) do_st_leN(env, &l.page[1], val, l.mmu_idx, l.memop, ra); 2858eed56642SAlex Bennée } 2859eed56642SAlex Bennée 286024e46e6cSRichard Henderson void helper_stl_mmu(CPUArchState *env, uint64_t addr, uint32_t val, 28619002ffcbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 2862eed56642SAlex Bennée { 28630cadc1edSRichard Henderson tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); 286459213461SRichard Henderson do_st4_mmu(env, addr, val, oi, retaddr); 286559213461SRichard Henderson } 286659213461SRichard Henderson 2867fb2c53cbSAnton Johansson static void do_st8_mmu(CPUArchState *env, vaddr addr, uint64_t val, 286859213461SRichard Henderson MemOpIdx oi, uintptr_t ra) 286959213461SRichard Henderson { 287059213461SRichard Henderson MMULookupLocals l; 287159213461SRichard Henderson bool crosspage; 287259213461SRichard Henderson 287359213461SRichard Henderson crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE, &l); 287459213461SRichard Henderson if (likely(!crosspage)) { 287559213461SRichard Henderson do_st_8(env, &l.page[0], val, l.mmu_idx, l.memop, ra); 287659213461SRichard Henderson return; 287759213461SRichard Henderson } 287859213461SRichard Henderson 287959213461SRichard Henderson /* Swap to little endian for simplicity, then store by bytes. */ 288059213461SRichard Henderson if ((l.memop & MO_BSWAP) != MO_LE) { 288159213461SRichard Henderson val = bswap64(val); 288259213461SRichard Henderson } 28835b36f268SRichard Henderson val = do_st_leN(env, &l.page[0], val, l.mmu_idx, l.memop, ra); 28845b36f268SRichard Henderson (void) do_st_leN(env, &l.page[1], val, l.mmu_idx, l.memop, ra); 2885eed56642SAlex Bennée } 2886eed56642SAlex Bennée 288724e46e6cSRichard Henderson void helper_stq_mmu(CPUArchState *env, uint64_t addr, uint64_t val, 28889002ffcbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 2889eed56642SAlex Bennée { 28900cadc1edSRichard Henderson tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); 289159213461SRichard Henderson do_st8_mmu(env, addr, val, oi, retaddr); 2892eed56642SAlex Bennée } 2893d9bb58e5SYang Zhong 2894fb2c53cbSAnton Johansson static void do_st16_mmu(CPUArchState *env, vaddr addr, Int128 val, 289535c653c4SRichard Henderson MemOpIdx oi, uintptr_t ra) 289635c653c4SRichard Henderson { 289735c653c4SRichard Henderson MMULookupLocals l; 289835c653c4SRichard Henderson bool crosspage; 289935c653c4SRichard Henderson uint64_t a, b; 290035c653c4SRichard Henderson int first; 290135c653c4SRichard Henderson 290235c653c4SRichard Henderson crosspage = mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE, &l); 290335c653c4SRichard Henderson if (likely(!crosspage)) { 290435c653c4SRichard Henderson /* Swap to host endian if necessary, then store. */ 290535c653c4SRichard Henderson if (l.memop & MO_BSWAP) { 290635c653c4SRichard Henderson val = bswap128(val); 290735c653c4SRichard Henderson } 290835c653c4SRichard Henderson if (unlikely(l.page[0].flags & TLB_MMIO)) { 290935c653c4SRichard Henderson QEMU_IOTHREAD_LOCK_GUARD(); 291035c653c4SRichard Henderson if (HOST_BIG_ENDIAN) { 291135c653c4SRichard Henderson b = int128_getlo(val), a = int128_gethi(val); 291235c653c4SRichard Henderson } else { 291335c653c4SRichard Henderson a = int128_getlo(val), b = int128_gethi(val); 291435c653c4SRichard Henderson } 291535c653c4SRichard Henderson io_writex(env, l.page[0].full, l.mmu_idx, a, addr, ra, MO_64); 291635c653c4SRichard Henderson io_writex(env, l.page[0].full, l.mmu_idx, b, addr + 8, ra, MO_64); 291735c653c4SRichard Henderson } else if (unlikely(l.page[0].flags & TLB_DISCARD_WRITE)) { 291835c653c4SRichard Henderson /* nothing */ 291935c653c4SRichard Henderson } else { 292035c653c4SRichard Henderson store_atom_16(env, ra, l.page[0].haddr, l.memop, val); 292135c653c4SRichard Henderson } 292235c653c4SRichard Henderson return; 292335c653c4SRichard Henderson } 292435c653c4SRichard Henderson 292535c653c4SRichard Henderson first = l.page[0].size; 292635c653c4SRichard Henderson if (first == 8) { 292735c653c4SRichard Henderson MemOp mop8 = (l.memop & ~(MO_SIZE | MO_BSWAP)) | MO_64; 292835c653c4SRichard Henderson 292935c653c4SRichard Henderson if (l.memop & MO_BSWAP) { 293035c653c4SRichard Henderson val = bswap128(val); 293135c653c4SRichard Henderson } 293235c653c4SRichard Henderson if (HOST_BIG_ENDIAN) { 293335c653c4SRichard Henderson b = int128_getlo(val), a = int128_gethi(val); 293435c653c4SRichard Henderson } else { 293535c653c4SRichard Henderson a = int128_getlo(val), b = int128_gethi(val); 293635c653c4SRichard Henderson } 293735c653c4SRichard Henderson do_st_8(env, &l.page[0], a, l.mmu_idx, mop8, ra); 293835c653c4SRichard Henderson do_st_8(env, &l.page[1], b, l.mmu_idx, mop8, ra); 293935c653c4SRichard Henderson return; 294035c653c4SRichard Henderson } 294135c653c4SRichard Henderson 294235c653c4SRichard Henderson if ((l.memop & MO_BSWAP) != MO_LE) { 294335c653c4SRichard Henderson val = bswap128(val); 294435c653c4SRichard Henderson } 294535c653c4SRichard Henderson if (first < 8) { 294635c653c4SRichard Henderson do_st_leN(env, &l.page[0], int128_getlo(val), l.mmu_idx, l.memop, ra); 294735c653c4SRichard Henderson val = int128_urshift(val, first * 8); 294835c653c4SRichard Henderson do_st16_leN(env, &l.page[1], val, l.mmu_idx, l.memop, ra); 294935c653c4SRichard Henderson } else { 295035c653c4SRichard Henderson b = do_st16_leN(env, &l.page[0], val, l.mmu_idx, l.memop, ra); 295135c653c4SRichard Henderson do_st_leN(env, &l.page[1], b, l.mmu_idx, l.memop, ra); 295235c653c4SRichard Henderson } 295335c653c4SRichard Henderson } 295435c653c4SRichard Henderson 295524e46e6cSRichard Henderson void helper_st16_mmu(CPUArchState *env, uint64_t addr, Int128 val, 295635c653c4SRichard Henderson MemOpIdx oi, uintptr_t retaddr) 295735c653c4SRichard Henderson { 295835c653c4SRichard Henderson tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); 295935c653c4SRichard Henderson do_st16_mmu(env, addr, val, oi, retaddr); 296035c653c4SRichard Henderson } 296135c653c4SRichard Henderson 2962e570597aSRichard Henderson void helper_st_i128(CPUArchState *env, uint64_t addr, Int128 val, MemOpIdx oi) 296335c653c4SRichard Henderson { 296435c653c4SRichard Henderson helper_st16_mmu(env, addr, val, oi, GETPC()); 296535c653c4SRichard Henderson } 296635c653c4SRichard Henderson 2967d03f1408SRichard Henderson /* 2968d03f1408SRichard Henderson * Store Helpers for cpu_ldst.h 2969d03f1408SRichard Henderson */ 2970d03f1408SRichard Henderson 297159213461SRichard Henderson static void plugin_store_cb(CPUArchState *env, abi_ptr addr, MemOpIdx oi) 2972d03f1408SRichard Henderson { 297337aff087SRichard Henderson qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); 2974d03f1408SRichard Henderson } 2975d03f1408SRichard Henderson 2976f83bcecbSRichard Henderson void cpu_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val, 2977f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 2978d03f1408SRichard Henderson { 29790cadc1edSRichard Henderson helper_stb_mmu(env, addr, val, oi, retaddr); 298059213461SRichard Henderson plugin_store_cb(env, addr, oi); 2981d03f1408SRichard Henderson } 2982d03f1408SRichard Henderson 2983fbea7a40SRichard Henderson void cpu_stw_mmu(CPUArchState *env, target_ulong addr, uint16_t val, 2984f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 2985d03f1408SRichard Henderson { 2986fbea7a40SRichard Henderson tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); 29870cadc1edSRichard Henderson do_st2_mmu(env, addr, val, oi, retaddr); 298859213461SRichard Henderson plugin_store_cb(env, addr, oi); 2989d03f1408SRichard Henderson } 2990d03f1408SRichard Henderson 2991fbea7a40SRichard Henderson void cpu_stl_mmu(CPUArchState *env, target_ulong addr, uint32_t val, 2992f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 2993d03f1408SRichard Henderson { 2994fbea7a40SRichard Henderson tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); 29950cadc1edSRichard Henderson do_st4_mmu(env, addr, val, oi, retaddr); 299659213461SRichard Henderson plugin_store_cb(env, addr, oi); 2997d03f1408SRichard Henderson } 2998d03f1408SRichard Henderson 2999fbea7a40SRichard Henderson void cpu_stq_mmu(CPUArchState *env, target_ulong addr, uint64_t val, 3000f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 3001d03f1408SRichard Henderson { 3002fbea7a40SRichard Henderson tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); 30030cadc1edSRichard Henderson do_st8_mmu(env, addr, val, oi, retaddr); 300459213461SRichard Henderson plugin_store_cb(env, addr, oi); 3005b9e60257SRichard Henderson } 3006b9e60257SRichard Henderson 3007fbea7a40SRichard Henderson void cpu_st16_mmu(CPUArchState *env, target_ulong addr, Int128 val, 3008f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t retaddr) 3009b9e60257SRichard Henderson { 3010fbea7a40SRichard Henderson tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); 301135c653c4SRichard Henderson do_st16_mmu(env, addr, val, oi, retaddr); 301235c653c4SRichard Henderson plugin_store_cb(env, addr, oi); 3013cb48f365SRichard Henderson } 3014cb48f365SRichard Henderson 3015f83bcecbSRichard Henderson #include "ldst_common.c.inc" 3016cfe04a4bSRichard Henderson 3017be9568b4SRichard Henderson /* 3018be9568b4SRichard Henderson * First set of functions passes in OI and RETADDR. 3019be9568b4SRichard Henderson * This makes them callable from other helpers. 3020be9568b4SRichard Henderson */ 3021d9bb58e5SYang Zhong 3022d9bb58e5SYang Zhong #define ATOMIC_NAME(X) \ 3023be9568b4SRichard Henderson glue(glue(glue(cpu_atomic_ ## X, SUFFIX), END), _mmu) 3024a754f7f3SRichard Henderson 3025707526adSRichard Henderson #define ATOMIC_MMU_CLEANUP 3026d9bb58e5SYang Zhong 3027139c1837SPaolo Bonzini #include "atomic_common.c.inc" 3028d9bb58e5SYang Zhong 3029d9bb58e5SYang Zhong #define DATA_SIZE 1 3030d9bb58e5SYang Zhong #include "atomic_template.h" 3031d9bb58e5SYang Zhong 3032d9bb58e5SYang Zhong #define DATA_SIZE 2 3033d9bb58e5SYang Zhong #include "atomic_template.h" 3034d9bb58e5SYang Zhong 3035d9bb58e5SYang Zhong #define DATA_SIZE 4 3036d9bb58e5SYang Zhong #include "atomic_template.h" 3037d9bb58e5SYang Zhong 3038d9bb58e5SYang Zhong #ifdef CONFIG_ATOMIC64 3039d9bb58e5SYang Zhong #define DATA_SIZE 8 3040d9bb58e5SYang Zhong #include "atomic_template.h" 3041d9bb58e5SYang Zhong #endif 3042d9bb58e5SYang Zhong 30434deb39ebSRichard Henderson #if defined(CONFIG_ATOMIC128) || defined(CONFIG_CMPXCHG128) 3044d9bb58e5SYang Zhong #define DATA_SIZE 16 3045d9bb58e5SYang Zhong #include "atomic_template.h" 3046d9bb58e5SYang Zhong #endif 3047d9bb58e5SYang Zhong 3048d9bb58e5SYang Zhong /* Code access functions. */ 3049d9bb58e5SYang Zhong 3050fc4120a3SRichard Henderson uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr addr) 3051eed56642SAlex Bennée { 30529002ffcbSRichard Henderson MemOpIdx oi = make_memop_idx(MO_UB, cpu_mmu_index(env, true)); 30538cfdacaaSRichard Henderson return do_ld1_mmu(env, addr, oi, 0, MMU_INST_FETCH); 30544cef72d0SAlex Bennée } 30554cef72d0SAlex Bennée 3056fc4120a3SRichard Henderson uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr addr) 30572dd92606SRichard Henderson { 30589002ffcbSRichard Henderson MemOpIdx oi = make_memop_idx(MO_TEUW, cpu_mmu_index(env, true)); 30598cfdacaaSRichard Henderson return do_ld2_mmu(env, addr, oi, 0, MMU_INST_FETCH); 30602dd92606SRichard Henderson } 30612dd92606SRichard Henderson 3062fc4120a3SRichard Henderson uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr addr) 30634cef72d0SAlex Bennée { 30649002ffcbSRichard Henderson MemOpIdx oi = make_memop_idx(MO_TEUL, cpu_mmu_index(env, true)); 30658cfdacaaSRichard Henderson return do_ld4_mmu(env, addr, oi, 0, MMU_INST_FETCH); 3066eed56642SAlex Bennée } 3067d9bb58e5SYang Zhong 3068fc4120a3SRichard Henderson uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr addr) 3069eed56642SAlex Bennée { 3070fc313c64SFrédéric Pétrot MemOpIdx oi = make_memop_idx(MO_TEUQ, cpu_mmu_index(env, true)); 30718cfdacaaSRichard Henderson return do_ld8_mmu(env, addr, oi, 0, MMU_INST_FETCH); 3072eed56642SAlex Bennée } 307328990626SRichard Henderson 307428990626SRichard Henderson uint8_t cpu_ldb_code_mmu(CPUArchState *env, abi_ptr addr, 307528990626SRichard Henderson MemOpIdx oi, uintptr_t retaddr) 307628990626SRichard Henderson { 30778cfdacaaSRichard Henderson return do_ld1_mmu(env, addr, oi, retaddr, MMU_INST_FETCH); 307828990626SRichard Henderson } 307928990626SRichard Henderson 308028990626SRichard Henderson uint16_t cpu_ldw_code_mmu(CPUArchState *env, abi_ptr addr, 308128990626SRichard Henderson MemOpIdx oi, uintptr_t retaddr) 308228990626SRichard Henderson { 30838cfdacaaSRichard Henderson return do_ld2_mmu(env, addr, oi, retaddr, MMU_INST_FETCH); 308428990626SRichard Henderson } 308528990626SRichard Henderson 308628990626SRichard Henderson uint32_t cpu_ldl_code_mmu(CPUArchState *env, abi_ptr addr, 308728990626SRichard Henderson MemOpIdx oi, uintptr_t retaddr) 308828990626SRichard Henderson { 30898cfdacaaSRichard Henderson return do_ld4_mmu(env, addr, oi, retaddr, MMU_INST_FETCH); 309028990626SRichard Henderson } 309128990626SRichard Henderson 309228990626SRichard Henderson uint64_t cpu_ldq_code_mmu(CPUArchState *env, abi_ptr addr, 309328990626SRichard Henderson MemOpIdx oi, uintptr_t retaddr) 309428990626SRichard Henderson { 30958cfdacaaSRichard Henderson return do_ld8_mmu(env, addr, oi, retaddr, MMU_INST_FETCH); 309628990626SRichard Henderson } 3097