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