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" 2474781c08SPhilippe Mathieu-Daudé #include "exec/page-protection.h" 25d9bb58e5SYang Zhong #include "exec/memory.h" 26d9bb58e5SYang Zhong #include "exec/cpu_ldst.h" 27d9bb58e5SYang Zhong #include "exec/cputlb.h" 28f4f826c0SPhilippe Mathieu-Daudé #include "exec/tb-flush.h" 29d9bb58e5SYang Zhong #include "exec/memory-internal.h" 30d9bb58e5SYang Zhong #include "exec/ram_addr.h" 31aacfd8bbSPhilippe Mathieu-Daudé #include "exec/mmu-access-type.h" 32aacfd8bbSPhilippe Mathieu-Daudé #include "exec/tlb-common.h" 33aacfd8bbSPhilippe Mathieu-Daudé #include "exec/vaddr.h" 34d9bb58e5SYang Zhong #include "tcg/tcg.h" 35d9bb58e5SYang Zhong #include "qemu/error-report.h" 36d9bb58e5SYang Zhong #include "exec/log.h" 37c213ee2dSRichard Henderson #include "exec/helper-proto-common.h" 38d9bb58e5SYang Zhong #include "qemu/atomic.h" 39e6cd4bb5SRichard Henderson #include "qemu/atomic128.h" 403b9bd3f4SPaolo Bonzini #include "exec/translate-all.h" 4151807763SPhilippe Mathieu-Daudé #include "trace.h" 42e5ceadffSPhilippe Mathieu-Daudé #include "tb-hash.h" 4343e7a2d3SPhilippe Mathieu-Daudé #include "internal-common.h" 444c268d6dSPhilippe Mathieu-Daudé #include "internal-target.h" 45235537faSAlex Bennée #ifdef CONFIG_PLUGIN 46235537faSAlex Bennée #include "qemu/plugin-memory.h" 47235537faSAlex Bennée #endif 48d2ba8026SRichard Henderson #include "tcg/tcg-ldst.h" 4970f168f8SRichard Henderson #include "tcg/oversized-guest.h" 50d9bb58e5SYang Zhong 51d9bb58e5SYang Zhong /* DEBUG defines, enable DEBUG_TLB_LOG to log to the CPU_LOG_MMU target */ 52d9bb58e5SYang Zhong /* #define DEBUG_TLB */ 53d9bb58e5SYang Zhong /* #define DEBUG_TLB_LOG */ 54d9bb58e5SYang Zhong 55d9bb58e5SYang Zhong #ifdef DEBUG_TLB 56d9bb58e5SYang Zhong # define DEBUG_TLB_GATE 1 57d9bb58e5SYang Zhong # ifdef DEBUG_TLB_LOG 58d9bb58e5SYang Zhong # define DEBUG_TLB_LOG_GATE 1 59d9bb58e5SYang Zhong # else 60d9bb58e5SYang Zhong # define DEBUG_TLB_LOG_GATE 0 61d9bb58e5SYang Zhong # endif 62d9bb58e5SYang Zhong #else 63d9bb58e5SYang Zhong # define DEBUG_TLB_GATE 0 64d9bb58e5SYang Zhong # define DEBUG_TLB_LOG_GATE 0 65d9bb58e5SYang Zhong #endif 66d9bb58e5SYang Zhong 67d9bb58e5SYang Zhong #define tlb_debug(fmt, ...) do { \ 68d9bb58e5SYang Zhong if (DEBUG_TLB_LOG_GATE) { \ 69d9bb58e5SYang Zhong qemu_log_mask(CPU_LOG_MMU, "%s: " fmt, __func__, \ 70d9bb58e5SYang Zhong ## __VA_ARGS__); \ 71d9bb58e5SYang Zhong } else if (DEBUG_TLB_GATE) { \ 72d9bb58e5SYang Zhong fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); \ 73d9bb58e5SYang Zhong } \ 74d9bb58e5SYang Zhong } while (0) 75d9bb58e5SYang Zhong 76ea9025cbSEmilio G. Cota #define assert_cpu_is_self(cpu) do { \ 77d9bb58e5SYang Zhong if (DEBUG_TLB_GATE) { \ 78ea9025cbSEmilio G. Cota g_assert(!(cpu)->created || qemu_cpu_is_self(cpu)); \ 79d9bb58e5SYang Zhong } \ 80d9bb58e5SYang Zhong } while (0) 81d9bb58e5SYang Zhong 82d9bb58e5SYang Zhong /* run_on_cpu_data.target_ptr should always be big enough for a 83e79f8142SAnton Johansson * vaddr even on 32 bit builds 84e79f8142SAnton Johansson */ 85e79f8142SAnton Johansson QEMU_BUILD_BUG_ON(sizeof(vaddr) > sizeof(run_on_cpu_data)); 86d9bb58e5SYang Zhong 87d9bb58e5SYang Zhong /* We currently can't handle more than 16 bits in the MMUIDX bitmask. 88d9bb58e5SYang Zhong */ 89d9bb58e5SYang Zhong QEMU_BUILD_BUG_ON(NB_MMU_MODES > 16); 90d9bb58e5SYang Zhong #define ALL_MMUIDX_BITS ((1 << NB_MMU_MODES) - 1) 91d9bb58e5SYang Zhong 92722a1c1eSRichard Henderson static inline size_t tlb_n_entries(CPUTLBDescFast *fast) 937a1efe1bSRichard Henderson { 94722a1c1eSRichard Henderson return (fast->mask >> CPU_TLB_ENTRY_BITS) + 1; 957a1efe1bSRichard Henderson } 967a1efe1bSRichard Henderson 97722a1c1eSRichard Henderson static inline size_t sizeof_tlb(CPUTLBDescFast *fast) 9886e1eff8SEmilio G. Cota { 99722a1c1eSRichard Henderson return fast->mask + (1 << CPU_TLB_ENTRY_BITS); 10086e1eff8SEmilio G. Cota } 10186e1eff8SEmilio G. Cota 102aacfd8bbSPhilippe Mathieu-Daudé static inline uint64_t tlb_read_idx(const CPUTLBEntry *entry, 103aacfd8bbSPhilippe Mathieu-Daudé MMUAccessType access_type) 104aacfd8bbSPhilippe Mathieu-Daudé { 105aacfd8bbSPhilippe Mathieu-Daudé /* Do not rearrange the CPUTLBEntry structure members. */ 106aacfd8bbSPhilippe Mathieu-Daudé QEMU_BUILD_BUG_ON(offsetof(CPUTLBEntry, addr_read) != 107aacfd8bbSPhilippe Mathieu-Daudé MMU_DATA_LOAD * sizeof(uint64_t)); 108aacfd8bbSPhilippe Mathieu-Daudé QEMU_BUILD_BUG_ON(offsetof(CPUTLBEntry, addr_write) != 109aacfd8bbSPhilippe Mathieu-Daudé MMU_DATA_STORE * sizeof(uint64_t)); 110aacfd8bbSPhilippe Mathieu-Daudé QEMU_BUILD_BUG_ON(offsetof(CPUTLBEntry, addr_code) != 111aacfd8bbSPhilippe Mathieu-Daudé MMU_INST_FETCH * sizeof(uint64_t)); 112aacfd8bbSPhilippe Mathieu-Daudé 113aacfd8bbSPhilippe Mathieu-Daudé #if TARGET_LONG_BITS == 32 114aacfd8bbSPhilippe Mathieu-Daudé /* Use qatomic_read, in case of addr_write; only care about low bits. */ 115aacfd8bbSPhilippe Mathieu-Daudé const uint32_t *ptr = (uint32_t *)&entry->addr_idx[access_type]; 116aacfd8bbSPhilippe Mathieu-Daudé ptr += HOST_BIG_ENDIAN; 117aacfd8bbSPhilippe Mathieu-Daudé return qatomic_read(ptr); 118aacfd8bbSPhilippe Mathieu-Daudé #else 119aacfd8bbSPhilippe Mathieu-Daudé const uint64_t *ptr = &entry->addr_idx[access_type]; 120aacfd8bbSPhilippe Mathieu-Daudé # if TCG_OVERSIZED_GUEST 121aacfd8bbSPhilippe Mathieu-Daudé return *ptr; 122aacfd8bbSPhilippe Mathieu-Daudé # else 123aacfd8bbSPhilippe Mathieu-Daudé /* ofs might correspond to .addr_write, so use qatomic_read */ 124aacfd8bbSPhilippe Mathieu-Daudé return qatomic_read(ptr); 125aacfd8bbSPhilippe Mathieu-Daudé # endif 126aacfd8bbSPhilippe Mathieu-Daudé #endif 127aacfd8bbSPhilippe Mathieu-Daudé } 128aacfd8bbSPhilippe Mathieu-Daudé 129aacfd8bbSPhilippe Mathieu-Daudé static inline uint64_t tlb_addr_write(const CPUTLBEntry *entry) 130aacfd8bbSPhilippe Mathieu-Daudé { 131aacfd8bbSPhilippe Mathieu-Daudé return tlb_read_idx(entry, MMU_DATA_STORE); 132aacfd8bbSPhilippe Mathieu-Daudé } 133aacfd8bbSPhilippe Mathieu-Daudé 134aacfd8bbSPhilippe Mathieu-Daudé /* Find the TLB index corresponding to the mmu_idx + address pair. */ 135aacfd8bbSPhilippe Mathieu-Daudé static inline uintptr_t tlb_index(CPUState *cpu, uintptr_t mmu_idx, 136aacfd8bbSPhilippe Mathieu-Daudé vaddr addr) 137aacfd8bbSPhilippe Mathieu-Daudé { 138aacfd8bbSPhilippe Mathieu-Daudé uintptr_t size_mask = cpu->neg.tlb.f[mmu_idx].mask >> CPU_TLB_ENTRY_BITS; 139aacfd8bbSPhilippe Mathieu-Daudé 140aacfd8bbSPhilippe Mathieu-Daudé return (addr >> TARGET_PAGE_BITS) & size_mask; 141aacfd8bbSPhilippe Mathieu-Daudé } 142aacfd8bbSPhilippe Mathieu-Daudé 143aacfd8bbSPhilippe Mathieu-Daudé /* Find the TLB entry corresponding to the mmu_idx + address pair. */ 144aacfd8bbSPhilippe Mathieu-Daudé static inline CPUTLBEntry *tlb_entry(CPUState *cpu, uintptr_t mmu_idx, 145aacfd8bbSPhilippe Mathieu-Daudé vaddr addr) 146aacfd8bbSPhilippe Mathieu-Daudé { 147aacfd8bbSPhilippe Mathieu-Daudé return &cpu->neg.tlb.f[mmu_idx].table[tlb_index(cpu, mmu_idx, addr)]; 148aacfd8bbSPhilippe Mathieu-Daudé } 149aacfd8bbSPhilippe Mathieu-Daudé 15079e42085SRichard Henderson static void tlb_window_reset(CPUTLBDesc *desc, int64_t ns, 15186e1eff8SEmilio G. Cota size_t max_entries) 15286e1eff8SEmilio G. Cota { 15379e42085SRichard Henderson desc->window_begin_ns = ns; 15479e42085SRichard Henderson desc->window_max_entries = max_entries; 15586e1eff8SEmilio G. Cota } 15686e1eff8SEmilio G. Cota 15706f3831cSAnton Johansson static void tb_jmp_cache_clear_page(CPUState *cpu, vaddr page_addr) 1580f4abea8SRichard Henderson { 159a976a99aSRichard Henderson CPUJumpCache *jc = cpu->tb_jmp_cache; 16099ab4d50SEric Auger int i, i0; 1610f4abea8SRichard Henderson 16299ab4d50SEric Auger if (unlikely(!jc)) { 16399ab4d50SEric Auger return; 16499ab4d50SEric Auger } 16599ab4d50SEric Auger 16699ab4d50SEric Auger i0 = tb_jmp_cache_hash_page(page_addr); 1670f4abea8SRichard Henderson for (i = 0; i < TB_JMP_PAGE_SIZE; i++) { 168a976a99aSRichard Henderson qatomic_set(&jc->array[i0 + i].tb, NULL); 1690f4abea8SRichard Henderson } 1700f4abea8SRichard Henderson } 1710f4abea8SRichard Henderson 17286e1eff8SEmilio G. Cota /** 17386e1eff8SEmilio G. Cota * tlb_mmu_resize_locked() - perform TLB resize bookkeeping; resize if necessary 17471ccd47bSRichard Henderson * @desc: The CPUTLBDesc portion of the TLB 17571ccd47bSRichard Henderson * @fast: The CPUTLBDescFast portion of the same TLB 17686e1eff8SEmilio G. Cota * 17786e1eff8SEmilio G. Cota * Called with tlb_lock_held. 17886e1eff8SEmilio G. Cota * 17986e1eff8SEmilio G. Cota * We have two main constraints when resizing a TLB: (1) we only resize it 18086e1eff8SEmilio G. Cota * on a TLB flush (otherwise we'd have to take a perf hit by either rehashing 18186e1eff8SEmilio G. Cota * the array or unnecessarily flushing it), which means we do not control how 18286e1eff8SEmilio G. Cota * frequently the resizing can occur; (2) we don't have access to the guest's 18386e1eff8SEmilio G. Cota * future scheduling decisions, and therefore have to decide the magnitude of 18486e1eff8SEmilio G. Cota * the resize based on past observations. 18586e1eff8SEmilio G. Cota * 18686e1eff8SEmilio G. Cota * In general, a memory-hungry process can benefit greatly from an appropriately 18786e1eff8SEmilio G. Cota * sized TLB, since a guest TLB miss is very expensive. This doesn't mean that 18886e1eff8SEmilio G. Cota * we just have to make the TLB as large as possible; while an oversized TLB 18986e1eff8SEmilio G. Cota * results in minimal TLB miss rates, it also takes longer to be flushed 19086e1eff8SEmilio G. Cota * (flushes can be _very_ frequent), and the reduced locality can also hurt 19186e1eff8SEmilio G. Cota * performance. 19286e1eff8SEmilio G. Cota * 19386e1eff8SEmilio G. Cota * To achieve near-optimal performance for all kinds of workloads, we: 19486e1eff8SEmilio G. Cota * 19586e1eff8SEmilio G. Cota * 1. Aggressively increase the size of the TLB when the use rate of the 19686e1eff8SEmilio G. Cota * TLB being flushed is high, since it is likely that in the near future this 19786e1eff8SEmilio G. Cota * memory-hungry process will execute again, and its memory hungriness will 19886e1eff8SEmilio G. Cota * probably be similar. 19986e1eff8SEmilio G. Cota * 20086e1eff8SEmilio G. Cota * 2. Slowly reduce the size of the TLB as the use rate declines over a 20186e1eff8SEmilio G. Cota * reasonably large time window. The rationale is that if in such a time window 20286e1eff8SEmilio G. Cota * we have not observed a high TLB use rate, it is likely that we won't observe 20386e1eff8SEmilio G. Cota * it in the near future. In that case, once a time window expires we downsize 20486e1eff8SEmilio G. Cota * the TLB to match the maximum use rate observed in the window. 20586e1eff8SEmilio G. Cota * 20686e1eff8SEmilio G. Cota * 3. Try to keep the maximum use rate in a time window in the 30-70% range, 20786e1eff8SEmilio G. Cota * since in that range performance is likely near-optimal. Recall that the TLB 20886e1eff8SEmilio G. Cota * is direct mapped, so we want the use rate to be low (or at least not too 20986e1eff8SEmilio G. Cota * high), since otherwise we are likely to have a significant amount of 21086e1eff8SEmilio G. Cota * conflict misses. 21186e1eff8SEmilio G. Cota */ 2123c3959f2SRichard Henderson static void tlb_mmu_resize_locked(CPUTLBDesc *desc, CPUTLBDescFast *fast, 2133c3959f2SRichard Henderson int64_t now) 21486e1eff8SEmilio G. Cota { 21571ccd47bSRichard Henderson size_t old_size = tlb_n_entries(fast); 21686e1eff8SEmilio G. Cota size_t rate; 21786e1eff8SEmilio G. Cota size_t new_size = old_size; 21886e1eff8SEmilio G. Cota int64_t window_len_ms = 100; 21986e1eff8SEmilio G. Cota int64_t window_len_ns = window_len_ms * 1000 * 1000; 22079e42085SRichard Henderson bool window_expired = now > desc->window_begin_ns + window_len_ns; 22186e1eff8SEmilio G. Cota 22279e42085SRichard Henderson if (desc->n_used_entries > desc->window_max_entries) { 22379e42085SRichard Henderson desc->window_max_entries = desc->n_used_entries; 22486e1eff8SEmilio G. Cota } 22579e42085SRichard Henderson rate = desc->window_max_entries * 100 / old_size; 22686e1eff8SEmilio G. Cota 22786e1eff8SEmilio G. Cota if (rate > 70) { 22886e1eff8SEmilio G. Cota new_size = MIN(old_size << 1, 1 << CPU_TLB_DYN_MAX_BITS); 22986e1eff8SEmilio G. Cota } else if (rate < 30 && window_expired) { 23079e42085SRichard Henderson size_t ceil = pow2ceil(desc->window_max_entries); 23179e42085SRichard Henderson size_t expected_rate = desc->window_max_entries * 100 / ceil; 23286e1eff8SEmilio G. Cota 23386e1eff8SEmilio G. Cota /* 23486e1eff8SEmilio G. Cota * Avoid undersizing when the max number of entries seen is just below 23586e1eff8SEmilio G. Cota * a pow2. For instance, if max_entries == 1025, the expected use rate 23686e1eff8SEmilio G. Cota * would be 1025/2048==50%. However, if max_entries == 1023, we'd get 23786e1eff8SEmilio G. Cota * 1023/1024==99.9% use rate, so we'd likely end up doubling the size 23886e1eff8SEmilio G. Cota * later. Thus, make sure that the expected use rate remains below 70%. 23986e1eff8SEmilio G. Cota * (and since we double the size, that means the lowest rate we'd 24086e1eff8SEmilio G. Cota * expect to get is 35%, which is still in the 30-70% range where 24186e1eff8SEmilio G. Cota * we consider that the size is appropriate.) 24286e1eff8SEmilio G. Cota */ 24386e1eff8SEmilio G. Cota if (expected_rate > 70) { 24486e1eff8SEmilio G. Cota ceil *= 2; 24586e1eff8SEmilio G. Cota } 24686e1eff8SEmilio G. Cota new_size = MAX(ceil, 1 << CPU_TLB_DYN_MIN_BITS); 24786e1eff8SEmilio G. Cota } 24886e1eff8SEmilio G. Cota 24986e1eff8SEmilio G. Cota if (new_size == old_size) { 25086e1eff8SEmilio G. Cota if (window_expired) { 25179e42085SRichard Henderson tlb_window_reset(desc, now, desc->n_used_entries); 25286e1eff8SEmilio G. Cota } 25386e1eff8SEmilio G. Cota return; 25486e1eff8SEmilio G. Cota } 25586e1eff8SEmilio G. Cota 25671ccd47bSRichard Henderson g_free(fast->table); 25725d3ec58SRichard Henderson g_free(desc->fulltlb); 25886e1eff8SEmilio G. Cota 25979e42085SRichard Henderson tlb_window_reset(desc, now, 0); 26086e1eff8SEmilio G. Cota /* desc->n_used_entries is cleared by the caller */ 26171ccd47bSRichard Henderson fast->mask = (new_size - 1) << CPU_TLB_ENTRY_BITS; 26271ccd47bSRichard Henderson fast->table = g_try_new(CPUTLBEntry, new_size); 26325d3ec58SRichard Henderson desc->fulltlb = g_try_new(CPUTLBEntryFull, new_size); 26471ccd47bSRichard Henderson 26586e1eff8SEmilio G. Cota /* 26686e1eff8SEmilio G. Cota * If the allocations fail, try smaller sizes. We just freed some 26786e1eff8SEmilio G. Cota * memory, so going back to half of new_size has a good chance of working. 26886e1eff8SEmilio G. Cota * Increased memory pressure elsewhere in the system might cause the 26986e1eff8SEmilio G. Cota * allocations to fail though, so we progressively reduce the allocation 27086e1eff8SEmilio G. Cota * size, aborting if we cannot even allocate the smallest TLB we support. 27186e1eff8SEmilio G. Cota */ 27225d3ec58SRichard Henderson while (fast->table == NULL || desc->fulltlb == NULL) { 27386e1eff8SEmilio G. Cota if (new_size == (1 << CPU_TLB_DYN_MIN_BITS)) { 27486e1eff8SEmilio G. Cota error_report("%s: %s", __func__, strerror(errno)); 27586e1eff8SEmilio G. Cota abort(); 27686e1eff8SEmilio G. Cota } 27786e1eff8SEmilio G. Cota new_size = MAX(new_size >> 1, 1 << CPU_TLB_DYN_MIN_BITS); 27871ccd47bSRichard Henderson fast->mask = (new_size - 1) << CPU_TLB_ENTRY_BITS; 27986e1eff8SEmilio G. Cota 28071ccd47bSRichard Henderson g_free(fast->table); 28125d3ec58SRichard Henderson g_free(desc->fulltlb); 28271ccd47bSRichard Henderson fast->table = g_try_new(CPUTLBEntry, new_size); 28325d3ec58SRichard Henderson desc->fulltlb = g_try_new(CPUTLBEntryFull, new_size); 28486e1eff8SEmilio G. Cota } 28586e1eff8SEmilio G. Cota } 28686e1eff8SEmilio G. Cota 287bbf021b0SRichard Henderson static void tlb_mmu_flush_locked(CPUTLBDesc *desc, CPUTLBDescFast *fast) 28886e1eff8SEmilio G. Cota { 2895c948e31SRichard Henderson desc->n_used_entries = 0; 2905c948e31SRichard Henderson desc->large_page_addr = -1; 2915c948e31SRichard Henderson desc->large_page_mask = -1; 2925c948e31SRichard Henderson desc->vindex = 0; 2935c948e31SRichard Henderson memset(fast->table, -1, sizeof_tlb(fast)); 2945c948e31SRichard Henderson memset(desc->vtable, -1, sizeof(desc->vtable)); 29586e1eff8SEmilio G. Cota } 29686e1eff8SEmilio G. Cota 29710b32e2cSAnton Johansson static void tlb_flush_one_mmuidx_locked(CPUState *cpu, int mmu_idx, 2983c3959f2SRichard Henderson int64_t now) 299bbf021b0SRichard Henderson { 30010b32e2cSAnton Johansson CPUTLBDesc *desc = &cpu->neg.tlb.d[mmu_idx]; 30110b32e2cSAnton Johansson CPUTLBDescFast *fast = &cpu->neg.tlb.f[mmu_idx]; 302bbf021b0SRichard Henderson 3033c3959f2SRichard Henderson tlb_mmu_resize_locked(desc, fast, now); 304bbf021b0SRichard Henderson tlb_mmu_flush_locked(desc, fast); 305bbf021b0SRichard Henderson } 306bbf021b0SRichard Henderson 30756e89f76SRichard Henderson static void tlb_mmu_init(CPUTLBDesc *desc, CPUTLBDescFast *fast, int64_t now) 30856e89f76SRichard Henderson { 30956e89f76SRichard Henderson size_t n_entries = 1 << CPU_TLB_DYN_DEFAULT_BITS; 31056e89f76SRichard Henderson 31156e89f76SRichard Henderson tlb_window_reset(desc, now, 0); 31256e89f76SRichard Henderson desc->n_used_entries = 0; 31356e89f76SRichard Henderson fast->mask = (n_entries - 1) << CPU_TLB_ENTRY_BITS; 31456e89f76SRichard Henderson fast->table = g_new(CPUTLBEntry, n_entries); 31525d3ec58SRichard Henderson desc->fulltlb = g_new(CPUTLBEntryFull, n_entries); 3163c16304aSRichard Henderson tlb_mmu_flush_locked(desc, fast); 31756e89f76SRichard Henderson } 31856e89f76SRichard Henderson 31910b32e2cSAnton Johansson static inline void tlb_n_used_entries_inc(CPUState *cpu, uintptr_t mmu_idx) 32086e1eff8SEmilio G. Cota { 32110b32e2cSAnton Johansson cpu->neg.tlb.d[mmu_idx].n_used_entries++; 32286e1eff8SEmilio G. Cota } 32386e1eff8SEmilio G. Cota 32410b32e2cSAnton Johansson static inline void tlb_n_used_entries_dec(CPUState *cpu, uintptr_t mmu_idx) 32586e1eff8SEmilio G. Cota { 32610b32e2cSAnton Johansson cpu->neg.tlb.d[mmu_idx].n_used_entries--; 32786e1eff8SEmilio G. Cota } 32886e1eff8SEmilio G. Cota 3295005e253SEmilio G. Cota void tlb_init(CPUState *cpu) 3305005e253SEmilio G. Cota { 33156e89f76SRichard Henderson int64_t now = get_clock_realtime(); 33256e89f76SRichard Henderson int i; 33371aec354SEmilio G. Cota 33410b32e2cSAnton Johansson qemu_spin_init(&cpu->neg.tlb.c.lock); 3353d1523ceSRichard Henderson 3363c16304aSRichard Henderson /* All tlbs are initialized flushed. */ 33710b32e2cSAnton Johansson cpu->neg.tlb.c.dirty = 0; 33886e1eff8SEmilio G. Cota 33956e89f76SRichard Henderson for (i = 0; i < NB_MMU_MODES; i++) { 34010b32e2cSAnton Johansson tlb_mmu_init(&cpu->neg.tlb.d[i], &cpu->neg.tlb.f[i], now); 34156e89f76SRichard Henderson } 3425005e253SEmilio G. Cota } 3435005e253SEmilio G. Cota 344816d9be5SEmilio G. Cota void tlb_destroy(CPUState *cpu) 345816d9be5SEmilio G. Cota { 346816d9be5SEmilio G. Cota int i; 347816d9be5SEmilio G. Cota 34810b32e2cSAnton Johansson qemu_spin_destroy(&cpu->neg.tlb.c.lock); 349816d9be5SEmilio G. Cota for (i = 0; i < NB_MMU_MODES; i++) { 35010b32e2cSAnton Johansson CPUTLBDesc *desc = &cpu->neg.tlb.d[i]; 35110b32e2cSAnton Johansson CPUTLBDescFast *fast = &cpu->neg.tlb.f[i]; 352816d9be5SEmilio G. Cota 353816d9be5SEmilio G. Cota g_free(fast->table); 35425d3ec58SRichard Henderson g_free(desc->fulltlb); 355816d9be5SEmilio G. Cota } 356816d9be5SEmilio G. Cota } 357816d9be5SEmilio G. Cota 358d9bb58e5SYang Zhong /* flush_all_helper: run fn across all cpus 359d9bb58e5SYang Zhong * 360d9bb58e5SYang Zhong * If the wait flag is set then the src cpu's helper will be queued as 361d9bb58e5SYang Zhong * "safe" work and the loop exited creating a synchronisation point 362d9bb58e5SYang Zhong * where all queued work will be finished before execution starts 363d9bb58e5SYang Zhong * again. 364d9bb58e5SYang Zhong */ 365d9bb58e5SYang Zhong static void flush_all_helper(CPUState *src, run_on_cpu_func fn, 366d9bb58e5SYang Zhong run_on_cpu_data d) 367d9bb58e5SYang Zhong { 368d9bb58e5SYang Zhong CPUState *cpu; 369d9bb58e5SYang Zhong 370d9bb58e5SYang Zhong CPU_FOREACH(cpu) { 371d9bb58e5SYang Zhong if (cpu != src) { 372d9bb58e5SYang Zhong async_run_on_cpu(cpu, fn, d); 373d9bb58e5SYang Zhong } 374d9bb58e5SYang Zhong } 375d9bb58e5SYang Zhong } 376d9bb58e5SYang Zhong 377d9bb58e5SYang Zhong static void tlb_flush_by_mmuidx_async_work(CPUState *cpu, run_on_cpu_data data) 378d9bb58e5SYang Zhong { 3793d1523ceSRichard Henderson uint16_t asked = data.host_int; 3803d1523ceSRichard Henderson uint16_t all_dirty, work, to_clean; 3813c3959f2SRichard Henderson int64_t now = get_clock_realtime(); 382d9bb58e5SYang Zhong 383d9bb58e5SYang Zhong assert_cpu_is_self(cpu); 384d9bb58e5SYang Zhong 3853d1523ceSRichard Henderson tlb_debug("mmu_idx:0x%04" PRIx16 "\n", asked); 386d9bb58e5SYang Zhong 38710b32e2cSAnton Johansson qemu_spin_lock(&cpu->neg.tlb.c.lock); 38860a2ad7dSRichard Henderson 38910b32e2cSAnton Johansson all_dirty = cpu->neg.tlb.c.dirty; 3903d1523ceSRichard Henderson to_clean = asked & all_dirty; 3913d1523ceSRichard Henderson all_dirty &= ~to_clean; 39210b32e2cSAnton Johansson cpu->neg.tlb.c.dirty = all_dirty; 3933d1523ceSRichard Henderson 3943d1523ceSRichard Henderson for (work = to_clean; work != 0; work &= work - 1) { 3953d1523ceSRichard Henderson int mmu_idx = ctz32(work); 39610b32e2cSAnton Johansson tlb_flush_one_mmuidx_locked(cpu, mmu_idx, now); 397d9bb58e5SYang Zhong } 3983d1523ceSRichard Henderson 39910b32e2cSAnton Johansson qemu_spin_unlock(&cpu->neg.tlb.c.lock); 400d9bb58e5SYang Zhong 401a976a99aSRichard Henderson tcg_flush_jmp_cache(cpu); 40264f2674bSRichard Henderson 4033d1523ceSRichard Henderson if (to_clean == ALL_MMUIDX_BITS) { 40410b32e2cSAnton Johansson qatomic_set(&cpu->neg.tlb.c.full_flush_count, 40510b32e2cSAnton Johansson cpu->neg.tlb.c.full_flush_count + 1); 406e09de0a2SRichard Henderson } else { 40710b32e2cSAnton Johansson qatomic_set(&cpu->neg.tlb.c.part_flush_count, 40810b32e2cSAnton Johansson cpu->neg.tlb.c.part_flush_count + ctpop16(to_clean)); 4093d1523ceSRichard Henderson if (to_clean != asked) { 41010b32e2cSAnton Johansson qatomic_set(&cpu->neg.tlb.c.elide_flush_count, 41110b32e2cSAnton Johansson cpu->neg.tlb.c.elide_flush_count + 4123d1523ceSRichard Henderson ctpop16(asked & ~to_clean)); 4133d1523ceSRichard Henderson } 41464f2674bSRichard Henderson } 415d9bb58e5SYang Zhong } 416d9bb58e5SYang Zhong 417d9bb58e5SYang Zhong void tlb_flush_by_mmuidx(CPUState *cpu, uint16_t idxmap) 418d9bb58e5SYang Zhong { 419d9bb58e5SYang Zhong tlb_debug("mmu_idx: 0x%" PRIx16 "\n", idxmap); 420d9bb58e5SYang Zhong 42130933c4fSNicholas Piggin assert_cpu_is_self(cpu); 42230933c4fSNicholas Piggin 42360a2ad7dSRichard Henderson tlb_flush_by_mmuidx_async_work(cpu, RUN_ON_CPU_HOST_INT(idxmap)); 424d9bb58e5SYang Zhong } 425d9bb58e5SYang Zhong 42664f2674bSRichard Henderson void tlb_flush(CPUState *cpu) 42764f2674bSRichard Henderson { 42864f2674bSRichard Henderson tlb_flush_by_mmuidx(cpu, ALL_MMUIDX_BITS); 42964f2674bSRichard Henderson } 43064f2674bSRichard Henderson 43164f2674bSRichard Henderson void tlb_flush_by_mmuidx_all_cpus_synced(CPUState *src_cpu, uint16_t idxmap) 432d9bb58e5SYang Zhong { 433d9bb58e5SYang Zhong const run_on_cpu_func fn = tlb_flush_by_mmuidx_async_work; 434d9bb58e5SYang Zhong 435d9bb58e5SYang Zhong tlb_debug("mmu_idx: 0x%"PRIx16"\n", idxmap); 436d9bb58e5SYang Zhong 437d9bb58e5SYang Zhong flush_all_helper(src_cpu, fn, RUN_ON_CPU_HOST_INT(idxmap)); 438d9bb58e5SYang Zhong async_safe_run_on_cpu(src_cpu, fn, RUN_ON_CPU_HOST_INT(idxmap)); 439d9bb58e5SYang Zhong } 440d9bb58e5SYang Zhong 44164f2674bSRichard Henderson void tlb_flush_all_cpus_synced(CPUState *src_cpu) 44264f2674bSRichard Henderson { 44364f2674bSRichard Henderson tlb_flush_by_mmuidx_all_cpus_synced(src_cpu, ALL_MMUIDX_BITS); 44464f2674bSRichard Henderson } 44564f2674bSRichard Henderson 4463ab6e68cSRichard Henderson static bool tlb_hit_page_mask_anyprot(CPUTLBEntry *tlb_entry, 447732d5487SAnton Johansson vaddr page, vaddr mask) 4483ab6e68cSRichard Henderson { 4493ab6e68cSRichard Henderson page &= mask; 4503ab6e68cSRichard Henderson mask &= TARGET_PAGE_MASK | TLB_INVALID_MASK; 4513ab6e68cSRichard Henderson 4523ab6e68cSRichard Henderson return (page == (tlb_entry->addr_read & mask) || 4533ab6e68cSRichard Henderson page == (tlb_addr_write(tlb_entry) & mask) || 4543ab6e68cSRichard Henderson page == (tlb_entry->addr_code & mask)); 4553ab6e68cSRichard Henderson } 4563ab6e68cSRichard Henderson 457732d5487SAnton Johansson static inline bool tlb_hit_page_anyprot(CPUTLBEntry *tlb_entry, vaddr page) 458d9bb58e5SYang Zhong { 4593ab6e68cSRichard Henderson return tlb_hit_page_mask_anyprot(tlb_entry, page, -1); 46068fea038SRichard Henderson } 46168fea038SRichard Henderson 4623cea94bbSEmilio G. Cota /** 4633cea94bbSEmilio G. Cota * tlb_entry_is_empty - return true if the entry is not in use 4643cea94bbSEmilio G. Cota * @te: pointer to CPUTLBEntry 4653cea94bbSEmilio G. Cota */ 4663cea94bbSEmilio G. Cota static inline bool tlb_entry_is_empty(const CPUTLBEntry *te) 4673cea94bbSEmilio G. Cota { 4683cea94bbSEmilio G. Cota return te->addr_read == -1 && te->addr_write == -1 && te->addr_code == -1; 4693cea94bbSEmilio G. Cota } 4703cea94bbSEmilio G. Cota 47153d28455SRichard Henderson /* Called with tlb_c.lock held */ 4723ab6e68cSRichard Henderson static bool tlb_flush_entry_mask_locked(CPUTLBEntry *tlb_entry, 473732d5487SAnton Johansson vaddr page, 474732d5487SAnton Johansson vaddr mask) 47568fea038SRichard Henderson { 4763ab6e68cSRichard Henderson if (tlb_hit_page_mask_anyprot(tlb_entry, page, mask)) { 477d9bb58e5SYang Zhong memset(tlb_entry, -1, sizeof(*tlb_entry)); 47886e1eff8SEmilio G. Cota return true; 479d9bb58e5SYang Zhong } 48086e1eff8SEmilio G. Cota return false; 481d9bb58e5SYang Zhong } 482d9bb58e5SYang Zhong 483732d5487SAnton Johansson static inline bool tlb_flush_entry_locked(CPUTLBEntry *tlb_entry, vaddr page) 48468fea038SRichard Henderson { 4853ab6e68cSRichard Henderson return tlb_flush_entry_mask_locked(tlb_entry, page, -1); 4863ab6e68cSRichard Henderson } 4873ab6e68cSRichard Henderson 4883ab6e68cSRichard Henderson /* Called with tlb_c.lock held */ 48910b32e2cSAnton Johansson static void tlb_flush_vtlb_page_mask_locked(CPUState *cpu, int mmu_idx, 490732d5487SAnton Johansson vaddr page, 491732d5487SAnton Johansson vaddr mask) 4923ab6e68cSRichard Henderson { 49310b32e2cSAnton Johansson CPUTLBDesc *d = &cpu->neg.tlb.d[mmu_idx]; 49468fea038SRichard Henderson int k; 49571aec354SEmilio G. Cota 49610b32e2cSAnton Johansson assert_cpu_is_self(cpu); 49768fea038SRichard Henderson for (k = 0; k < CPU_VTLB_SIZE; k++) { 4983ab6e68cSRichard Henderson if (tlb_flush_entry_mask_locked(&d->vtable[k], page, mask)) { 49910b32e2cSAnton Johansson tlb_n_used_entries_dec(cpu, mmu_idx); 50086e1eff8SEmilio G. Cota } 50168fea038SRichard Henderson } 50268fea038SRichard Henderson } 50368fea038SRichard Henderson 50410b32e2cSAnton Johansson static inline void tlb_flush_vtlb_page_locked(CPUState *cpu, int mmu_idx, 505732d5487SAnton Johansson vaddr page) 5063ab6e68cSRichard Henderson { 50710b32e2cSAnton Johansson tlb_flush_vtlb_page_mask_locked(cpu, mmu_idx, page, -1); 5083ab6e68cSRichard Henderson } 5093ab6e68cSRichard Henderson 51010b32e2cSAnton Johansson static void tlb_flush_page_locked(CPUState *cpu, int midx, vaddr page) 5111308e026SRichard Henderson { 51210b32e2cSAnton Johansson vaddr lp_addr = cpu->neg.tlb.d[midx].large_page_addr; 51310b32e2cSAnton Johansson vaddr lp_mask = cpu->neg.tlb.d[midx].large_page_mask; 5141308e026SRichard Henderson 5151308e026SRichard Henderson /* Check if we need to flush due to large pages. */ 5161308e026SRichard Henderson if ((page & lp_mask) == lp_addr) { 5178c605cf1SAnton Johansson tlb_debug("forcing full flush midx %d (%016" 5188c605cf1SAnton Johansson VADDR_PRIx "/%016" VADDR_PRIx ")\n", 5191308e026SRichard Henderson midx, lp_addr, lp_mask); 52010b32e2cSAnton Johansson tlb_flush_one_mmuidx_locked(cpu, midx, get_clock_realtime()); 5211308e026SRichard Henderson } else { 52210b32e2cSAnton Johansson if (tlb_flush_entry_locked(tlb_entry(cpu, midx, page), page)) { 52310b32e2cSAnton Johansson tlb_n_used_entries_dec(cpu, midx); 52486e1eff8SEmilio G. Cota } 52510b32e2cSAnton Johansson tlb_flush_vtlb_page_locked(cpu, midx, page); 5261308e026SRichard Henderson } 5271308e026SRichard Henderson } 5281308e026SRichard Henderson 5297b7d00e0SRichard Henderson /** 5307b7d00e0SRichard Henderson * tlb_flush_page_by_mmuidx_async_0: 5317b7d00e0SRichard Henderson * @cpu: cpu on which to flush 5327b7d00e0SRichard Henderson * @addr: page of virtual address to flush 5337b7d00e0SRichard Henderson * @idxmap: set of mmu_idx to flush 5347b7d00e0SRichard Henderson * 5357b7d00e0SRichard Henderson * Helper for tlb_flush_page_by_mmuidx and friends, flush one page 5367b7d00e0SRichard Henderson * at @addr from the tlbs indicated by @idxmap from @cpu. 537d9bb58e5SYang Zhong */ 5387b7d00e0SRichard Henderson static void tlb_flush_page_by_mmuidx_async_0(CPUState *cpu, 539732d5487SAnton Johansson vaddr addr, 5407b7d00e0SRichard Henderson uint16_t idxmap) 541d9bb58e5SYang Zhong { 542d9bb58e5SYang Zhong int mmu_idx; 543d9bb58e5SYang Zhong 544d9bb58e5SYang Zhong assert_cpu_is_self(cpu); 545d9bb58e5SYang Zhong 5468c605cf1SAnton Johansson tlb_debug("page addr: %016" VADDR_PRIx " mmu_map:0x%x\n", addr, idxmap); 547d9bb58e5SYang Zhong 54810b32e2cSAnton Johansson qemu_spin_lock(&cpu->neg.tlb.c.lock); 549d9bb58e5SYang Zhong for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 5507b7d00e0SRichard Henderson if ((idxmap >> mmu_idx) & 1) { 55110b32e2cSAnton Johansson tlb_flush_page_locked(cpu, mmu_idx, addr); 552d9bb58e5SYang Zhong } 553d9bb58e5SYang Zhong } 55410b32e2cSAnton Johansson qemu_spin_unlock(&cpu->neg.tlb.c.lock); 555d9bb58e5SYang Zhong 5561d41a79bSRichard Henderson /* 5571d41a79bSRichard Henderson * Discard jump cache entries for any tb which might potentially 5581d41a79bSRichard Henderson * overlap the flushed page, which includes the previous. 5591d41a79bSRichard Henderson */ 5601d41a79bSRichard Henderson tb_jmp_cache_clear_page(cpu, addr - TARGET_PAGE_SIZE); 5611d41a79bSRichard Henderson tb_jmp_cache_clear_page(cpu, addr); 562d9bb58e5SYang Zhong } 563d9bb58e5SYang Zhong 5647b7d00e0SRichard Henderson /** 5657b7d00e0SRichard Henderson * tlb_flush_page_by_mmuidx_async_1: 5667b7d00e0SRichard Henderson * @cpu: cpu on which to flush 5677b7d00e0SRichard Henderson * @data: encoded addr + idxmap 5687b7d00e0SRichard Henderson * 5697b7d00e0SRichard Henderson * Helper for tlb_flush_page_by_mmuidx and friends, called through 5707b7d00e0SRichard Henderson * async_run_on_cpu. The idxmap parameter is encoded in the page 5717b7d00e0SRichard Henderson * offset of the target_ptr field. This limits the set of mmu_idx 5727b7d00e0SRichard Henderson * that can be passed via this method. 5737b7d00e0SRichard Henderson */ 5747b7d00e0SRichard Henderson static void tlb_flush_page_by_mmuidx_async_1(CPUState *cpu, 5757b7d00e0SRichard Henderson run_on_cpu_data data) 5767b7d00e0SRichard Henderson { 577732d5487SAnton Johansson vaddr addr_and_idxmap = data.target_ptr; 578732d5487SAnton Johansson vaddr addr = addr_and_idxmap & TARGET_PAGE_MASK; 5797b7d00e0SRichard Henderson uint16_t idxmap = addr_and_idxmap & ~TARGET_PAGE_MASK; 5807b7d00e0SRichard Henderson 5817b7d00e0SRichard Henderson tlb_flush_page_by_mmuidx_async_0(cpu, addr, idxmap); 5827b7d00e0SRichard Henderson } 5837b7d00e0SRichard Henderson 5847b7d00e0SRichard Henderson typedef struct { 585732d5487SAnton Johansson vaddr addr; 5867b7d00e0SRichard Henderson uint16_t idxmap; 5877b7d00e0SRichard Henderson } TLBFlushPageByMMUIdxData; 5887b7d00e0SRichard Henderson 5897b7d00e0SRichard Henderson /** 5907b7d00e0SRichard Henderson * tlb_flush_page_by_mmuidx_async_2: 5917b7d00e0SRichard Henderson * @cpu: cpu on which to flush 5927b7d00e0SRichard Henderson * @data: allocated addr + idxmap 5937b7d00e0SRichard Henderson * 5947b7d00e0SRichard Henderson * Helper for tlb_flush_page_by_mmuidx and friends, called through 5957b7d00e0SRichard Henderson * async_run_on_cpu. The addr+idxmap parameters are stored in a 5967b7d00e0SRichard Henderson * TLBFlushPageByMMUIdxData structure that has been allocated 5977b7d00e0SRichard Henderson * specifically for this helper. Free the structure when done. 5987b7d00e0SRichard Henderson */ 5997b7d00e0SRichard Henderson static void tlb_flush_page_by_mmuidx_async_2(CPUState *cpu, 6007b7d00e0SRichard Henderson run_on_cpu_data data) 6017b7d00e0SRichard Henderson { 6027b7d00e0SRichard Henderson TLBFlushPageByMMUIdxData *d = data.host_ptr; 6037b7d00e0SRichard Henderson 6047b7d00e0SRichard Henderson tlb_flush_page_by_mmuidx_async_0(cpu, d->addr, d->idxmap); 6057b7d00e0SRichard Henderson g_free(d); 6067b7d00e0SRichard Henderson } 6077b7d00e0SRichard Henderson 608732d5487SAnton Johansson void tlb_flush_page_by_mmuidx(CPUState *cpu, vaddr addr, uint16_t idxmap) 609d9bb58e5SYang Zhong { 6108c605cf1SAnton Johansson tlb_debug("addr: %016" VADDR_PRIx " mmu_idx:%" PRIx16 "\n", addr, idxmap); 611d9bb58e5SYang Zhong 61230933c4fSNicholas Piggin assert_cpu_is_self(cpu); 61330933c4fSNicholas Piggin 614d9bb58e5SYang Zhong /* This should already be page aligned */ 6157b7d00e0SRichard Henderson addr &= TARGET_PAGE_MASK; 616d9bb58e5SYang Zhong 6177b7d00e0SRichard Henderson tlb_flush_page_by_mmuidx_async_0(cpu, addr, idxmap); 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 625d9bb58e5SYang Zhong void tlb_flush_page_by_mmuidx_all_cpus_synced(CPUState *src_cpu, 626732d5487SAnton Johansson vaddr addr, 627d9bb58e5SYang Zhong uint16_t idxmap) 628d9bb58e5SYang Zhong { 6298c605cf1SAnton Johansson tlb_debug("addr: %016" VADDR_PRIx " mmu_idx:%"PRIx16"\n", addr, idxmap); 630d9bb58e5SYang Zhong 631d9bb58e5SYang Zhong /* This should already be page aligned */ 6327b7d00e0SRichard Henderson addr &= TARGET_PAGE_MASK; 633d9bb58e5SYang Zhong 6347b7d00e0SRichard Henderson /* 6357b7d00e0SRichard Henderson * Allocate memory to hold addr+idxmap only when needed. 6367b7d00e0SRichard Henderson * See tlb_flush_page_by_mmuidx for details. 6377b7d00e0SRichard Henderson */ 6387b7d00e0SRichard Henderson if (idxmap < TARGET_PAGE_SIZE) { 6397b7d00e0SRichard Henderson flush_all_helper(src_cpu, tlb_flush_page_by_mmuidx_async_1, 6407b7d00e0SRichard Henderson RUN_ON_CPU_TARGET_PTR(addr | idxmap)); 6417b7d00e0SRichard Henderson async_safe_run_on_cpu(src_cpu, tlb_flush_page_by_mmuidx_async_1, 6427b7d00e0SRichard Henderson RUN_ON_CPU_TARGET_PTR(addr | idxmap)); 6437b7d00e0SRichard Henderson } else { 6447b7d00e0SRichard Henderson CPUState *dst_cpu; 6457b7d00e0SRichard Henderson TLBFlushPageByMMUIdxData *d; 6467b7d00e0SRichard Henderson 6477b7d00e0SRichard Henderson /* Allocate a separate data block for each destination cpu. */ 6487b7d00e0SRichard Henderson CPU_FOREACH(dst_cpu) { 6497b7d00e0SRichard Henderson if (dst_cpu != src_cpu) { 6507b7d00e0SRichard Henderson d = g_new(TLBFlushPageByMMUIdxData, 1); 6517b7d00e0SRichard Henderson d->addr = addr; 6527b7d00e0SRichard Henderson d->idxmap = idxmap; 6537b7d00e0SRichard Henderson async_run_on_cpu(dst_cpu, tlb_flush_page_by_mmuidx_async_2, 6547b7d00e0SRichard Henderson RUN_ON_CPU_HOST_PTR(d)); 6557b7d00e0SRichard Henderson } 6567b7d00e0SRichard Henderson } 6577b7d00e0SRichard Henderson 6587b7d00e0SRichard Henderson d = g_new(TLBFlushPageByMMUIdxData, 1); 6597b7d00e0SRichard Henderson d->addr = addr; 6607b7d00e0SRichard Henderson d->idxmap = idxmap; 6617b7d00e0SRichard Henderson async_safe_run_on_cpu(src_cpu, tlb_flush_page_by_mmuidx_async_2, 6627b7d00e0SRichard Henderson RUN_ON_CPU_HOST_PTR(d)); 6637b7d00e0SRichard Henderson } 664d9bb58e5SYang Zhong } 665d9bb58e5SYang Zhong 666732d5487SAnton Johansson void tlb_flush_page_all_cpus_synced(CPUState *src, vaddr addr) 667d9bb58e5SYang Zhong { 668f8144c6cSRichard Henderson tlb_flush_page_by_mmuidx_all_cpus_synced(src, addr, ALL_MMUIDX_BITS); 669d9bb58e5SYang Zhong } 670d9bb58e5SYang Zhong 67110b32e2cSAnton Johansson static void tlb_flush_range_locked(CPUState *cpu, int midx, 672732d5487SAnton Johansson vaddr addr, vaddr len, 6733c4ddec1SRichard Henderson unsigned bits) 6743ab6e68cSRichard Henderson { 67510b32e2cSAnton Johansson CPUTLBDesc *d = &cpu->neg.tlb.d[midx]; 67610b32e2cSAnton Johansson CPUTLBDescFast *f = &cpu->neg.tlb.f[midx]; 677732d5487SAnton Johansson vaddr mask = MAKE_64BIT_MASK(0, bits); 6783ab6e68cSRichard Henderson 6793ab6e68cSRichard Henderson /* 6803ab6e68cSRichard Henderson * If @bits is smaller than the tlb size, there may be multiple entries 6813ab6e68cSRichard Henderson * within the TLB; otherwise all addresses that match under @mask hit 6823ab6e68cSRichard Henderson * the same TLB entry. 6833ab6e68cSRichard Henderson * TODO: Perhaps allow bits to be a few bits less than the size. 6843ab6e68cSRichard Henderson * For now, just flush the entire TLB. 6853c4ddec1SRichard Henderson * 6863c4ddec1SRichard Henderson * If @len is larger than the tlb size, then it will take longer to 6873c4ddec1SRichard Henderson * test all of the entries in the TLB than it will to flush it all. 6883ab6e68cSRichard Henderson */ 6893c4ddec1SRichard Henderson if (mask < f->mask || len > f->mask) { 6903ab6e68cSRichard Henderson tlb_debug("forcing full flush midx %d (" 6918c605cf1SAnton Johansson "%016" VADDR_PRIx "/%016" VADDR_PRIx "+%016" VADDR_PRIx ")\n", 6923c4ddec1SRichard Henderson midx, addr, mask, len); 69310b32e2cSAnton Johansson tlb_flush_one_mmuidx_locked(cpu, midx, get_clock_realtime()); 6943ab6e68cSRichard Henderson return; 6953ab6e68cSRichard Henderson } 6963ab6e68cSRichard Henderson 6973c4ddec1SRichard Henderson /* 6983c4ddec1SRichard Henderson * Check if we need to flush due to large pages. 6993c4ddec1SRichard Henderson * Because large_page_mask contains all 1's from the msb, 7003c4ddec1SRichard Henderson * we only need to test the end of the range. 7013c4ddec1SRichard Henderson */ 7023c4ddec1SRichard Henderson if (((addr + len - 1) & d->large_page_mask) == d->large_page_addr) { 7033ab6e68cSRichard Henderson tlb_debug("forcing full flush midx %d (" 7048c605cf1SAnton Johansson "%016" VADDR_PRIx "/%016" VADDR_PRIx ")\n", 7053ab6e68cSRichard Henderson midx, d->large_page_addr, d->large_page_mask); 70610b32e2cSAnton Johansson tlb_flush_one_mmuidx_locked(cpu, midx, get_clock_realtime()); 7073ab6e68cSRichard Henderson return; 7083ab6e68cSRichard Henderson } 7093ab6e68cSRichard Henderson 710732d5487SAnton Johansson for (vaddr i = 0; i < len; i += TARGET_PAGE_SIZE) { 711732d5487SAnton Johansson vaddr page = addr + i; 71210b32e2cSAnton Johansson CPUTLBEntry *entry = tlb_entry(cpu, midx, page); 7133c4ddec1SRichard Henderson 7143c4ddec1SRichard Henderson if (tlb_flush_entry_mask_locked(entry, page, mask)) { 71510b32e2cSAnton Johansson tlb_n_used_entries_dec(cpu, midx); 7163ab6e68cSRichard Henderson } 71710b32e2cSAnton Johansson tlb_flush_vtlb_page_mask_locked(cpu, midx, page, mask); 7183ab6e68cSRichard Henderson } 7193c4ddec1SRichard Henderson } 7203ab6e68cSRichard Henderson 7213ab6e68cSRichard Henderson typedef struct { 722732d5487SAnton Johansson vaddr addr; 723732d5487SAnton Johansson vaddr len; 7243ab6e68cSRichard Henderson uint16_t idxmap; 7253ab6e68cSRichard Henderson uint16_t bits; 7263960a59fSRichard Henderson } TLBFlushRangeData; 7273ab6e68cSRichard Henderson 7286be48e45SRichard Henderson static void tlb_flush_range_by_mmuidx_async_0(CPUState *cpu, 7293960a59fSRichard Henderson TLBFlushRangeData d) 7303ab6e68cSRichard Henderson { 7313ab6e68cSRichard Henderson int mmu_idx; 7323ab6e68cSRichard Henderson 7333ab6e68cSRichard Henderson assert_cpu_is_self(cpu); 7343ab6e68cSRichard Henderson 7358c605cf1SAnton Johansson tlb_debug("range: %016" VADDR_PRIx "/%u+%016" VADDR_PRIx " mmu_map:0x%x\n", 7363c4ddec1SRichard Henderson d.addr, d.bits, d.len, d.idxmap); 7373ab6e68cSRichard Henderson 73810b32e2cSAnton Johansson qemu_spin_lock(&cpu->neg.tlb.c.lock); 7393ab6e68cSRichard Henderson for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 7403ab6e68cSRichard Henderson if ((d.idxmap >> mmu_idx) & 1) { 74110b32e2cSAnton Johansson tlb_flush_range_locked(cpu, mmu_idx, d.addr, d.len, d.bits); 7423ab6e68cSRichard Henderson } 7433ab6e68cSRichard Henderson } 74410b32e2cSAnton Johansson qemu_spin_unlock(&cpu->neg.tlb.c.lock); 7453ab6e68cSRichard Henderson 746cfc2a2d6SIdan Horowitz /* 747cfc2a2d6SIdan Horowitz * If the length is larger than the jump cache size, then it will take 748cfc2a2d6SIdan Horowitz * longer to clear each entry individually than it will to clear it all. 749cfc2a2d6SIdan Horowitz */ 750cfc2a2d6SIdan Horowitz if (d.len >= (TARGET_PAGE_SIZE * TB_JMP_CACHE_SIZE)) { 751a976a99aSRichard Henderson tcg_flush_jmp_cache(cpu); 752cfc2a2d6SIdan Horowitz return; 753cfc2a2d6SIdan Horowitz } 754cfc2a2d6SIdan Horowitz 7551d41a79bSRichard Henderson /* 7561d41a79bSRichard Henderson * Discard jump cache entries for any tb which might potentially 7571d41a79bSRichard Henderson * overlap the flushed pages, which includes the previous. 7581d41a79bSRichard Henderson */ 7591d41a79bSRichard Henderson d.addr -= TARGET_PAGE_SIZE; 760732d5487SAnton Johansson for (vaddr i = 0, n = d.len / TARGET_PAGE_SIZE + 1; i < n; i++) { 7611d41a79bSRichard Henderson tb_jmp_cache_clear_page(cpu, d.addr); 7621d41a79bSRichard Henderson d.addr += TARGET_PAGE_SIZE; 7633c4ddec1SRichard Henderson } 7643ab6e68cSRichard Henderson } 7653ab6e68cSRichard Henderson 766206a583dSRichard Henderson static void tlb_flush_range_by_mmuidx_async_1(CPUState *cpu, 7673ab6e68cSRichard Henderson run_on_cpu_data data) 7683ab6e68cSRichard Henderson { 7693960a59fSRichard Henderson TLBFlushRangeData *d = data.host_ptr; 7706be48e45SRichard Henderson tlb_flush_range_by_mmuidx_async_0(cpu, *d); 7713ab6e68cSRichard Henderson g_free(d); 7723ab6e68cSRichard Henderson } 7733ab6e68cSRichard Henderson 774732d5487SAnton Johansson void tlb_flush_range_by_mmuidx(CPUState *cpu, vaddr addr, 775732d5487SAnton Johansson vaddr len, uint16_t idxmap, 776e5b1921bSRichard Henderson unsigned bits) 7773ab6e68cSRichard Henderson { 7783960a59fSRichard Henderson TLBFlushRangeData d; 7793ab6e68cSRichard Henderson 78030933c4fSNicholas Piggin assert_cpu_is_self(cpu); 78130933c4fSNicholas Piggin 782e5b1921bSRichard Henderson /* 783e5b1921bSRichard Henderson * If all bits are significant, and len is small, 784e5b1921bSRichard Henderson * this devolves to tlb_flush_page. 785e5b1921bSRichard Henderson */ 786e5b1921bSRichard Henderson if (bits >= TARGET_LONG_BITS && len <= TARGET_PAGE_SIZE) { 7873ab6e68cSRichard Henderson tlb_flush_page_by_mmuidx(cpu, addr, idxmap); 7883ab6e68cSRichard Henderson return; 7893ab6e68cSRichard Henderson } 7903ab6e68cSRichard Henderson /* If no page bits are significant, this devolves to tlb_flush. */ 7913ab6e68cSRichard Henderson if (bits < TARGET_PAGE_BITS) { 7923ab6e68cSRichard Henderson tlb_flush_by_mmuidx(cpu, idxmap); 7933ab6e68cSRichard Henderson return; 7943ab6e68cSRichard Henderson } 7953ab6e68cSRichard Henderson 7963ab6e68cSRichard Henderson /* This should already be page aligned */ 7973ab6e68cSRichard Henderson d.addr = addr & TARGET_PAGE_MASK; 798e5b1921bSRichard Henderson d.len = len; 7993ab6e68cSRichard Henderson d.idxmap = idxmap; 8003ab6e68cSRichard Henderson d.bits = bits; 8013ab6e68cSRichard Henderson 8026be48e45SRichard Henderson tlb_flush_range_by_mmuidx_async_0(cpu, d); 8033ab6e68cSRichard Henderson } 8043ab6e68cSRichard Henderson 805732d5487SAnton Johansson void tlb_flush_page_bits_by_mmuidx(CPUState *cpu, vaddr addr, 806e5b1921bSRichard Henderson uint16_t idxmap, unsigned bits) 807e5b1921bSRichard Henderson { 808e5b1921bSRichard Henderson tlb_flush_range_by_mmuidx(cpu, addr, TARGET_PAGE_SIZE, idxmap, bits); 809e5b1921bSRichard Henderson } 810e5b1921bSRichard Henderson 811c13b27d8SRichard Henderson void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *src_cpu, 812732d5487SAnton Johansson vaddr addr, 813732d5487SAnton Johansson vaddr len, 8143ab6e68cSRichard Henderson uint16_t idxmap, 8153ab6e68cSRichard Henderson unsigned bits) 8163ab6e68cSRichard Henderson { 817d34e4d1aSRichard Henderson TLBFlushRangeData d, *p; 818d34e4d1aSRichard Henderson CPUState *dst_cpu; 8193ab6e68cSRichard Henderson 820c13b27d8SRichard Henderson /* 821c13b27d8SRichard Henderson * If all bits are significant, and len is small, 822c13b27d8SRichard Henderson * this devolves to tlb_flush_page. 823c13b27d8SRichard Henderson */ 824c13b27d8SRichard Henderson if (bits >= TARGET_LONG_BITS && len <= TARGET_PAGE_SIZE) { 8253ab6e68cSRichard Henderson tlb_flush_page_by_mmuidx_all_cpus_synced(src_cpu, addr, idxmap); 8263ab6e68cSRichard Henderson return; 8273ab6e68cSRichard Henderson } 8283ab6e68cSRichard Henderson /* If no page bits are significant, this devolves to tlb_flush. */ 8293ab6e68cSRichard Henderson if (bits < TARGET_PAGE_BITS) { 8303ab6e68cSRichard Henderson tlb_flush_by_mmuidx_all_cpus_synced(src_cpu, idxmap); 8313ab6e68cSRichard Henderson return; 8323ab6e68cSRichard Henderson } 8333ab6e68cSRichard Henderson 8343ab6e68cSRichard Henderson /* This should already be page aligned */ 8353ab6e68cSRichard Henderson d.addr = addr & TARGET_PAGE_MASK; 836c13b27d8SRichard Henderson d.len = len; 8373ab6e68cSRichard Henderson d.idxmap = idxmap; 8383ab6e68cSRichard Henderson d.bits = bits; 8393ab6e68cSRichard Henderson 8403ab6e68cSRichard Henderson /* Allocate a separate data block for each destination cpu. */ 8413ab6e68cSRichard Henderson CPU_FOREACH(dst_cpu) { 8423ab6e68cSRichard Henderson if (dst_cpu != src_cpu) { 8436d244788SRichard Henderson p = g_memdup(&d, sizeof(d)); 844206a583dSRichard Henderson async_run_on_cpu(dst_cpu, tlb_flush_range_by_mmuidx_async_1, 8453ab6e68cSRichard Henderson RUN_ON_CPU_HOST_PTR(p)); 8463ab6e68cSRichard Henderson } 8473ab6e68cSRichard Henderson } 8483ab6e68cSRichard Henderson 8496d244788SRichard Henderson p = g_memdup(&d, sizeof(d)); 850206a583dSRichard Henderson async_safe_run_on_cpu(src_cpu, tlb_flush_range_by_mmuidx_async_1, 8513ab6e68cSRichard Henderson RUN_ON_CPU_HOST_PTR(p)); 8523ab6e68cSRichard Henderson } 8533ab6e68cSRichard Henderson 854c13b27d8SRichard Henderson void tlb_flush_page_bits_by_mmuidx_all_cpus_synced(CPUState *src_cpu, 855732d5487SAnton Johansson vaddr addr, 856c13b27d8SRichard Henderson uint16_t idxmap, 857c13b27d8SRichard Henderson unsigned bits) 858c13b27d8SRichard Henderson { 859c13b27d8SRichard Henderson tlb_flush_range_by_mmuidx_all_cpus_synced(src_cpu, addr, TARGET_PAGE_SIZE, 860c13b27d8SRichard Henderson idxmap, bits); 861c13b27d8SRichard Henderson } 862c13b27d8SRichard Henderson 863d9bb58e5SYang Zhong /* update the TLBs so that writes to code in the virtual page 'addr' 864d9bb58e5SYang Zhong can be detected */ 865d9bb58e5SYang Zhong void tlb_protect_code(ram_addr_t ram_addr) 866d9bb58e5SYang Zhong { 86793b99616SRichard Henderson cpu_physical_memory_test_and_clear_dirty(ram_addr & TARGET_PAGE_MASK, 86893b99616SRichard Henderson TARGET_PAGE_SIZE, 869d9bb58e5SYang Zhong DIRTY_MEMORY_CODE); 870d9bb58e5SYang Zhong } 871d9bb58e5SYang Zhong 872d9bb58e5SYang Zhong /* update the TLB so that writes in physical page 'phys_addr' are no longer 873d9bb58e5SYang Zhong tested for self modifying code */ 874d9bb58e5SYang Zhong void tlb_unprotect_code(ram_addr_t ram_addr) 875d9bb58e5SYang Zhong { 876d9bb58e5SYang Zhong cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_CODE); 877d9bb58e5SYang Zhong } 878d9bb58e5SYang Zhong 879d9bb58e5SYang Zhong 880d9bb58e5SYang Zhong /* 881d9bb58e5SYang Zhong * Dirty write flag handling 882d9bb58e5SYang Zhong * 883d9bb58e5SYang Zhong * When the TCG code writes to a location it looks up the address in 884d9bb58e5SYang Zhong * the TLB and uses that data to compute the final address. If any of 885d9bb58e5SYang Zhong * the lower bits of the address are set then the slow path is forced. 886d9bb58e5SYang Zhong * There are a number of reasons to do this but for normal RAM the 887d9bb58e5SYang Zhong * most usual is detecting writes to code regions which may invalidate 888d9bb58e5SYang Zhong * generated code. 889d9bb58e5SYang Zhong * 89071aec354SEmilio G. Cota * Other vCPUs might be reading their TLBs during guest execution, so we update 891d73415a3SStefan Hajnoczi * te->addr_write with qatomic_set. We don't need to worry about this for 89271aec354SEmilio G. Cota * oversized guests as MTTCG is disabled for them. 893d9bb58e5SYang Zhong * 89453d28455SRichard Henderson * Called with tlb_c.lock held. 895d9bb58e5SYang Zhong */ 89671aec354SEmilio G. Cota static void tlb_reset_dirty_range_locked(CPUTLBEntry *tlb_entry, 89771aec354SEmilio G. Cota uintptr_t start, uintptr_t length) 898d9bb58e5SYang Zhong { 899d9bb58e5SYang Zhong uintptr_t addr = tlb_entry->addr_write; 900d9bb58e5SYang Zhong 9017b0d792cSRichard Henderson if ((addr & (TLB_INVALID_MASK | TLB_MMIO | 9027b0d792cSRichard Henderson TLB_DISCARD_WRITE | TLB_NOTDIRTY)) == 0) { 903d9bb58e5SYang Zhong addr &= TARGET_PAGE_MASK; 904d9bb58e5SYang Zhong addr += tlb_entry->addend; 905d9bb58e5SYang Zhong if ((addr - start) < length) { 906238f4380SRichard Henderson #if TARGET_LONG_BITS == 32 907238f4380SRichard Henderson uint32_t *ptr_write = (uint32_t *)&tlb_entry->addr_write; 908238f4380SRichard Henderson ptr_write += HOST_BIG_ENDIAN; 909238f4380SRichard Henderson qatomic_set(ptr_write, *ptr_write | TLB_NOTDIRTY); 910238f4380SRichard Henderson #elif TCG_OVERSIZED_GUEST 91171aec354SEmilio G. Cota tlb_entry->addr_write |= TLB_NOTDIRTY; 912d9bb58e5SYang Zhong #else 913d73415a3SStefan Hajnoczi qatomic_set(&tlb_entry->addr_write, 91471aec354SEmilio G. Cota tlb_entry->addr_write | TLB_NOTDIRTY); 915d9bb58e5SYang Zhong #endif 916d9bb58e5SYang Zhong } 91771aec354SEmilio G. Cota } 91871aec354SEmilio G. Cota } 91971aec354SEmilio G. Cota 92071aec354SEmilio G. Cota /* 92153d28455SRichard Henderson * Called with tlb_c.lock held. 92271aec354SEmilio G. Cota * Called only from the vCPU context, i.e. the TLB's owner thread. 92371aec354SEmilio G. Cota */ 92471aec354SEmilio G. Cota static inline void copy_tlb_helper_locked(CPUTLBEntry *d, const CPUTLBEntry *s) 92571aec354SEmilio G. Cota { 92671aec354SEmilio G. Cota *d = *s; 92771aec354SEmilio G. Cota } 928d9bb58e5SYang Zhong 929d9bb58e5SYang Zhong /* This is a cross vCPU call (i.e. another vCPU resetting the flags of 93071aec354SEmilio G. Cota * the target vCPU). 93153d28455SRichard Henderson * We must take tlb_c.lock to avoid racing with another vCPU update. The only 93271aec354SEmilio G. Cota * thing actually updated is the target TLB entry ->addr_write flags. 933d9bb58e5SYang Zhong */ 934d9bb58e5SYang Zhong void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length) 935d9bb58e5SYang Zhong { 936d9bb58e5SYang Zhong int mmu_idx; 937d9bb58e5SYang Zhong 93810b32e2cSAnton Johansson qemu_spin_lock(&cpu->neg.tlb.c.lock); 939d9bb58e5SYang Zhong for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 940d9bb58e5SYang Zhong unsigned int i; 94110b32e2cSAnton Johansson unsigned int n = tlb_n_entries(&cpu->neg.tlb.f[mmu_idx]); 942d9bb58e5SYang Zhong 94386e1eff8SEmilio G. Cota for (i = 0; i < n; i++) { 94410b32e2cSAnton Johansson tlb_reset_dirty_range_locked(&cpu->neg.tlb.f[mmu_idx].table[i], 945a40ec84eSRichard Henderson start1, length); 946d9bb58e5SYang Zhong } 947d9bb58e5SYang Zhong 948d9bb58e5SYang Zhong for (i = 0; i < CPU_VTLB_SIZE; i++) { 94910b32e2cSAnton Johansson tlb_reset_dirty_range_locked(&cpu->neg.tlb.d[mmu_idx].vtable[i], 950a40ec84eSRichard Henderson start1, length); 951d9bb58e5SYang Zhong } 952d9bb58e5SYang Zhong } 95310b32e2cSAnton Johansson qemu_spin_unlock(&cpu->neg.tlb.c.lock); 954d9bb58e5SYang Zhong } 955d9bb58e5SYang Zhong 95653d28455SRichard Henderson /* Called with tlb_c.lock held */ 95771aec354SEmilio G. Cota static inline void tlb_set_dirty1_locked(CPUTLBEntry *tlb_entry, 958732d5487SAnton Johansson vaddr addr) 959d9bb58e5SYang Zhong { 960732d5487SAnton Johansson if (tlb_entry->addr_write == (addr | TLB_NOTDIRTY)) { 961732d5487SAnton Johansson tlb_entry->addr_write = addr; 962d9bb58e5SYang Zhong } 963d9bb58e5SYang Zhong } 964d9bb58e5SYang Zhong 965d9bb58e5SYang Zhong /* update the TLB corresponding to virtual page vaddr 966d9bb58e5SYang Zhong so that it is no longer dirty */ 96751579d40SPhilippe Mathieu-Daudé static void tlb_set_dirty(CPUState *cpu, vaddr addr) 968d9bb58e5SYang Zhong { 969d9bb58e5SYang Zhong int mmu_idx; 970d9bb58e5SYang Zhong 971d9bb58e5SYang Zhong assert_cpu_is_self(cpu); 972d9bb58e5SYang Zhong 973732d5487SAnton Johansson addr &= TARGET_PAGE_MASK; 97410b32e2cSAnton Johansson qemu_spin_lock(&cpu->neg.tlb.c.lock); 975d9bb58e5SYang Zhong for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 97610b32e2cSAnton Johansson tlb_set_dirty1_locked(tlb_entry(cpu, mmu_idx, addr), addr); 977d9bb58e5SYang Zhong } 978d9bb58e5SYang Zhong 979d9bb58e5SYang Zhong for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 980d9bb58e5SYang Zhong int k; 981d9bb58e5SYang Zhong for (k = 0; k < CPU_VTLB_SIZE; k++) { 98210b32e2cSAnton Johansson tlb_set_dirty1_locked(&cpu->neg.tlb.d[mmu_idx].vtable[k], addr); 983d9bb58e5SYang Zhong } 984d9bb58e5SYang Zhong } 98510b32e2cSAnton Johansson qemu_spin_unlock(&cpu->neg.tlb.c.lock); 986d9bb58e5SYang Zhong } 987d9bb58e5SYang Zhong 988d9bb58e5SYang Zhong /* Our TLB does not support large pages, so remember the area covered by 989d9bb58e5SYang Zhong large pages and trigger a full TLB flush if these are invalidated. */ 99010b32e2cSAnton Johansson static void tlb_add_large_page(CPUState *cpu, int mmu_idx, 991732d5487SAnton Johansson vaddr addr, uint64_t size) 992d9bb58e5SYang Zhong { 99310b32e2cSAnton Johansson vaddr lp_addr = cpu->neg.tlb.d[mmu_idx].large_page_addr; 994732d5487SAnton Johansson vaddr lp_mask = ~(size - 1); 995d9bb58e5SYang Zhong 996732d5487SAnton Johansson if (lp_addr == (vaddr)-1) { 9971308e026SRichard Henderson /* No previous large page. */ 998732d5487SAnton Johansson lp_addr = addr; 9991308e026SRichard Henderson } else { 1000d9bb58e5SYang Zhong /* Extend the existing region to include the new page. 10011308e026SRichard Henderson This is a compromise between unnecessary flushes and 10021308e026SRichard Henderson the cost of maintaining a full variable size TLB. */ 100310b32e2cSAnton Johansson lp_mask &= cpu->neg.tlb.d[mmu_idx].large_page_mask; 1004732d5487SAnton Johansson while (((lp_addr ^ addr) & lp_mask) != 0) { 10051308e026SRichard Henderson lp_mask <<= 1; 1006d9bb58e5SYang Zhong } 10071308e026SRichard Henderson } 100810b32e2cSAnton Johansson cpu->neg.tlb.d[mmu_idx].large_page_addr = lp_addr & lp_mask; 100910b32e2cSAnton Johansson cpu->neg.tlb.d[mmu_idx].large_page_mask = lp_mask; 1010d9bb58e5SYang Zhong } 1011d9bb58e5SYang Zhong 101258e8f1f6SRichard Henderson static inline void tlb_set_compare(CPUTLBEntryFull *full, CPUTLBEntry *ent, 1013d712b116SAnton Johansson vaddr address, int flags, 101458e8f1f6SRichard Henderson MMUAccessType access_type, bool enable) 101558e8f1f6SRichard Henderson { 101658e8f1f6SRichard Henderson if (enable) { 101758e8f1f6SRichard Henderson address |= flags & TLB_FLAGS_MASK; 101858e8f1f6SRichard Henderson flags &= TLB_SLOW_FLAGS_MASK; 101958e8f1f6SRichard Henderson if (flags) { 102058e8f1f6SRichard Henderson address |= TLB_FORCE_SLOW; 102158e8f1f6SRichard Henderson } 102258e8f1f6SRichard Henderson } else { 102358e8f1f6SRichard Henderson address = -1; 102458e8f1f6SRichard Henderson flags = 0; 102558e8f1f6SRichard Henderson } 102658e8f1f6SRichard Henderson ent->addr_idx[access_type] = address; 102758e8f1f6SRichard Henderson full->slow_flags[access_type] = flags; 102858e8f1f6SRichard Henderson } 102958e8f1f6SRichard Henderson 103040473689SRichard Henderson /* 103140473689SRichard Henderson * Add a new TLB entry. At most one entry for a given virtual address 1032d9bb58e5SYang Zhong * is permitted. Only a single TARGET_PAGE_SIZE region is mapped, the 1033d9bb58e5SYang Zhong * supplied size is only used by tlb_flush_page. 1034d9bb58e5SYang Zhong * 1035d9bb58e5SYang Zhong * Called from TCG-generated code, which is under an RCU read-side 1036d9bb58e5SYang Zhong * critical section. 1037d9bb58e5SYang Zhong */ 103840473689SRichard Henderson void tlb_set_page_full(CPUState *cpu, int mmu_idx, 1039732d5487SAnton Johansson vaddr addr, CPUTLBEntryFull *full) 1040d9bb58e5SYang Zhong { 104110b32e2cSAnton Johansson CPUTLB *tlb = &cpu->neg.tlb; 1042a40ec84eSRichard Henderson CPUTLBDesc *desc = &tlb->d[mmu_idx]; 1043d9bb58e5SYang Zhong MemoryRegionSection *section; 104458e8f1f6SRichard Henderson unsigned int index, read_flags, write_flags; 1045d9bb58e5SYang Zhong uintptr_t addend; 104668fea038SRichard Henderson CPUTLBEntry *te, tn; 104755df6fcfSPeter Maydell hwaddr iotlb, xlat, sz, paddr_page; 1048732d5487SAnton Johansson vaddr addr_page; 104940473689SRichard Henderson int asidx, wp_flags, prot; 10508f5db641SRichard Henderson bool is_ram, is_romd; 1051d9bb58e5SYang Zhong 1052d9bb58e5SYang Zhong assert_cpu_is_self(cpu); 105355df6fcfSPeter Maydell 105440473689SRichard Henderson if (full->lg_page_size <= TARGET_PAGE_BITS) { 105555df6fcfSPeter Maydell sz = TARGET_PAGE_SIZE; 105655df6fcfSPeter Maydell } else { 105740473689SRichard Henderson sz = (hwaddr)1 << full->lg_page_size; 105810b32e2cSAnton Johansson tlb_add_large_page(cpu, mmu_idx, addr, sz); 105955df6fcfSPeter Maydell } 1060732d5487SAnton Johansson addr_page = addr & TARGET_PAGE_MASK; 106140473689SRichard Henderson paddr_page = full->phys_addr & TARGET_PAGE_MASK; 106255df6fcfSPeter Maydell 106340473689SRichard Henderson prot = full->prot; 106440473689SRichard Henderson asidx = cpu_asidx_from_attrs(cpu, full->attrs); 106555df6fcfSPeter Maydell section = address_space_translate_for_iotlb(cpu, asidx, paddr_page, 106640473689SRichard Henderson &xlat, &sz, full->attrs, &prot); 1067d9bb58e5SYang Zhong assert(sz >= TARGET_PAGE_SIZE); 1068d9bb58e5SYang Zhong 10698c605cf1SAnton Johansson tlb_debug("vaddr=%016" VADDR_PRIx " paddr=0x" HWADDR_FMT_plx 1070d9bb58e5SYang Zhong " prot=%x idx=%d\n", 1071732d5487SAnton Johansson addr, full->phys_addr, prot, mmu_idx); 1072d9bb58e5SYang Zhong 1073a0ff4a87SRichard Henderson read_flags = full->tlb_fill_flags; 107440473689SRichard Henderson if (full->lg_page_size < TARGET_PAGE_BITS) { 107530d7e098SRichard Henderson /* Repeat the MMU check and TLB fill on every access. */ 107658e8f1f6SRichard Henderson read_flags |= TLB_INVALID_MASK; 107755df6fcfSPeter Maydell } 10788f5db641SRichard Henderson 10798f5db641SRichard Henderson is_ram = memory_region_is_ram(section->mr); 10808f5db641SRichard Henderson is_romd = memory_region_is_romd(section->mr); 10818f5db641SRichard Henderson 10828f5db641SRichard Henderson if (is_ram || is_romd) { 10838f5db641SRichard Henderson /* RAM and ROMD both have associated host memory. */ 1084d9bb58e5SYang Zhong addend = (uintptr_t)memory_region_get_ram_ptr(section->mr) + xlat; 10858f5db641SRichard Henderson } else { 10868f5db641SRichard Henderson /* I/O does not; force the host address to NULL. */ 10878f5db641SRichard Henderson addend = 0; 1088d9bb58e5SYang Zhong } 1089d9bb58e5SYang Zhong 109058e8f1f6SRichard Henderson write_flags = read_flags; 10918f5db641SRichard Henderson if (is_ram) { 10928f5db641SRichard Henderson iotlb = memory_region_get_ram_addr(section->mr) + xlat; 1093dff1ab68SLIU Zhiwei assert(!(iotlb & ~TARGET_PAGE_MASK)); 10948f5db641SRichard Henderson /* 10958f5db641SRichard Henderson * Computing is_clean is expensive; avoid all that unless 10968f5db641SRichard Henderson * the page is actually writable. 10978f5db641SRichard Henderson */ 10988f5db641SRichard Henderson if (prot & PAGE_WRITE) { 10998f5db641SRichard Henderson if (section->readonly) { 110058e8f1f6SRichard Henderson write_flags |= TLB_DISCARD_WRITE; 11018f5db641SRichard Henderson } else if (cpu_physical_memory_is_clean(iotlb)) { 110258e8f1f6SRichard Henderson write_flags |= TLB_NOTDIRTY; 11038f5db641SRichard Henderson } 11048f5db641SRichard Henderson } 11058f5db641SRichard Henderson } else { 11068f5db641SRichard Henderson /* I/O or ROMD */ 11078f5db641SRichard Henderson iotlb = memory_region_section_get_iotlb(cpu, section) + xlat; 11088f5db641SRichard Henderson /* 11098f5db641SRichard Henderson * Writes to romd devices must go through MMIO to enable write. 11108f5db641SRichard Henderson * Reads to romd devices go through the ram_ptr found above, 11118f5db641SRichard Henderson * but of course reads to I/O must go through MMIO. 11128f5db641SRichard Henderson */ 111358e8f1f6SRichard Henderson write_flags |= TLB_MMIO; 11148f5db641SRichard Henderson if (!is_romd) { 111558e8f1f6SRichard Henderson read_flags = write_flags; 11168f5db641SRichard Henderson } 11178f5db641SRichard Henderson } 11188f5db641SRichard Henderson 1119732d5487SAnton Johansson wp_flags = cpu_watchpoint_address_matches(cpu, addr_page, 112050b107c5SRichard Henderson TARGET_PAGE_SIZE); 1121d9bb58e5SYang Zhong 112210b32e2cSAnton Johansson index = tlb_index(cpu, mmu_idx, addr_page); 112310b32e2cSAnton Johansson te = tlb_entry(cpu, mmu_idx, addr_page); 1124d9bb58e5SYang Zhong 112568fea038SRichard Henderson /* 112671aec354SEmilio G. Cota * Hold the TLB lock for the rest of the function. We could acquire/release 112771aec354SEmilio G. Cota * the lock several times in the function, but it is faster to amortize the 112871aec354SEmilio G. Cota * acquisition cost by acquiring it just once. Note that this leads to 112971aec354SEmilio G. Cota * a longer critical section, but this is not a concern since the TLB lock 113071aec354SEmilio G. Cota * is unlikely to be contended. 113171aec354SEmilio G. Cota */ 1132a40ec84eSRichard Henderson qemu_spin_lock(&tlb->c.lock); 113371aec354SEmilio G. Cota 11343d1523ceSRichard Henderson /* Note that the tlb is no longer clean. */ 1135a40ec84eSRichard Henderson tlb->c.dirty |= 1 << mmu_idx; 11363d1523ceSRichard Henderson 113771aec354SEmilio G. Cota /* Make sure there's no cached translation for the new page. */ 113810b32e2cSAnton Johansson tlb_flush_vtlb_page_locked(cpu, mmu_idx, addr_page); 113971aec354SEmilio G. Cota 114071aec354SEmilio G. Cota /* 114168fea038SRichard Henderson * Only evict the old entry to the victim tlb if it's for a 114268fea038SRichard Henderson * different page; otherwise just overwrite the stale data. 114368fea038SRichard Henderson */ 1144732d5487SAnton Johansson if (!tlb_hit_page_anyprot(te, addr_page) && !tlb_entry_is_empty(te)) { 1145a40ec84eSRichard Henderson unsigned vidx = desc->vindex++ % CPU_VTLB_SIZE; 1146a40ec84eSRichard Henderson CPUTLBEntry *tv = &desc->vtable[vidx]; 114768fea038SRichard Henderson 114868fea038SRichard Henderson /* Evict the old entry into the victim tlb. */ 114971aec354SEmilio G. Cota copy_tlb_helper_locked(tv, te); 115025d3ec58SRichard Henderson desc->vfulltlb[vidx] = desc->fulltlb[index]; 115110b32e2cSAnton Johansson tlb_n_used_entries_dec(cpu, mmu_idx); 115268fea038SRichard Henderson } 1153d9bb58e5SYang Zhong 1154d9bb58e5SYang Zhong /* refill the tlb */ 1155ace41090SPeter Maydell /* 1156dff1ab68SLIU Zhiwei * When memory region is ram, iotlb contains a TARGET_PAGE_BITS 1157dff1ab68SLIU Zhiwei * aligned ram_addr_t of the page base of the target RAM. 1158dff1ab68SLIU Zhiwei * Otherwise, iotlb contains 1159dff1ab68SLIU Zhiwei * - a physical section number in the lower TARGET_PAGE_BITS 1160dff1ab68SLIU Zhiwei * - the offset within section->mr of the page base (I/O, ROMD) with the 1161dff1ab68SLIU Zhiwei * TARGET_PAGE_BITS masked off. 116258e8f1f6SRichard Henderson * We subtract addr_page (which is page aligned and thus won't 1163ace41090SPeter Maydell * disturb the low bits) to give an offset which can be added to the 1164ace41090SPeter Maydell * (non-page-aligned) vaddr of the eventual memory access to get 1165ace41090SPeter Maydell * the MemoryRegion offset for the access. Note that the vaddr we 1166ace41090SPeter Maydell * subtract here is that of the page base, and not the same as the 1167fb3cb376SRichard Henderson * vaddr we add back in io_prepare()/get_page_addr_code(). 1168ace41090SPeter Maydell */ 116940473689SRichard Henderson desc->fulltlb[index] = *full; 117058e8f1f6SRichard Henderson full = &desc->fulltlb[index]; 117158e8f1f6SRichard Henderson full->xlat_section = iotlb - addr_page; 117258e8f1f6SRichard Henderson full->phys_addr = paddr_page; 1173d9bb58e5SYang Zhong 1174d9bb58e5SYang Zhong /* Now calculate the new entry */ 1175732d5487SAnton Johansson tn.addend = addend - addr_page; 117658e8f1f6SRichard Henderson 117758e8f1f6SRichard Henderson tlb_set_compare(full, &tn, addr_page, read_flags, 117858e8f1f6SRichard Henderson MMU_INST_FETCH, prot & PAGE_EXEC); 117958e8f1f6SRichard Henderson 118050b107c5SRichard Henderson if (wp_flags & BP_MEM_READ) { 118158e8f1f6SRichard Henderson read_flags |= TLB_WATCHPOINT; 118250b107c5SRichard Henderson } 118358e8f1f6SRichard Henderson tlb_set_compare(full, &tn, addr_page, read_flags, 118458e8f1f6SRichard Henderson MMU_DATA_LOAD, prot & PAGE_READ); 1185d9bb58e5SYang Zhong 1186f52bfb12SDavid Hildenbrand if (prot & PAGE_WRITE_INV) { 118758e8f1f6SRichard Henderson write_flags |= TLB_INVALID_MASK; 1188f52bfb12SDavid Hildenbrand } 118950b107c5SRichard Henderson if (wp_flags & BP_MEM_WRITE) { 119058e8f1f6SRichard Henderson write_flags |= TLB_WATCHPOINT; 119150b107c5SRichard Henderson } 119258e8f1f6SRichard Henderson tlb_set_compare(full, &tn, addr_page, write_flags, 119358e8f1f6SRichard Henderson MMU_DATA_STORE, prot & PAGE_WRITE); 1194d9bb58e5SYang Zhong 119571aec354SEmilio G. Cota copy_tlb_helper_locked(te, &tn); 119610b32e2cSAnton Johansson tlb_n_used_entries_inc(cpu, mmu_idx); 1197a40ec84eSRichard Henderson qemu_spin_unlock(&tlb->c.lock); 1198d9bb58e5SYang Zhong } 1199d9bb58e5SYang Zhong 1200732d5487SAnton Johansson void tlb_set_page_with_attrs(CPUState *cpu, vaddr addr, 120140473689SRichard Henderson hwaddr paddr, MemTxAttrs attrs, int prot, 1202732d5487SAnton Johansson int mmu_idx, uint64_t size) 120340473689SRichard Henderson { 120440473689SRichard Henderson CPUTLBEntryFull full = { 120540473689SRichard Henderson .phys_addr = paddr, 120640473689SRichard Henderson .attrs = attrs, 120740473689SRichard Henderson .prot = prot, 120840473689SRichard Henderson .lg_page_size = ctz64(size) 120940473689SRichard Henderson }; 121040473689SRichard Henderson 121140473689SRichard Henderson assert(is_power_of_2(size)); 1212732d5487SAnton Johansson tlb_set_page_full(cpu, mmu_idx, addr, &full); 121340473689SRichard Henderson } 121440473689SRichard Henderson 1215732d5487SAnton Johansson void tlb_set_page(CPUState *cpu, vaddr addr, 1216d9bb58e5SYang Zhong hwaddr paddr, int prot, 1217732d5487SAnton Johansson int mmu_idx, uint64_t size) 1218d9bb58e5SYang Zhong { 1219732d5487SAnton Johansson tlb_set_page_with_attrs(cpu, addr, paddr, MEMTXATTRS_UNSPECIFIED, 1220d9bb58e5SYang Zhong prot, mmu_idx, size); 1221d9bb58e5SYang Zhong } 1222d9bb58e5SYang Zhong 1223c319dc13SRichard Henderson /* 1224*f168808dSRichard Henderson * Note: tlb_fill_align() can trigger a resize of the TLB. 1225*f168808dSRichard Henderson * This means that all of the caller's prior references to the TLB table 1226*f168808dSRichard Henderson * (e.g. CPUTLBEntry pointers) must be discarded and looked up again 1227*f168808dSRichard Henderson * (e.g. via tlb_entry()). 1228c319dc13SRichard Henderson */ 1229*f168808dSRichard Henderson static bool tlb_fill_align(CPUState *cpu, vaddr addr, MMUAccessType type, 1230*f168808dSRichard Henderson int mmu_idx, MemOp memop, int size, 1231*f168808dSRichard Henderson bool probe, uintptr_t ra) 1232c319dc13SRichard Henderson { 1233*f168808dSRichard Henderson const TCGCPUOps *ops = cpu->cc->tcg_ops; 1234*f168808dSRichard Henderson CPUTLBEntryFull full; 1235c319dc13SRichard Henderson 1236*f168808dSRichard Henderson if (ops->tlb_fill_align) { 1237*f168808dSRichard Henderson if (ops->tlb_fill_align(cpu, &full, addr, type, mmu_idx, 1238*f168808dSRichard Henderson memop, size, probe, ra)) { 1239*f168808dSRichard Henderson tlb_set_page_full(cpu, mmu_idx, addr, &full); 1240*f168808dSRichard Henderson return true; 1241*f168808dSRichard Henderson } 1242*f168808dSRichard Henderson } else { 1243*f168808dSRichard Henderson /* Legacy behaviour is alignment before paging. */ 1244*f168808dSRichard Henderson if (addr & ((1u << memop_alignment_bits(memop)) - 1)) { 1245*f168808dSRichard Henderson ops->do_unaligned_access(cpu, addr, type, mmu_idx, ra); 1246*f168808dSRichard Henderson } 1247*f168808dSRichard Henderson if (ops->tlb_fill(cpu, addr, size, type, mmu_idx, probe, ra)) { 1248*f168808dSRichard Henderson return true; 1249*f168808dSRichard Henderson } 1250*f168808dSRichard Henderson } 1251*f168808dSRichard Henderson assert(probe); 1252*f168808dSRichard Henderson return false; 1253c319dc13SRichard Henderson } 1254c319dc13SRichard Henderson 125578271684SClaudio Fontana static inline void cpu_unaligned_access(CPUState *cpu, vaddr addr, 125678271684SClaudio Fontana MMUAccessType access_type, 125778271684SClaudio Fontana int mmu_idx, uintptr_t retaddr) 125878271684SClaudio Fontana { 12598810ee2aSAlex Bennée cpu->cc->tcg_ops->do_unaligned_access(cpu, addr, access_type, 12608810ee2aSAlex Bennée mmu_idx, retaddr); 126178271684SClaudio Fontana } 126278271684SClaudio Fontana 1263fb3cb376SRichard Henderson static MemoryRegionSection * 1264d50ef446SAnton Johansson io_prepare(hwaddr *out_offset, CPUState *cpu, hwaddr xlat, 1265fb3cb376SRichard Henderson MemTxAttrs attrs, vaddr addr, uintptr_t retaddr) 1266d9bb58e5SYang Zhong { 12672d54f194SPeter Maydell MemoryRegionSection *section; 1268fb3cb376SRichard Henderson hwaddr mr_offset; 1269d9bb58e5SYang Zhong 1270fb3cb376SRichard Henderson section = iotlb_to_section(cpu, xlat, attrs); 1271fb3cb376SRichard Henderson mr_offset = (xlat & TARGET_PAGE_MASK) + addr; 1272d9bb58e5SYang Zhong cpu->mem_io_pc = retaddr; 1273464dacf6SRichard Henderson if (!cpu->neg.can_do_io) { 1274d9bb58e5SYang Zhong cpu_io_recompile(cpu, retaddr); 1275d9bb58e5SYang Zhong } 1276d9bb58e5SYang Zhong 1277fb3cb376SRichard Henderson *out_offset = mr_offset; 1278fb3cb376SRichard Henderson return section; 1279fb3cb376SRichard Henderson } 1280fb3cb376SRichard Henderson 1281d50ef446SAnton Johansson static void io_failed(CPUState *cpu, CPUTLBEntryFull *full, vaddr addr, 1282fb3cb376SRichard Henderson unsigned size, MMUAccessType access_type, int mmu_idx, 12830e114440SRichard Henderson MemTxResult response, uintptr_t retaddr) 1284fb3cb376SRichard Henderson { 1285d50ef446SAnton Johansson if (!cpu->ignore_memory_transaction_failures 1286d50ef446SAnton Johansson && cpu->cc->tcg_ops->do_transaction_failed) { 12870e114440SRichard Henderson hwaddr physaddr = full->phys_addr | (addr & ~TARGET_PAGE_MASK); 1288bef0c216SRichard Henderson 1289d50ef446SAnton Johansson cpu->cc->tcg_ops->do_transaction_failed(cpu, physaddr, addr, size, 1290bef0c216SRichard Henderson access_type, mmu_idx, 1291bef0c216SRichard Henderson full->attrs, response, retaddr); 1292bef0c216SRichard Henderson } 1293bef0c216SRichard Henderson } 1294fb3cb376SRichard Henderson 1295d9bb58e5SYang Zhong /* Return true if ADDR is present in the victim tlb, and has been copied 1296d9bb58e5SYang Zhong back to the main tlb. */ 129710b32e2cSAnton Johansson static bool victim_tlb_hit(CPUState *cpu, size_t mmu_idx, size_t index, 1298732d5487SAnton Johansson MMUAccessType access_type, vaddr page) 1299d9bb58e5SYang Zhong { 1300d9bb58e5SYang Zhong size_t vidx; 130171aec354SEmilio G. Cota 130210b32e2cSAnton Johansson assert_cpu_is_self(cpu); 1303d9bb58e5SYang Zhong for (vidx = 0; vidx < CPU_VTLB_SIZE; ++vidx) { 130410b32e2cSAnton Johansson CPUTLBEntry *vtlb = &cpu->neg.tlb.d[mmu_idx].vtable[vidx]; 13059e39de98SAnton Johansson uint64_t cmp = tlb_read_idx(vtlb, access_type); 1306d9bb58e5SYang Zhong 1307d9bb58e5SYang Zhong if (cmp == page) { 1308d9bb58e5SYang Zhong /* Found entry in victim tlb, swap tlb and iotlb. */ 130910b32e2cSAnton Johansson CPUTLBEntry tmptlb, *tlb = &cpu->neg.tlb.f[mmu_idx].table[index]; 1310d9bb58e5SYang Zhong 131110b32e2cSAnton Johansson qemu_spin_lock(&cpu->neg.tlb.c.lock); 131271aec354SEmilio G. Cota copy_tlb_helper_locked(&tmptlb, tlb); 131371aec354SEmilio G. Cota copy_tlb_helper_locked(tlb, vtlb); 131471aec354SEmilio G. Cota copy_tlb_helper_locked(vtlb, &tmptlb); 131510b32e2cSAnton Johansson qemu_spin_unlock(&cpu->neg.tlb.c.lock); 1316d9bb58e5SYang Zhong 131710b32e2cSAnton Johansson CPUTLBEntryFull *f1 = &cpu->neg.tlb.d[mmu_idx].fulltlb[index]; 131810b32e2cSAnton Johansson CPUTLBEntryFull *f2 = &cpu->neg.tlb.d[mmu_idx].vfulltlb[vidx]; 131925d3ec58SRichard Henderson CPUTLBEntryFull tmpf; 132025d3ec58SRichard Henderson tmpf = *f1; *f1 = *f2; *f2 = tmpf; 1321d9bb58e5SYang Zhong return true; 1322d9bb58e5SYang Zhong } 1323d9bb58e5SYang Zhong } 1324d9bb58e5SYang Zhong return false; 1325d9bb58e5SYang Zhong } 1326d9bb58e5SYang Zhong 1327707526adSRichard Henderson static void notdirty_write(CPUState *cpu, vaddr mem_vaddr, unsigned size, 132825d3ec58SRichard Henderson CPUTLBEntryFull *full, uintptr_t retaddr) 1329707526adSRichard Henderson { 133025d3ec58SRichard Henderson ram_addr_t ram_addr = mem_vaddr + full->xlat_section; 1331707526adSRichard Henderson 1332707526adSRichard Henderson trace_memory_notdirty_write_access(mem_vaddr, ram_addr, size); 1333707526adSRichard Henderson 1334707526adSRichard Henderson if (!cpu_physical_memory_get_dirty_flag(ram_addr, DIRTY_MEMORY_CODE)) { 1335f349e92eSPhilippe Mathieu-Daudé tb_invalidate_phys_range_fast(ram_addr, size, retaddr); 1336707526adSRichard Henderson } 1337707526adSRichard Henderson 1338707526adSRichard Henderson /* 1339707526adSRichard Henderson * Set both VGA and migration bits for simplicity and to remove 1340707526adSRichard Henderson * the notdirty callback faster. 1341707526adSRichard Henderson */ 1342707526adSRichard Henderson cpu_physical_memory_set_dirty_range(ram_addr, size, DIRTY_CLIENTS_NOCODE); 1343707526adSRichard Henderson 1344707526adSRichard Henderson /* We remove the notdirty callback only if the code has been flushed. */ 1345707526adSRichard Henderson if (!cpu_physical_memory_is_clean(ram_addr)) { 1346707526adSRichard Henderson trace_memory_notdirty_set_dirty(mem_vaddr); 1347707526adSRichard Henderson tlb_set_dirty(cpu, mem_vaddr); 1348707526adSRichard Henderson } 1349707526adSRichard Henderson } 1350707526adSRichard Henderson 13515afec1c6SAnton Johansson static int probe_access_internal(CPUState *cpu, vaddr addr, 1352069cfe77SRichard Henderson int fault_size, MMUAccessType access_type, 1353069cfe77SRichard Henderson int mmu_idx, bool nonfault, 1354af803a4fSRichard Henderson void **phost, CPUTLBEntryFull **pfull, 13556d03226bSAlex Bennée uintptr_t retaddr, bool check_mem_cbs) 1356d9bb58e5SYang Zhong { 13575afec1c6SAnton Johansson uintptr_t index = tlb_index(cpu, mmu_idx, addr); 13585afec1c6SAnton Johansson CPUTLBEntry *entry = tlb_entry(cpu, mmu_idx, addr); 13599e39de98SAnton Johansson uint64_t tlb_addr = tlb_read_idx(entry, access_type); 13604f8f4127SAnton Johansson vaddr page_addr = addr & TARGET_PAGE_MASK; 136158e8f1f6SRichard Henderson int flags = TLB_FLAGS_MASK & ~TLB_FORCE_SLOW; 13625afec1c6SAnton Johansson bool force_mmio = check_mem_cbs && cpu_plugin_mem_cbs_enabled(cpu); 136358e8f1f6SRichard Henderson CPUTLBEntryFull *full; 1364ca86cf32SDavid Hildenbrand 1365069cfe77SRichard Henderson if (!tlb_hit_page(tlb_addr, page_addr)) { 13665afec1c6SAnton Johansson if (!victim_tlb_hit(cpu, mmu_idx, index, access_type, page_addr)) { 1367*f168808dSRichard Henderson if (!tlb_fill_align(cpu, addr, access_type, mmu_idx, 1368*f168808dSRichard Henderson 0, fault_size, nonfault, retaddr)) { 1369069cfe77SRichard Henderson /* Non-faulting page table read failed. */ 1370069cfe77SRichard Henderson *phost = NULL; 1371af803a4fSRichard Henderson *pfull = NULL; 1372069cfe77SRichard Henderson return TLB_INVALID_MASK; 1373069cfe77SRichard Henderson } 1374069cfe77SRichard Henderson 1375*f168808dSRichard Henderson /* TLB resize via tlb_fill_align may have moved the entry. */ 13765afec1c6SAnton Johansson index = tlb_index(cpu, mmu_idx, addr); 13775afec1c6SAnton Johansson entry = tlb_entry(cpu, mmu_idx, addr); 1378c3c8bf57SRichard Henderson 1379c3c8bf57SRichard Henderson /* 1380c3c8bf57SRichard Henderson * With PAGE_WRITE_INV, we set TLB_INVALID_MASK immediately, 1381*f168808dSRichard Henderson * to force the next access through tlb_fill_align. We've just 1382*f168808dSRichard Henderson * called tlb_fill_align, so we know that this entry *is* valid. 1383c3c8bf57SRichard Henderson */ 1384c3c8bf57SRichard Henderson flags &= ~TLB_INVALID_MASK; 1385d9bb58e5SYang Zhong } 13860b3c75adSRichard Henderson tlb_addr = tlb_read_idx(entry, access_type); 138703a98189SDavid Hildenbrand } 1388c3c8bf57SRichard Henderson flags &= tlb_addr; 138903a98189SDavid Hildenbrand 13905afec1c6SAnton Johansson *pfull = full = &cpu->neg.tlb.d[mmu_idx].fulltlb[index]; 139158e8f1f6SRichard Henderson flags |= full->slow_flags[access_type]; 1392af803a4fSRichard Henderson 1393069cfe77SRichard Henderson /* Fold all "mmio-like" bits into TLB_MMIO. This is not RAM. */ 139449fa457cSRichard Henderson if (unlikely(flags & ~(TLB_WATCHPOINT | TLB_NOTDIRTY | TLB_CHECK_ALIGNED)) 139549fa457cSRichard Henderson || (access_type != MMU_INST_FETCH && force_mmio)) { 1396069cfe77SRichard Henderson *phost = NULL; 1397069cfe77SRichard Henderson return TLB_MMIO; 1398fef39ccdSDavid Hildenbrand } 1399fef39ccdSDavid Hildenbrand 1400069cfe77SRichard Henderson /* Everything else is RAM. */ 1401069cfe77SRichard Henderson *phost = (void *)((uintptr_t)addr + entry->addend); 1402069cfe77SRichard Henderson return flags; 1403069cfe77SRichard Henderson } 1404069cfe77SRichard Henderson 14054f8f4127SAnton Johansson int probe_access_full(CPUArchState *env, vaddr addr, int size, 1406069cfe77SRichard Henderson MMUAccessType access_type, int mmu_idx, 1407af803a4fSRichard Henderson bool nonfault, void **phost, CPUTLBEntryFull **pfull, 1408af803a4fSRichard Henderson uintptr_t retaddr) 1409069cfe77SRichard Henderson { 14105afec1c6SAnton Johansson int flags = probe_access_internal(env_cpu(env), addr, size, access_type, 14115afec1c6SAnton Johansson mmu_idx, nonfault, phost, pfull, retaddr, 14125afec1c6SAnton Johansson true); 1413069cfe77SRichard Henderson 1414069cfe77SRichard Henderson /* Handle clean RAM pages. */ 1415069cfe77SRichard Henderson if (unlikely(flags & TLB_NOTDIRTY)) { 1416e2faabeeSJessica Clarke int dirtysize = size == 0 ? 1 : size; 1417e2faabeeSJessica Clarke notdirty_write(env_cpu(env), addr, dirtysize, *pfull, retaddr); 1418069cfe77SRichard Henderson flags &= ~TLB_NOTDIRTY; 1419069cfe77SRichard Henderson } 1420069cfe77SRichard Henderson 1421069cfe77SRichard Henderson return flags; 1422069cfe77SRichard Henderson } 1423069cfe77SRichard Henderson 14246d03226bSAlex Bennée int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size, 14256d03226bSAlex Bennée MMUAccessType access_type, int mmu_idx, 14266d03226bSAlex Bennée void **phost, CPUTLBEntryFull **pfull) 14276d03226bSAlex Bennée { 14286d03226bSAlex Bennée void *discard_phost; 14296d03226bSAlex Bennée CPUTLBEntryFull *discard_tlb; 14306d03226bSAlex Bennée 14316d03226bSAlex Bennée /* privately handle users that don't need full results */ 14326d03226bSAlex Bennée phost = phost ? phost : &discard_phost; 14336d03226bSAlex Bennée pfull = pfull ? pfull : &discard_tlb; 14346d03226bSAlex Bennée 14355afec1c6SAnton Johansson int flags = probe_access_internal(env_cpu(env), addr, size, access_type, 14365afec1c6SAnton Johansson mmu_idx, true, phost, pfull, 0, false); 14376d03226bSAlex Bennée 14386d03226bSAlex Bennée /* Handle clean RAM pages. */ 14396d03226bSAlex Bennée if (unlikely(flags & TLB_NOTDIRTY)) { 1440e2faabeeSJessica Clarke int dirtysize = size == 0 ? 1 : size; 1441e2faabeeSJessica Clarke notdirty_write(env_cpu(env), addr, dirtysize, *pfull, 0); 14426d03226bSAlex Bennée flags &= ~TLB_NOTDIRTY; 14436d03226bSAlex Bennée } 14446d03226bSAlex Bennée 14456d03226bSAlex Bennée return flags; 14466d03226bSAlex Bennée } 14476d03226bSAlex Bennée 14484f8f4127SAnton Johansson int probe_access_flags(CPUArchState *env, vaddr addr, int size, 1449af803a4fSRichard Henderson MMUAccessType access_type, int mmu_idx, 1450af803a4fSRichard Henderson bool nonfault, void **phost, uintptr_t retaddr) 1451af803a4fSRichard Henderson { 1452af803a4fSRichard Henderson CPUTLBEntryFull *full; 14531770b2f2SDaniel Henrique Barboza int flags; 1454af803a4fSRichard Henderson 14551770b2f2SDaniel Henrique Barboza g_assert(-(addr | TARGET_PAGE_MASK) >= size); 14561770b2f2SDaniel Henrique Barboza 14575afec1c6SAnton Johansson flags = probe_access_internal(env_cpu(env), addr, size, access_type, 14585afec1c6SAnton Johansson mmu_idx, nonfault, phost, &full, retaddr, 14595afec1c6SAnton Johansson true); 14601770b2f2SDaniel Henrique Barboza 14611770b2f2SDaniel Henrique Barboza /* Handle clean RAM pages. */ 14621770b2f2SDaniel Henrique Barboza if (unlikely(flags & TLB_NOTDIRTY)) { 1463e2faabeeSJessica Clarke int dirtysize = size == 0 ? 1 : size; 1464e2faabeeSJessica Clarke notdirty_write(env_cpu(env), addr, dirtysize, full, retaddr); 14651770b2f2SDaniel Henrique Barboza flags &= ~TLB_NOTDIRTY; 14661770b2f2SDaniel Henrique Barboza } 14671770b2f2SDaniel Henrique Barboza 14681770b2f2SDaniel Henrique Barboza return flags; 1469af803a4fSRichard Henderson } 1470af803a4fSRichard Henderson 14714f8f4127SAnton Johansson void *probe_access(CPUArchState *env, vaddr addr, int size, 1472069cfe77SRichard Henderson MMUAccessType access_type, int mmu_idx, uintptr_t retaddr) 1473069cfe77SRichard Henderson { 1474af803a4fSRichard Henderson CPUTLBEntryFull *full; 1475069cfe77SRichard Henderson void *host; 1476069cfe77SRichard Henderson int flags; 1477069cfe77SRichard Henderson 1478069cfe77SRichard Henderson g_assert(-(addr | TARGET_PAGE_MASK) >= size); 1479069cfe77SRichard Henderson 14805afec1c6SAnton Johansson flags = probe_access_internal(env_cpu(env), addr, size, access_type, 14815afec1c6SAnton Johansson mmu_idx, false, &host, &full, retaddr, 14825afec1c6SAnton Johansson true); 1483069cfe77SRichard Henderson 1484069cfe77SRichard Henderson /* Per the interface, size == 0 merely faults the access. */ 1485069cfe77SRichard Henderson if (size == 0) { 148673bc0bd4SRichard Henderson return NULL; 148773bc0bd4SRichard Henderson } 148873bc0bd4SRichard Henderson 1489069cfe77SRichard Henderson if (unlikely(flags & (TLB_NOTDIRTY | TLB_WATCHPOINT))) { 149003a98189SDavid Hildenbrand /* Handle watchpoints. */ 1491069cfe77SRichard Henderson if (flags & TLB_WATCHPOINT) { 1492069cfe77SRichard Henderson int wp_access = (access_type == MMU_DATA_STORE 1493069cfe77SRichard Henderson ? BP_MEM_WRITE : BP_MEM_READ); 149403a98189SDavid Hildenbrand cpu_check_watchpoint(env_cpu(env), addr, size, 149525d3ec58SRichard Henderson full->attrs, wp_access, retaddr); 1496d9bb58e5SYang Zhong } 1497fef39ccdSDavid Hildenbrand 149873bc0bd4SRichard Henderson /* Handle clean RAM pages. */ 1499069cfe77SRichard Henderson if (flags & TLB_NOTDIRTY) { 1500e2faabeeSJessica Clarke notdirty_write(env_cpu(env), addr, size, full, retaddr); 150173bc0bd4SRichard Henderson } 1502fef39ccdSDavid Hildenbrand } 1503fef39ccdSDavid Hildenbrand 1504069cfe77SRichard Henderson return host; 1505d9bb58e5SYang Zhong } 1506d9bb58e5SYang Zhong 15074811e909SRichard Henderson void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr, 15084811e909SRichard Henderson MMUAccessType access_type, int mmu_idx) 15094811e909SRichard Henderson { 1510af803a4fSRichard Henderson CPUTLBEntryFull *full; 1511069cfe77SRichard Henderson void *host; 1512069cfe77SRichard Henderson int flags; 15134811e909SRichard Henderson 15145afec1c6SAnton Johansson flags = probe_access_internal(env_cpu(env), addr, 0, access_type, 15156d03226bSAlex Bennée mmu_idx, true, &host, &full, 0, false); 1516069cfe77SRichard Henderson 1517069cfe77SRichard Henderson /* No combination of flags are expected by the caller. */ 1518069cfe77SRichard Henderson return flags ? NULL : host; 15194811e909SRichard Henderson } 15204811e909SRichard Henderson 15217e0d9973SRichard Henderson /* 15227e0d9973SRichard Henderson * Return a ram_addr_t for the virtual address for execution. 15237e0d9973SRichard Henderson * 15247e0d9973SRichard Henderson * Return -1 if we can't translate and execute from an entire page 15257e0d9973SRichard Henderson * of RAM. This will force us to execute by loading and translating 15267e0d9973SRichard Henderson * one insn at a time, without caching. 15277e0d9973SRichard Henderson * 15287e0d9973SRichard Henderson * NOTE: This function will trigger an exception if the page is 15297e0d9973SRichard Henderson * not executable. 15307e0d9973SRichard Henderson */ 15314f8f4127SAnton Johansson tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, vaddr addr, 15327e0d9973SRichard Henderson void **hostp) 15337e0d9973SRichard Henderson { 1534af803a4fSRichard Henderson CPUTLBEntryFull *full; 15357e0d9973SRichard Henderson void *p; 15367e0d9973SRichard Henderson 15375afec1c6SAnton Johansson (void)probe_access_internal(env_cpu(env), addr, 1, MMU_INST_FETCH, 15383b916140SRichard Henderson cpu_mmu_index(env_cpu(env), true), false, 15396d03226bSAlex Bennée &p, &full, 0, false); 15407e0d9973SRichard Henderson if (p == NULL) { 15417e0d9973SRichard Henderson return -1; 15427e0d9973SRichard Henderson } 1543ac01ec6fSWeiwei Li 1544ac01ec6fSWeiwei Li if (full->lg_page_size < TARGET_PAGE_BITS) { 1545ac01ec6fSWeiwei Li return -1; 1546ac01ec6fSWeiwei Li } 1547ac01ec6fSWeiwei Li 15487e0d9973SRichard Henderson if (hostp) { 15497e0d9973SRichard Henderson *hostp = p; 15507e0d9973SRichard Henderson } 15517e0d9973SRichard Henderson return qemu_ram_addr_from_host_nofail(p); 15527e0d9973SRichard Henderson } 15537e0d9973SRichard Henderson 1554cdfac37bSRichard Henderson /* Load/store with atomicity primitives. */ 1555cdfac37bSRichard Henderson #include "ldst_atomicity.c.inc" 1556cdfac37bSRichard Henderson 1557235537faSAlex Bennée #ifdef CONFIG_PLUGIN 1558235537faSAlex Bennée /* 1559235537faSAlex Bennée * Perform a TLB lookup and populate the qemu_plugin_hwaddr structure. 1560235537faSAlex Bennée * This should be a hot path as we will have just looked this path up 1561235537faSAlex Bennée * in the softmmu lookup code (or helper). We don't handle re-fills or 1562235537faSAlex Bennée * checking the victim table. This is purely informational. 1563235537faSAlex Bennée * 1564da6aef48SRichard Henderson * The one corner case is i/o write, which can cause changes to the 1565da6aef48SRichard Henderson * address space. Those changes, and the corresponding tlb flush, 1566da6aef48SRichard Henderson * should be delayed until the next TB, so even then this ought not fail. 1567da6aef48SRichard Henderson * But check, Just in Case. 1568235537faSAlex Bennée */ 1569732d5487SAnton Johansson bool tlb_plugin_lookup(CPUState *cpu, vaddr addr, int mmu_idx, 1570235537faSAlex Bennée bool is_store, struct qemu_plugin_hwaddr *data) 1571235537faSAlex Bennée { 157210b32e2cSAnton Johansson CPUTLBEntry *tlbe = tlb_entry(cpu, mmu_idx, addr); 157310b32e2cSAnton Johansson uintptr_t index = tlb_index(cpu, mmu_idx, addr); 1574da6aef48SRichard Henderson MMUAccessType access_type = is_store ? MMU_DATA_STORE : MMU_DATA_LOAD; 1575da6aef48SRichard Henderson uint64_t tlb_addr = tlb_read_idx(tlbe, access_type); 1576405c02d8SRichard Henderson CPUTLBEntryFull *full; 1577235537faSAlex Bennée 1578da6aef48SRichard Henderson if (unlikely(!tlb_hit(tlb_addr, addr))) { 1579da6aef48SRichard Henderson return false; 1580da6aef48SRichard Henderson } 1581da6aef48SRichard Henderson 158210b32e2cSAnton Johansson full = &cpu->neg.tlb.d[mmu_idx].fulltlb[index]; 1583405c02d8SRichard Henderson data->phys_addr = full->phys_addr | (addr & ~TARGET_PAGE_MASK); 1584405c02d8SRichard Henderson 1585235537faSAlex Bennée /* We must have an iotlb entry for MMIO */ 1586235537faSAlex Bennée if (tlb_addr & TLB_MMIO) { 1587405c02d8SRichard Henderson MemoryRegionSection *section = 1588405c02d8SRichard Henderson iotlb_to_section(cpu, full->xlat_section & ~TARGET_PAGE_MASK, 1589405c02d8SRichard Henderson full->attrs); 1590235537faSAlex Bennée data->is_io = true; 1591405c02d8SRichard Henderson data->mr = section->mr; 1592235537faSAlex Bennée } else { 1593235537faSAlex Bennée data->is_io = false; 1594405c02d8SRichard Henderson data->mr = NULL; 1595235537faSAlex Bennée } 1596235537faSAlex Bennée return true; 1597235537faSAlex Bennée } 1598235537faSAlex Bennée #endif 1599235537faSAlex Bennée 160008dff435SRichard Henderson /* 16018cfdacaaSRichard Henderson * Probe for a load/store operation. 16028cfdacaaSRichard Henderson * Return the host address and into @flags. 16038cfdacaaSRichard Henderson */ 16048cfdacaaSRichard Henderson 16058cfdacaaSRichard Henderson typedef struct MMULookupPageData { 16068cfdacaaSRichard Henderson CPUTLBEntryFull *full; 16078cfdacaaSRichard Henderson void *haddr; 1608fb2c53cbSAnton Johansson vaddr addr; 16098cfdacaaSRichard Henderson int flags; 16108cfdacaaSRichard Henderson int size; 16118cfdacaaSRichard Henderson } MMULookupPageData; 16128cfdacaaSRichard Henderson 16138cfdacaaSRichard Henderson typedef struct MMULookupLocals { 16148cfdacaaSRichard Henderson MMULookupPageData page[2]; 16158cfdacaaSRichard Henderson MemOp memop; 16168cfdacaaSRichard Henderson int mmu_idx; 16178cfdacaaSRichard Henderson } MMULookupLocals; 16188cfdacaaSRichard Henderson 16198cfdacaaSRichard Henderson /** 16208cfdacaaSRichard Henderson * mmu_lookup1: translate one page 1621d50ef446SAnton Johansson * @cpu: generic cpu state 16228cfdacaaSRichard Henderson * @data: lookup parameters 16238cfdacaaSRichard Henderson * @mmu_idx: virtual address context 16248cfdacaaSRichard Henderson * @access_type: load/store/code 16258cfdacaaSRichard Henderson * @ra: return address into tcg generated code, or 0 16268cfdacaaSRichard Henderson * 16278cfdacaaSRichard Henderson * Resolve the translation for the one page at @data.addr, filling in 16288cfdacaaSRichard Henderson * the rest of @data with the results. If the translation fails, 1629*f168808dSRichard Henderson * tlb_fill_align will longjmp out. Return true if the softmmu tlb for 16308cfdacaaSRichard Henderson * @mmu_idx may have resized. 16318cfdacaaSRichard Henderson */ 1632d50ef446SAnton Johansson static bool mmu_lookup1(CPUState *cpu, MMULookupPageData *data, 16338cfdacaaSRichard Henderson int mmu_idx, MMUAccessType access_type, uintptr_t ra) 16348cfdacaaSRichard Henderson { 1635fb2c53cbSAnton Johansson vaddr addr = data->addr; 1636d50ef446SAnton Johansson uintptr_t index = tlb_index(cpu, mmu_idx, addr); 1637d50ef446SAnton Johansson CPUTLBEntry *entry = tlb_entry(cpu, mmu_idx, addr); 16389e39de98SAnton Johansson uint64_t tlb_addr = tlb_read_idx(entry, access_type); 16398cfdacaaSRichard Henderson bool maybe_resized = false; 164058e8f1f6SRichard Henderson CPUTLBEntryFull *full; 164158e8f1f6SRichard Henderson int flags; 16428cfdacaaSRichard Henderson 16438cfdacaaSRichard Henderson /* If the TLB entry is for a different page, reload and try again. */ 16448cfdacaaSRichard Henderson if (!tlb_hit(tlb_addr, addr)) { 1645d50ef446SAnton Johansson if (!victim_tlb_hit(cpu, mmu_idx, index, access_type, 16468cfdacaaSRichard Henderson addr & TARGET_PAGE_MASK)) { 1647*f168808dSRichard Henderson tlb_fill_align(cpu, addr, access_type, mmu_idx, 1648*f168808dSRichard Henderson 0, data->size, false, ra); 16498cfdacaaSRichard Henderson maybe_resized = true; 1650d50ef446SAnton Johansson index = tlb_index(cpu, mmu_idx, addr); 1651d50ef446SAnton Johansson entry = tlb_entry(cpu, mmu_idx, addr); 16528cfdacaaSRichard Henderson } 16538cfdacaaSRichard Henderson tlb_addr = tlb_read_idx(entry, access_type) & ~TLB_INVALID_MASK; 16548cfdacaaSRichard Henderson } 16558cfdacaaSRichard Henderson 1656d50ef446SAnton Johansson full = &cpu->neg.tlb.d[mmu_idx].fulltlb[index]; 165758e8f1f6SRichard Henderson flags = tlb_addr & (TLB_FLAGS_MASK & ~TLB_FORCE_SLOW); 165858e8f1f6SRichard Henderson flags |= full->slow_flags[access_type]; 165958e8f1f6SRichard Henderson 166058e8f1f6SRichard Henderson data->full = full; 166158e8f1f6SRichard Henderson data->flags = flags; 16628cfdacaaSRichard Henderson /* Compute haddr speculatively; depending on flags it might be invalid. */ 16638cfdacaaSRichard Henderson data->haddr = (void *)((uintptr_t)addr + entry->addend); 16648cfdacaaSRichard Henderson 16658cfdacaaSRichard Henderson return maybe_resized; 16668cfdacaaSRichard Henderson } 16678cfdacaaSRichard Henderson 16688cfdacaaSRichard Henderson /** 16698cfdacaaSRichard Henderson * mmu_watch_or_dirty 1670d50ef446SAnton Johansson * @cpu: generic cpu state 16718cfdacaaSRichard Henderson * @data: lookup parameters 16728cfdacaaSRichard Henderson * @access_type: load/store/code 16738cfdacaaSRichard Henderson * @ra: return address into tcg generated code, or 0 16748cfdacaaSRichard Henderson * 16758cfdacaaSRichard Henderson * Trigger watchpoints for @data.addr:@data.size; 16768cfdacaaSRichard Henderson * record writes to protected clean pages. 16778cfdacaaSRichard Henderson */ 1678d50ef446SAnton Johansson static void mmu_watch_or_dirty(CPUState *cpu, MMULookupPageData *data, 16798cfdacaaSRichard Henderson MMUAccessType access_type, uintptr_t ra) 16808cfdacaaSRichard Henderson { 16818cfdacaaSRichard Henderson CPUTLBEntryFull *full = data->full; 1682fb2c53cbSAnton Johansson vaddr addr = data->addr; 16838cfdacaaSRichard Henderson int flags = data->flags; 16848cfdacaaSRichard Henderson int size = data->size; 16858cfdacaaSRichard Henderson 16868cfdacaaSRichard Henderson /* On watchpoint hit, this will longjmp out. */ 16878cfdacaaSRichard Henderson if (flags & TLB_WATCHPOINT) { 16888cfdacaaSRichard Henderson int wp = access_type == MMU_DATA_STORE ? BP_MEM_WRITE : BP_MEM_READ; 1689d50ef446SAnton Johansson cpu_check_watchpoint(cpu, addr, size, full->attrs, wp, ra); 16908cfdacaaSRichard Henderson flags &= ~TLB_WATCHPOINT; 16918cfdacaaSRichard Henderson } 16928cfdacaaSRichard Henderson 16938cfdacaaSRichard Henderson /* Note that notdirty is only set for writes. */ 16948cfdacaaSRichard Henderson if (flags & TLB_NOTDIRTY) { 1695d50ef446SAnton Johansson notdirty_write(cpu, addr, size, full, ra); 16968cfdacaaSRichard Henderson flags &= ~TLB_NOTDIRTY; 16978cfdacaaSRichard Henderson } 16988cfdacaaSRichard Henderson data->flags = flags; 16998cfdacaaSRichard Henderson } 17008cfdacaaSRichard Henderson 17018cfdacaaSRichard Henderson /** 17028cfdacaaSRichard Henderson * mmu_lookup: translate page(s) 1703d50ef446SAnton Johansson * @cpu: generic cpu state 17048cfdacaaSRichard Henderson * @addr: virtual address 17058cfdacaaSRichard Henderson * @oi: combined mmu_idx and MemOp 17068cfdacaaSRichard Henderson * @ra: return address into tcg generated code, or 0 17078cfdacaaSRichard Henderson * @access_type: load/store/code 17088cfdacaaSRichard Henderson * @l: output result 17098cfdacaaSRichard Henderson * 17108cfdacaaSRichard Henderson * Resolve the translation for the page(s) beginning at @addr, for MemOp.size 17118cfdacaaSRichard Henderson * bytes. Return true if the lookup crosses a page boundary. 17128cfdacaaSRichard Henderson */ 1713d50ef446SAnton Johansson static bool mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi, 17148cfdacaaSRichard Henderson uintptr_t ra, MMUAccessType type, MMULookupLocals *l) 17158cfdacaaSRichard Henderson { 17168cfdacaaSRichard Henderson unsigned a_bits; 17178cfdacaaSRichard Henderson bool crosspage; 17188cfdacaaSRichard Henderson int flags; 17198cfdacaaSRichard Henderson 17208cfdacaaSRichard Henderson l->memop = get_memop(oi); 17218cfdacaaSRichard Henderson l->mmu_idx = get_mmuidx(oi); 17228cfdacaaSRichard Henderson 17238cfdacaaSRichard Henderson tcg_debug_assert(l->mmu_idx < NB_MMU_MODES); 17248cfdacaaSRichard Henderson 17258cfdacaaSRichard Henderson /* Handle CPU specific unaligned behaviour */ 1726c5809eeeSRichard Henderson a_bits = memop_alignment_bits(l->memop); 17278cfdacaaSRichard Henderson if (addr & ((1 << a_bits) - 1)) { 1728d50ef446SAnton Johansson cpu_unaligned_access(cpu, addr, type, l->mmu_idx, ra); 17298cfdacaaSRichard Henderson } 17308cfdacaaSRichard Henderson 17318cfdacaaSRichard Henderson l->page[0].addr = addr; 17328cfdacaaSRichard Henderson l->page[0].size = memop_size(l->memop); 17338cfdacaaSRichard Henderson l->page[1].addr = (addr + l->page[0].size - 1) & TARGET_PAGE_MASK; 17348cfdacaaSRichard Henderson l->page[1].size = 0; 17358cfdacaaSRichard Henderson crosspage = (addr ^ l->page[1].addr) & TARGET_PAGE_MASK; 17368cfdacaaSRichard Henderson 17378cfdacaaSRichard Henderson if (likely(!crosspage)) { 1738d50ef446SAnton Johansson mmu_lookup1(cpu, &l->page[0], l->mmu_idx, type, ra); 17398cfdacaaSRichard Henderson 17408cfdacaaSRichard Henderson flags = l->page[0].flags; 17418cfdacaaSRichard Henderson if (unlikely(flags & (TLB_WATCHPOINT | TLB_NOTDIRTY))) { 1742d50ef446SAnton Johansson mmu_watch_or_dirty(cpu, &l->page[0], type, ra); 17438cfdacaaSRichard Henderson } 17448cfdacaaSRichard Henderson if (unlikely(flags & TLB_BSWAP)) { 17458cfdacaaSRichard Henderson l->memop ^= MO_BSWAP; 17468cfdacaaSRichard Henderson } 17478cfdacaaSRichard Henderson } else { 17488cfdacaaSRichard Henderson /* Finish compute of page crossing. */ 17498cfdacaaSRichard Henderson int size0 = l->page[1].addr - addr; 17508cfdacaaSRichard Henderson l->page[1].size = l->page[0].size - size0; 17518cfdacaaSRichard Henderson l->page[0].size = size0; 17528cfdacaaSRichard Henderson 17538cfdacaaSRichard Henderson /* 17548cfdacaaSRichard Henderson * Lookup both pages, recognizing exceptions from either. If the 17558cfdacaaSRichard Henderson * second lookup potentially resized, refresh first CPUTLBEntryFull. 17568cfdacaaSRichard Henderson */ 1757d50ef446SAnton Johansson mmu_lookup1(cpu, &l->page[0], l->mmu_idx, type, ra); 1758d50ef446SAnton Johansson if (mmu_lookup1(cpu, &l->page[1], l->mmu_idx, type, ra)) { 1759d50ef446SAnton Johansson uintptr_t index = tlb_index(cpu, l->mmu_idx, addr); 1760d50ef446SAnton Johansson l->page[0].full = &cpu->neg.tlb.d[l->mmu_idx].fulltlb[index]; 17618cfdacaaSRichard Henderson } 17628cfdacaaSRichard Henderson 17638cfdacaaSRichard Henderson flags = l->page[0].flags | l->page[1].flags; 17648cfdacaaSRichard Henderson if (unlikely(flags & (TLB_WATCHPOINT | TLB_NOTDIRTY))) { 1765d50ef446SAnton Johansson mmu_watch_or_dirty(cpu, &l->page[0], type, ra); 1766d50ef446SAnton Johansson mmu_watch_or_dirty(cpu, &l->page[1], type, ra); 17678cfdacaaSRichard Henderson } 17688cfdacaaSRichard Henderson 17698cfdacaaSRichard Henderson /* 17708cfdacaaSRichard Henderson * Since target/sparc is the only user of TLB_BSWAP, and all 17718cfdacaaSRichard Henderson * Sparc accesses are aligned, any treatment across two pages 17728cfdacaaSRichard Henderson * would be arbitrary. Refuse it until there's a use. 17738cfdacaaSRichard Henderson */ 17748cfdacaaSRichard Henderson tcg_debug_assert((flags & TLB_BSWAP) == 0); 17758cfdacaaSRichard Henderson } 17768cfdacaaSRichard Henderson 177749fa457cSRichard Henderson /* 177849fa457cSRichard Henderson * This alignment check differs from the one above, in that this is 177949fa457cSRichard Henderson * based on the atomicity of the operation. The intended use case is 178049fa457cSRichard Henderson * the ARM memory type field of each PTE, where access to pages with 178149fa457cSRichard Henderson * Device memory type require alignment. 178249fa457cSRichard Henderson */ 178349fa457cSRichard Henderson if (unlikely(flags & TLB_CHECK_ALIGNED)) { 1784e5b063e8SRichard Henderson a_bits = memop_atomicity_bits(l->memop); 1785e5b063e8SRichard Henderson if (addr & ((1 << a_bits) - 1)) { 178649fa457cSRichard Henderson cpu_unaligned_access(cpu, addr, type, l->mmu_idx, ra); 178749fa457cSRichard Henderson } 178849fa457cSRichard Henderson } 178949fa457cSRichard Henderson 17908cfdacaaSRichard Henderson return crosspage; 17918cfdacaaSRichard Henderson } 17928cfdacaaSRichard Henderson 17938cfdacaaSRichard Henderson /* 179408dff435SRichard Henderson * Probe for an atomic operation. Do not allow unaligned operations, 179508dff435SRichard Henderson * or io operations to proceed. Return the host address. 179608dff435SRichard Henderson */ 1797d560225fSAnton Johansson static void *atomic_mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi, 1798b0326eb9SAnton Johansson int size, uintptr_t retaddr) 1799d9bb58e5SYang Zhong { 1800b826044fSRichard Henderson uintptr_t mmu_idx = get_mmuidx(oi); 180114776ab5STony Nguyen MemOp mop = get_memop(oi); 1802c5809eeeSRichard Henderson int a_bits = memop_alignment_bits(mop); 180308dff435SRichard Henderson uintptr_t index; 180408dff435SRichard Henderson CPUTLBEntry *tlbe; 1805b0326eb9SAnton Johansson vaddr tlb_addr; 180634d49937SPeter Maydell void *hostaddr; 1807417aeaffSRichard Henderson CPUTLBEntryFull *full; 1808d9bb58e5SYang Zhong 1809b826044fSRichard Henderson tcg_debug_assert(mmu_idx < NB_MMU_MODES); 1810b826044fSRichard Henderson 1811d9bb58e5SYang Zhong /* Adjust the given return address. */ 1812d9bb58e5SYang Zhong retaddr -= GETPC_ADJ; 1813d9bb58e5SYang Zhong 1814d9bb58e5SYang Zhong /* Enforce guest required alignment. */ 1815d9bb58e5SYang Zhong if (unlikely(a_bits > 0 && (addr & ((1 << a_bits) - 1)))) { 1816d9bb58e5SYang Zhong /* ??? Maybe indicate atomic op to cpu_unaligned_access */ 1817d560225fSAnton Johansson cpu_unaligned_access(cpu, addr, MMU_DATA_STORE, 1818d9bb58e5SYang Zhong mmu_idx, retaddr); 1819d9bb58e5SYang Zhong } 1820d9bb58e5SYang Zhong 1821d9bb58e5SYang Zhong /* Enforce qemu required alignment. */ 182208dff435SRichard Henderson if (unlikely(addr & (size - 1))) { 1823d9bb58e5SYang Zhong /* We get here if guest alignment was not requested, 1824d9bb58e5SYang Zhong or was not enforced by cpu_unaligned_access above. 1825d9bb58e5SYang Zhong We might widen the access and emulate, but for now 1826d9bb58e5SYang Zhong mark an exception and exit the cpu loop. */ 1827d9bb58e5SYang Zhong goto stop_the_world; 1828d9bb58e5SYang Zhong } 1829d9bb58e5SYang Zhong 1830d560225fSAnton Johansson index = tlb_index(cpu, mmu_idx, addr); 1831d560225fSAnton Johansson tlbe = tlb_entry(cpu, mmu_idx, addr); 183208dff435SRichard Henderson 1833d9bb58e5SYang Zhong /* Check TLB entry and enforce page permissions. */ 183408dff435SRichard Henderson tlb_addr = tlb_addr_write(tlbe); 1835334692bcSPeter Maydell if (!tlb_hit(tlb_addr, addr)) { 1836d560225fSAnton Johansson if (!victim_tlb_hit(cpu, mmu_idx, index, MMU_DATA_STORE, 18370b3c75adSRichard Henderson addr & TARGET_PAGE_MASK)) { 1838*f168808dSRichard Henderson tlb_fill_align(cpu, addr, MMU_DATA_STORE, mmu_idx, 1839*f168808dSRichard Henderson 0, size, false, retaddr); 1840d560225fSAnton Johansson index = tlb_index(cpu, mmu_idx, addr); 1841d560225fSAnton Johansson tlbe = tlb_entry(cpu, mmu_idx, addr); 1842d9bb58e5SYang Zhong } 1843403f290cSEmilio G. Cota tlb_addr = tlb_addr_write(tlbe) & ~TLB_INVALID_MASK; 1844d9bb58e5SYang Zhong } 1845d9bb58e5SYang Zhong 1846417aeaffSRichard Henderson /* 1847417aeaffSRichard Henderson * Let the guest notice RMW on a write-only page. 1848417aeaffSRichard Henderson * We have just verified that the page is writable. 1849417aeaffSRichard Henderson * Subpage lookups may have left TLB_INVALID_MASK set, 1850417aeaffSRichard Henderson * but addr_read will only be -1 if PAGE_READ was unset. 1851417aeaffSRichard Henderson */ 1852417aeaffSRichard Henderson if (unlikely(tlbe->addr_read == -1)) { 1853*f168808dSRichard Henderson tlb_fill_align(cpu, addr, MMU_DATA_LOAD, mmu_idx, 1854*f168808dSRichard Henderson 0, size, false, retaddr); 185508dff435SRichard Henderson /* 1856417aeaffSRichard Henderson * Since we don't support reads and writes to different 1857417aeaffSRichard Henderson * addresses, and we do have the proper page loaded for 185849d1866aSRichard Henderson * write, this shouldn't ever return. 185908dff435SRichard Henderson */ 186049d1866aSRichard Henderson g_assert_not_reached(); 186108dff435SRichard Henderson } 1862187ba694SRichard Henderson /* Collect tlb flags for read. */ 1863417aeaffSRichard Henderson tlb_addr |= tlbe->addr_read; 186408dff435SRichard Henderson 186555df6fcfSPeter Maydell /* Notice an IO access or a needs-MMU-lookup access */ 18660953674eSRichard Henderson if (unlikely(tlb_addr & (TLB_MMIO | TLB_DISCARD_WRITE))) { 1867d9bb58e5SYang Zhong /* There's really nothing that can be done to 1868d9bb58e5SYang Zhong support this apart from stop-the-world. */ 1869d9bb58e5SYang Zhong goto stop_the_world; 1870d9bb58e5SYang Zhong } 1871d9bb58e5SYang Zhong 187234d49937SPeter Maydell hostaddr = (void *)((uintptr_t)addr + tlbe->addend); 1873d560225fSAnton Johansson full = &cpu->neg.tlb.d[mmu_idx].fulltlb[index]; 187434d49937SPeter Maydell 187534d49937SPeter Maydell if (unlikely(tlb_addr & TLB_NOTDIRTY)) { 1876d560225fSAnton Johansson notdirty_write(cpu, addr, size, full, retaddr); 1877417aeaffSRichard Henderson } 1878417aeaffSRichard Henderson 1879187ba694SRichard Henderson if (unlikely(tlb_addr & TLB_FORCE_SLOW)) { 1880187ba694SRichard Henderson int wp_flags = 0; 1881187ba694SRichard Henderson 1882187ba694SRichard Henderson if (full->slow_flags[MMU_DATA_STORE] & TLB_WATCHPOINT) { 1883187ba694SRichard Henderson wp_flags |= BP_MEM_WRITE; 1884187ba694SRichard Henderson } 1885187ba694SRichard Henderson if (full->slow_flags[MMU_DATA_LOAD] & TLB_WATCHPOINT) { 1886187ba694SRichard Henderson wp_flags |= BP_MEM_READ; 1887187ba694SRichard Henderson } 1888187ba694SRichard Henderson if (wp_flags) { 1889d560225fSAnton Johansson cpu_check_watchpoint(cpu, addr, size, 1890187ba694SRichard Henderson full->attrs, wp_flags, retaddr); 1891187ba694SRichard Henderson } 189234d49937SPeter Maydell } 189334d49937SPeter Maydell 189434d49937SPeter Maydell return hostaddr; 1895d9bb58e5SYang Zhong 1896d9bb58e5SYang Zhong stop_the_world: 1897d560225fSAnton Johansson cpu_loop_exit_atomic(cpu, retaddr); 1898d9bb58e5SYang Zhong } 1899d9bb58e5SYang Zhong 1900eed56642SAlex Bennée /* 1901eed56642SAlex Bennée * Load Helpers 1902eed56642SAlex Bennée * 1903eed56642SAlex Bennée * We support two different access types. SOFTMMU_CODE_ACCESS is 1904eed56642SAlex Bennée * specifically for reading instructions from system memory. It is 1905eed56642SAlex Bennée * called by the translation loop and in some helpers where the code 1906eed56642SAlex Bennée * is disassembled. It shouldn't be called directly by guest code. 1907cdfac37bSRichard Henderson * 1908eed56642SAlex Bennée * For the benefit of TCG generated code, we want to avoid the 1909eed56642SAlex Bennée * complication of ABI-specific return type promotion and always 1910eed56642SAlex Bennée * return a value extended to the register size of the host. This is 1911eed56642SAlex Bennée * tcg_target_long, except in the case of a 32-bit host and 64-bit 1912eed56642SAlex Bennée * data, and for that we always have uint64_t. 1913eed56642SAlex Bennée * 1914eed56642SAlex Bennée * We don't bother with this widened value for SOFTMMU_CODE_ACCESS. 1915eed56642SAlex Bennée */ 1916eed56642SAlex Bennée 19178cfdacaaSRichard Henderson /** 19188cfdacaaSRichard Henderson * do_ld_mmio_beN: 1919d50ef446SAnton Johansson * @cpu: generic cpu state 19201966855eSRichard Henderson * @full: page parameters 19218cfdacaaSRichard Henderson * @ret_be: accumulated data 19221966855eSRichard Henderson * @addr: virtual address 19231966855eSRichard Henderson * @size: number of bytes 19248cfdacaaSRichard Henderson * @mmu_idx: virtual address context 19258cfdacaaSRichard Henderson * @ra: return address into tcg generated code, or 0 1926a4a411fbSStefan Hajnoczi * Context: BQL held 19278cfdacaaSRichard Henderson * 19281966855eSRichard Henderson * Load @size bytes from @addr, which is memory-mapped i/o. 19298cfdacaaSRichard Henderson * The bytes are concatenated in big-endian order with @ret_be. 19308cfdacaaSRichard Henderson */ 1931d50ef446SAnton Johansson static uint64_t int_ld_mmio_beN(CPUState *cpu, CPUTLBEntryFull *full, 19321966855eSRichard Henderson uint64_t ret_be, vaddr addr, int size, 19338bf67267SRichard Henderson int mmu_idx, MMUAccessType type, uintptr_t ra, 19348bf67267SRichard Henderson MemoryRegion *mr, hwaddr mr_offset) 19352dd92606SRichard Henderson { 1936190aba80SRichard Henderson do { 193713e61747SRichard Henderson MemOp this_mop; 193813e61747SRichard Henderson unsigned this_size; 193913e61747SRichard Henderson uint64_t val; 194013e61747SRichard Henderson MemTxResult r; 194113e61747SRichard Henderson 1942190aba80SRichard Henderson /* Read aligned pieces up to 8 bytes. */ 194313e61747SRichard Henderson this_mop = ctz32(size | (int)addr | 8); 194413e61747SRichard Henderson this_size = 1 << this_mop; 194513e61747SRichard Henderson this_mop |= MO_BE; 194613e61747SRichard Henderson 19478bf67267SRichard Henderson r = memory_region_dispatch_read(mr, mr_offset, &val, 19488bf67267SRichard Henderson this_mop, full->attrs); 194913e61747SRichard Henderson if (unlikely(r != MEMTX_OK)) { 1950d50ef446SAnton Johansson io_failed(cpu, full, addr, this_size, type, mmu_idx, r, ra); 19518cfdacaaSRichard Henderson } 195213e61747SRichard Henderson if (this_size == 8) { 195313e61747SRichard Henderson return val; 195413e61747SRichard Henderson } 195513e61747SRichard Henderson 195613e61747SRichard Henderson ret_be = (ret_be << (this_size * 8)) | val; 195713e61747SRichard Henderson addr += this_size; 195813e61747SRichard Henderson mr_offset += this_size; 195913e61747SRichard Henderson size -= this_size; 1960190aba80SRichard Henderson } while (size); 196113e61747SRichard Henderson 19628cfdacaaSRichard Henderson return ret_be; 19638cfdacaaSRichard Henderson } 19648cfdacaaSRichard Henderson 1965d50ef446SAnton Johansson static uint64_t do_ld_mmio_beN(CPUState *cpu, CPUTLBEntryFull *full, 19668bf67267SRichard Henderson uint64_t ret_be, vaddr addr, int size, 19678bf67267SRichard Henderson int mmu_idx, MMUAccessType type, uintptr_t ra) 19688bf67267SRichard Henderson { 19698bf67267SRichard Henderson MemoryRegionSection *section; 19708bf67267SRichard Henderson MemoryRegion *mr; 19718bf67267SRichard Henderson hwaddr mr_offset; 19728bf67267SRichard Henderson MemTxAttrs attrs; 19738bf67267SRichard Henderson 19748bf67267SRichard Henderson tcg_debug_assert(size > 0 && size <= 8); 19758bf67267SRichard Henderson 19768bf67267SRichard Henderson attrs = full->attrs; 1977d50ef446SAnton Johansson section = io_prepare(&mr_offset, cpu, full->xlat_section, attrs, addr, ra); 19788bf67267SRichard Henderson mr = section->mr; 19798bf67267SRichard Henderson 19806aba908dSJonathan Cameron BQL_LOCK_GUARD(); 19816aba908dSJonathan Cameron return int_ld_mmio_beN(cpu, full, ret_be, addr, size, mmu_idx, 19828bf67267SRichard Henderson type, ra, mr, mr_offset); 19838bf67267SRichard Henderson } 19848bf67267SRichard Henderson 1985d50ef446SAnton Johansson static Int128 do_ld16_mmio_beN(CPUState *cpu, CPUTLBEntryFull *full, 19868bf67267SRichard Henderson uint64_t ret_be, vaddr addr, int size, 19878bf67267SRichard Henderson int mmu_idx, uintptr_t ra) 19888bf67267SRichard Henderson { 19898bf67267SRichard Henderson MemoryRegionSection *section; 19908bf67267SRichard Henderson MemoryRegion *mr; 19918bf67267SRichard Henderson hwaddr mr_offset; 19928bf67267SRichard Henderson MemTxAttrs attrs; 19938bf67267SRichard Henderson uint64_t a, b; 19948bf67267SRichard Henderson 19958bf67267SRichard Henderson tcg_debug_assert(size > 8 && size <= 16); 19968bf67267SRichard Henderson 19978bf67267SRichard Henderson attrs = full->attrs; 1998d50ef446SAnton Johansson section = io_prepare(&mr_offset, cpu, full->xlat_section, attrs, addr, ra); 19998bf67267SRichard Henderson mr = section->mr; 20008bf67267SRichard Henderson 20016aba908dSJonathan Cameron BQL_LOCK_GUARD(); 2002d50ef446SAnton Johansson a = int_ld_mmio_beN(cpu, full, ret_be, addr, size - 8, mmu_idx, 20038bf67267SRichard Henderson MMU_DATA_LOAD, ra, mr, mr_offset); 2004d50ef446SAnton Johansson b = int_ld_mmio_beN(cpu, full, ret_be, addr + size - 8, 8, mmu_idx, 20058bf67267SRichard Henderson MMU_DATA_LOAD, ra, mr, mr_offset + size - 8); 20068bf67267SRichard Henderson return int128_make128(b, a); 20078bf67267SRichard Henderson } 20088bf67267SRichard Henderson 20098cfdacaaSRichard Henderson /** 20108cfdacaaSRichard Henderson * do_ld_bytes_beN 20118cfdacaaSRichard Henderson * @p: translation parameters 20128cfdacaaSRichard Henderson * @ret_be: accumulated data 20138cfdacaaSRichard Henderson * 20148cfdacaaSRichard Henderson * Load @p->size bytes from @p->haddr, which is RAM. 20158cfdacaaSRichard Henderson * The bytes to concatenated in big-endian order with @ret_be. 20168cfdacaaSRichard Henderson */ 20178cfdacaaSRichard Henderson static uint64_t do_ld_bytes_beN(MMULookupPageData *p, uint64_t ret_be) 20188cfdacaaSRichard Henderson { 20198cfdacaaSRichard Henderson uint8_t *haddr = p->haddr; 20208cfdacaaSRichard Henderson int i, size = p->size; 20218cfdacaaSRichard Henderson 20228cfdacaaSRichard Henderson for (i = 0; i < size; i++) { 20238cfdacaaSRichard Henderson ret_be = (ret_be << 8) | haddr[i]; 20248cfdacaaSRichard Henderson } 20258cfdacaaSRichard Henderson return ret_be; 20268cfdacaaSRichard Henderson } 20278cfdacaaSRichard Henderson 2028cdfac37bSRichard Henderson /** 2029cdfac37bSRichard Henderson * do_ld_parts_beN 2030cdfac37bSRichard Henderson * @p: translation parameters 2031cdfac37bSRichard Henderson * @ret_be: accumulated data 2032cdfac37bSRichard Henderson * 2033cdfac37bSRichard Henderson * As do_ld_bytes_beN, but atomically on each aligned part. 2034cdfac37bSRichard Henderson */ 2035cdfac37bSRichard Henderson static uint64_t do_ld_parts_beN(MMULookupPageData *p, uint64_t ret_be) 2036cdfac37bSRichard Henderson { 2037cdfac37bSRichard Henderson void *haddr = p->haddr; 2038cdfac37bSRichard Henderson int size = p->size; 2039cdfac37bSRichard Henderson 2040cdfac37bSRichard Henderson do { 2041cdfac37bSRichard Henderson uint64_t x; 2042cdfac37bSRichard Henderson int n; 2043cdfac37bSRichard Henderson 2044cdfac37bSRichard Henderson /* 2045cdfac37bSRichard Henderson * Find minimum of alignment and size. 2046cdfac37bSRichard Henderson * This is slightly stronger than required by MO_ATOM_SUBALIGN, which 2047cdfac37bSRichard Henderson * would have only checked the low bits of addr|size once at the start, 2048cdfac37bSRichard Henderson * but is just as easy. 2049cdfac37bSRichard Henderson */ 2050cdfac37bSRichard Henderson switch (((uintptr_t)haddr | size) & 7) { 2051cdfac37bSRichard Henderson case 4: 2052cdfac37bSRichard Henderson x = cpu_to_be32(load_atomic4(haddr)); 2053cdfac37bSRichard Henderson ret_be = (ret_be << 32) | x; 2054cdfac37bSRichard Henderson n = 4; 2055cdfac37bSRichard Henderson break; 2056cdfac37bSRichard Henderson case 2: 2057cdfac37bSRichard Henderson case 6: 2058cdfac37bSRichard Henderson x = cpu_to_be16(load_atomic2(haddr)); 2059cdfac37bSRichard Henderson ret_be = (ret_be << 16) | x; 2060cdfac37bSRichard Henderson n = 2; 2061cdfac37bSRichard Henderson break; 2062cdfac37bSRichard Henderson default: 2063cdfac37bSRichard Henderson x = *(uint8_t *)haddr; 2064cdfac37bSRichard Henderson ret_be = (ret_be << 8) | x; 2065cdfac37bSRichard Henderson n = 1; 2066cdfac37bSRichard Henderson break; 2067cdfac37bSRichard Henderson case 0: 2068cdfac37bSRichard Henderson g_assert_not_reached(); 2069cdfac37bSRichard Henderson } 2070cdfac37bSRichard Henderson haddr += n; 2071cdfac37bSRichard Henderson size -= n; 2072cdfac37bSRichard Henderson } while (size != 0); 2073cdfac37bSRichard Henderson return ret_be; 2074cdfac37bSRichard Henderson } 2075cdfac37bSRichard Henderson 2076cdfac37bSRichard Henderson /** 2077cdfac37bSRichard Henderson * do_ld_parts_be4 2078cdfac37bSRichard Henderson * @p: translation parameters 2079cdfac37bSRichard Henderson * @ret_be: accumulated data 2080cdfac37bSRichard Henderson * 2081cdfac37bSRichard Henderson * As do_ld_bytes_beN, but with one atomic load. 2082cdfac37bSRichard Henderson * Four aligned bytes are guaranteed to cover the load. 2083cdfac37bSRichard Henderson */ 2084cdfac37bSRichard Henderson static uint64_t do_ld_whole_be4(MMULookupPageData *p, uint64_t ret_be) 2085cdfac37bSRichard Henderson { 2086cdfac37bSRichard Henderson int o = p->addr & 3; 2087cdfac37bSRichard Henderson uint32_t x = load_atomic4(p->haddr - o); 2088cdfac37bSRichard Henderson 2089cdfac37bSRichard Henderson x = cpu_to_be32(x); 2090cdfac37bSRichard Henderson x <<= o * 8; 2091cdfac37bSRichard Henderson x >>= (4 - p->size) * 8; 2092cdfac37bSRichard Henderson return (ret_be << (p->size * 8)) | x; 2093cdfac37bSRichard Henderson } 2094cdfac37bSRichard Henderson 2095cdfac37bSRichard Henderson /** 2096cdfac37bSRichard Henderson * do_ld_parts_be8 2097cdfac37bSRichard Henderson * @p: translation parameters 2098cdfac37bSRichard Henderson * @ret_be: accumulated data 2099cdfac37bSRichard Henderson * 2100cdfac37bSRichard Henderson * As do_ld_bytes_beN, but with one atomic load. 2101cdfac37bSRichard Henderson * Eight aligned bytes are guaranteed to cover the load. 2102cdfac37bSRichard Henderson */ 2103d50ef446SAnton Johansson static uint64_t do_ld_whole_be8(CPUState *cpu, uintptr_t ra, 2104cdfac37bSRichard Henderson MMULookupPageData *p, uint64_t ret_be) 2105cdfac37bSRichard Henderson { 2106cdfac37bSRichard Henderson int o = p->addr & 7; 210773fda56fSAnton Johansson uint64_t x = load_atomic8_or_exit(cpu, ra, p->haddr - o); 2108cdfac37bSRichard Henderson 2109cdfac37bSRichard Henderson x = cpu_to_be64(x); 2110cdfac37bSRichard Henderson x <<= o * 8; 2111cdfac37bSRichard Henderson x >>= (8 - p->size) * 8; 2112cdfac37bSRichard Henderson return (ret_be << (p->size * 8)) | x; 2113cdfac37bSRichard Henderson } 2114cdfac37bSRichard Henderson 211535c653c4SRichard Henderson /** 211635c653c4SRichard Henderson * do_ld_parts_be16 211735c653c4SRichard Henderson * @p: translation parameters 211835c653c4SRichard Henderson * @ret_be: accumulated data 211935c653c4SRichard Henderson * 212035c653c4SRichard Henderson * As do_ld_bytes_beN, but with one atomic load. 212135c653c4SRichard Henderson * 16 aligned bytes are guaranteed to cover the load. 212235c653c4SRichard Henderson */ 2123d50ef446SAnton Johansson static Int128 do_ld_whole_be16(CPUState *cpu, uintptr_t ra, 212435c653c4SRichard Henderson MMULookupPageData *p, uint64_t ret_be) 212535c653c4SRichard Henderson { 212635c653c4SRichard Henderson int o = p->addr & 15; 212773fda56fSAnton Johansson Int128 x, y = load_atomic16_or_exit(cpu, ra, p->haddr - o); 212835c653c4SRichard Henderson int size = p->size; 212935c653c4SRichard Henderson 213035c653c4SRichard Henderson if (!HOST_BIG_ENDIAN) { 213135c653c4SRichard Henderson y = bswap128(y); 213235c653c4SRichard Henderson } 213335c653c4SRichard Henderson y = int128_lshift(y, o * 8); 213435c653c4SRichard Henderson y = int128_urshift(y, (16 - size) * 8); 213535c653c4SRichard Henderson x = int128_make64(ret_be); 213635c653c4SRichard Henderson x = int128_lshift(x, size * 8); 213735c653c4SRichard Henderson return int128_or(x, y); 213835c653c4SRichard Henderson } 213935c653c4SRichard Henderson 21408cfdacaaSRichard Henderson /* 21418cfdacaaSRichard Henderson * Wrapper for the above. 21428cfdacaaSRichard Henderson */ 2143d50ef446SAnton Johansson static uint64_t do_ld_beN(CPUState *cpu, MMULookupPageData *p, 2144cdfac37bSRichard Henderson uint64_t ret_be, int mmu_idx, MMUAccessType type, 2145cdfac37bSRichard Henderson MemOp mop, uintptr_t ra) 21468cfdacaaSRichard Henderson { 2147cdfac37bSRichard Henderson MemOp atom; 2148cdfac37bSRichard Henderson unsigned tmp, half_size; 2149cdfac37bSRichard Henderson 21508cfdacaaSRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 2151d50ef446SAnton Johansson return do_ld_mmio_beN(cpu, p->full, ret_be, p->addr, p->size, 21521966855eSRichard Henderson mmu_idx, type, ra); 2153cdfac37bSRichard Henderson } 2154cdfac37bSRichard Henderson 2155cdfac37bSRichard Henderson /* 2156cdfac37bSRichard Henderson * It is a given that we cross a page and therefore there is no 2157cdfac37bSRichard Henderson * atomicity for the load as a whole, but subobjects may need attention. 2158cdfac37bSRichard Henderson */ 2159cdfac37bSRichard Henderson atom = mop & MO_ATOM_MASK; 2160cdfac37bSRichard Henderson switch (atom) { 2161cdfac37bSRichard Henderson case MO_ATOM_SUBALIGN: 2162cdfac37bSRichard Henderson return do_ld_parts_beN(p, ret_be); 2163cdfac37bSRichard Henderson 2164cdfac37bSRichard Henderson case MO_ATOM_IFALIGN_PAIR: 2165cdfac37bSRichard Henderson case MO_ATOM_WITHIN16_PAIR: 2166cdfac37bSRichard Henderson tmp = mop & MO_SIZE; 2167cdfac37bSRichard Henderson tmp = tmp ? tmp - 1 : 0; 2168cdfac37bSRichard Henderson half_size = 1 << tmp; 2169cdfac37bSRichard Henderson if (atom == MO_ATOM_IFALIGN_PAIR 2170cdfac37bSRichard Henderson ? p->size == half_size 2171cdfac37bSRichard Henderson : p->size >= half_size) { 2172cdfac37bSRichard Henderson if (!HAVE_al8_fast && p->size < 4) { 2173cdfac37bSRichard Henderson return do_ld_whole_be4(p, ret_be); 21748cfdacaaSRichard Henderson } else { 2175d50ef446SAnton Johansson return do_ld_whole_be8(cpu, ra, p, ret_be); 2176cdfac37bSRichard Henderson } 2177cdfac37bSRichard Henderson } 2178cdfac37bSRichard Henderson /* fall through */ 2179cdfac37bSRichard Henderson 2180cdfac37bSRichard Henderson case MO_ATOM_IFALIGN: 2181cdfac37bSRichard Henderson case MO_ATOM_WITHIN16: 2182cdfac37bSRichard Henderson case MO_ATOM_NONE: 21838cfdacaaSRichard Henderson return do_ld_bytes_beN(p, ret_be); 2184cdfac37bSRichard Henderson 2185cdfac37bSRichard Henderson default: 2186cdfac37bSRichard Henderson g_assert_not_reached(); 21878cfdacaaSRichard Henderson } 21888cfdacaaSRichard Henderson } 21898cfdacaaSRichard Henderson 219035c653c4SRichard Henderson /* 219135c653c4SRichard Henderson * Wrapper for the above, for 8 < size < 16. 219235c653c4SRichard Henderson */ 2193d50ef446SAnton Johansson static Int128 do_ld16_beN(CPUState *cpu, MMULookupPageData *p, 219435c653c4SRichard Henderson uint64_t a, int mmu_idx, MemOp mop, uintptr_t ra) 219535c653c4SRichard Henderson { 219635c653c4SRichard Henderson int size = p->size; 219735c653c4SRichard Henderson uint64_t b; 219835c653c4SRichard Henderson MemOp atom; 219935c653c4SRichard Henderson 220035c653c4SRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 2201d50ef446SAnton Johansson return do_ld16_mmio_beN(cpu, p->full, a, p->addr, size, mmu_idx, ra); 220235c653c4SRichard Henderson } 220335c653c4SRichard Henderson 220435c653c4SRichard Henderson /* 220535c653c4SRichard Henderson * It is a given that we cross a page and therefore there is no 220635c653c4SRichard Henderson * atomicity for the load as a whole, but subobjects may need attention. 220735c653c4SRichard Henderson */ 220835c653c4SRichard Henderson atom = mop & MO_ATOM_MASK; 220935c653c4SRichard Henderson switch (atom) { 221035c653c4SRichard Henderson case MO_ATOM_SUBALIGN: 221135c653c4SRichard Henderson p->size = size - 8; 221235c653c4SRichard Henderson a = do_ld_parts_beN(p, a); 221335c653c4SRichard Henderson p->haddr += size - 8; 221435c653c4SRichard Henderson p->size = 8; 221535c653c4SRichard Henderson b = do_ld_parts_beN(p, 0); 221635c653c4SRichard Henderson break; 221735c653c4SRichard Henderson 221835c653c4SRichard Henderson case MO_ATOM_WITHIN16_PAIR: 221935c653c4SRichard Henderson /* Since size > 8, this is the half that must be atomic. */ 2220d50ef446SAnton Johansson return do_ld_whole_be16(cpu, ra, p, a); 222135c653c4SRichard Henderson 222235c653c4SRichard Henderson case MO_ATOM_IFALIGN_PAIR: 222335c653c4SRichard Henderson /* 222435c653c4SRichard Henderson * Since size > 8, both halves are misaligned, 222535c653c4SRichard Henderson * and so neither is atomic. 222635c653c4SRichard Henderson */ 222735c653c4SRichard Henderson case MO_ATOM_IFALIGN: 222835c653c4SRichard Henderson case MO_ATOM_WITHIN16: 222935c653c4SRichard Henderson case MO_ATOM_NONE: 223035c653c4SRichard Henderson p->size = size - 8; 223135c653c4SRichard Henderson a = do_ld_bytes_beN(p, a); 223235c653c4SRichard Henderson b = ldq_be_p(p->haddr + size - 8); 223335c653c4SRichard Henderson break; 223435c653c4SRichard Henderson 223535c653c4SRichard Henderson default: 223635c653c4SRichard Henderson g_assert_not_reached(); 223735c653c4SRichard Henderson } 223835c653c4SRichard Henderson 223935c653c4SRichard Henderson return int128_make128(b, a); 224035c653c4SRichard Henderson } 224135c653c4SRichard Henderson 2242d50ef446SAnton Johansson static uint8_t do_ld_1(CPUState *cpu, MMULookupPageData *p, int mmu_idx, 22438cfdacaaSRichard Henderson MMUAccessType type, uintptr_t ra) 22448cfdacaaSRichard Henderson { 22458cfdacaaSRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 2246d50ef446SAnton Johansson return do_ld_mmio_beN(cpu, p->full, 0, p->addr, 1, mmu_idx, type, ra); 22478cfdacaaSRichard Henderson } else { 22488cfdacaaSRichard Henderson return *(uint8_t *)p->haddr; 22498cfdacaaSRichard Henderson } 22508cfdacaaSRichard Henderson } 22518cfdacaaSRichard Henderson 2252d50ef446SAnton Johansson static uint16_t do_ld_2(CPUState *cpu, MMULookupPageData *p, int mmu_idx, 22538cfdacaaSRichard Henderson MMUAccessType type, MemOp memop, uintptr_t ra) 22548cfdacaaSRichard Henderson { 2255f7eaf9d7SRichard Henderson uint16_t ret; 22568cfdacaaSRichard Henderson 22578cfdacaaSRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 2258d50ef446SAnton Johansson ret = do_ld_mmio_beN(cpu, p->full, 0, p->addr, 2, mmu_idx, type, ra); 2259f7eaf9d7SRichard Henderson if ((memop & MO_BSWAP) == MO_LE) { 2260f7eaf9d7SRichard Henderson ret = bswap16(ret); 22618cfdacaaSRichard Henderson } 2262f7eaf9d7SRichard Henderson } else { 22638cfdacaaSRichard Henderson /* Perform the load host endian, then swap if necessary. */ 226473fda56fSAnton Johansson ret = load_atom_2(cpu, ra, p->haddr, memop); 22658cfdacaaSRichard Henderson if (memop & MO_BSWAP) { 22668cfdacaaSRichard Henderson ret = bswap16(ret); 22678cfdacaaSRichard Henderson } 2268f7eaf9d7SRichard Henderson } 22698cfdacaaSRichard Henderson return ret; 22708cfdacaaSRichard Henderson } 22718cfdacaaSRichard Henderson 2272d50ef446SAnton Johansson static uint32_t do_ld_4(CPUState *cpu, MMULookupPageData *p, int mmu_idx, 22738cfdacaaSRichard Henderson MMUAccessType type, MemOp memop, uintptr_t ra) 22748cfdacaaSRichard Henderson { 22758cfdacaaSRichard Henderson uint32_t ret; 22768cfdacaaSRichard Henderson 22778cfdacaaSRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 2278d50ef446SAnton Johansson ret = do_ld_mmio_beN(cpu, p->full, 0, p->addr, 4, mmu_idx, type, ra); 2279f7eaf9d7SRichard Henderson if ((memop & MO_BSWAP) == MO_LE) { 2280f7eaf9d7SRichard Henderson ret = bswap32(ret); 22818cfdacaaSRichard Henderson } 2282f7eaf9d7SRichard Henderson } else { 22838cfdacaaSRichard Henderson /* Perform the load host endian. */ 228473fda56fSAnton Johansson ret = load_atom_4(cpu, ra, p->haddr, memop); 22858cfdacaaSRichard Henderson if (memop & MO_BSWAP) { 22868cfdacaaSRichard Henderson ret = bswap32(ret); 22878cfdacaaSRichard Henderson } 2288f7eaf9d7SRichard Henderson } 22898cfdacaaSRichard Henderson return ret; 22908cfdacaaSRichard Henderson } 22918cfdacaaSRichard Henderson 2292d50ef446SAnton Johansson static uint64_t do_ld_8(CPUState *cpu, MMULookupPageData *p, int mmu_idx, 22938cfdacaaSRichard Henderson MMUAccessType type, MemOp memop, uintptr_t ra) 22948cfdacaaSRichard Henderson { 22958cfdacaaSRichard Henderson uint64_t ret; 22968cfdacaaSRichard Henderson 22978cfdacaaSRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 2298d50ef446SAnton Johansson ret = do_ld_mmio_beN(cpu, p->full, 0, p->addr, 8, mmu_idx, type, ra); 2299f7eaf9d7SRichard Henderson if ((memop & MO_BSWAP) == MO_LE) { 2300f7eaf9d7SRichard Henderson ret = bswap64(ret); 23018cfdacaaSRichard Henderson } 2302f7eaf9d7SRichard Henderson } else { 23038cfdacaaSRichard Henderson /* Perform the load host endian. */ 230473fda56fSAnton Johansson ret = load_atom_8(cpu, ra, p->haddr, memop); 23058cfdacaaSRichard Henderson if (memop & MO_BSWAP) { 23068cfdacaaSRichard Henderson ret = bswap64(ret); 23078cfdacaaSRichard Henderson } 2308f7eaf9d7SRichard Henderson } 23098cfdacaaSRichard Henderson return ret; 23108cfdacaaSRichard Henderson } 23118cfdacaaSRichard Henderson 2312d50ef446SAnton Johansson static uint8_t do_ld1_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, 23138cfdacaaSRichard Henderson uintptr_t ra, MMUAccessType access_type) 23148cfdacaaSRichard Henderson { 23158cfdacaaSRichard Henderson MMULookupLocals l; 23168cfdacaaSRichard Henderson bool crosspage; 23178cfdacaaSRichard Henderson 2318f86e8f3dSRichard Henderson cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); 2319d50ef446SAnton Johansson crosspage = mmu_lookup(cpu, addr, oi, ra, access_type, &l); 23208cfdacaaSRichard Henderson tcg_debug_assert(!crosspage); 23218cfdacaaSRichard Henderson 2322d50ef446SAnton Johansson return do_ld_1(cpu, &l.page[0], l.mmu_idx, access_type, ra); 23232dd92606SRichard Henderson } 23242dd92606SRichard Henderson 2325d50ef446SAnton Johansson static uint16_t do_ld2_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, 23268cfdacaaSRichard Henderson uintptr_t ra, MMUAccessType access_type) 23272dd92606SRichard Henderson { 23288cfdacaaSRichard Henderson MMULookupLocals l; 23298cfdacaaSRichard Henderson bool crosspage; 23308cfdacaaSRichard Henderson uint16_t ret; 23318cfdacaaSRichard Henderson uint8_t a, b; 23328cfdacaaSRichard Henderson 2333f86e8f3dSRichard Henderson cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); 2334d50ef446SAnton Johansson crosspage = mmu_lookup(cpu, addr, oi, ra, access_type, &l); 23358cfdacaaSRichard Henderson if (likely(!crosspage)) { 2336d50ef446SAnton Johansson return do_ld_2(cpu, &l.page[0], l.mmu_idx, access_type, l.memop, ra); 23378cfdacaaSRichard Henderson } 23388cfdacaaSRichard Henderson 2339d50ef446SAnton Johansson a = do_ld_1(cpu, &l.page[0], l.mmu_idx, access_type, ra); 2340d50ef446SAnton Johansson b = do_ld_1(cpu, &l.page[1], l.mmu_idx, access_type, ra); 23418cfdacaaSRichard Henderson 23428cfdacaaSRichard Henderson if ((l.memop & MO_BSWAP) == MO_LE) { 23438cfdacaaSRichard Henderson ret = a | (b << 8); 23448cfdacaaSRichard Henderson } else { 23458cfdacaaSRichard Henderson ret = b | (a << 8); 23468cfdacaaSRichard Henderson } 23478cfdacaaSRichard Henderson return ret; 2348eed56642SAlex Bennée } 2349eed56642SAlex Bennée 2350d50ef446SAnton Johansson static uint32_t do_ld4_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, 23518cfdacaaSRichard Henderson uintptr_t ra, MMUAccessType access_type) 23522dd92606SRichard Henderson { 23538cfdacaaSRichard Henderson MMULookupLocals l; 23548cfdacaaSRichard Henderson bool crosspage; 23558cfdacaaSRichard Henderson uint32_t ret; 23568cfdacaaSRichard Henderson 2357f86e8f3dSRichard Henderson cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); 2358d50ef446SAnton Johansson crosspage = mmu_lookup(cpu, addr, oi, ra, access_type, &l); 23598cfdacaaSRichard Henderson if (likely(!crosspage)) { 2360d50ef446SAnton Johansson return do_ld_4(cpu, &l.page[0], l.mmu_idx, access_type, l.memop, ra); 23618cfdacaaSRichard Henderson } 23628cfdacaaSRichard Henderson 2363d50ef446SAnton Johansson ret = do_ld_beN(cpu, &l.page[0], 0, l.mmu_idx, access_type, l.memop, ra); 2364d50ef446SAnton Johansson ret = do_ld_beN(cpu, &l.page[1], ret, l.mmu_idx, access_type, l.memop, ra); 23658cfdacaaSRichard Henderson if ((l.memop & MO_BSWAP) == MO_LE) { 23668cfdacaaSRichard Henderson ret = bswap32(ret); 23678cfdacaaSRichard Henderson } 23688cfdacaaSRichard Henderson return ret; 2369eed56642SAlex Bennée } 2370eed56642SAlex Bennée 2371d50ef446SAnton Johansson static uint64_t do_ld8_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, 23728cfdacaaSRichard Henderson uintptr_t ra, MMUAccessType access_type) 23738cfdacaaSRichard Henderson { 23748cfdacaaSRichard Henderson MMULookupLocals l; 23758cfdacaaSRichard Henderson bool crosspage; 23768cfdacaaSRichard Henderson uint64_t ret; 23778cfdacaaSRichard Henderson 2378f86e8f3dSRichard Henderson cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); 2379d50ef446SAnton Johansson crosspage = mmu_lookup(cpu, addr, oi, ra, access_type, &l); 23808cfdacaaSRichard Henderson if (likely(!crosspage)) { 2381d50ef446SAnton Johansson return do_ld_8(cpu, &l.page[0], l.mmu_idx, access_type, l.memop, ra); 23828cfdacaaSRichard Henderson } 23838cfdacaaSRichard Henderson 2384d50ef446SAnton Johansson ret = do_ld_beN(cpu, &l.page[0], 0, l.mmu_idx, access_type, l.memop, ra); 2385d50ef446SAnton Johansson ret = do_ld_beN(cpu, &l.page[1], ret, l.mmu_idx, access_type, l.memop, ra); 23868cfdacaaSRichard Henderson if ((l.memop & MO_BSWAP) == MO_LE) { 23878cfdacaaSRichard Henderson ret = bswap64(ret); 23888cfdacaaSRichard Henderson } 23898cfdacaaSRichard Henderson return ret; 2390eed56642SAlex Bennée } 2391eed56642SAlex Bennée 2392d50ef446SAnton Johansson static Int128 do_ld16_mmu(CPUState *cpu, vaddr addr, 239335c653c4SRichard Henderson MemOpIdx oi, uintptr_t ra) 239435c653c4SRichard Henderson { 239535c653c4SRichard Henderson MMULookupLocals l; 239635c653c4SRichard Henderson bool crosspage; 239735c653c4SRichard Henderson uint64_t a, b; 239835c653c4SRichard Henderson Int128 ret; 239935c653c4SRichard Henderson int first; 240035c653c4SRichard Henderson 2401f86e8f3dSRichard Henderson cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); 2402d50ef446SAnton Johansson crosspage = mmu_lookup(cpu, addr, oi, ra, MMU_DATA_LOAD, &l); 240335c653c4SRichard Henderson if (likely(!crosspage)) { 240435c653c4SRichard Henderson if (unlikely(l.page[0].flags & TLB_MMIO)) { 2405d50ef446SAnton Johansson ret = do_ld16_mmio_beN(cpu, l.page[0].full, 0, addr, 16, 24068bf67267SRichard Henderson l.mmu_idx, ra); 2407f7eaf9d7SRichard Henderson if ((l.memop & MO_BSWAP) == MO_LE) { 2408f7eaf9d7SRichard Henderson ret = bswap128(ret); 240935c653c4SRichard Henderson } 2410f7eaf9d7SRichard Henderson } else { 2411f7eaf9d7SRichard Henderson /* Perform the load host endian. */ 241273fda56fSAnton Johansson ret = load_atom_16(cpu, ra, l.page[0].haddr, l.memop); 241335c653c4SRichard Henderson if (l.memop & MO_BSWAP) { 241435c653c4SRichard Henderson ret = bswap128(ret); 241535c653c4SRichard Henderson } 2416f7eaf9d7SRichard Henderson } 241735c653c4SRichard Henderson return ret; 241835c653c4SRichard Henderson } 241935c653c4SRichard Henderson 242035c653c4SRichard Henderson first = l.page[0].size; 242135c653c4SRichard Henderson if (first == 8) { 242235c653c4SRichard Henderson MemOp mop8 = (l.memop & ~MO_SIZE) | MO_64; 242335c653c4SRichard Henderson 2424d50ef446SAnton Johansson a = do_ld_8(cpu, &l.page[0], l.mmu_idx, MMU_DATA_LOAD, mop8, ra); 2425d50ef446SAnton Johansson b = do_ld_8(cpu, &l.page[1], l.mmu_idx, MMU_DATA_LOAD, mop8, ra); 242635c653c4SRichard Henderson if ((mop8 & MO_BSWAP) == MO_LE) { 242735c653c4SRichard Henderson ret = int128_make128(a, b); 242835c653c4SRichard Henderson } else { 242935c653c4SRichard Henderson ret = int128_make128(b, a); 243035c653c4SRichard Henderson } 243135c653c4SRichard Henderson return ret; 243235c653c4SRichard Henderson } 243335c653c4SRichard Henderson 243435c653c4SRichard Henderson if (first < 8) { 2435d50ef446SAnton Johansson a = do_ld_beN(cpu, &l.page[0], 0, l.mmu_idx, 243635c653c4SRichard Henderson MMU_DATA_LOAD, l.memop, ra); 2437d50ef446SAnton Johansson ret = do_ld16_beN(cpu, &l.page[1], a, l.mmu_idx, l.memop, ra); 243835c653c4SRichard Henderson } else { 2439d50ef446SAnton Johansson ret = do_ld16_beN(cpu, &l.page[0], 0, l.mmu_idx, l.memop, ra); 244035c653c4SRichard Henderson b = int128_getlo(ret); 244135c653c4SRichard Henderson ret = int128_lshift(ret, l.page[1].size * 8); 244235c653c4SRichard Henderson a = int128_gethi(ret); 2443d50ef446SAnton Johansson b = do_ld_beN(cpu, &l.page[1], b, l.mmu_idx, 244435c653c4SRichard Henderson MMU_DATA_LOAD, l.memop, ra); 244535c653c4SRichard Henderson ret = int128_make128(b, a); 244635c653c4SRichard Henderson } 244735c653c4SRichard Henderson if ((l.memop & MO_BSWAP) == MO_LE) { 244835c653c4SRichard Henderson ret = bswap128(ret); 244935c653c4SRichard Henderson } 245035c653c4SRichard Henderson return ret; 245135c653c4SRichard Henderson } 245235c653c4SRichard Henderson 2453d03f1408SRichard Henderson /* 2454eed56642SAlex Bennée * Store Helpers 2455eed56642SAlex Bennée */ 2456eed56642SAlex Bennée 245759213461SRichard Henderson /** 245859213461SRichard Henderson * do_st_mmio_leN: 2459d50ef446SAnton Johansson * @cpu: generic cpu state 24601966855eSRichard Henderson * @full: page parameters 246159213461SRichard Henderson * @val_le: data to store 24621966855eSRichard Henderson * @addr: virtual address 24631966855eSRichard Henderson * @size: number of bytes 246459213461SRichard Henderson * @mmu_idx: virtual address context 246559213461SRichard Henderson * @ra: return address into tcg generated code, or 0 2466a4a411fbSStefan Hajnoczi * Context: BQL held 246759213461SRichard Henderson * 24681966855eSRichard Henderson * Store @size bytes at @addr, which is memory-mapped i/o. 246959213461SRichard Henderson * The bytes to store are extracted in little-endian order from @val_le; 247059213461SRichard Henderson * return the bytes of @val_le beyond @p->size that have not been stored. 247159213461SRichard Henderson */ 2472d50ef446SAnton Johansson static uint64_t int_st_mmio_leN(CPUState *cpu, CPUTLBEntryFull *full, 24731966855eSRichard Henderson uint64_t val_le, vaddr addr, int size, 24741f9823ceSRichard Henderson int mmu_idx, uintptr_t ra, 24751f9823ceSRichard Henderson MemoryRegion *mr, hwaddr mr_offset) 24766b8b622eSRichard Henderson { 2477190aba80SRichard Henderson do { 24785646d6a7SRichard Henderson MemOp this_mop; 24795646d6a7SRichard Henderson unsigned this_size; 24805646d6a7SRichard Henderson MemTxResult r; 24815646d6a7SRichard Henderson 2482190aba80SRichard Henderson /* Store aligned pieces up to 8 bytes. */ 24835646d6a7SRichard Henderson this_mop = ctz32(size | (int)addr | 8); 24845646d6a7SRichard Henderson this_size = 1 << this_mop; 24855646d6a7SRichard Henderson this_mop |= MO_LE; 24865646d6a7SRichard Henderson 24875646d6a7SRichard Henderson r = memory_region_dispatch_write(mr, mr_offset, val_le, 24881f9823ceSRichard Henderson this_mop, full->attrs); 24895646d6a7SRichard Henderson if (unlikely(r != MEMTX_OK)) { 2490d50ef446SAnton Johansson io_failed(cpu, full, addr, this_size, MMU_DATA_STORE, 24915646d6a7SRichard Henderson mmu_idx, r, ra); 249259213461SRichard Henderson } 24935646d6a7SRichard Henderson if (this_size == 8) { 24945646d6a7SRichard Henderson return 0; 24955646d6a7SRichard Henderson } 24965646d6a7SRichard Henderson 24975646d6a7SRichard Henderson val_le >>= this_size * 8; 24985646d6a7SRichard Henderson addr += this_size; 24995646d6a7SRichard Henderson mr_offset += this_size; 25005646d6a7SRichard Henderson size -= this_size; 2501190aba80SRichard Henderson } while (size); 2502190aba80SRichard Henderson 250359213461SRichard Henderson return val_le; 250459213461SRichard Henderson } 250559213461SRichard Henderson 2506d50ef446SAnton Johansson static uint64_t do_st_mmio_leN(CPUState *cpu, CPUTLBEntryFull *full, 25071f9823ceSRichard Henderson uint64_t val_le, vaddr addr, int size, 25081f9823ceSRichard Henderson int mmu_idx, uintptr_t ra) 25091f9823ceSRichard Henderson { 25101f9823ceSRichard Henderson MemoryRegionSection *section; 25111f9823ceSRichard Henderson hwaddr mr_offset; 25121f9823ceSRichard Henderson MemoryRegion *mr; 25131f9823ceSRichard Henderson MemTxAttrs attrs; 25141f9823ceSRichard Henderson 25151f9823ceSRichard Henderson tcg_debug_assert(size > 0 && size <= 8); 25161f9823ceSRichard Henderson 25171f9823ceSRichard Henderson attrs = full->attrs; 2518d50ef446SAnton Johansson section = io_prepare(&mr_offset, cpu, full->xlat_section, attrs, addr, ra); 25191f9823ceSRichard Henderson mr = section->mr; 25201f9823ceSRichard Henderson 25216aba908dSJonathan Cameron BQL_LOCK_GUARD(); 25226aba908dSJonathan Cameron return int_st_mmio_leN(cpu, full, val_le, addr, size, mmu_idx, 25231f9823ceSRichard Henderson ra, mr, mr_offset); 25241f9823ceSRichard Henderson } 25251f9823ceSRichard Henderson 2526d50ef446SAnton Johansson static uint64_t do_st16_mmio_leN(CPUState *cpu, CPUTLBEntryFull *full, 25271f9823ceSRichard Henderson Int128 val_le, vaddr addr, int size, 25281f9823ceSRichard Henderson int mmu_idx, uintptr_t ra) 25291f9823ceSRichard Henderson { 25301f9823ceSRichard Henderson MemoryRegionSection *section; 25311f9823ceSRichard Henderson MemoryRegion *mr; 25321f9823ceSRichard Henderson hwaddr mr_offset; 25331f9823ceSRichard Henderson MemTxAttrs attrs; 25341f9823ceSRichard Henderson 25351f9823ceSRichard Henderson tcg_debug_assert(size > 8 && size <= 16); 25361f9823ceSRichard Henderson 25371f9823ceSRichard Henderson attrs = full->attrs; 2538d50ef446SAnton Johansson section = io_prepare(&mr_offset, cpu, full->xlat_section, attrs, addr, ra); 25391f9823ceSRichard Henderson mr = section->mr; 25401f9823ceSRichard Henderson 25416aba908dSJonathan Cameron BQL_LOCK_GUARD(); 2542d50ef446SAnton Johansson int_st_mmio_leN(cpu, full, int128_getlo(val_le), addr, 8, 25431f9823ceSRichard Henderson mmu_idx, ra, mr, mr_offset); 25446aba908dSJonathan Cameron return int_st_mmio_leN(cpu, full, int128_gethi(val_le), addr + 8, 25451f9823ceSRichard Henderson size - 8, mmu_idx, ra, mr, mr_offset + 8); 25461f9823ceSRichard Henderson } 25471f9823ceSRichard Henderson 25486b8b622eSRichard Henderson /* 254959213461SRichard Henderson * Wrapper for the above. 25506b8b622eSRichard Henderson */ 2551d50ef446SAnton Johansson static uint64_t do_st_leN(CPUState *cpu, MMULookupPageData *p, 25525b36f268SRichard Henderson uint64_t val_le, int mmu_idx, 25535b36f268SRichard Henderson MemOp mop, uintptr_t ra) 255459213461SRichard Henderson { 25555b36f268SRichard Henderson MemOp atom; 25565b36f268SRichard Henderson unsigned tmp, half_size; 25575b36f268SRichard Henderson 255859213461SRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 2559d50ef446SAnton Johansson return do_st_mmio_leN(cpu, p->full, val_le, p->addr, 25601966855eSRichard Henderson p->size, mmu_idx, ra); 256159213461SRichard Henderson } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { 256259213461SRichard Henderson return val_le >> (p->size * 8); 25635b36f268SRichard Henderson } 25645b36f268SRichard Henderson 25655b36f268SRichard Henderson /* 25665b36f268SRichard Henderson * It is a given that we cross a page and therefore there is no atomicity 25675b36f268SRichard Henderson * for the store as a whole, but subobjects may need attention. 25685b36f268SRichard Henderson */ 25695b36f268SRichard Henderson atom = mop & MO_ATOM_MASK; 25705b36f268SRichard Henderson switch (atom) { 25715b36f268SRichard Henderson case MO_ATOM_SUBALIGN: 25725b36f268SRichard Henderson return store_parts_leN(p->haddr, p->size, val_le); 25735b36f268SRichard Henderson 25745b36f268SRichard Henderson case MO_ATOM_IFALIGN_PAIR: 25755b36f268SRichard Henderson case MO_ATOM_WITHIN16_PAIR: 25765b36f268SRichard Henderson tmp = mop & MO_SIZE; 25775b36f268SRichard Henderson tmp = tmp ? tmp - 1 : 0; 25785b36f268SRichard Henderson half_size = 1 << tmp; 25795b36f268SRichard Henderson if (atom == MO_ATOM_IFALIGN_PAIR 25805b36f268SRichard Henderson ? p->size == half_size 25815b36f268SRichard Henderson : p->size >= half_size) { 25825b36f268SRichard Henderson if (!HAVE_al8_fast && p->size <= 4) { 25835b36f268SRichard Henderson return store_whole_le4(p->haddr, p->size, val_le); 25845b36f268SRichard Henderson } else if (HAVE_al8) { 25855b36f268SRichard Henderson return store_whole_le8(p->haddr, p->size, val_le); 25866b8b622eSRichard Henderson } else { 2587d50ef446SAnton Johansson cpu_loop_exit_atomic(cpu, ra); 25885b36f268SRichard Henderson } 25895b36f268SRichard Henderson } 25905b36f268SRichard Henderson /* fall through */ 25915b36f268SRichard Henderson 25925b36f268SRichard Henderson case MO_ATOM_IFALIGN: 25935b36f268SRichard Henderson case MO_ATOM_WITHIN16: 25945b36f268SRichard Henderson case MO_ATOM_NONE: 25955b36f268SRichard Henderson return store_bytes_leN(p->haddr, p->size, val_le); 25965b36f268SRichard Henderson 25975b36f268SRichard Henderson default: 25985b36f268SRichard Henderson g_assert_not_reached(); 25996b8b622eSRichard Henderson } 26006b8b622eSRichard Henderson } 26016b8b622eSRichard Henderson 260235c653c4SRichard Henderson /* 260335c653c4SRichard Henderson * Wrapper for the above, for 8 < size < 16. 260435c653c4SRichard Henderson */ 2605d50ef446SAnton Johansson static uint64_t do_st16_leN(CPUState *cpu, MMULookupPageData *p, 260635c653c4SRichard Henderson Int128 val_le, int mmu_idx, 260735c653c4SRichard Henderson MemOp mop, uintptr_t ra) 260835c653c4SRichard Henderson { 260935c653c4SRichard Henderson int size = p->size; 261035c653c4SRichard Henderson MemOp atom; 261135c653c4SRichard Henderson 261235c653c4SRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 2613d50ef446SAnton Johansson return do_st16_mmio_leN(cpu, p->full, val_le, p->addr, 26141f9823ceSRichard Henderson size, mmu_idx, ra); 261535c653c4SRichard Henderson } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { 261635c653c4SRichard Henderson return int128_gethi(val_le) >> ((size - 8) * 8); 261735c653c4SRichard Henderson } 261835c653c4SRichard Henderson 261935c653c4SRichard Henderson /* 262035c653c4SRichard Henderson * It is a given that we cross a page and therefore there is no atomicity 262135c653c4SRichard Henderson * for the store as a whole, but subobjects may need attention. 262235c653c4SRichard Henderson */ 262335c653c4SRichard Henderson atom = mop & MO_ATOM_MASK; 262435c653c4SRichard Henderson switch (atom) { 262535c653c4SRichard Henderson case MO_ATOM_SUBALIGN: 262635c653c4SRichard Henderson store_parts_leN(p->haddr, 8, int128_getlo(val_le)); 262735c653c4SRichard Henderson return store_parts_leN(p->haddr + 8, p->size - 8, 262835c653c4SRichard Henderson int128_gethi(val_le)); 262935c653c4SRichard Henderson 263035c653c4SRichard Henderson case MO_ATOM_WITHIN16_PAIR: 263135c653c4SRichard Henderson /* Since size > 8, this is the half that must be atomic. */ 26326046f6e9SRichard Henderson if (!HAVE_CMPXCHG128) { 2633d50ef446SAnton Johansson cpu_loop_exit_atomic(cpu, ra); 263435c653c4SRichard Henderson } 263535c653c4SRichard Henderson return store_whole_le16(p->haddr, p->size, val_le); 263635c653c4SRichard Henderson 263735c653c4SRichard Henderson case MO_ATOM_IFALIGN_PAIR: 263835c653c4SRichard Henderson /* 263935c653c4SRichard Henderson * Since size > 8, both halves are misaligned, 264035c653c4SRichard Henderson * and so neither is atomic. 264135c653c4SRichard Henderson */ 264235c653c4SRichard Henderson case MO_ATOM_IFALIGN: 26432be6a486SRichard Henderson case MO_ATOM_WITHIN16: 264435c653c4SRichard Henderson case MO_ATOM_NONE: 264535c653c4SRichard Henderson stq_le_p(p->haddr, int128_getlo(val_le)); 264635c653c4SRichard Henderson return store_bytes_leN(p->haddr + 8, p->size - 8, 264735c653c4SRichard Henderson int128_gethi(val_le)); 264835c653c4SRichard Henderson 264935c653c4SRichard Henderson default: 265035c653c4SRichard Henderson g_assert_not_reached(); 265135c653c4SRichard Henderson } 265235c653c4SRichard Henderson } 265335c653c4SRichard Henderson 2654d50ef446SAnton Johansson static void do_st_1(CPUState *cpu, MMULookupPageData *p, uint8_t val, 265559213461SRichard Henderson int mmu_idx, uintptr_t ra) 2656eed56642SAlex Bennée { 265759213461SRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 2658d50ef446SAnton Johansson do_st_mmio_leN(cpu, p->full, val, p->addr, 1, mmu_idx, ra); 265959213461SRichard Henderson } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { 266059213461SRichard Henderson /* nothing */ 26615b87b3e6SRichard Henderson } else { 266259213461SRichard Henderson *(uint8_t *)p->haddr = val; 26635b87b3e6SRichard Henderson } 2664eed56642SAlex Bennée } 2665eed56642SAlex Bennée 2666d50ef446SAnton Johansson static void do_st_2(CPUState *cpu, MMULookupPageData *p, uint16_t val, 266759213461SRichard Henderson int mmu_idx, MemOp memop, uintptr_t ra) 2668eed56642SAlex Bennée { 266959213461SRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 2670f7eaf9d7SRichard Henderson if ((memop & MO_BSWAP) != MO_LE) { 2671f7eaf9d7SRichard Henderson val = bswap16(val); 2672f7eaf9d7SRichard Henderson } 2673d50ef446SAnton Johansson do_st_mmio_leN(cpu, p->full, val, p->addr, 2, mmu_idx, ra); 267459213461SRichard Henderson } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { 267559213461SRichard Henderson /* nothing */ 267659213461SRichard Henderson } else { 267759213461SRichard Henderson /* Swap to host endian if necessary, then store. */ 267859213461SRichard Henderson if (memop & MO_BSWAP) { 267959213461SRichard Henderson val = bswap16(val); 268059213461SRichard Henderson } 268173fda56fSAnton Johansson store_atom_2(cpu, ra, p->haddr, memop, val); 268259213461SRichard Henderson } 268359213461SRichard Henderson } 268459213461SRichard Henderson 2685d50ef446SAnton Johansson static void do_st_4(CPUState *cpu, MMULookupPageData *p, uint32_t val, 268659213461SRichard Henderson int mmu_idx, MemOp memop, uintptr_t ra) 268759213461SRichard Henderson { 268859213461SRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 2689f7eaf9d7SRichard Henderson if ((memop & MO_BSWAP) != MO_LE) { 2690f7eaf9d7SRichard Henderson val = bswap32(val); 2691f7eaf9d7SRichard Henderson } 2692d50ef446SAnton Johansson do_st_mmio_leN(cpu, p->full, val, p->addr, 4, mmu_idx, ra); 269359213461SRichard Henderson } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { 269459213461SRichard Henderson /* nothing */ 269559213461SRichard Henderson } else { 269659213461SRichard Henderson /* Swap to host endian if necessary, then store. */ 269759213461SRichard Henderson if (memop & MO_BSWAP) { 269859213461SRichard Henderson val = bswap32(val); 269959213461SRichard Henderson } 270073fda56fSAnton Johansson store_atom_4(cpu, ra, p->haddr, memop, val); 270159213461SRichard Henderson } 270259213461SRichard Henderson } 270359213461SRichard Henderson 2704d50ef446SAnton Johansson static void do_st_8(CPUState *cpu, MMULookupPageData *p, uint64_t val, 270559213461SRichard Henderson int mmu_idx, MemOp memop, uintptr_t ra) 270659213461SRichard Henderson { 270759213461SRichard Henderson if (unlikely(p->flags & TLB_MMIO)) { 2708f7eaf9d7SRichard Henderson if ((memop & MO_BSWAP) != MO_LE) { 2709f7eaf9d7SRichard Henderson val = bswap64(val); 2710f7eaf9d7SRichard Henderson } 2711d50ef446SAnton Johansson do_st_mmio_leN(cpu, p->full, val, p->addr, 8, mmu_idx, ra); 271259213461SRichard Henderson } else if (unlikely(p->flags & TLB_DISCARD_WRITE)) { 271359213461SRichard Henderson /* nothing */ 271459213461SRichard Henderson } else { 271559213461SRichard Henderson /* Swap to host endian if necessary, then store. */ 271659213461SRichard Henderson if (memop & MO_BSWAP) { 271759213461SRichard Henderson val = bswap64(val); 271859213461SRichard Henderson } 271973fda56fSAnton Johansson store_atom_8(cpu, ra, p->haddr, memop, val); 272059213461SRichard Henderson } 2721eed56642SAlex Bennée } 2722eed56642SAlex Bennée 2723e20f73fbSAnton Johansson static void do_st1_mmu(CPUState *cpu, vaddr addr, uint8_t val, 272459213461SRichard Henderson MemOpIdx oi, uintptr_t ra) 2725f83bcecbSRichard Henderson { 272659213461SRichard Henderson MMULookupLocals l; 272759213461SRichard Henderson bool crosspage; 272859213461SRichard Henderson 2729f86e8f3dSRichard Henderson cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); 2730e20f73fbSAnton Johansson crosspage = mmu_lookup(cpu, addr, oi, ra, MMU_DATA_STORE, &l); 273159213461SRichard Henderson tcg_debug_assert(!crosspage); 273259213461SRichard Henderson 2733e20f73fbSAnton Johansson do_st_1(cpu, &l.page[0], val, l.mmu_idx, ra); 2734e20f73fbSAnton Johansson } 2735e20f73fbSAnton Johansson 2736d50ef446SAnton Johansson static void do_st2_mmu(CPUState *cpu, vaddr addr, uint16_t val, 273759213461SRichard Henderson MemOpIdx oi, uintptr_t ra) 2738f83bcecbSRichard Henderson { 273959213461SRichard Henderson MMULookupLocals l; 274059213461SRichard Henderson bool crosspage; 274159213461SRichard Henderson uint8_t a, b; 274259213461SRichard Henderson 2743f86e8f3dSRichard Henderson cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); 2744d50ef446SAnton Johansson crosspage = mmu_lookup(cpu, addr, oi, ra, MMU_DATA_STORE, &l); 274559213461SRichard Henderson if (likely(!crosspage)) { 2746d50ef446SAnton Johansson do_st_2(cpu, &l.page[0], val, l.mmu_idx, l.memop, ra); 274759213461SRichard Henderson return; 274859213461SRichard Henderson } 274959213461SRichard Henderson 275059213461SRichard Henderson if ((l.memop & MO_BSWAP) == MO_LE) { 275159213461SRichard Henderson a = val, b = val >> 8; 275259213461SRichard Henderson } else { 275359213461SRichard Henderson b = val, a = val >> 8; 275459213461SRichard Henderson } 2755d50ef446SAnton Johansson do_st_1(cpu, &l.page[0], a, l.mmu_idx, ra); 2756d50ef446SAnton Johansson do_st_1(cpu, &l.page[1], b, l.mmu_idx, ra); 2757f83bcecbSRichard Henderson } 2758f83bcecbSRichard Henderson 2759d50ef446SAnton Johansson static void do_st4_mmu(CPUState *cpu, vaddr addr, uint32_t val, 276059213461SRichard Henderson MemOpIdx oi, uintptr_t ra) 2761f83bcecbSRichard Henderson { 276259213461SRichard Henderson MMULookupLocals l; 276359213461SRichard Henderson bool crosspage; 276459213461SRichard Henderson 2765f86e8f3dSRichard Henderson cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); 2766d50ef446SAnton Johansson crosspage = mmu_lookup(cpu, addr, oi, ra, MMU_DATA_STORE, &l); 276759213461SRichard Henderson if (likely(!crosspage)) { 2768d50ef446SAnton Johansson do_st_4(cpu, &l.page[0], val, l.mmu_idx, l.memop, ra); 276959213461SRichard Henderson return; 277059213461SRichard Henderson } 277159213461SRichard Henderson 277259213461SRichard Henderson /* Swap to little endian for simplicity, then store by bytes. */ 277359213461SRichard Henderson if ((l.memop & MO_BSWAP) != MO_LE) { 277459213461SRichard Henderson val = bswap32(val); 277559213461SRichard Henderson } 2776d50ef446SAnton Johansson val = do_st_leN(cpu, &l.page[0], val, l.mmu_idx, l.memop, ra); 2777d50ef446SAnton Johansson (void) do_st_leN(cpu, &l.page[1], val, l.mmu_idx, l.memop, ra); 2778eed56642SAlex Bennée } 2779eed56642SAlex Bennée 2780d50ef446SAnton Johansson static void do_st8_mmu(CPUState *cpu, vaddr addr, uint64_t val, 278159213461SRichard Henderson MemOpIdx oi, uintptr_t ra) 278259213461SRichard Henderson { 278359213461SRichard Henderson MMULookupLocals l; 278459213461SRichard Henderson bool crosspage; 278559213461SRichard Henderson 2786f86e8f3dSRichard Henderson cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); 2787d50ef446SAnton Johansson crosspage = mmu_lookup(cpu, addr, oi, ra, MMU_DATA_STORE, &l); 278859213461SRichard Henderson if (likely(!crosspage)) { 2789d50ef446SAnton Johansson do_st_8(cpu, &l.page[0], val, l.mmu_idx, l.memop, ra); 279059213461SRichard Henderson return; 279159213461SRichard Henderson } 279259213461SRichard Henderson 279359213461SRichard Henderson /* Swap to little endian for simplicity, then store by bytes. */ 279459213461SRichard Henderson if ((l.memop & MO_BSWAP) != MO_LE) { 279559213461SRichard Henderson val = bswap64(val); 279659213461SRichard Henderson } 2797d50ef446SAnton Johansson val = do_st_leN(cpu, &l.page[0], val, l.mmu_idx, l.memop, ra); 2798d50ef446SAnton Johansson (void) do_st_leN(cpu, &l.page[1], val, l.mmu_idx, l.memop, ra); 2799eed56642SAlex Bennée } 2800eed56642SAlex Bennée 2801d50ef446SAnton Johansson static void do_st16_mmu(CPUState *cpu, vaddr addr, Int128 val, 280235c653c4SRichard Henderson MemOpIdx oi, uintptr_t ra) 280335c653c4SRichard Henderson { 280435c653c4SRichard Henderson MMULookupLocals l; 280535c653c4SRichard Henderson bool crosspage; 280635c653c4SRichard Henderson uint64_t a, b; 280735c653c4SRichard Henderson int first; 280835c653c4SRichard Henderson 2809f86e8f3dSRichard Henderson cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); 2810d50ef446SAnton Johansson crosspage = mmu_lookup(cpu, addr, oi, ra, MMU_DATA_STORE, &l); 281135c653c4SRichard Henderson if (likely(!crosspage)) { 2812f7eaf9d7SRichard Henderson if (unlikely(l.page[0].flags & TLB_MMIO)) { 2813f7eaf9d7SRichard Henderson if ((l.memop & MO_BSWAP) != MO_LE) { 2814f7eaf9d7SRichard Henderson val = bswap128(val); 2815f7eaf9d7SRichard Henderson } 2816d50ef446SAnton Johansson do_st16_mmio_leN(cpu, l.page[0].full, val, addr, 16, l.mmu_idx, ra); 2817f7eaf9d7SRichard Henderson } else if (unlikely(l.page[0].flags & TLB_DISCARD_WRITE)) { 2818f7eaf9d7SRichard Henderson /* nothing */ 2819f7eaf9d7SRichard Henderson } else { 282035c653c4SRichard Henderson /* Swap to host endian if necessary, then store. */ 282135c653c4SRichard Henderson if (l.memop & MO_BSWAP) { 282235c653c4SRichard Henderson val = bswap128(val); 282335c653c4SRichard Henderson } 282473fda56fSAnton Johansson store_atom_16(cpu, ra, l.page[0].haddr, l.memop, val); 282535c653c4SRichard Henderson } 282635c653c4SRichard Henderson return; 282735c653c4SRichard Henderson } 282835c653c4SRichard Henderson 282935c653c4SRichard Henderson first = l.page[0].size; 283035c653c4SRichard Henderson if (first == 8) { 283135c653c4SRichard Henderson MemOp mop8 = (l.memop & ~(MO_SIZE | MO_BSWAP)) | MO_64; 283235c653c4SRichard Henderson 283335c653c4SRichard Henderson if (l.memop & MO_BSWAP) { 283435c653c4SRichard Henderson val = bswap128(val); 283535c653c4SRichard Henderson } 283635c653c4SRichard Henderson if (HOST_BIG_ENDIAN) { 283735c653c4SRichard Henderson b = int128_getlo(val), a = int128_gethi(val); 283835c653c4SRichard Henderson } else { 283935c653c4SRichard Henderson a = int128_getlo(val), b = int128_gethi(val); 284035c653c4SRichard Henderson } 2841d50ef446SAnton Johansson do_st_8(cpu, &l.page[0], a, l.mmu_idx, mop8, ra); 2842d50ef446SAnton Johansson do_st_8(cpu, &l.page[1], b, l.mmu_idx, mop8, ra); 284335c653c4SRichard Henderson return; 284435c653c4SRichard Henderson } 284535c653c4SRichard Henderson 284635c653c4SRichard Henderson if ((l.memop & MO_BSWAP) != MO_LE) { 284735c653c4SRichard Henderson val = bswap128(val); 284835c653c4SRichard Henderson } 284935c653c4SRichard Henderson if (first < 8) { 2850d50ef446SAnton Johansson do_st_leN(cpu, &l.page[0], int128_getlo(val), l.mmu_idx, l.memop, ra); 285135c653c4SRichard Henderson val = int128_urshift(val, first * 8); 2852d50ef446SAnton Johansson do_st16_leN(cpu, &l.page[1], val, l.mmu_idx, l.memop, ra); 285335c653c4SRichard Henderson } else { 2854d50ef446SAnton Johansson b = do_st16_leN(cpu, &l.page[0], val, l.mmu_idx, l.memop, ra); 2855d50ef446SAnton Johansson do_st_leN(cpu, &l.page[1], b, l.mmu_idx, l.memop, ra); 285635c653c4SRichard Henderson } 285735c653c4SRichard Henderson } 285835c653c4SRichard Henderson 2859f83bcecbSRichard Henderson #include "ldst_common.c.inc" 2860cfe04a4bSRichard Henderson 2861be9568b4SRichard Henderson /* 2862be9568b4SRichard Henderson * First set of functions passes in OI and RETADDR. 2863be9568b4SRichard Henderson * This makes them callable from other helpers. 2864be9568b4SRichard Henderson */ 2865d9bb58e5SYang Zhong 2866d9bb58e5SYang Zhong #define ATOMIC_NAME(X) \ 2867be9568b4SRichard Henderson glue(glue(glue(cpu_atomic_ ## X, SUFFIX), END), _mmu) 2868a754f7f3SRichard Henderson 2869707526adSRichard Henderson #define ATOMIC_MMU_CLEANUP 2870d9bb58e5SYang Zhong 2871139c1837SPaolo Bonzini #include "atomic_common.c.inc" 2872d9bb58e5SYang Zhong 2873d9bb58e5SYang Zhong #define DATA_SIZE 1 2874d9bb58e5SYang Zhong #include "atomic_template.h" 2875d9bb58e5SYang Zhong 2876d9bb58e5SYang Zhong #define DATA_SIZE 2 2877d9bb58e5SYang Zhong #include "atomic_template.h" 2878d9bb58e5SYang Zhong 2879d9bb58e5SYang Zhong #define DATA_SIZE 4 2880d9bb58e5SYang Zhong #include "atomic_template.h" 2881d9bb58e5SYang Zhong 2882d9bb58e5SYang Zhong #ifdef CONFIG_ATOMIC64 2883d9bb58e5SYang Zhong #define DATA_SIZE 8 2884d9bb58e5SYang Zhong #include "atomic_template.h" 2885d9bb58e5SYang Zhong #endif 2886d9bb58e5SYang Zhong 288776f9d6adSRichard Henderson #if defined(CONFIG_ATOMIC128) || HAVE_CMPXCHG128 2888d9bb58e5SYang Zhong #define DATA_SIZE 16 2889d9bb58e5SYang Zhong #include "atomic_template.h" 2890d9bb58e5SYang Zhong #endif 2891d9bb58e5SYang Zhong 2892d9bb58e5SYang Zhong /* Code access functions. */ 2893d9bb58e5SYang Zhong 2894fc4120a3SRichard Henderson uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr addr) 2895eed56642SAlex Bennée { 28963b916140SRichard Henderson CPUState *cs = env_cpu(env); 28973b916140SRichard Henderson MemOpIdx oi = make_memop_idx(MO_UB, cpu_mmu_index(cs, true)); 28983b916140SRichard Henderson return do_ld1_mmu(cs, addr, oi, 0, MMU_INST_FETCH); 28994cef72d0SAlex Bennée } 29004cef72d0SAlex Bennée 2901fc4120a3SRichard Henderson uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr addr) 29022dd92606SRichard Henderson { 29033b916140SRichard Henderson CPUState *cs = env_cpu(env); 29043b916140SRichard Henderson MemOpIdx oi = make_memop_idx(MO_TEUW, cpu_mmu_index(cs, true)); 29053b916140SRichard Henderson return do_ld2_mmu(cs, addr, oi, 0, MMU_INST_FETCH); 29062dd92606SRichard Henderson } 29072dd92606SRichard Henderson 2908fc4120a3SRichard Henderson uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr addr) 29094cef72d0SAlex Bennée { 29103b916140SRichard Henderson CPUState *cs = env_cpu(env); 29113b916140SRichard Henderson MemOpIdx oi = make_memop_idx(MO_TEUL, cpu_mmu_index(cs, true)); 29123b916140SRichard Henderson return do_ld4_mmu(cs, addr, oi, 0, MMU_INST_FETCH); 2913eed56642SAlex Bennée } 2914d9bb58e5SYang Zhong 2915fc4120a3SRichard Henderson uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr addr) 2916eed56642SAlex Bennée { 29173b916140SRichard Henderson CPUState *cs = env_cpu(env); 29183b916140SRichard Henderson MemOpIdx oi = make_memop_idx(MO_TEUQ, cpu_mmu_index(cs, true)); 29193b916140SRichard Henderson return do_ld8_mmu(cs, addr, oi, 0, MMU_INST_FETCH); 2920eed56642SAlex Bennée } 292128990626SRichard Henderson 292228990626SRichard Henderson uint8_t cpu_ldb_code_mmu(CPUArchState *env, abi_ptr addr, 292328990626SRichard Henderson MemOpIdx oi, uintptr_t retaddr) 292428990626SRichard Henderson { 2925d50ef446SAnton Johansson return do_ld1_mmu(env_cpu(env), addr, oi, retaddr, MMU_INST_FETCH); 292628990626SRichard Henderson } 292728990626SRichard Henderson 292828990626SRichard Henderson uint16_t cpu_ldw_code_mmu(CPUArchState *env, abi_ptr addr, 292928990626SRichard Henderson MemOpIdx oi, uintptr_t retaddr) 293028990626SRichard Henderson { 2931d50ef446SAnton Johansson return do_ld2_mmu(env_cpu(env), addr, oi, retaddr, MMU_INST_FETCH); 293228990626SRichard Henderson } 293328990626SRichard Henderson 293428990626SRichard Henderson uint32_t cpu_ldl_code_mmu(CPUArchState *env, abi_ptr addr, 293528990626SRichard Henderson MemOpIdx oi, uintptr_t retaddr) 293628990626SRichard Henderson { 2937d50ef446SAnton Johansson return do_ld4_mmu(env_cpu(env), addr, oi, retaddr, MMU_INST_FETCH); 293828990626SRichard Henderson } 293928990626SRichard Henderson 294028990626SRichard Henderson uint64_t cpu_ldq_code_mmu(CPUArchState *env, abi_ptr addr, 294128990626SRichard Henderson MemOpIdx oi, uintptr_t retaddr) 294228990626SRichard Henderson { 2943d50ef446SAnton Johansson return do_ld8_mmu(env_cpu(env), addr, oi, retaddr, MMU_INST_FETCH); 294428990626SRichard Henderson } 2945