xref: /openbmc/qemu/target/ppc/mmu_helper.c (revision fcf5ef2ab52c621a4617ebbef36bf43b4003f4c0)
1*fcf5ef2aSThomas Huth /*
2*fcf5ef2aSThomas Huth  *  PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU.
3*fcf5ef2aSThomas Huth  *
4*fcf5ef2aSThomas Huth  *  Copyright (c) 2003-2007 Jocelyn Mayer
5*fcf5ef2aSThomas Huth  *
6*fcf5ef2aSThomas Huth  * This library is free software; you can redistribute it and/or
7*fcf5ef2aSThomas Huth  * modify it under the terms of the GNU Lesser General Public
8*fcf5ef2aSThomas Huth  * License as published by the Free Software Foundation; either
9*fcf5ef2aSThomas Huth  * version 2 of the License, or (at your option) any later version.
10*fcf5ef2aSThomas Huth  *
11*fcf5ef2aSThomas Huth  * This library is distributed in the hope that it will be useful,
12*fcf5ef2aSThomas Huth  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*fcf5ef2aSThomas Huth  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14*fcf5ef2aSThomas Huth  * Lesser General Public License for more details.
15*fcf5ef2aSThomas Huth  *
16*fcf5ef2aSThomas Huth  * You should have received a copy of the GNU Lesser General Public
17*fcf5ef2aSThomas Huth  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18*fcf5ef2aSThomas Huth  */
19*fcf5ef2aSThomas Huth #include "qemu/osdep.h"
20*fcf5ef2aSThomas Huth #include "qapi/error.h"
21*fcf5ef2aSThomas Huth #include "cpu.h"
22*fcf5ef2aSThomas Huth #include "exec/helper-proto.h"
23*fcf5ef2aSThomas Huth #include "sysemu/kvm.h"
24*fcf5ef2aSThomas Huth #include "kvm_ppc.h"
25*fcf5ef2aSThomas Huth #include "mmu-hash64.h"
26*fcf5ef2aSThomas Huth #include "mmu-hash32.h"
27*fcf5ef2aSThomas Huth #include "exec/exec-all.h"
28*fcf5ef2aSThomas Huth #include "exec/cpu_ldst.h"
29*fcf5ef2aSThomas Huth #include "exec/log.h"
30*fcf5ef2aSThomas Huth #include "helper_regs.h"
31*fcf5ef2aSThomas Huth 
32*fcf5ef2aSThomas Huth //#define DEBUG_MMU
33*fcf5ef2aSThomas Huth //#define DEBUG_BATS
34*fcf5ef2aSThomas Huth //#define DEBUG_SOFTWARE_TLB
35*fcf5ef2aSThomas Huth //#define DUMP_PAGE_TABLES
36*fcf5ef2aSThomas Huth //#define FLUSH_ALL_TLBS
37*fcf5ef2aSThomas Huth 
38*fcf5ef2aSThomas Huth #ifdef DEBUG_MMU
39*fcf5ef2aSThomas Huth #  define LOG_MMU_STATE(cpu) log_cpu_state_mask(CPU_LOG_MMU, (cpu), 0)
40*fcf5ef2aSThomas Huth #else
41*fcf5ef2aSThomas Huth #  define LOG_MMU_STATE(cpu) do { } while (0)
42*fcf5ef2aSThomas Huth #endif
43*fcf5ef2aSThomas Huth 
44*fcf5ef2aSThomas Huth #ifdef DEBUG_SOFTWARE_TLB
45*fcf5ef2aSThomas Huth #  define LOG_SWTLB(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
46*fcf5ef2aSThomas Huth #else
47*fcf5ef2aSThomas Huth #  define LOG_SWTLB(...) do { } while (0)
48*fcf5ef2aSThomas Huth #endif
49*fcf5ef2aSThomas Huth 
50*fcf5ef2aSThomas Huth #ifdef DEBUG_BATS
51*fcf5ef2aSThomas Huth #  define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
52*fcf5ef2aSThomas Huth #else
53*fcf5ef2aSThomas Huth #  define LOG_BATS(...) do { } while (0)
54*fcf5ef2aSThomas Huth #endif
55*fcf5ef2aSThomas Huth 
56*fcf5ef2aSThomas Huth /*****************************************************************************/
57*fcf5ef2aSThomas Huth /* PowerPC MMU emulation */
58*fcf5ef2aSThomas Huth 
59*fcf5ef2aSThomas Huth /* Context used internally during MMU translations */
60*fcf5ef2aSThomas Huth typedef struct mmu_ctx_t mmu_ctx_t;
61*fcf5ef2aSThomas Huth struct mmu_ctx_t {
62*fcf5ef2aSThomas Huth     hwaddr raddr;      /* Real address              */
63*fcf5ef2aSThomas Huth     hwaddr eaddr;      /* Effective address         */
64*fcf5ef2aSThomas Huth     int prot;                      /* Protection bits           */
65*fcf5ef2aSThomas Huth     hwaddr hash[2];    /* Pagetable hash values     */
66*fcf5ef2aSThomas Huth     target_ulong ptem;             /* Virtual segment ID | API  */
67*fcf5ef2aSThomas Huth     int key;                       /* Access key                */
68*fcf5ef2aSThomas Huth     int nx;                        /* Non-execute area          */
69*fcf5ef2aSThomas Huth };
70*fcf5ef2aSThomas Huth 
71*fcf5ef2aSThomas Huth /* Common routines used by software and hardware TLBs emulation */
72*fcf5ef2aSThomas Huth static inline int pte_is_valid(target_ulong pte0)
73*fcf5ef2aSThomas Huth {
74*fcf5ef2aSThomas Huth     return pte0 & 0x80000000 ? 1 : 0;
75*fcf5ef2aSThomas Huth }
76*fcf5ef2aSThomas Huth 
77*fcf5ef2aSThomas Huth static inline void pte_invalidate(target_ulong *pte0)
78*fcf5ef2aSThomas Huth {
79*fcf5ef2aSThomas Huth     *pte0 &= ~0x80000000;
80*fcf5ef2aSThomas Huth }
81*fcf5ef2aSThomas Huth 
82*fcf5ef2aSThomas Huth #define PTE_PTEM_MASK 0x7FFFFFBF
83*fcf5ef2aSThomas Huth #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
84*fcf5ef2aSThomas Huth 
85*fcf5ef2aSThomas Huth static int pp_check(int key, int pp, int nx)
86*fcf5ef2aSThomas Huth {
87*fcf5ef2aSThomas Huth     int access;
88*fcf5ef2aSThomas Huth 
89*fcf5ef2aSThomas Huth     /* Compute access rights */
90*fcf5ef2aSThomas Huth     access = 0;
91*fcf5ef2aSThomas Huth     if (key == 0) {
92*fcf5ef2aSThomas Huth         switch (pp) {
93*fcf5ef2aSThomas Huth         case 0x0:
94*fcf5ef2aSThomas Huth         case 0x1:
95*fcf5ef2aSThomas Huth         case 0x2:
96*fcf5ef2aSThomas Huth             access |= PAGE_WRITE;
97*fcf5ef2aSThomas Huth             /* No break here */
98*fcf5ef2aSThomas Huth         case 0x3:
99*fcf5ef2aSThomas Huth             access |= PAGE_READ;
100*fcf5ef2aSThomas Huth             break;
101*fcf5ef2aSThomas Huth         }
102*fcf5ef2aSThomas Huth     } else {
103*fcf5ef2aSThomas Huth         switch (pp) {
104*fcf5ef2aSThomas Huth         case 0x0:
105*fcf5ef2aSThomas Huth             access = 0;
106*fcf5ef2aSThomas Huth             break;
107*fcf5ef2aSThomas Huth         case 0x1:
108*fcf5ef2aSThomas Huth         case 0x3:
109*fcf5ef2aSThomas Huth             access = PAGE_READ;
110*fcf5ef2aSThomas Huth             break;
111*fcf5ef2aSThomas Huth         case 0x2:
112*fcf5ef2aSThomas Huth             access = PAGE_READ | PAGE_WRITE;
113*fcf5ef2aSThomas Huth             break;
114*fcf5ef2aSThomas Huth         }
115*fcf5ef2aSThomas Huth     }
116*fcf5ef2aSThomas Huth     if (nx == 0) {
117*fcf5ef2aSThomas Huth         access |= PAGE_EXEC;
118*fcf5ef2aSThomas Huth     }
119*fcf5ef2aSThomas Huth 
120*fcf5ef2aSThomas Huth     return access;
121*fcf5ef2aSThomas Huth }
122*fcf5ef2aSThomas Huth 
123*fcf5ef2aSThomas Huth static int check_prot(int prot, int rw, int access_type)
124*fcf5ef2aSThomas Huth {
125*fcf5ef2aSThomas Huth     int ret;
126*fcf5ef2aSThomas Huth 
127*fcf5ef2aSThomas Huth     if (access_type == ACCESS_CODE) {
128*fcf5ef2aSThomas Huth         if (prot & PAGE_EXEC) {
129*fcf5ef2aSThomas Huth             ret = 0;
130*fcf5ef2aSThomas Huth         } else {
131*fcf5ef2aSThomas Huth             ret = -2;
132*fcf5ef2aSThomas Huth         }
133*fcf5ef2aSThomas Huth     } else if (rw) {
134*fcf5ef2aSThomas Huth         if (prot & PAGE_WRITE) {
135*fcf5ef2aSThomas Huth             ret = 0;
136*fcf5ef2aSThomas Huth         } else {
137*fcf5ef2aSThomas Huth             ret = -2;
138*fcf5ef2aSThomas Huth         }
139*fcf5ef2aSThomas Huth     } else {
140*fcf5ef2aSThomas Huth         if (prot & PAGE_READ) {
141*fcf5ef2aSThomas Huth             ret = 0;
142*fcf5ef2aSThomas Huth         } else {
143*fcf5ef2aSThomas Huth             ret = -2;
144*fcf5ef2aSThomas Huth         }
145*fcf5ef2aSThomas Huth     }
146*fcf5ef2aSThomas Huth 
147*fcf5ef2aSThomas Huth     return ret;
148*fcf5ef2aSThomas Huth }
149*fcf5ef2aSThomas Huth 
150*fcf5ef2aSThomas Huth static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
151*fcf5ef2aSThomas Huth                                        target_ulong pte1, int h, int rw, int type)
152*fcf5ef2aSThomas Huth {
153*fcf5ef2aSThomas Huth     target_ulong ptem, mmask;
154*fcf5ef2aSThomas Huth     int access, ret, pteh, ptev, pp;
155*fcf5ef2aSThomas Huth 
156*fcf5ef2aSThomas Huth     ret = -1;
157*fcf5ef2aSThomas Huth     /* Check validity and table match */
158*fcf5ef2aSThomas Huth     ptev = pte_is_valid(pte0);
159*fcf5ef2aSThomas Huth     pteh = (pte0 >> 6) & 1;
160*fcf5ef2aSThomas Huth     if (ptev && h == pteh) {
161*fcf5ef2aSThomas Huth         /* Check vsid & api */
162*fcf5ef2aSThomas Huth         ptem = pte0 & PTE_PTEM_MASK;
163*fcf5ef2aSThomas Huth         mmask = PTE_CHECK_MASK;
164*fcf5ef2aSThomas Huth         pp = pte1 & 0x00000003;
165*fcf5ef2aSThomas Huth         if (ptem == ctx->ptem) {
166*fcf5ef2aSThomas Huth             if (ctx->raddr != (hwaddr)-1ULL) {
167*fcf5ef2aSThomas Huth                 /* all matches should have equal RPN, WIMG & PP */
168*fcf5ef2aSThomas Huth                 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
169*fcf5ef2aSThomas Huth                     qemu_log_mask(CPU_LOG_MMU, "Bad RPN/WIMG/PP\n");
170*fcf5ef2aSThomas Huth                     return -3;
171*fcf5ef2aSThomas Huth                 }
172*fcf5ef2aSThomas Huth             }
173*fcf5ef2aSThomas Huth             /* Compute access rights */
174*fcf5ef2aSThomas Huth             access = pp_check(ctx->key, pp, ctx->nx);
175*fcf5ef2aSThomas Huth             /* Keep the matching PTE informations */
176*fcf5ef2aSThomas Huth             ctx->raddr = pte1;
177*fcf5ef2aSThomas Huth             ctx->prot = access;
178*fcf5ef2aSThomas Huth             ret = check_prot(ctx->prot, rw, type);
179*fcf5ef2aSThomas Huth             if (ret == 0) {
180*fcf5ef2aSThomas Huth                 /* Access granted */
181*fcf5ef2aSThomas Huth                 qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
182*fcf5ef2aSThomas Huth             } else {
183*fcf5ef2aSThomas Huth                 /* Access right violation */
184*fcf5ef2aSThomas Huth                 qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
185*fcf5ef2aSThomas Huth             }
186*fcf5ef2aSThomas Huth         }
187*fcf5ef2aSThomas Huth     }
188*fcf5ef2aSThomas Huth 
189*fcf5ef2aSThomas Huth     return ret;
190*fcf5ef2aSThomas Huth }
191*fcf5ef2aSThomas Huth 
192*fcf5ef2aSThomas Huth static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
193*fcf5ef2aSThomas Huth                             int ret, int rw)
194*fcf5ef2aSThomas Huth {
195*fcf5ef2aSThomas Huth     int store = 0;
196*fcf5ef2aSThomas Huth 
197*fcf5ef2aSThomas Huth     /* Update page flags */
198*fcf5ef2aSThomas Huth     if (!(*pte1p & 0x00000100)) {
199*fcf5ef2aSThomas Huth         /* Update accessed flag */
200*fcf5ef2aSThomas Huth         *pte1p |= 0x00000100;
201*fcf5ef2aSThomas Huth         store = 1;
202*fcf5ef2aSThomas Huth     }
203*fcf5ef2aSThomas Huth     if (!(*pte1p & 0x00000080)) {
204*fcf5ef2aSThomas Huth         if (rw == 1 && ret == 0) {
205*fcf5ef2aSThomas Huth             /* Update changed flag */
206*fcf5ef2aSThomas Huth             *pte1p |= 0x00000080;
207*fcf5ef2aSThomas Huth             store = 1;
208*fcf5ef2aSThomas Huth         } else {
209*fcf5ef2aSThomas Huth             /* Force page fault for first write access */
210*fcf5ef2aSThomas Huth             ctx->prot &= ~PAGE_WRITE;
211*fcf5ef2aSThomas Huth         }
212*fcf5ef2aSThomas Huth     }
213*fcf5ef2aSThomas Huth 
214*fcf5ef2aSThomas Huth     return store;
215*fcf5ef2aSThomas Huth }
216*fcf5ef2aSThomas Huth 
217*fcf5ef2aSThomas Huth /* Software driven TLB helpers */
218*fcf5ef2aSThomas Huth static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
219*fcf5ef2aSThomas Huth                                     int way, int is_code)
220*fcf5ef2aSThomas Huth {
221*fcf5ef2aSThomas Huth     int nr;
222*fcf5ef2aSThomas Huth 
223*fcf5ef2aSThomas Huth     /* Select TLB num in a way from address */
224*fcf5ef2aSThomas Huth     nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
225*fcf5ef2aSThomas Huth     /* Select TLB way */
226*fcf5ef2aSThomas Huth     nr += env->tlb_per_way * way;
227*fcf5ef2aSThomas Huth     /* 6xx have separate TLBs for instructions and data */
228*fcf5ef2aSThomas Huth     if (is_code && env->id_tlbs == 1) {
229*fcf5ef2aSThomas Huth         nr += env->nb_tlb;
230*fcf5ef2aSThomas Huth     }
231*fcf5ef2aSThomas Huth 
232*fcf5ef2aSThomas Huth     return nr;
233*fcf5ef2aSThomas Huth }
234*fcf5ef2aSThomas Huth 
235*fcf5ef2aSThomas Huth static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
236*fcf5ef2aSThomas Huth {
237*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = ppc_env_get_cpu(env);
238*fcf5ef2aSThomas Huth     ppc6xx_tlb_t *tlb;
239*fcf5ef2aSThomas Huth     int nr, max;
240*fcf5ef2aSThomas Huth 
241*fcf5ef2aSThomas Huth     /* LOG_SWTLB("Invalidate all TLBs\n"); */
242*fcf5ef2aSThomas Huth     /* Invalidate all defined software TLB */
243*fcf5ef2aSThomas Huth     max = env->nb_tlb;
244*fcf5ef2aSThomas Huth     if (env->id_tlbs == 1) {
245*fcf5ef2aSThomas Huth         max *= 2;
246*fcf5ef2aSThomas Huth     }
247*fcf5ef2aSThomas Huth     for (nr = 0; nr < max; nr++) {
248*fcf5ef2aSThomas Huth         tlb = &env->tlb.tlb6[nr];
249*fcf5ef2aSThomas Huth         pte_invalidate(&tlb->pte0);
250*fcf5ef2aSThomas Huth     }
251*fcf5ef2aSThomas Huth     tlb_flush(CPU(cpu), 1);
252*fcf5ef2aSThomas Huth }
253*fcf5ef2aSThomas Huth 
254*fcf5ef2aSThomas Huth static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env,
255*fcf5ef2aSThomas Huth                                                target_ulong eaddr,
256*fcf5ef2aSThomas Huth                                                int is_code, int match_epn)
257*fcf5ef2aSThomas Huth {
258*fcf5ef2aSThomas Huth #if !defined(FLUSH_ALL_TLBS)
259*fcf5ef2aSThomas Huth     CPUState *cs = CPU(ppc_env_get_cpu(env));
260*fcf5ef2aSThomas Huth     ppc6xx_tlb_t *tlb;
261*fcf5ef2aSThomas Huth     int way, nr;
262*fcf5ef2aSThomas Huth 
263*fcf5ef2aSThomas Huth     /* Invalidate ITLB + DTLB, all ways */
264*fcf5ef2aSThomas Huth     for (way = 0; way < env->nb_ways; way++) {
265*fcf5ef2aSThomas Huth         nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
266*fcf5ef2aSThomas Huth         tlb = &env->tlb.tlb6[nr];
267*fcf5ef2aSThomas Huth         if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
268*fcf5ef2aSThomas Huth             LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
269*fcf5ef2aSThomas Huth                       env->nb_tlb, eaddr);
270*fcf5ef2aSThomas Huth             pte_invalidate(&tlb->pte0);
271*fcf5ef2aSThomas Huth             tlb_flush_page(cs, tlb->EPN);
272*fcf5ef2aSThomas Huth         }
273*fcf5ef2aSThomas Huth     }
274*fcf5ef2aSThomas Huth #else
275*fcf5ef2aSThomas Huth     /* XXX: PowerPC specification say this is valid as well */
276*fcf5ef2aSThomas Huth     ppc6xx_tlb_invalidate_all(env);
277*fcf5ef2aSThomas Huth #endif
278*fcf5ef2aSThomas Huth }
279*fcf5ef2aSThomas Huth 
280*fcf5ef2aSThomas Huth static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
281*fcf5ef2aSThomas Huth                                               target_ulong eaddr, int is_code)
282*fcf5ef2aSThomas Huth {
283*fcf5ef2aSThomas Huth     ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0);
284*fcf5ef2aSThomas Huth }
285*fcf5ef2aSThomas Huth 
286*fcf5ef2aSThomas Huth static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way,
287*fcf5ef2aSThomas Huth                              int is_code, target_ulong pte0, target_ulong pte1)
288*fcf5ef2aSThomas Huth {
289*fcf5ef2aSThomas Huth     ppc6xx_tlb_t *tlb;
290*fcf5ef2aSThomas Huth     int nr;
291*fcf5ef2aSThomas Huth 
292*fcf5ef2aSThomas Huth     nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
293*fcf5ef2aSThomas Huth     tlb = &env->tlb.tlb6[nr];
294*fcf5ef2aSThomas Huth     LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
295*fcf5ef2aSThomas Huth               " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
296*fcf5ef2aSThomas Huth     /* Invalidate any pending reference in QEMU for this virtual address */
297*fcf5ef2aSThomas Huth     ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1);
298*fcf5ef2aSThomas Huth     tlb->pte0 = pte0;
299*fcf5ef2aSThomas Huth     tlb->pte1 = pte1;
300*fcf5ef2aSThomas Huth     tlb->EPN = EPN;
301*fcf5ef2aSThomas Huth     /* Store last way for LRU mechanism */
302*fcf5ef2aSThomas Huth     env->last_way = way;
303*fcf5ef2aSThomas Huth }
304*fcf5ef2aSThomas Huth 
305*fcf5ef2aSThomas Huth static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
306*fcf5ef2aSThomas Huth                                    target_ulong eaddr, int rw, int access_type)
307*fcf5ef2aSThomas Huth {
308*fcf5ef2aSThomas Huth     ppc6xx_tlb_t *tlb;
309*fcf5ef2aSThomas Huth     int nr, best, way;
310*fcf5ef2aSThomas Huth     int ret;
311*fcf5ef2aSThomas Huth 
312*fcf5ef2aSThomas Huth     best = -1;
313*fcf5ef2aSThomas Huth     ret = -1; /* No TLB found */
314*fcf5ef2aSThomas Huth     for (way = 0; way < env->nb_ways; way++) {
315*fcf5ef2aSThomas Huth         nr = ppc6xx_tlb_getnum(env, eaddr, way,
316*fcf5ef2aSThomas Huth                                access_type == ACCESS_CODE ? 1 : 0);
317*fcf5ef2aSThomas Huth         tlb = &env->tlb.tlb6[nr];
318*fcf5ef2aSThomas Huth         /* This test "emulates" the PTE index match for hardware TLBs */
319*fcf5ef2aSThomas Huth         if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
320*fcf5ef2aSThomas Huth             LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
321*fcf5ef2aSThomas Huth                       "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
322*fcf5ef2aSThomas Huth                       pte_is_valid(tlb->pte0) ? "valid" : "inval",
323*fcf5ef2aSThomas Huth                       tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
324*fcf5ef2aSThomas Huth             continue;
325*fcf5ef2aSThomas Huth         }
326*fcf5ef2aSThomas Huth         LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
327*fcf5ef2aSThomas Huth                   TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
328*fcf5ef2aSThomas Huth                   pte_is_valid(tlb->pte0) ? "valid" : "inval",
329*fcf5ef2aSThomas Huth                   tlb->EPN, eaddr, tlb->pte1,
330*fcf5ef2aSThomas Huth                   rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
331*fcf5ef2aSThomas Huth         switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
332*fcf5ef2aSThomas Huth         case -3:
333*fcf5ef2aSThomas Huth             /* TLB inconsistency */
334*fcf5ef2aSThomas Huth             return -1;
335*fcf5ef2aSThomas Huth         case -2:
336*fcf5ef2aSThomas Huth             /* Access violation */
337*fcf5ef2aSThomas Huth             ret = -2;
338*fcf5ef2aSThomas Huth             best = nr;
339*fcf5ef2aSThomas Huth             break;
340*fcf5ef2aSThomas Huth         case -1:
341*fcf5ef2aSThomas Huth         default:
342*fcf5ef2aSThomas Huth             /* No match */
343*fcf5ef2aSThomas Huth             break;
344*fcf5ef2aSThomas Huth         case 0:
345*fcf5ef2aSThomas Huth             /* access granted */
346*fcf5ef2aSThomas Huth             /* XXX: we should go on looping to check all TLBs consistency
347*fcf5ef2aSThomas Huth              *      but we can speed-up the whole thing as the
348*fcf5ef2aSThomas Huth              *      result would be undefined if TLBs are not consistent.
349*fcf5ef2aSThomas Huth              */
350*fcf5ef2aSThomas Huth             ret = 0;
351*fcf5ef2aSThomas Huth             best = nr;
352*fcf5ef2aSThomas Huth             goto done;
353*fcf5ef2aSThomas Huth         }
354*fcf5ef2aSThomas Huth     }
355*fcf5ef2aSThomas Huth     if (best != -1) {
356*fcf5ef2aSThomas Huth     done:
357*fcf5ef2aSThomas Huth         LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
358*fcf5ef2aSThomas Huth                   ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
359*fcf5ef2aSThomas Huth         /* Update page flags */
360*fcf5ef2aSThomas Huth         pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
361*fcf5ef2aSThomas Huth     }
362*fcf5ef2aSThomas Huth 
363*fcf5ef2aSThomas Huth     return ret;
364*fcf5ef2aSThomas Huth }
365*fcf5ef2aSThomas Huth 
366*fcf5ef2aSThomas Huth /* Perform BAT hit & translation */
367*fcf5ef2aSThomas Huth static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
368*fcf5ef2aSThomas Huth                                  int *validp, int *protp, target_ulong *BATu,
369*fcf5ef2aSThomas Huth                                  target_ulong *BATl)
370*fcf5ef2aSThomas Huth {
371*fcf5ef2aSThomas Huth     target_ulong bl;
372*fcf5ef2aSThomas Huth     int pp, valid, prot;
373*fcf5ef2aSThomas Huth 
374*fcf5ef2aSThomas Huth     bl = (*BATu & 0x00001FFC) << 15;
375*fcf5ef2aSThomas Huth     valid = 0;
376*fcf5ef2aSThomas Huth     prot = 0;
377*fcf5ef2aSThomas Huth     if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
378*fcf5ef2aSThomas Huth         ((msr_pr != 0) && (*BATu & 0x00000001))) {
379*fcf5ef2aSThomas Huth         valid = 1;
380*fcf5ef2aSThomas Huth         pp = *BATl & 0x00000003;
381*fcf5ef2aSThomas Huth         if (pp != 0) {
382*fcf5ef2aSThomas Huth             prot = PAGE_READ | PAGE_EXEC;
383*fcf5ef2aSThomas Huth             if (pp == 0x2) {
384*fcf5ef2aSThomas Huth                 prot |= PAGE_WRITE;
385*fcf5ef2aSThomas Huth             }
386*fcf5ef2aSThomas Huth         }
387*fcf5ef2aSThomas Huth     }
388*fcf5ef2aSThomas Huth     *blp = bl;
389*fcf5ef2aSThomas Huth     *validp = valid;
390*fcf5ef2aSThomas Huth     *protp = prot;
391*fcf5ef2aSThomas Huth }
392*fcf5ef2aSThomas Huth 
393*fcf5ef2aSThomas Huth static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
394*fcf5ef2aSThomas Huth                            target_ulong virtual, int rw, int type)
395*fcf5ef2aSThomas Huth {
396*fcf5ef2aSThomas Huth     target_ulong *BATlt, *BATut, *BATu, *BATl;
397*fcf5ef2aSThomas Huth     target_ulong BEPIl, BEPIu, bl;
398*fcf5ef2aSThomas Huth     int i, valid, prot;
399*fcf5ef2aSThomas Huth     int ret = -1;
400*fcf5ef2aSThomas Huth 
401*fcf5ef2aSThomas Huth     LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
402*fcf5ef2aSThomas Huth              type == ACCESS_CODE ? 'I' : 'D', virtual);
403*fcf5ef2aSThomas Huth     switch (type) {
404*fcf5ef2aSThomas Huth     case ACCESS_CODE:
405*fcf5ef2aSThomas Huth         BATlt = env->IBAT[1];
406*fcf5ef2aSThomas Huth         BATut = env->IBAT[0];
407*fcf5ef2aSThomas Huth         break;
408*fcf5ef2aSThomas Huth     default:
409*fcf5ef2aSThomas Huth         BATlt = env->DBAT[1];
410*fcf5ef2aSThomas Huth         BATut = env->DBAT[0];
411*fcf5ef2aSThomas Huth         break;
412*fcf5ef2aSThomas Huth     }
413*fcf5ef2aSThomas Huth     for (i = 0; i < env->nb_BATs; i++) {
414*fcf5ef2aSThomas Huth         BATu = &BATut[i];
415*fcf5ef2aSThomas Huth         BATl = &BATlt[i];
416*fcf5ef2aSThomas Huth         BEPIu = *BATu & 0xF0000000;
417*fcf5ef2aSThomas Huth         BEPIl = *BATu & 0x0FFE0000;
418*fcf5ef2aSThomas Huth         bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
419*fcf5ef2aSThomas Huth         LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
420*fcf5ef2aSThomas Huth                  " BATl " TARGET_FMT_lx "\n", __func__,
421*fcf5ef2aSThomas Huth                  type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
422*fcf5ef2aSThomas Huth         if ((virtual & 0xF0000000) == BEPIu &&
423*fcf5ef2aSThomas Huth             ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
424*fcf5ef2aSThomas Huth             /* BAT matches */
425*fcf5ef2aSThomas Huth             if (valid != 0) {
426*fcf5ef2aSThomas Huth                 /* Get physical address */
427*fcf5ef2aSThomas Huth                 ctx->raddr = (*BATl & 0xF0000000) |
428*fcf5ef2aSThomas Huth                     ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
429*fcf5ef2aSThomas Huth                     (virtual & 0x0001F000);
430*fcf5ef2aSThomas Huth                 /* Compute access rights */
431*fcf5ef2aSThomas Huth                 ctx->prot = prot;
432*fcf5ef2aSThomas Huth                 ret = check_prot(ctx->prot, rw, type);
433*fcf5ef2aSThomas Huth                 if (ret == 0) {
434*fcf5ef2aSThomas Huth                     LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
435*fcf5ef2aSThomas Huth                              i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
436*fcf5ef2aSThomas Huth                              ctx->prot & PAGE_WRITE ? 'W' : '-');
437*fcf5ef2aSThomas Huth                 }
438*fcf5ef2aSThomas Huth                 break;
439*fcf5ef2aSThomas Huth             }
440*fcf5ef2aSThomas Huth         }
441*fcf5ef2aSThomas Huth     }
442*fcf5ef2aSThomas Huth     if (ret < 0) {
443*fcf5ef2aSThomas Huth #if defined(DEBUG_BATS)
444*fcf5ef2aSThomas Huth         if (qemu_log_enabled()) {
445*fcf5ef2aSThomas Huth             LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
446*fcf5ef2aSThomas Huth             for (i = 0; i < 4; i++) {
447*fcf5ef2aSThomas Huth                 BATu = &BATut[i];
448*fcf5ef2aSThomas Huth                 BATl = &BATlt[i];
449*fcf5ef2aSThomas Huth                 BEPIu = *BATu & 0xF0000000;
450*fcf5ef2aSThomas Huth                 BEPIl = *BATu & 0x0FFE0000;
451*fcf5ef2aSThomas Huth                 bl = (*BATu & 0x00001FFC) << 15;
452*fcf5ef2aSThomas Huth                 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
453*fcf5ef2aSThomas Huth                          " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
454*fcf5ef2aSThomas Huth                          TARGET_FMT_lx " " TARGET_FMT_lx "\n",
455*fcf5ef2aSThomas Huth                          __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
456*fcf5ef2aSThomas Huth                          *BATu, *BATl, BEPIu, BEPIl, bl);
457*fcf5ef2aSThomas Huth             }
458*fcf5ef2aSThomas Huth         }
459*fcf5ef2aSThomas Huth #endif
460*fcf5ef2aSThomas Huth     }
461*fcf5ef2aSThomas Huth     /* No hit */
462*fcf5ef2aSThomas Huth     return ret;
463*fcf5ef2aSThomas Huth }
464*fcf5ef2aSThomas Huth 
465*fcf5ef2aSThomas Huth /* Perform segment based translation */
466*fcf5ef2aSThomas Huth static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
467*fcf5ef2aSThomas Huth                                       target_ulong eaddr, int rw, int type)
468*fcf5ef2aSThomas Huth {
469*fcf5ef2aSThomas Huth     hwaddr hash;
470*fcf5ef2aSThomas Huth     target_ulong vsid;
471*fcf5ef2aSThomas Huth     int ds, pr, target_page_bits;
472*fcf5ef2aSThomas Huth     int ret;
473*fcf5ef2aSThomas Huth     target_ulong sr, pgidx;
474*fcf5ef2aSThomas Huth 
475*fcf5ef2aSThomas Huth     pr = msr_pr;
476*fcf5ef2aSThomas Huth     ctx->eaddr = eaddr;
477*fcf5ef2aSThomas Huth 
478*fcf5ef2aSThomas Huth     sr = env->sr[eaddr >> 28];
479*fcf5ef2aSThomas Huth     ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
480*fcf5ef2aSThomas Huth                 ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
481*fcf5ef2aSThomas Huth     ds = sr & 0x80000000 ? 1 : 0;
482*fcf5ef2aSThomas Huth     ctx->nx = sr & 0x10000000 ? 1 : 0;
483*fcf5ef2aSThomas Huth     vsid = sr & 0x00FFFFFF;
484*fcf5ef2aSThomas Huth     target_page_bits = TARGET_PAGE_BITS;
485*fcf5ef2aSThomas Huth     qemu_log_mask(CPU_LOG_MMU,
486*fcf5ef2aSThomas Huth             "Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx
487*fcf5ef2aSThomas Huth             " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx
488*fcf5ef2aSThomas Huth             " ir=%d dr=%d pr=%d %d t=%d\n",
489*fcf5ef2aSThomas Huth             eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
490*fcf5ef2aSThomas Huth             (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
491*fcf5ef2aSThomas Huth     pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
492*fcf5ef2aSThomas Huth     hash = vsid ^ pgidx;
493*fcf5ef2aSThomas Huth     ctx->ptem = (vsid << 7) | (pgidx >> 10);
494*fcf5ef2aSThomas Huth 
495*fcf5ef2aSThomas Huth     qemu_log_mask(CPU_LOG_MMU,
496*fcf5ef2aSThomas Huth             "pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
497*fcf5ef2aSThomas Huth             ctx->key, ds, ctx->nx, vsid);
498*fcf5ef2aSThomas Huth     ret = -1;
499*fcf5ef2aSThomas Huth     if (!ds) {
500*fcf5ef2aSThomas Huth         /* Check if instruction fetch is allowed, if needed */
501*fcf5ef2aSThomas Huth         if (type != ACCESS_CODE || ctx->nx == 0) {
502*fcf5ef2aSThomas Huth             /* Page address translation */
503*fcf5ef2aSThomas Huth             qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
504*fcf5ef2aSThomas Huth                     " htab_mask " TARGET_FMT_plx
505*fcf5ef2aSThomas Huth                     " hash " TARGET_FMT_plx "\n",
506*fcf5ef2aSThomas Huth                     env->htab_base, env->htab_mask, hash);
507*fcf5ef2aSThomas Huth             ctx->hash[0] = hash;
508*fcf5ef2aSThomas Huth             ctx->hash[1] = ~hash;
509*fcf5ef2aSThomas Huth 
510*fcf5ef2aSThomas Huth             /* Initialize real address with an invalid value */
511*fcf5ef2aSThomas Huth             ctx->raddr = (hwaddr)-1ULL;
512*fcf5ef2aSThomas Huth             /* Software TLB search */
513*fcf5ef2aSThomas Huth             ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
514*fcf5ef2aSThomas Huth #if defined(DUMP_PAGE_TABLES)
515*fcf5ef2aSThomas Huth             if (qemu_loglevel_mask(CPU_LOG_MMU)) {
516*fcf5ef2aSThomas Huth                 CPUState *cs = ENV_GET_CPU(env);
517*fcf5ef2aSThomas Huth                 hwaddr curaddr;
518*fcf5ef2aSThomas Huth                 uint32_t a0, a1, a2, a3;
519*fcf5ef2aSThomas Huth 
520*fcf5ef2aSThomas Huth                 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
521*fcf5ef2aSThomas Huth                          "\n", env->htab_base, env->htab_mask + 0x80);
522*fcf5ef2aSThomas Huth                 for (curaddr = env->htab_base;
523*fcf5ef2aSThomas Huth                      curaddr < (env->htab_base + env->htab_mask + 0x80);
524*fcf5ef2aSThomas Huth                      curaddr += 16) {
525*fcf5ef2aSThomas Huth                     a0 = ldl_phys(cs->as, curaddr);
526*fcf5ef2aSThomas Huth                     a1 = ldl_phys(cs->as, curaddr + 4);
527*fcf5ef2aSThomas Huth                     a2 = ldl_phys(cs->as, curaddr + 8);
528*fcf5ef2aSThomas Huth                     a3 = ldl_phys(cs->as, curaddr + 12);
529*fcf5ef2aSThomas Huth                     if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
530*fcf5ef2aSThomas Huth                         qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
531*fcf5ef2aSThomas Huth                                  curaddr, a0, a1, a2, a3);
532*fcf5ef2aSThomas Huth                     }
533*fcf5ef2aSThomas Huth                 }
534*fcf5ef2aSThomas Huth             }
535*fcf5ef2aSThomas Huth #endif
536*fcf5ef2aSThomas Huth         } else {
537*fcf5ef2aSThomas Huth             qemu_log_mask(CPU_LOG_MMU, "No access allowed\n");
538*fcf5ef2aSThomas Huth             ret = -3;
539*fcf5ef2aSThomas Huth         }
540*fcf5ef2aSThomas Huth     } else {
541*fcf5ef2aSThomas Huth         target_ulong sr;
542*fcf5ef2aSThomas Huth 
543*fcf5ef2aSThomas Huth         qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
544*fcf5ef2aSThomas Huth         /* Direct-store segment : absolutely *BUGGY* for now */
545*fcf5ef2aSThomas Huth 
546*fcf5ef2aSThomas Huth         /* Direct-store implies a 32-bit MMU.
547*fcf5ef2aSThomas Huth          * Check the Segment Register's bus unit ID (BUID).
548*fcf5ef2aSThomas Huth          */
549*fcf5ef2aSThomas Huth         sr = env->sr[eaddr >> 28];
550*fcf5ef2aSThomas Huth         if ((sr & 0x1FF00000) >> 20 == 0x07f) {
551*fcf5ef2aSThomas Huth             /* Memory-forced I/O controller interface access */
552*fcf5ef2aSThomas Huth             /* If T=1 and BUID=x'07F', the 601 performs a memory access
553*fcf5ef2aSThomas Huth              * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
554*fcf5ef2aSThomas Huth              */
555*fcf5ef2aSThomas Huth             ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
556*fcf5ef2aSThomas Huth             ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
557*fcf5ef2aSThomas Huth             return 0;
558*fcf5ef2aSThomas Huth         }
559*fcf5ef2aSThomas Huth 
560*fcf5ef2aSThomas Huth         switch (type) {
561*fcf5ef2aSThomas Huth         case ACCESS_INT:
562*fcf5ef2aSThomas Huth             /* Integer load/store : only access allowed */
563*fcf5ef2aSThomas Huth             break;
564*fcf5ef2aSThomas Huth         case ACCESS_CODE:
565*fcf5ef2aSThomas Huth             /* No code fetch is allowed in direct-store areas */
566*fcf5ef2aSThomas Huth             return -4;
567*fcf5ef2aSThomas Huth         case ACCESS_FLOAT:
568*fcf5ef2aSThomas Huth             /* Floating point load/store */
569*fcf5ef2aSThomas Huth             return -4;
570*fcf5ef2aSThomas Huth         case ACCESS_RES:
571*fcf5ef2aSThomas Huth             /* lwarx, ldarx or srwcx. */
572*fcf5ef2aSThomas Huth             return -4;
573*fcf5ef2aSThomas Huth         case ACCESS_CACHE:
574*fcf5ef2aSThomas Huth             /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
575*fcf5ef2aSThomas Huth             /* Should make the instruction do no-op.
576*fcf5ef2aSThomas Huth              * As it already do no-op, it's quite easy :-)
577*fcf5ef2aSThomas Huth              */
578*fcf5ef2aSThomas Huth             ctx->raddr = eaddr;
579*fcf5ef2aSThomas Huth             return 0;
580*fcf5ef2aSThomas Huth         case ACCESS_EXT:
581*fcf5ef2aSThomas Huth             /* eciwx or ecowx */
582*fcf5ef2aSThomas Huth             return -4;
583*fcf5ef2aSThomas Huth         default:
584*fcf5ef2aSThomas Huth             qemu_log_mask(CPU_LOG_MMU, "ERROR: instruction should not need "
585*fcf5ef2aSThomas Huth                           "address translation\n");
586*fcf5ef2aSThomas Huth             return -4;
587*fcf5ef2aSThomas Huth         }
588*fcf5ef2aSThomas Huth         if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
589*fcf5ef2aSThomas Huth             ctx->raddr = eaddr;
590*fcf5ef2aSThomas Huth             ret = 2;
591*fcf5ef2aSThomas Huth         } else {
592*fcf5ef2aSThomas Huth             ret = -2;
593*fcf5ef2aSThomas Huth         }
594*fcf5ef2aSThomas Huth     }
595*fcf5ef2aSThomas Huth 
596*fcf5ef2aSThomas Huth     return ret;
597*fcf5ef2aSThomas Huth }
598*fcf5ef2aSThomas Huth 
599*fcf5ef2aSThomas Huth /* Generic TLB check function for embedded PowerPC implementations */
600*fcf5ef2aSThomas Huth static int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
601*fcf5ef2aSThomas Huth                             hwaddr *raddrp,
602*fcf5ef2aSThomas Huth                             target_ulong address, uint32_t pid, int ext,
603*fcf5ef2aSThomas Huth                             int i)
604*fcf5ef2aSThomas Huth {
605*fcf5ef2aSThomas Huth     target_ulong mask;
606*fcf5ef2aSThomas Huth 
607*fcf5ef2aSThomas Huth     /* Check valid flag */
608*fcf5ef2aSThomas Huth     if (!(tlb->prot & PAGE_VALID)) {
609*fcf5ef2aSThomas Huth         return -1;
610*fcf5ef2aSThomas Huth     }
611*fcf5ef2aSThomas Huth     mask = ~(tlb->size - 1);
612*fcf5ef2aSThomas Huth     LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
613*fcf5ef2aSThomas Huth               " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
614*fcf5ef2aSThomas Huth               mask, (uint32_t)tlb->PID, tlb->prot);
615*fcf5ef2aSThomas Huth     /* Check PID */
616*fcf5ef2aSThomas Huth     if (tlb->PID != 0 && tlb->PID != pid) {
617*fcf5ef2aSThomas Huth         return -1;
618*fcf5ef2aSThomas Huth     }
619*fcf5ef2aSThomas Huth     /* Check effective address */
620*fcf5ef2aSThomas Huth     if ((address & mask) != tlb->EPN) {
621*fcf5ef2aSThomas Huth         return -1;
622*fcf5ef2aSThomas Huth     }
623*fcf5ef2aSThomas Huth     *raddrp = (tlb->RPN & mask) | (address & ~mask);
624*fcf5ef2aSThomas Huth     if (ext) {
625*fcf5ef2aSThomas Huth         /* Extend the physical address to 36 bits */
626*fcf5ef2aSThomas Huth         *raddrp |= (uint64_t)(tlb->RPN & 0xF) << 32;
627*fcf5ef2aSThomas Huth     }
628*fcf5ef2aSThomas Huth 
629*fcf5ef2aSThomas Huth     return 0;
630*fcf5ef2aSThomas Huth }
631*fcf5ef2aSThomas Huth 
632*fcf5ef2aSThomas Huth /* Generic TLB search function for PowerPC embedded implementations */
633*fcf5ef2aSThomas Huth static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address,
634*fcf5ef2aSThomas Huth                              uint32_t pid)
635*fcf5ef2aSThomas Huth {
636*fcf5ef2aSThomas Huth     ppcemb_tlb_t *tlb;
637*fcf5ef2aSThomas Huth     hwaddr raddr;
638*fcf5ef2aSThomas Huth     int i, ret;
639*fcf5ef2aSThomas Huth 
640*fcf5ef2aSThomas Huth     /* Default return value is no match */
641*fcf5ef2aSThomas Huth     ret = -1;
642*fcf5ef2aSThomas Huth     for (i = 0; i < env->nb_tlb; i++) {
643*fcf5ef2aSThomas Huth         tlb = &env->tlb.tlbe[i];
644*fcf5ef2aSThomas Huth         if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
645*fcf5ef2aSThomas Huth             ret = i;
646*fcf5ef2aSThomas Huth             break;
647*fcf5ef2aSThomas Huth         }
648*fcf5ef2aSThomas Huth     }
649*fcf5ef2aSThomas Huth 
650*fcf5ef2aSThomas Huth     return ret;
651*fcf5ef2aSThomas Huth }
652*fcf5ef2aSThomas Huth 
653*fcf5ef2aSThomas Huth /* Helpers specific to PowerPC 40x implementations */
654*fcf5ef2aSThomas Huth static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
655*fcf5ef2aSThomas Huth {
656*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = ppc_env_get_cpu(env);
657*fcf5ef2aSThomas Huth     ppcemb_tlb_t *tlb;
658*fcf5ef2aSThomas Huth     int i;
659*fcf5ef2aSThomas Huth 
660*fcf5ef2aSThomas Huth     for (i = 0; i < env->nb_tlb; i++) {
661*fcf5ef2aSThomas Huth         tlb = &env->tlb.tlbe[i];
662*fcf5ef2aSThomas Huth         tlb->prot &= ~PAGE_VALID;
663*fcf5ef2aSThomas Huth     }
664*fcf5ef2aSThomas Huth     tlb_flush(CPU(cpu), 1);
665*fcf5ef2aSThomas Huth }
666*fcf5ef2aSThomas Huth 
667*fcf5ef2aSThomas Huth static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
668*fcf5ef2aSThomas Huth                                        target_ulong address, int rw,
669*fcf5ef2aSThomas Huth                                        int access_type)
670*fcf5ef2aSThomas Huth {
671*fcf5ef2aSThomas Huth     ppcemb_tlb_t *tlb;
672*fcf5ef2aSThomas Huth     hwaddr raddr;
673*fcf5ef2aSThomas Huth     int i, ret, zsel, zpr, pr;
674*fcf5ef2aSThomas Huth 
675*fcf5ef2aSThomas Huth     ret = -1;
676*fcf5ef2aSThomas Huth     raddr = (hwaddr)-1ULL;
677*fcf5ef2aSThomas Huth     pr = msr_pr;
678*fcf5ef2aSThomas Huth     for (i = 0; i < env->nb_tlb; i++) {
679*fcf5ef2aSThomas Huth         tlb = &env->tlb.tlbe[i];
680*fcf5ef2aSThomas Huth         if (ppcemb_tlb_check(env, tlb, &raddr, address,
681*fcf5ef2aSThomas Huth                              env->spr[SPR_40x_PID], 0, i) < 0) {
682*fcf5ef2aSThomas Huth             continue;
683*fcf5ef2aSThomas Huth         }
684*fcf5ef2aSThomas Huth         zsel = (tlb->attr >> 4) & 0xF;
685*fcf5ef2aSThomas Huth         zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
686*fcf5ef2aSThomas Huth         LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
687*fcf5ef2aSThomas Huth                     __func__, i, zsel, zpr, rw, tlb->attr);
688*fcf5ef2aSThomas Huth         /* Check execute enable bit */
689*fcf5ef2aSThomas Huth         switch (zpr) {
690*fcf5ef2aSThomas Huth         case 0x2:
691*fcf5ef2aSThomas Huth             if (pr != 0) {
692*fcf5ef2aSThomas Huth                 goto check_perms;
693*fcf5ef2aSThomas Huth             }
694*fcf5ef2aSThomas Huth             /* No break here */
695*fcf5ef2aSThomas Huth         case 0x3:
696*fcf5ef2aSThomas Huth             /* All accesses granted */
697*fcf5ef2aSThomas Huth             ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
698*fcf5ef2aSThomas Huth             ret = 0;
699*fcf5ef2aSThomas Huth             break;
700*fcf5ef2aSThomas Huth         case 0x0:
701*fcf5ef2aSThomas Huth             if (pr != 0) {
702*fcf5ef2aSThomas Huth                 /* Raise Zone protection fault.  */
703*fcf5ef2aSThomas Huth                 env->spr[SPR_40x_ESR] = 1 << 22;
704*fcf5ef2aSThomas Huth                 ctx->prot = 0;
705*fcf5ef2aSThomas Huth                 ret = -2;
706*fcf5ef2aSThomas Huth                 break;
707*fcf5ef2aSThomas Huth             }
708*fcf5ef2aSThomas Huth             /* No break here */
709*fcf5ef2aSThomas Huth         case 0x1:
710*fcf5ef2aSThomas Huth         check_perms:
711*fcf5ef2aSThomas Huth             /* Check from TLB entry */
712*fcf5ef2aSThomas Huth             ctx->prot = tlb->prot;
713*fcf5ef2aSThomas Huth             ret = check_prot(ctx->prot, rw, access_type);
714*fcf5ef2aSThomas Huth             if (ret == -2) {
715*fcf5ef2aSThomas Huth                 env->spr[SPR_40x_ESR] = 0;
716*fcf5ef2aSThomas Huth             }
717*fcf5ef2aSThomas Huth             break;
718*fcf5ef2aSThomas Huth         }
719*fcf5ef2aSThomas Huth         if (ret >= 0) {
720*fcf5ef2aSThomas Huth             ctx->raddr = raddr;
721*fcf5ef2aSThomas Huth             LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
722*fcf5ef2aSThomas Huth                       " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
723*fcf5ef2aSThomas Huth                       ret);
724*fcf5ef2aSThomas Huth             return 0;
725*fcf5ef2aSThomas Huth         }
726*fcf5ef2aSThomas Huth     }
727*fcf5ef2aSThomas Huth     LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
728*fcf5ef2aSThomas Huth               " %d %d\n", __func__, address, raddr, ctx->prot, ret);
729*fcf5ef2aSThomas Huth 
730*fcf5ef2aSThomas Huth     return ret;
731*fcf5ef2aSThomas Huth }
732*fcf5ef2aSThomas Huth 
733*fcf5ef2aSThomas Huth void store_40x_sler(CPUPPCState *env, uint32_t val)
734*fcf5ef2aSThomas Huth {
735*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = ppc_env_get_cpu(env);
736*fcf5ef2aSThomas Huth 
737*fcf5ef2aSThomas Huth     /* XXX: TO BE FIXED */
738*fcf5ef2aSThomas Huth     if (val != 0x00000000) {
739*fcf5ef2aSThomas Huth         cpu_abort(CPU(cpu), "Little-endian regions are not supported by now\n");
740*fcf5ef2aSThomas Huth     }
741*fcf5ef2aSThomas Huth     env->spr[SPR_405_SLER] = val;
742*fcf5ef2aSThomas Huth }
743*fcf5ef2aSThomas Huth 
744*fcf5ef2aSThomas Huth static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
745*fcf5ef2aSThomas Huth                                      hwaddr *raddr, int *prot,
746*fcf5ef2aSThomas Huth                                      target_ulong address, int rw,
747*fcf5ef2aSThomas Huth                                      int access_type, int i)
748*fcf5ef2aSThomas Huth {
749*fcf5ef2aSThomas Huth     int ret, prot2;
750*fcf5ef2aSThomas Huth 
751*fcf5ef2aSThomas Huth     if (ppcemb_tlb_check(env, tlb, raddr, address,
752*fcf5ef2aSThomas Huth                          env->spr[SPR_BOOKE_PID],
753*fcf5ef2aSThomas Huth                          !env->nb_pids, i) >= 0) {
754*fcf5ef2aSThomas Huth         goto found_tlb;
755*fcf5ef2aSThomas Huth     }
756*fcf5ef2aSThomas Huth 
757*fcf5ef2aSThomas Huth     if (env->spr[SPR_BOOKE_PID1] &&
758*fcf5ef2aSThomas Huth         ppcemb_tlb_check(env, tlb, raddr, address,
759*fcf5ef2aSThomas Huth                          env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
760*fcf5ef2aSThomas Huth         goto found_tlb;
761*fcf5ef2aSThomas Huth     }
762*fcf5ef2aSThomas Huth 
763*fcf5ef2aSThomas Huth     if (env->spr[SPR_BOOKE_PID2] &&
764*fcf5ef2aSThomas Huth         ppcemb_tlb_check(env, tlb, raddr, address,
765*fcf5ef2aSThomas Huth                          env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
766*fcf5ef2aSThomas Huth         goto found_tlb;
767*fcf5ef2aSThomas Huth     }
768*fcf5ef2aSThomas Huth 
769*fcf5ef2aSThomas Huth     LOG_SWTLB("%s: TLB entry not found\n", __func__);
770*fcf5ef2aSThomas Huth     return -1;
771*fcf5ef2aSThomas Huth 
772*fcf5ef2aSThomas Huth found_tlb:
773*fcf5ef2aSThomas Huth 
774*fcf5ef2aSThomas Huth     if (msr_pr != 0) {
775*fcf5ef2aSThomas Huth         prot2 = tlb->prot & 0xF;
776*fcf5ef2aSThomas Huth     } else {
777*fcf5ef2aSThomas Huth         prot2 = (tlb->prot >> 4) & 0xF;
778*fcf5ef2aSThomas Huth     }
779*fcf5ef2aSThomas Huth 
780*fcf5ef2aSThomas Huth     /* Check the address space */
781*fcf5ef2aSThomas Huth     if (access_type == ACCESS_CODE) {
782*fcf5ef2aSThomas Huth         if (msr_ir != (tlb->attr & 1)) {
783*fcf5ef2aSThomas Huth             LOG_SWTLB("%s: AS doesn't match\n", __func__);
784*fcf5ef2aSThomas Huth             return -1;
785*fcf5ef2aSThomas Huth         }
786*fcf5ef2aSThomas Huth 
787*fcf5ef2aSThomas Huth         *prot = prot2;
788*fcf5ef2aSThomas Huth         if (prot2 & PAGE_EXEC) {
789*fcf5ef2aSThomas Huth             LOG_SWTLB("%s: good TLB!\n", __func__);
790*fcf5ef2aSThomas Huth             return 0;
791*fcf5ef2aSThomas Huth         }
792*fcf5ef2aSThomas Huth 
793*fcf5ef2aSThomas Huth         LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
794*fcf5ef2aSThomas Huth         ret = -3;
795*fcf5ef2aSThomas Huth     } else {
796*fcf5ef2aSThomas Huth         if (msr_dr != (tlb->attr & 1)) {
797*fcf5ef2aSThomas Huth             LOG_SWTLB("%s: AS doesn't match\n", __func__);
798*fcf5ef2aSThomas Huth             return -1;
799*fcf5ef2aSThomas Huth         }
800*fcf5ef2aSThomas Huth 
801*fcf5ef2aSThomas Huth         *prot = prot2;
802*fcf5ef2aSThomas Huth         if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
803*fcf5ef2aSThomas Huth             LOG_SWTLB("%s: found TLB!\n", __func__);
804*fcf5ef2aSThomas Huth             return 0;
805*fcf5ef2aSThomas Huth         }
806*fcf5ef2aSThomas Huth 
807*fcf5ef2aSThomas Huth         LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
808*fcf5ef2aSThomas Huth         ret = -2;
809*fcf5ef2aSThomas Huth     }
810*fcf5ef2aSThomas Huth 
811*fcf5ef2aSThomas Huth     return ret;
812*fcf5ef2aSThomas Huth }
813*fcf5ef2aSThomas Huth 
814*fcf5ef2aSThomas Huth static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
815*fcf5ef2aSThomas Huth                                          target_ulong address, int rw,
816*fcf5ef2aSThomas Huth                                          int access_type)
817*fcf5ef2aSThomas Huth {
818*fcf5ef2aSThomas Huth     ppcemb_tlb_t *tlb;
819*fcf5ef2aSThomas Huth     hwaddr raddr;
820*fcf5ef2aSThomas Huth     int i, ret;
821*fcf5ef2aSThomas Huth 
822*fcf5ef2aSThomas Huth     ret = -1;
823*fcf5ef2aSThomas Huth     raddr = (hwaddr)-1ULL;
824*fcf5ef2aSThomas Huth     for (i = 0; i < env->nb_tlb; i++) {
825*fcf5ef2aSThomas Huth         tlb = &env->tlb.tlbe[i];
826*fcf5ef2aSThomas Huth         ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
827*fcf5ef2aSThomas Huth                                  access_type, i);
828*fcf5ef2aSThomas Huth         if (!ret) {
829*fcf5ef2aSThomas Huth             break;
830*fcf5ef2aSThomas Huth         }
831*fcf5ef2aSThomas Huth     }
832*fcf5ef2aSThomas Huth 
833*fcf5ef2aSThomas Huth     if (ret >= 0) {
834*fcf5ef2aSThomas Huth         ctx->raddr = raddr;
835*fcf5ef2aSThomas Huth         LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
836*fcf5ef2aSThomas Huth                   " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
837*fcf5ef2aSThomas Huth                   ret);
838*fcf5ef2aSThomas Huth     } else {
839*fcf5ef2aSThomas Huth         LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
840*fcf5ef2aSThomas Huth                   " %d %d\n", __func__, address, raddr, ctx->prot, ret);
841*fcf5ef2aSThomas Huth     }
842*fcf5ef2aSThomas Huth 
843*fcf5ef2aSThomas Huth     return ret;
844*fcf5ef2aSThomas Huth }
845*fcf5ef2aSThomas Huth 
846*fcf5ef2aSThomas Huth static void booke206_flush_tlb(CPUPPCState *env, int flags,
847*fcf5ef2aSThomas Huth                                const int check_iprot)
848*fcf5ef2aSThomas Huth {
849*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = ppc_env_get_cpu(env);
850*fcf5ef2aSThomas Huth     int tlb_size;
851*fcf5ef2aSThomas Huth     int i, j;
852*fcf5ef2aSThomas Huth     ppcmas_tlb_t *tlb = env->tlb.tlbm;
853*fcf5ef2aSThomas Huth 
854*fcf5ef2aSThomas Huth     for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
855*fcf5ef2aSThomas Huth         if (flags & (1 << i)) {
856*fcf5ef2aSThomas Huth             tlb_size = booke206_tlb_size(env, i);
857*fcf5ef2aSThomas Huth             for (j = 0; j < tlb_size; j++) {
858*fcf5ef2aSThomas Huth                 if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
859*fcf5ef2aSThomas Huth                     tlb[j].mas1 &= ~MAS1_VALID;
860*fcf5ef2aSThomas Huth                 }
861*fcf5ef2aSThomas Huth             }
862*fcf5ef2aSThomas Huth         }
863*fcf5ef2aSThomas Huth         tlb += booke206_tlb_size(env, i);
864*fcf5ef2aSThomas Huth     }
865*fcf5ef2aSThomas Huth 
866*fcf5ef2aSThomas Huth     tlb_flush(CPU(cpu), 1);
867*fcf5ef2aSThomas Huth }
868*fcf5ef2aSThomas Huth 
869*fcf5ef2aSThomas Huth static hwaddr booke206_tlb_to_page_size(CPUPPCState *env,
870*fcf5ef2aSThomas Huth                                         ppcmas_tlb_t *tlb)
871*fcf5ef2aSThomas Huth {
872*fcf5ef2aSThomas Huth     int tlbm_size;
873*fcf5ef2aSThomas Huth 
874*fcf5ef2aSThomas Huth     tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
875*fcf5ef2aSThomas Huth 
876*fcf5ef2aSThomas Huth     return 1024ULL << tlbm_size;
877*fcf5ef2aSThomas Huth }
878*fcf5ef2aSThomas Huth 
879*fcf5ef2aSThomas Huth /* TLB check function for MAS based SoftTLBs */
880*fcf5ef2aSThomas Huth static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
881*fcf5ef2aSThomas Huth                             hwaddr *raddrp, target_ulong address,
882*fcf5ef2aSThomas Huth                             uint32_t pid)
883*fcf5ef2aSThomas Huth {
884*fcf5ef2aSThomas Huth     hwaddr mask;
885*fcf5ef2aSThomas Huth     uint32_t tlb_pid;
886*fcf5ef2aSThomas Huth 
887*fcf5ef2aSThomas Huth     if (!msr_cm) {
888*fcf5ef2aSThomas Huth         /* In 32bit mode we can only address 32bit EAs */
889*fcf5ef2aSThomas Huth         address = (uint32_t)address;
890*fcf5ef2aSThomas Huth     }
891*fcf5ef2aSThomas Huth 
892*fcf5ef2aSThomas Huth     /* Check valid flag */
893*fcf5ef2aSThomas Huth     if (!(tlb->mas1 & MAS1_VALID)) {
894*fcf5ef2aSThomas Huth         return -1;
895*fcf5ef2aSThomas Huth     }
896*fcf5ef2aSThomas Huth 
897*fcf5ef2aSThomas Huth     mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
898*fcf5ef2aSThomas Huth     LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
899*fcf5ef2aSThomas Huth               PRIx64 " mask=0x%" HWADDR_PRIx " MAS7_3=0x%" PRIx64 " MAS8=0x%"
900*fcf5ef2aSThomas Huth               PRIx32 "\n", __func__, address, pid, tlb->mas1, tlb->mas2, mask,
901*fcf5ef2aSThomas Huth               tlb->mas7_3, tlb->mas8);
902*fcf5ef2aSThomas Huth 
903*fcf5ef2aSThomas Huth     /* Check PID */
904*fcf5ef2aSThomas Huth     tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
905*fcf5ef2aSThomas Huth     if (tlb_pid != 0 && tlb_pid != pid) {
906*fcf5ef2aSThomas Huth         return -1;
907*fcf5ef2aSThomas Huth     }
908*fcf5ef2aSThomas Huth 
909*fcf5ef2aSThomas Huth     /* Check effective address */
910*fcf5ef2aSThomas Huth     if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
911*fcf5ef2aSThomas Huth         return -1;
912*fcf5ef2aSThomas Huth     }
913*fcf5ef2aSThomas Huth 
914*fcf5ef2aSThomas Huth     if (raddrp) {
915*fcf5ef2aSThomas Huth         *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
916*fcf5ef2aSThomas Huth     }
917*fcf5ef2aSThomas Huth 
918*fcf5ef2aSThomas Huth     return 0;
919*fcf5ef2aSThomas Huth }
920*fcf5ef2aSThomas Huth 
921*fcf5ef2aSThomas Huth static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
922*fcf5ef2aSThomas Huth                                  hwaddr *raddr, int *prot,
923*fcf5ef2aSThomas Huth                                  target_ulong address, int rw,
924*fcf5ef2aSThomas Huth                                  int access_type)
925*fcf5ef2aSThomas Huth {
926*fcf5ef2aSThomas Huth     int ret;
927*fcf5ef2aSThomas Huth     int prot2 = 0;
928*fcf5ef2aSThomas Huth 
929*fcf5ef2aSThomas Huth     if (ppcmas_tlb_check(env, tlb, raddr, address,
930*fcf5ef2aSThomas Huth                          env->spr[SPR_BOOKE_PID]) >= 0) {
931*fcf5ef2aSThomas Huth         goto found_tlb;
932*fcf5ef2aSThomas Huth     }
933*fcf5ef2aSThomas Huth 
934*fcf5ef2aSThomas Huth     if (env->spr[SPR_BOOKE_PID1] &&
935*fcf5ef2aSThomas Huth         ppcmas_tlb_check(env, tlb, raddr, address,
936*fcf5ef2aSThomas Huth                          env->spr[SPR_BOOKE_PID1]) >= 0) {
937*fcf5ef2aSThomas Huth         goto found_tlb;
938*fcf5ef2aSThomas Huth     }
939*fcf5ef2aSThomas Huth 
940*fcf5ef2aSThomas Huth     if (env->spr[SPR_BOOKE_PID2] &&
941*fcf5ef2aSThomas Huth         ppcmas_tlb_check(env, tlb, raddr, address,
942*fcf5ef2aSThomas Huth                          env->spr[SPR_BOOKE_PID2]) >= 0) {
943*fcf5ef2aSThomas Huth         goto found_tlb;
944*fcf5ef2aSThomas Huth     }
945*fcf5ef2aSThomas Huth 
946*fcf5ef2aSThomas Huth     LOG_SWTLB("%s: TLB entry not found\n", __func__);
947*fcf5ef2aSThomas Huth     return -1;
948*fcf5ef2aSThomas Huth 
949*fcf5ef2aSThomas Huth found_tlb:
950*fcf5ef2aSThomas Huth 
951*fcf5ef2aSThomas Huth     if (msr_pr != 0) {
952*fcf5ef2aSThomas Huth         if (tlb->mas7_3 & MAS3_UR) {
953*fcf5ef2aSThomas Huth             prot2 |= PAGE_READ;
954*fcf5ef2aSThomas Huth         }
955*fcf5ef2aSThomas Huth         if (tlb->mas7_3 & MAS3_UW) {
956*fcf5ef2aSThomas Huth             prot2 |= PAGE_WRITE;
957*fcf5ef2aSThomas Huth         }
958*fcf5ef2aSThomas Huth         if (tlb->mas7_3 & MAS3_UX) {
959*fcf5ef2aSThomas Huth             prot2 |= PAGE_EXEC;
960*fcf5ef2aSThomas Huth         }
961*fcf5ef2aSThomas Huth     } else {
962*fcf5ef2aSThomas Huth         if (tlb->mas7_3 & MAS3_SR) {
963*fcf5ef2aSThomas Huth             prot2 |= PAGE_READ;
964*fcf5ef2aSThomas Huth         }
965*fcf5ef2aSThomas Huth         if (tlb->mas7_3 & MAS3_SW) {
966*fcf5ef2aSThomas Huth             prot2 |= PAGE_WRITE;
967*fcf5ef2aSThomas Huth         }
968*fcf5ef2aSThomas Huth         if (tlb->mas7_3 & MAS3_SX) {
969*fcf5ef2aSThomas Huth             prot2 |= PAGE_EXEC;
970*fcf5ef2aSThomas Huth         }
971*fcf5ef2aSThomas Huth     }
972*fcf5ef2aSThomas Huth 
973*fcf5ef2aSThomas Huth     /* Check the address space and permissions */
974*fcf5ef2aSThomas Huth     if (access_type == ACCESS_CODE) {
975*fcf5ef2aSThomas Huth         if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
976*fcf5ef2aSThomas Huth             LOG_SWTLB("%s: AS doesn't match\n", __func__);
977*fcf5ef2aSThomas Huth             return -1;
978*fcf5ef2aSThomas Huth         }
979*fcf5ef2aSThomas Huth 
980*fcf5ef2aSThomas Huth         *prot = prot2;
981*fcf5ef2aSThomas Huth         if (prot2 & PAGE_EXEC) {
982*fcf5ef2aSThomas Huth             LOG_SWTLB("%s: good TLB!\n", __func__);
983*fcf5ef2aSThomas Huth             return 0;
984*fcf5ef2aSThomas Huth         }
985*fcf5ef2aSThomas Huth 
986*fcf5ef2aSThomas Huth         LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
987*fcf5ef2aSThomas Huth         ret = -3;
988*fcf5ef2aSThomas Huth     } else {
989*fcf5ef2aSThomas Huth         if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
990*fcf5ef2aSThomas Huth             LOG_SWTLB("%s: AS doesn't match\n", __func__);
991*fcf5ef2aSThomas Huth             return -1;
992*fcf5ef2aSThomas Huth         }
993*fcf5ef2aSThomas Huth 
994*fcf5ef2aSThomas Huth         *prot = prot2;
995*fcf5ef2aSThomas Huth         if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
996*fcf5ef2aSThomas Huth             LOG_SWTLB("%s: found TLB!\n", __func__);
997*fcf5ef2aSThomas Huth             return 0;
998*fcf5ef2aSThomas Huth         }
999*fcf5ef2aSThomas Huth 
1000*fcf5ef2aSThomas Huth         LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
1001*fcf5ef2aSThomas Huth         ret = -2;
1002*fcf5ef2aSThomas Huth     }
1003*fcf5ef2aSThomas Huth 
1004*fcf5ef2aSThomas Huth     return ret;
1005*fcf5ef2aSThomas Huth }
1006*fcf5ef2aSThomas Huth 
1007*fcf5ef2aSThomas Huth static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1008*fcf5ef2aSThomas Huth                                             target_ulong address, int rw,
1009*fcf5ef2aSThomas Huth                                             int access_type)
1010*fcf5ef2aSThomas Huth {
1011*fcf5ef2aSThomas Huth     ppcmas_tlb_t *tlb;
1012*fcf5ef2aSThomas Huth     hwaddr raddr;
1013*fcf5ef2aSThomas Huth     int i, j, ret;
1014*fcf5ef2aSThomas Huth 
1015*fcf5ef2aSThomas Huth     ret = -1;
1016*fcf5ef2aSThomas Huth     raddr = (hwaddr)-1ULL;
1017*fcf5ef2aSThomas Huth 
1018*fcf5ef2aSThomas Huth     for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1019*fcf5ef2aSThomas Huth         int ways = booke206_tlb_ways(env, i);
1020*fcf5ef2aSThomas Huth 
1021*fcf5ef2aSThomas Huth         for (j = 0; j < ways; j++) {
1022*fcf5ef2aSThomas Huth             tlb = booke206_get_tlbm(env, i, address, j);
1023*fcf5ef2aSThomas Huth             if (!tlb) {
1024*fcf5ef2aSThomas Huth                 continue;
1025*fcf5ef2aSThomas Huth             }
1026*fcf5ef2aSThomas Huth             ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
1027*fcf5ef2aSThomas Huth                                         rw, access_type);
1028*fcf5ef2aSThomas Huth             if (ret != -1) {
1029*fcf5ef2aSThomas Huth                 goto found_tlb;
1030*fcf5ef2aSThomas Huth             }
1031*fcf5ef2aSThomas Huth         }
1032*fcf5ef2aSThomas Huth     }
1033*fcf5ef2aSThomas Huth 
1034*fcf5ef2aSThomas Huth found_tlb:
1035*fcf5ef2aSThomas Huth 
1036*fcf5ef2aSThomas Huth     if (ret >= 0) {
1037*fcf5ef2aSThomas Huth         ctx->raddr = raddr;
1038*fcf5ef2aSThomas Huth         LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1039*fcf5ef2aSThomas Huth                   " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1040*fcf5ef2aSThomas Huth                   ret);
1041*fcf5ef2aSThomas Huth     } else {
1042*fcf5ef2aSThomas Huth         LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1043*fcf5ef2aSThomas Huth                   " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1044*fcf5ef2aSThomas Huth     }
1045*fcf5ef2aSThomas Huth 
1046*fcf5ef2aSThomas Huth     return ret;
1047*fcf5ef2aSThomas Huth }
1048*fcf5ef2aSThomas Huth 
1049*fcf5ef2aSThomas Huth static const char *book3e_tsize_to_str[32] = {
1050*fcf5ef2aSThomas Huth     "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
1051*fcf5ef2aSThomas Huth     "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
1052*fcf5ef2aSThomas Huth     "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
1053*fcf5ef2aSThomas Huth     "1T", "2T"
1054*fcf5ef2aSThomas Huth };
1055*fcf5ef2aSThomas Huth 
1056*fcf5ef2aSThomas Huth static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1057*fcf5ef2aSThomas Huth                                  CPUPPCState *env)
1058*fcf5ef2aSThomas Huth {
1059*fcf5ef2aSThomas Huth     ppcemb_tlb_t *entry;
1060*fcf5ef2aSThomas Huth     int i;
1061*fcf5ef2aSThomas Huth 
1062*fcf5ef2aSThomas Huth     if (kvm_enabled() && !env->kvm_sw_tlb) {
1063*fcf5ef2aSThomas Huth         cpu_fprintf(f, "Cannot access KVM TLB\n");
1064*fcf5ef2aSThomas Huth         return;
1065*fcf5ef2aSThomas Huth     }
1066*fcf5ef2aSThomas Huth 
1067*fcf5ef2aSThomas Huth     cpu_fprintf(f, "\nTLB:\n");
1068*fcf5ef2aSThomas Huth     cpu_fprintf(f, "Effective          Physical           Size PID   Prot     "
1069*fcf5ef2aSThomas Huth                 "Attr\n");
1070*fcf5ef2aSThomas Huth 
1071*fcf5ef2aSThomas Huth     entry = &env->tlb.tlbe[0];
1072*fcf5ef2aSThomas Huth     for (i = 0; i < env->nb_tlb; i++, entry++) {
1073*fcf5ef2aSThomas Huth         hwaddr ea, pa;
1074*fcf5ef2aSThomas Huth         target_ulong mask;
1075*fcf5ef2aSThomas Huth         uint64_t size = (uint64_t)entry->size;
1076*fcf5ef2aSThomas Huth         char size_buf[20];
1077*fcf5ef2aSThomas Huth 
1078*fcf5ef2aSThomas Huth         /* Check valid flag */
1079*fcf5ef2aSThomas Huth         if (!(entry->prot & PAGE_VALID)) {
1080*fcf5ef2aSThomas Huth             continue;
1081*fcf5ef2aSThomas Huth         }
1082*fcf5ef2aSThomas Huth 
1083*fcf5ef2aSThomas Huth         mask = ~(entry->size - 1);
1084*fcf5ef2aSThomas Huth         ea = entry->EPN & mask;
1085*fcf5ef2aSThomas Huth         pa = entry->RPN & mask;
1086*fcf5ef2aSThomas Huth         /* Extend the physical address to 36 bits */
1087*fcf5ef2aSThomas Huth         pa |= (hwaddr)(entry->RPN & 0xF) << 32;
1088*fcf5ef2aSThomas Huth         size /= 1024;
1089*fcf5ef2aSThomas Huth         if (size >= 1024) {
1090*fcf5ef2aSThomas Huth             snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024);
1091*fcf5ef2aSThomas Huth         } else {
1092*fcf5ef2aSThomas Huth             snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size);
1093*fcf5ef2aSThomas Huth         }
1094*fcf5ef2aSThomas Huth         cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
1095*fcf5ef2aSThomas Huth                     (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
1096*fcf5ef2aSThomas Huth                     entry->prot, entry->attr);
1097*fcf5ef2aSThomas Huth     }
1098*fcf5ef2aSThomas Huth 
1099*fcf5ef2aSThomas Huth }
1100*fcf5ef2aSThomas Huth 
1101*fcf5ef2aSThomas Huth static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
1102*fcf5ef2aSThomas Huth                                      CPUPPCState *env, int tlbn, int offset,
1103*fcf5ef2aSThomas Huth                                      int tlbsize)
1104*fcf5ef2aSThomas Huth {
1105*fcf5ef2aSThomas Huth     ppcmas_tlb_t *entry;
1106*fcf5ef2aSThomas Huth     int i;
1107*fcf5ef2aSThomas Huth 
1108*fcf5ef2aSThomas Huth     cpu_fprintf(f, "\nTLB%d:\n", tlbn);
1109*fcf5ef2aSThomas Huth     cpu_fprintf(f, "Effective          Physical           Size TID   TS SRWX"
1110*fcf5ef2aSThomas Huth                 " URWX WIMGE U0123\n");
1111*fcf5ef2aSThomas Huth 
1112*fcf5ef2aSThomas Huth     entry = &env->tlb.tlbm[offset];
1113*fcf5ef2aSThomas Huth     for (i = 0; i < tlbsize; i++, entry++) {
1114*fcf5ef2aSThomas Huth         hwaddr ea, pa, size;
1115*fcf5ef2aSThomas Huth         int tsize;
1116*fcf5ef2aSThomas Huth 
1117*fcf5ef2aSThomas Huth         if (!(entry->mas1 & MAS1_VALID)) {
1118*fcf5ef2aSThomas Huth             continue;
1119*fcf5ef2aSThomas Huth         }
1120*fcf5ef2aSThomas Huth 
1121*fcf5ef2aSThomas Huth         tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1122*fcf5ef2aSThomas Huth         size = 1024ULL << tsize;
1123*fcf5ef2aSThomas Huth         ea = entry->mas2 & ~(size - 1);
1124*fcf5ef2aSThomas Huth         pa = entry->mas7_3 & ~(size - 1);
1125*fcf5ef2aSThomas Huth 
1126*fcf5ef2aSThomas Huth         cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u  S%c%c%c"
1127*fcf5ef2aSThomas Huth                     "U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
1128*fcf5ef2aSThomas Huth                     (uint64_t)ea, (uint64_t)pa,
1129*fcf5ef2aSThomas Huth                     book3e_tsize_to_str[tsize],
1130*fcf5ef2aSThomas Huth                     (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
1131*fcf5ef2aSThomas Huth                     (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
1132*fcf5ef2aSThomas Huth                     entry->mas7_3 & MAS3_SR ? 'R' : '-',
1133*fcf5ef2aSThomas Huth                     entry->mas7_3 & MAS3_SW ? 'W' : '-',
1134*fcf5ef2aSThomas Huth                     entry->mas7_3 & MAS3_SX ? 'X' : '-',
1135*fcf5ef2aSThomas Huth                     entry->mas7_3 & MAS3_UR ? 'R' : '-',
1136*fcf5ef2aSThomas Huth                     entry->mas7_3 & MAS3_UW ? 'W' : '-',
1137*fcf5ef2aSThomas Huth                     entry->mas7_3 & MAS3_UX ? 'X' : '-',
1138*fcf5ef2aSThomas Huth                     entry->mas2 & MAS2_W ? 'W' : '-',
1139*fcf5ef2aSThomas Huth                     entry->mas2 & MAS2_I ? 'I' : '-',
1140*fcf5ef2aSThomas Huth                     entry->mas2 & MAS2_M ? 'M' : '-',
1141*fcf5ef2aSThomas Huth                     entry->mas2 & MAS2_G ? 'G' : '-',
1142*fcf5ef2aSThomas Huth                     entry->mas2 & MAS2_E ? 'E' : '-',
1143*fcf5ef2aSThomas Huth                     entry->mas7_3 & MAS3_U0 ? '0' : '-',
1144*fcf5ef2aSThomas Huth                     entry->mas7_3 & MAS3_U1 ? '1' : '-',
1145*fcf5ef2aSThomas Huth                     entry->mas7_3 & MAS3_U2 ? '2' : '-',
1146*fcf5ef2aSThomas Huth                     entry->mas7_3 & MAS3_U3 ? '3' : '-');
1147*fcf5ef2aSThomas Huth     }
1148*fcf5ef2aSThomas Huth }
1149*fcf5ef2aSThomas Huth 
1150*fcf5ef2aSThomas Huth static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1151*fcf5ef2aSThomas Huth                                  CPUPPCState *env)
1152*fcf5ef2aSThomas Huth {
1153*fcf5ef2aSThomas Huth     int offset = 0;
1154*fcf5ef2aSThomas Huth     int i;
1155*fcf5ef2aSThomas Huth 
1156*fcf5ef2aSThomas Huth     if (kvm_enabled() && !env->kvm_sw_tlb) {
1157*fcf5ef2aSThomas Huth         cpu_fprintf(f, "Cannot access KVM TLB\n");
1158*fcf5ef2aSThomas Huth         return;
1159*fcf5ef2aSThomas Huth     }
1160*fcf5ef2aSThomas Huth 
1161*fcf5ef2aSThomas Huth     for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1162*fcf5ef2aSThomas Huth         int size = booke206_tlb_size(env, i);
1163*fcf5ef2aSThomas Huth 
1164*fcf5ef2aSThomas Huth         if (size == 0) {
1165*fcf5ef2aSThomas Huth             continue;
1166*fcf5ef2aSThomas Huth         }
1167*fcf5ef2aSThomas Huth 
1168*fcf5ef2aSThomas Huth         mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size);
1169*fcf5ef2aSThomas Huth         offset += size;
1170*fcf5ef2aSThomas Huth     }
1171*fcf5ef2aSThomas Huth }
1172*fcf5ef2aSThomas Huth 
1173*fcf5ef2aSThomas Huth static void mmu6xx_dump_BATs(FILE *f, fprintf_function cpu_fprintf,
1174*fcf5ef2aSThomas Huth                              CPUPPCState *env, int type)
1175*fcf5ef2aSThomas Huth {
1176*fcf5ef2aSThomas Huth     target_ulong *BATlt, *BATut, *BATu, *BATl;
1177*fcf5ef2aSThomas Huth     target_ulong BEPIl, BEPIu, bl;
1178*fcf5ef2aSThomas Huth     int i;
1179*fcf5ef2aSThomas Huth 
1180*fcf5ef2aSThomas Huth     switch (type) {
1181*fcf5ef2aSThomas Huth     case ACCESS_CODE:
1182*fcf5ef2aSThomas Huth         BATlt = env->IBAT[1];
1183*fcf5ef2aSThomas Huth         BATut = env->IBAT[0];
1184*fcf5ef2aSThomas Huth         break;
1185*fcf5ef2aSThomas Huth     default:
1186*fcf5ef2aSThomas Huth         BATlt = env->DBAT[1];
1187*fcf5ef2aSThomas Huth         BATut = env->DBAT[0];
1188*fcf5ef2aSThomas Huth         break;
1189*fcf5ef2aSThomas Huth     }
1190*fcf5ef2aSThomas Huth 
1191*fcf5ef2aSThomas Huth     for (i = 0; i < env->nb_BATs; i++) {
1192*fcf5ef2aSThomas Huth         BATu = &BATut[i];
1193*fcf5ef2aSThomas Huth         BATl = &BATlt[i];
1194*fcf5ef2aSThomas Huth         BEPIu = *BATu & 0xF0000000;
1195*fcf5ef2aSThomas Huth         BEPIl = *BATu & 0x0FFE0000;
1196*fcf5ef2aSThomas Huth         bl = (*BATu & 0x00001FFC) << 15;
1197*fcf5ef2aSThomas Huth         cpu_fprintf(f, "%s BAT%d BATu " TARGET_FMT_lx
1198*fcf5ef2aSThomas Huth                     " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
1199*fcf5ef2aSThomas Huth                     TARGET_FMT_lx " " TARGET_FMT_lx "\n",
1200*fcf5ef2aSThomas Huth                     type == ACCESS_CODE ? "code" : "data", i,
1201*fcf5ef2aSThomas Huth                     *BATu, *BATl, BEPIu, BEPIl, bl);
1202*fcf5ef2aSThomas Huth     }
1203*fcf5ef2aSThomas Huth }
1204*fcf5ef2aSThomas Huth 
1205*fcf5ef2aSThomas Huth static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1206*fcf5ef2aSThomas Huth                             CPUPPCState *env)
1207*fcf5ef2aSThomas Huth {
1208*fcf5ef2aSThomas Huth     ppc6xx_tlb_t *tlb;
1209*fcf5ef2aSThomas Huth     target_ulong sr;
1210*fcf5ef2aSThomas Huth     int type, way, entry, i;
1211*fcf5ef2aSThomas Huth 
1212*fcf5ef2aSThomas Huth     cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", env->htab_base);
1213*fcf5ef2aSThomas Huth     cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", env->htab_mask);
1214*fcf5ef2aSThomas Huth 
1215*fcf5ef2aSThomas Huth     cpu_fprintf(f, "\nSegment registers:\n");
1216*fcf5ef2aSThomas Huth     for (i = 0; i < 32; i++) {
1217*fcf5ef2aSThomas Huth         sr = env->sr[i];
1218*fcf5ef2aSThomas Huth         if (sr & 0x80000000) {
1219*fcf5ef2aSThomas Huth             cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d BUID=0x%03x "
1220*fcf5ef2aSThomas Huth                         "CNTLR_SPEC=0x%05x\n", i,
1221*fcf5ef2aSThomas Huth                         sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1222*fcf5ef2aSThomas Huth                         sr & 0x20000000 ? 1 : 0, (uint32_t)((sr >> 20) & 0x1FF),
1223*fcf5ef2aSThomas Huth                         (uint32_t)(sr & 0xFFFFF));
1224*fcf5ef2aSThomas Huth         } else {
1225*fcf5ef2aSThomas Huth             cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d N=%d VSID=0x%06x\n", i,
1226*fcf5ef2aSThomas Huth                         sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1227*fcf5ef2aSThomas Huth                         sr & 0x20000000 ? 1 : 0, sr & 0x10000000 ? 1 : 0,
1228*fcf5ef2aSThomas Huth                         (uint32_t)(sr & 0x00FFFFFF));
1229*fcf5ef2aSThomas Huth         }
1230*fcf5ef2aSThomas Huth     }
1231*fcf5ef2aSThomas Huth 
1232*fcf5ef2aSThomas Huth     cpu_fprintf(f, "\nBATs:\n");
1233*fcf5ef2aSThomas Huth     mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_INT);
1234*fcf5ef2aSThomas Huth     mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_CODE);
1235*fcf5ef2aSThomas Huth 
1236*fcf5ef2aSThomas Huth     if (env->id_tlbs != 1) {
1237*fcf5ef2aSThomas Huth         cpu_fprintf(f, "ERROR: 6xx MMU should have separated TLB"
1238*fcf5ef2aSThomas Huth                     " for code and data\n");
1239*fcf5ef2aSThomas Huth     }
1240*fcf5ef2aSThomas Huth 
1241*fcf5ef2aSThomas Huth     cpu_fprintf(f, "\nTLBs                       [EPN    EPN + SIZE]\n");
1242*fcf5ef2aSThomas Huth 
1243*fcf5ef2aSThomas Huth     for (type = 0; type < 2; type++) {
1244*fcf5ef2aSThomas Huth         for (way = 0; way < env->nb_ways; way++) {
1245*fcf5ef2aSThomas Huth             for (entry = env->nb_tlb * type + env->tlb_per_way * way;
1246*fcf5ef2aSThomas Huth                  entry < (env->nb_tlb * type + env->tlb_per_way * (way + 1));
1247*fcf5ef2aSThomas Huth                  entry++) {
1248*fcf5ef2aSThomas Huth 
1249*fcf5ef2aSThomas Huth                 tlb = &env->tlb.tlb6[entry];
1250*fcf5ef2aSThomas Huth                 cpu_fprintf(f, "%s TLB %02d/%02d way:%d %s ["
1251*fcf5ef2aSThomas Huth                             TARGET_FMT_lx " " TARGET_FMT_lx "]\n",
1252*fcf5ef2aSThomas Huth                             type ? "code" : "data", entry % env->nb_tlb,
1253*fcf5ef2aSThomas Huth                             env->nb_tlb, way,
1254*fcf5ef2aSThomas Huth                             pte_is_valid(tlb->pte0) ? "valid" : "inval",
1255*fcf5ef2aSThomas Huth                             tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE);
1256*fcf5ef2aSThomas Huth             }
1257*fcf5ef2aSThomas Huth         }
1258*fcf5ef2aSThomas Huth     }
1259*fcf5ef2aSThomas Huth }
1260*fcf5ef2aSThomas Huth 
1261*fcf5ef2aSThomas Huth void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
1262*fcf5ef2aSThomas Huth {
1263*fcf5ef2aSThomas Huth     switch (env->mmu_model) {
1264*fcf5ef2aSThomas Huth     case POWERPC_MMU_BOOKE:
1265*fcf5ef2aSThomas Huth         mmubooke_dump_mmu(f, cpu_fprintf, env);
1266*fcf5ef2aSThomas Huth         break;
1267*fcf5ef2aSThomas Huth     case POWERPC_MMU_BOOKE206:
1268*fcf5ef2aSThomas Huth         mmubooke206_dump_mmu(f, cpu_fprintf, env);
1269*fcf5ef2aSThomas Huth         break;
1270*fcf5ef2aSThomas Huth     case POWERPC_MMU_SOFT_6xx:
1271*fcf5ef2aSThomas Huth     case POWERPC_MMU_SOFT_74xx:
1272*fcf5ef2aSThomas Huth         mmu6xx_dump_mmu(f, cpu_fprintf, env);
1273*fcf5ef2aSThomas Huth         break;
1274*fcf5ef2aSThomas Huth #if defined(TARGET_PPC64)
1275*fcf5ef2aSThomas Huth     case POWERPC_MMU_64B:
1276*fcf5ef2aSThomas Huth     case POWERPC_MMU_2_03:
1277*fcf5ef2aSThomas Huth     case POWERPC_MMU_2_06:
1278*fcf5ef2aSThomas Huth     case POWERPC_MMU_2_06a:
1279*fcf5ef2aSThomas Huth     case POWERPC_MMU_2_07:
1280*fcf5ef2aSThomas Huth     case POWERPC_MMU_2_07a:
1281*fcf5ef2aSThomas Huth         dump_slb(f, cpu_fprintf, ppc_env_get_cpu(env));
1282*fcf5ef2aSThomas Huth         break;
1283*fcf5ef2aSThomas Huth #endif
1284*fcf5ef2aSThomas Huth     default:
1285*fcf5ef2aSThomas Huth         qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
1286*fcf5ef2aSThomas Huth     }
1287*fcf5ef2aSThomas Huth }
1288*fcf5ef2aSThomas Huth 
1289*fcf5ef2aSThomas Huth static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
1290*fcf5ef2aSThomas Huth                                  target_ulong eaddr, int rw)
1291*fcf5ef2aSThomas Huth {
1292*fcf5ef2aSThomas Huth     int in_plb, ret;
1293*fcf5ef2aSThomas Huth 
1294*fcf5ef2aSThomas Huth     ctx->raddr = eaddr;
1295*fcf5ef2aSThomas Huth     ctx->prot = PAGE_READ | PAGE_EXEC;
1296*fcf5ef2aSThomas Huth     ret = 0;
1297*fcf5ef2aSThomas Huth     switch (env->mmu_model) {
1298*fcf5ef2aSThomas Huth     case POWERPC_MMU_SOFT_6xx:
1299*fcf5ef2aSThomas Huth     case POWERPC_MMU_SOFT_74xx:
1300*fcf5ef2aSThomas Huth     case POWERPC_MMU_SOFT_4xx:
1301*fcf5ef2aSThomas Huth     case POWERPC_MMU_REAL:
1302*fcf5ef2aSThomas Huth     case POWERPC_MMU_BOOKE:
1303*fcf5ef2aSThomas Huth         ctx->prot |= PAGE_WRITE;
1304*fcf5ef2aSThomas Huth         break;
1305*fcf5ef2aSThomas Huth 
1306*fcf5ef2aSThomas Huth     case POWERPC_MMU_SOFT_4xx_Z:
1307*fcf5ef2aSThomas Huth         if (unlikely(msr_pe != 0)) {
1308*fcf5ef2aSThomas Huth             /* 403 family add some particular protections,
1309*fcf5ef2aSThomas Huth              * using PBL/PBU registers for accesses with no translation.
1310*fcf5ef2aSThomas Huth              */
1311*fcf5ef2aSThomas Huth             in_plb =
1312*fcf5ef2aSThomas Huth                 /* Check PLB validity */
1313*fcf5ef2aSThomas Huth                 (env->pb[0] < env->pb[1] &&
1314*fcf5ef2aSThomas Huth                  /* and address in plb area */
1315*fcf5ef2aSThomas Huth                  eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
1316*fcf5ef2aSThomas Huth                 (env->pb[2] < env->pb[3] &&
1317*fcf5ef2aSThomas Huth                  eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
1318*fcf5ef2aSThomas Huth             if (in_plb ^ msr_px) {
1319*fcf5ef2aSThomas Huth                 /* Access in protected area */
1320*fcf5ef2aSThomas Huth                 if (rw == 1) {
1321*fcf5ef2aSThomas Huth                     /* Access is not allowed */
1322*fcf5ef2aSThomas Huth                     ret = -2;
1323*fcf5ef2aSThomas Huth                 }
1324*fcf5ef2aSThomas Huth             } else {
1325*fcf5ef2aSThomas Huth                 /* Read-write access is allowed */
1326*fcf5ef2aSThomas Huth                 ctx->prot |= PAGE_WRITE;
1327*fcf5ef2aSThomas Huth             }
1328*fcf5ef2aSThomas Huth         }
1329*fcf5ef2aSThomas Huth         break;
1330*fcf5ef2aSThomas Huth 
1331*fcf5ef2aSThomas Huth     default:
1332*fcf5ef2aSThomas Huth         /* Caller's checks mean we should never get here for other models */
1333*fcf5ef2aSThomas Huth         abort();
1334*fcf5ef2aSThomas Huth         return -1;
1335*fcf5ef2aSThomas Huth     }
1336*fcf5ef2aSThomas Huth 
1337*fcf5ef2aSThomas Huth     return ret;
1338*fcf5ef2aSThomas Huth }
1339*fcf5ef2aSThomas Huth 
1340*fcf5ef2aSThomas Huth static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1341*fcf5ef2aSThomas Huth                                 target_ulong eaddr, int rw, int access_type)
1342*fcf5ef2aSThomas Huth {
1343*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = ppc_env_get_cpu(env);
1344*fcf5ef2aSThomas Huth     int ret = -1;
1345*fcf5ef2aSThomas Huth     bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
1346*fcf5ef2aSThomas Huth         || (access_type != ACCESS_CODE && msr_dr == 0);
1347*fcf5ef2aSThomas Huth 
1348*fcf5ef2aSThomas Huth #if 0
1349*fcf5ef2aSThomas Huth     qemu_log("%s\n", __func__);
1350*fcf5ef2aSThomas Huth #endif
1351*fcf5ef2aSThomas Huth 
1352*fcf5ef2aSThomas Huth     switch (env->mmu_model) {
1353*fcf5ef2aSThomas Huth     case POWERPC_MMU_SOFT_6xx:
1354*fcf5ef2aSThomas Huth     case POWERPC_MMU_SOFT_74xx:
1355*fcf5ef2aSThomas Huth         if (real_mode) {
1356*fcf5ef2aSThomas Huth             ret = check_physical(env, ctx, eaddr, rw);
1357*fcf5ef2aSThomas Huth         } else {
1358*fcf5ef2aSThomas Huth             /* Try to find a BAT */
1359*fcf5ef2aSThomas Huth             if (env->nb_BATs != 0) {
1360*fcf5ef2aSThomas Huth                 ret = get_bat_6xx_tlb(env, ctx, eaddr, rw, access_type);
1361*fcf5ef2aSThomas Huth             }
1362*fcf5ef2aSThomas Huth             if (ret < 0) {
1363*fcf5ef2aSThomas Huth                 /* We didn't match any BAT entry or don't have BATs */
1364*fcf5ef2aSThomas Huth                 ret = get_segment_6xx_tlb(env, ctx, eaddr, rw, access_type);
1365*fcf5ef2aSThomas Huth             }
1366*fcf5ef2aSThomas Huth         }
1367*fcf5ef2aSThomas Huth         break;
1368*fcf5ef2aSThomas Huth 
1369*fcf5ef2aSThomas Huth     case POWERPC_MMU_SOFT_4xx:
1370*fcf5ef2aSThomas Huth     case POWERPC_MMU_SOFT_4xx_Z:
1371*fcf5ef2aSThomas Huth         if (real_mode) {
1372*fcf5ef2aSThomas Huth             ret = check_physical(env, ctx, eaddr, rw);
1373*fcf5ef2aSThomas Huth         } else {
1374*fcf5ef2aSThomas Huth             ret = mmu40x_get_physical_address(env, ctx, eaddr,
1375*fcf5ef2aSThomas Huth                                               rw, access_type);
1376*fcf5ef2aSThomas Huth         }
1377*fcf5ef2aSThomas Huth         break;
1378*fcf5ef2aSThomas Huth     case POWERPC_MMU_BOOKE:
1379*fcf5ef2aSThomas Huth         ret = mmubooke_get_physical_address(env, ctx, eaddr,
1380*fcf5ef2aSThomas Huth                                             rw, access_type);
1381*fcf5ef2aSThomas Huth         break;
1382*fcf5ef2aSThomas Huth     case POWERPC_MMU_BOOKE206:
1383*fcf5ef2aSThomas Huth         ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
1384*fcf5ef2aSThomas Huth                                                access_type);
1385*fcf5ef2aSThomas Huth         break;
1386*fcf5ef2aSThomas Huth     case POWERPC_MMU_MPC8xx:
1387*fcf5ef2aSThomas Huth         /* XXX: TODO */
1388*fcf5ef2aSThomas Huth         cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1389*fcf5ef2aSThomas Huth         break;
1390*fcf5ef2aSThomas Huth     case POWERPC_MMU_REAL:
1391*fcf5ef2aSThomas Huth         if (real_mode) {
1392*fcf5ef2aSThomas Huth             ret = check_physical(env, ctx, eaddr, rw);
1393*fcf5ef2aSThomas Huth         } else {
1394*fcf5ef2aSThomas Huth             cpu_abort(CPU(cpu), "PowerPC in real mode do not do any translation\n");
1395*fcf5ef2aSThomas Huth         }
1396*fcf5ef2aSThomas Huth         return -1;
1397*fcf5ef2aSThomas Huth     default:
1398*fcf5ef2aSThomas Huth         cpu_abort(CPU(cpu), "Unknown or invalid MMU model\n");
1399*fcf5ef2aSThomas Huth         return -1;
1400*fcf5ef2aSThomas Huth     }
1401*fcf5ef2aSThomas Huth #if 0
1402*fcf5ef2aSThomas Huth     qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
1403*fcf5ef2aSThomas Huth              __func__, eaddr, ret, ctx->raddr);
1404*fcf5ef2aSThomas Huth #endif
1405*fcf5ef2aSThomas Huth 
1406*fcf5ef2aSThomas Huth     return ret;
1407*fcf5ef2aSThomas Huth }
1408*fcf5ef2aSThomas Huth 
1409*fcf5ef2aSThomas Huth hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
1410*fcf5ef2aSThomas Huth {
1411*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = POWERPC_CPU(cs);
1412*fcf5ef2aSThomas Huth     CPUPPCState *env = &cpu->env;
1413*fcf5ef2aSThomas Huth     mmu_ctx_t ctx;
1414*fcf5ef2aSThomas Huth 
1415*fcf5ef2aSThomas Huth     switch (env->mmu_model) {
1416*fcf5ef2aSThomas Huth #if defined(TARGET_PPC64)
1417*fcf5ef2aSThomas Huth     case POWERPC_MMU_64B:
1418*fcf5ef2aSThomas Huth     case POWERPC_MMU_2_03:
1419*fcf5ef2aSThomas Huth     case POWERPC_MMU_2_06:
1420*fcf5ef2aSThomas Huth     case POWERPC_MMU_2_06a:
1421*fcf5ef2aSThomas Huth     case POWERPC_MMU_2_07:
1422*fcf5ef2aSThomas Huth     case POWERPC_MMU_2_07a:
1423*fcf5ef2aSThomas Huth         return ppc_hash64_get_phys_page_debug(cpu, addr);
1424*fcf5ef2aSThomas Huth #endif
1425*fcf5ef2aSThomas Huth 
1426*fcf5ef2aSThomas Huth     case POWERPC_MMU_32B:
1427*fcf5ef2aSThomas Huth     case POWERPC_MMU_601:
1428*fcf5ef2aSThomas Huth         return ppc_hash32_get_phys_page_debug(cpu, addr);
1429*fcf5ef2aSThomas Huth 
1430*fcf5ef2aSThomas Huth     default:
1431*fcf5ef2aSThomas Huth         ;
1432*fcf5ef2aSThomas Huth     }
1433*fcf5ef2aSThomas Huth 
1434*fcf5ef2aSThomas Huth     if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {
1435*fcf5ef2aSThomas Huth 
1436*fcf5ef2aSThomas Huth         /* Some MMUs have separate TLBs for code and data. If we only try an
1437*fcf5ef2aSThomas Huth          * ACCESS_INT, we may not be able to read instructions mapped by code
1438*fcf5ef2aSThomas Huth          * TLBs, so we also try a ACCESS_CODE.
1439*fcf5ef2aSThomas Huth          */
1440*fcf5ef2aSThomas Huth         if (unlikely(get_physical_address(env, &ctx, addr, 0,
1441*fcf5ef2aSThomas Huth                                           ACCESS_CODE) != 0)) {
1442*fcf5ef2aSThomas Huth             return -1;
1443*fcf5ef2aSThomas Huth         }
1444*fcf5ef2aSThomas Huth     }
1445*fcf5ef2aSThomas Huth 
1446*fcf5ef2aSThomas Huth     return ctx.raddr & TARGET_PAGE_MASK;
1447*fcf5ef2aSThomas Huth }
1448*fcf5ef2aSThomas Huth 
1449*fcf5ef2aSThomas Huth static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
1450*fcf5ef2aSThomas Huth                                      int rw)
1451*fcf5ef2aSThomas Huth {
1452*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
1453*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
1454*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
1455*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS3] = 0;
1456*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS6] = 0;
1457*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS7] = 0;
1458*fcf5ef2aSThomas Huth 
1459*fcf5ef2aSThomas Huth     /* AS */
1460*fcf5ef2aSThomas Huth     if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
1461*fcf5ef2aSThomas Huth         env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
1462*fcf5ef2aSThomas Huth         env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
1463*fcf5ef2aSThomas Huth     }
1464*fcf5ef2aSThomas Huth 
1465*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
1466*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
1467*fcf5ef2aSThomas Huth 
1468*fcf5ef2aSThomas Huth     switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
1469*fcf5ef2aSThomas Huth     case MAS4_TIDSELD_PID0:
1470*fcf5ef2aSThomas Huth         env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
1471*fcf5ef2aSThomas Huth         break;
1472*fcf5ef2aSThomas Huth     case MAS4_TIDSELD_PID1:
1473*fcf5ef2aSThomas Huth         env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
1474*fcf5ef2aSThomas Huth         break;
1475*fcf5ef2aSThomas Huth     case MAS4_TIDSELD_PID2:
1476*fcf5ef2aSThomas Huth         env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
1477*fcf5ef2aSThomas Huth         break;
1478*fcf5ef2aSThomas Huth     }
1479*fcf5ef2aSThomas Huth 
1480*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
1481*fcf5ef2aSThomas Huth 
1482*fcf5ef2aSThomas Huth     /* next victim logic */
1483*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
1484*fcf5ef2aSThomas Huth     env->last_way++;
1485*fcf5ef2aSThomas Huth     env->last_way &= booke206_tlb_ways(env, 0) - 1;
1486*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
1487*fcf5ef2aSThomas Huth }
1488*fcf5ef2aSThomas Huth 
1489*fcf5ef2aSThomas Huth /* Perform address translation */
1490*fcf5ef2aSThomas Huth static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
1491*fcf5ef2aSThomas Huth                                     int rw, int mmu_idx)
1492*fcf5ef2aSThomas Huth {
1493*fcf5ef2aSThomas Huth     CPUState *cs = CPU(ppc_env_get_cpu(env));
1494*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = POWERPC_CPU(cs);
1495*fcf5ef2aSThomas Huth     mmu_ctx_t ctx;
1496*fcf5ef2aSThomas Huth     int access_type;
1497*fcf5ef2aSThomas Huth     int ret = 0;
1498*fcf5ef2aSThomas Huth 
1499*fcf5ef2aSThomas Huth     if (rw == 2) {
1500*fcf5ef2aSThomas Huth         /* code access */
1501*fcf5ef2aSThomas Huth         rw = 0;
1502*fcf5ef2aSThomas Huth         access_type = ACCESS_CODE;
1503*fcf5ef2aSThomas Huth     } else {
1504*fcf5ef2aSThomas Huth         /* data access */
1505*fcf5ef2aSThomas Huth         access_type = env->access_type;
1506*fcf5ef2aSThomas Huth     }
1507*fcf5ef2aSThomas Huth     ret = get_physical_address(env, &ctx, address, rw, access_type);
1508*fcf5ef2aSThomas Huth     if (ret == 0) {
1509*fcf5ef2aSThomas Huth         tlb_set_page(cs, address & TARGET_PAGE_MASK,
1510*fcf5ef2aSThomas Huth                      ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
1511*fcf5ef2aSThomas Huth                      mmu_idx, TARGET_PAGE_SIZE);
1512*fcf5ef2aSThomas Huth         ret = 0;
1513*fcf5ef2aSThomas Huth     } else if (ret < 0) {
1514*fcf5ef2aSThomas Huth         LOG_MMU_STATE(cs);
1515*fcf5ef2aSThomas Huth         if (access_type == ACCESS_CODE) {
1516*fcf5ef2aSThomas Huth             switch (ret) {
1517*fcf5ef2aSThomas Huth             case -1:
1518*fcf5ef2aSThomas Huth                 /* No matches in page tables or TLB */
1519*fcf5ef2aSThomas Huth                 switch (env->mmu_model) {
1520*fcf5ef2aSThomas Huth                 case POWERPC_MMU_SOFT_6xx:
1521*fcf5ef2aSThomas Huth                     cs->exception_index = POWERPC_EXCP_IFTLB;
1522*fcf5ef2aSThomas Huth                     env->error_code = 1 << 18;
1523*fcf5ef2aSThomas Huth                     env->spr[SPR_IMISS] = address;
1524*fcf5ef2aSThomas Huth                     env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
1525*fcf5ef2aSThomas Huth                     goto tlb_miss;
1526*fcf5ef2aSThomas Huth                 case POWERPC_MMU_SOFT_74xx:
1527*fcf5ef2aSThomas Huth                     cs->exception_index = POWERPC_EXCP_IFTLB;
1528*fcf5ef2aSThomas Huth                     goto tlb_miss_74xx;
1529*fcf5ef2aSThomas Huth                 case POWERPC_MMU_SOFT_4xx:
1530*fcf5ef2aSThomas Huth                 case POWERPC_MMU_SOFT_4xx_Z:
1531*fcf5ef2aSThomas Huth                     cs->exception_index = POWERPC_EXCP_ITLB;
1532*fcf5ef2aSThomas Huth                     env->error_code = 0;
1533*fcf5ef2aSThomas Huth                     env->spr[SPR_40x_DEAR] = address;
1534*fcf5ef2aSThomas Huth                     env->spr[SPR_40x_ESR] = 0x00000000;
1535*fcf5ef2aSThomas Huth                     break;
1536*fcf5ef2aSThomas Huth                 case POWERPC_MMU_BOOKE206:
1537*fcf5ef2aSThomas Huth                     booke206_update_mas_tlb_miss(env, address, rw);
1538*fcf5ef2aSThomas Huth                     /* fall through */
1539*fcf5ef2aSThomas Huth                 case POWERPC_MMU_BOOKE:
1540*fcf5ef2aSThomas Huth                     cs->exception_index = POWERPC_EXCP_ITLB;
1541*fcf5ef2aSThomas Huth                     env->error_code = 0;
1542*fcf5ef2aSThomas Huth                     env->spr[SPR_BOOKE_DEAR] = address;
1543*fcf5ef2aSThomas Huth                     return -1;
1544*fcf5ef2aSThomas Huth                 case POWERPC_MMU_MPC8xx:
1545*fcf5ef2aSThomas Huth                     /* XXX: TODO */
1546*fcf5ef2aSThomas Huth                     cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1547*fcf5ef2aSThomas Huth                     break;
1548*fcf5ef2aSThomas Huth                 case POWERPC_MMU_REAL:
1549*fcf5ef2aSThomas Huth                     cpu_abort(cs, "PowerPC in real mode should never raise "
1550*fcf5ef2aSThomas Huth                               "any MMU exceptions\n");
1551*fcf5ef2aSThomas Huth                     return -1;
1552*fcf5ef2aSThomas Huth                 default:
1553*fcf5ef2aSThomas Huth                     cpu_abort(cs, "Unknown or invalid MMU model\n");
1554*fcf5ef2aSThomas Huth                     return -1;
1555*fcf5ef2aSThomas Huth                 }
1556*fcf5ef2aSThomas Huth                 break;
1557*fcf5ef2aSThomas Huth             case -2:
1558*fcf5ef2aSThomas Huth                 /* Access rights violation */
1559*fcf5ef2aSThomas Huth                 cs->exception_index = POWERPC_EXCP_ISI;
1560*fcf5ef2aSThomas Huth                 env->error_code = 0x08000000;
1561*fcf5ef2aSThomas Huth                 break;
1562*fcf5ef2aSThomas Huth             case -3:
1563*fcf5ef2aSThomas Huth                 /* No execute protection violation */
1564*fcf5ef2aSThomas Huth                 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1565*fcf5ef2aSThomas Huth                     (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1566*fcf5ef2aSThomas Huth                     env->spr[SPR_BOOKE_ESR] = 0x00000000;
1567*fcf5ef2aSThomas Huth                 }
1568*fcf5ef2aSThomas Huth                 cs->exception_index = POWERPC_EXCP_ISI;
1569*fcf5ef2aSThomas Huth                 env->error_code = 0x10000000;
1570*fcf5ef2aSThomas Huth                 break;
1571*fcf5ef2aSThomas Huth             case -4:
1572*fcf5ef2aSThomas Huth                 /* Direct store exception */
1573*fcf5ef2aSThomas Huth                 /* No code fetch is allowed in direct-store areas */
1574*fcf5ef2aSThomas Huth                 cs->exception_index = POWERPC_EXCP_ISI;
1575*fcf5ef2aSThomas Huth                 env->error_code = 0x10000000;
1576*fcf5ef2aSThomas Huth                 break;
1577*fcf5ef2aSThomas Huth             }
1578*fcf5ef2aSThomas Huth         } else {
1579*fcf5ef2aSThomas Huth             switch (ret) {
1580*fcf5ef2aSThomas Huth             case -1:
1581*fcf5ef2aSThomas Huth                 /* No matches in page tables or TLB */
1582*fcf5ef2aSThomas Huth                 switch (env->mmu_model) {
1583*fcf5ef2aSThomas Huth                 case POWERPC_MMU_SOFT_6xx:
1584*fcf5ef2aSThomas Huth                     if (rw == 1) {
1585*fcf5ef2aSThomas Huth                         cs->exception_index = POWERPC_EXCP_DSTLB;
1586*fcf5ef2aSThomas Huth                         env->error_code = 1 << 16;
1587*fcf5ef2aSThomas Huth                     } else {
1588*fcf5ef2aSThomas Huth                         cs->exception_index = POWERPC_EXCP_DLTLB;
1589*fcf5ef2aSThomas Huth                         env->error_code = 0;
1590*fcf5ef2aSThomas Huth                     }
1591*fcf5ef2aSThomas Huth                     env->spr[SPR_DMISS] = address;
1592*fcf5ef2aSThomas Huth                     env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
1593*fcf5ef2aSThomas Huth                 tlb_miss:
1594*fcf5ef2aSThomas Huth                     env->error_code |= ctx.key << 19;
1595*fcf5ef2aSThomas Huth                     env->spr[SPR_HASH1] = env->htab_base +
1596*fcf5ef2aSThomas Huth                         get_pteg_offset32(cpu, ctx.hash[0]);
1597*fcf5ef2aSThomas Huth                     env->spr[SPR_HASH2] = env->htab_base +
1598*fcf5ef2aSThomas Huth                         get_pteg_offset32(cpu, ctx.hash[1]);
1599*fcf5ef2aSThomas Huth                     break;
1600*fcf5ef2aSThomas Huth                 case POWERPC_MMU_SOFT_74xx:
1601*fcf5ef2aSThomas Huth                     if (rw == 1) {
1602*fcf5ef2aSThomas Huth                         cs->exception_index = POWERPC_EXCP_DSTLB;
1603*fcf5ef2aSThomas Huth                     } else {
1604*fcf5ef2aSThomas Huth                         cs->exception_index = POWERPC_EXCP_DLTLB;
1605*fcf5ef2aSThomas Huth                     }
1606*fcf5ef2aSThomas Huth                 tlb_miss_74xx:
1607*fcf5ef2aSThomas Huth                     /* Implement LRU algorithm */
1608*fcf5ef2aSThomas Huth                     env->error_code = ctx.key << 19;
1609*fcf5ef2aSThomas Huth                     env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
1610*fcf5ef2aSThomas Huth                         ((env->last_way + 1) & (env->nb_ways - 1));
1611*fcf5ef2aSThomas Huth                     env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
1612*fcf5ef2aSThomas Huth                     break;
1613*fcf5ef2aSThomas Huth                 case POWERPC_MMU_SOFT_4xx:
1614*fcf5ef2aSThomas Huth                 case POWERPC_MMU_SOFT_4xx_Z:
1615*fcf5ef2aSThomas Huth                     cs->exception_index = POWERPC_EXCP_DTLB;
1616*fcf5ef2aSThomas Huth                     env->error_code = 0;
1617*fcf5ef2aSThomas Huth                     env->spr[SPR_40x_DEAR] = address;
1618*fcf5ef2aSThomas Huth                     if (rw) {
1619*fcf5ef2aSThomas Huth                         env->spr[SPR_40x_ESR] = 0x00800000;
1620*fcf5ef2aSThomas Huth                     } else {
1621*fcf5ef2aSThomas Huth                         env->spr[SPR_40x_ESR] = 0x00000000;
1622*fcf5ef2aSThomas Huth                     }
1623*fcf5ef2aSThomas Huth                     break;
1624*fcf5ef2aSThomas Huth                 case POWERPC_MMU_MPC8xx:
1625*fcf5ef2aSThomas Huth                     /* XXX: TODO */
1626*fcf5ef2aSThomas Huth                     cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1627*fcf5ef2aSThomas Huth                     break;
1628*fcf5ef2aSThomas Huth                 case POWERPC_MMU_BOOKE206:
1629*fcf5ef2aSThomas Huth                     booke206_update_mas_tlb_miss(env, address, rw);
1630*fcf5ef2aSThomas Huth                     /* fall through */
1631*fcf5ef2aSThomas Huth                 case POWERPC_MMU_BOOKE:
1632*fcf5ef2aSThomas Huth                     cs->exception_index = POWERPC_EXCP_DTLB;
1633*fcf5ef2aSThomas Huth                     env->error_code = 0;
1634*fcf5ef2aSThomas Huth                     env->spr[SPR_BOOKE_DEAR] = address;
1635*fcf5ef2aSThomas Huth                     env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1636*fcf5ef2aSThomas Huth                     return -1;
1637*fcf5ef2aSThomas Huth                 case POWERPC_MMU_REAL:
1638*fcf5ef2aSThomas Huth                     cpu_abort(cs, "PowerPC in real mode should never raise "
1639*fcf5ef2aSThomas Huth                               "any MMU exceptions\n");
1640*fcf5ef2aSThomas Huth                     return -1;
1641*fcf5ef2aSThomas Huth                 default:
1642*fcf5ef2aSThomas Huth                     cpu_abort(cs, "Unknown or invalid MMU model\n");
1643*fcf5ef2aSThomas Huth                     return -1;
1644*fcf5ef2aSThomas Huth                 }
1645*fcf5ef2aSThomas Huth                 break;
1646*fcf5ef2aSThomas Huth             case -2:
1647*fcf5ef2aSThomas Huth                 /* Access rights violation */
1648*fcf5ef2aSThomas Huth                 cs->exception_index = POWERPC_EXCP_DSI;
1649*fcf5ef2aSThomas Huth                 env->error_code = 0;
1650*fcf5ef2aSThomas Huth                 if (env->mmu_model == POWERPC_MMU_SOFT_4xx
1651*fcf5ef2aSThomas Huth                     || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
1652*fcf5ef2aSThomas Huth                     env->spr[SPR_40x_DEAR] = address;
1653*fcf5ef2aSThomas Huth                     if (rw) {
1654*fcf5ef2aSThomas Huth                         env->spr[SPR_40x_ESR] |= 0x00800000;
1655*fcf5ef2aSThomas Huth                     }
1656*fcf5ef2aSThomas Huth                 } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1657*fcf5ef2aSThomas Huth                            (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1658*fcf5ef2aSThomas Huth                     env->spr[SPR_BOOKE_DEAR] = address;
1659*fcf5ef2aSThomas Huth                     env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1660*fcf5ef2aSThomas Huth                 } else {
1661*fcf5ef2aSThomas Huth                     env->spr[SPR_DAR] = address;
1662*fcf5ef2aSThomas Huth                     if (rw == 1) {
1663*fcf5ef2aSThomas Huth                         env->spr[SPR_DSISR] = 0x0A000000;
1664*fcf5ef2aSThomas Huth                     } else {
1665*fcf5ef2aSThomas Huth                         env->spr[SPR_DSISR] = 0x08000000;
1666*fcf5ef2aSThomas Huth                     }
1667*fcf5ef2aSThomas Huth                 }
1668*fcf5ef2aSThomas Huth                 break;
1669*fcf5ef2aSThomas Huth             case -4:
1670*fcf5ef2aSThomas Huth                 /* Direct store exception */
1671*fcf5ef2aSThomas Huth                 switch (access_type) {
1672*fcf5ef2aSThomas Huth                 case ACCESS_FLOAT:
1673*fcf5ef2aSThomas Huth                     /* Floating point load/store */
1674*fcf5ef2aSThomas Huth                     cs->exception_index = POWERPC_EXCP_ALIGN;
1675*fcf5ef2aSThomas Huth                     env->error_code = POWERPC_EXCP_ALIGN_FP;
1676*fcf5ef2aSThomas Huth                     env->spr[SPR_DAR] = address;
1677*fcf5ef2aSThomas Huth                     break;
1678*fcf5ef2aSThomas Huth                 case ACCESS_RES:
1679*fcf5ef2aSThomas Huth                     /* lwarx, ldarx or stwcx. */
1680*fcf5ef2aSThomas Huth                     cs->exception_index = POWERPC_EXCP_DSI;
1681*fcf5ef2aSThomas Huth                     env->error_code = 0;
1682*fcf5ef2aSThomas Huth                     env->spr[SPR_DAR] = address;
1683*fcf5ef2aSThomas Huth                     if (rw == 1) {
1684*fcf5ef2aSThomas Huth                         env->spr[SPR_DSISR] = 0x06000000;
1685*fcf5ef2aSThomas Huth                     } else {
1686*fcf5ef2aSThomas Huth                         env->spr[SPR_DSISR] = 0x04000000;
1687*fcf5ef2aSThomas Huth                     }
1688*fcf5ef2aSThomas Huth                     break;
1689*fcf5ef2aSThomas Huth                 case ACCESS_EXT:
1690*fcf5ef2aSThomas Huth                     /* eciwx or ecowx */
1691*fcf5ef2aSThomas Huth                     cs->exception_index = POWERPC_EXCP_DSI;
1692*fcf5ef2aSThomas Huth                     env->error_code = 0;
1693*fcf5ef2aSThomas Huth                     env->spr[SPR_DAR] = address;
1694*fcf5ef2aSThomas Huth                     if (rw == 1) {
1695*fcf5ef2aSThomas Huth                         env->spr[SPR_DSISR] = 0x06100000;
1696*fcf5ef2aSThomas Huth                     } else {
1697*fcf5ef2aSThomas Huth                         env->spr[SPR_DSISR] = 0x04100000;
1698*fcf5ef2aSThomas Huth                     }
1699*fcf5ef2aSThomas Huth                     break;
1700*fcf5ef2aSThomas Huth                 default:
1701*fcf5ef2aSThomas Huth                     printf("DSI: invalid exception (%d)\n", ret);
1702*fcf5ef2aSThomas Huth                     cs->exception_index = POWERPC_EXCP_PROGRAM;
1703*fcf5ef2aSThomas Huth                     env->error_code =
1704*fcf5ef2aSThomas Huth                         POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
1705*fcf5ef2aSThomas Huth                     env->spr[SPR_DAR] = address;
1706*fcf5ef2aSThomas Huth                     break;
1707*fcf5ef2aSThomas Huth                 }
1708*fcf5ef2aSThomas Huth                 break;
1709*fcf5ef2aSThomas Huth             }
1710*fcf5ef2aSThomas Huth         }
1711*fcf5ef2aSThomas Huth #if 0
1712*fcf5ef2aSThomas Huth         printf("%s: set exception to %d %02x\n", __func__,
1713*fcf5ef2aSThomas Huth                cs->exception, env->error_code);
1714*fcf5ef2aSThomas Huth #endif
1715*fcf5ef2aSThomas Huth         ret = 1;
1716*fcf5ef2aSThomas Huth     }
1717*fcf5ef2aSThomas Huth 
1718*fcf5ef2aSThomas Huth     return ret;
1719*fcf5ef2aSThomas Huth }
1720*fcf5ef2aSThomas Huth 
1721*fcf5ef2aSThomas Huth /*****************************************************************************/
1722*fcf5ef2aSThomas Huth /* BATs management */
1723*fcf5ef2aSThomas Huth #if !defined(FLUSH_ALL_TLBS)
1724*fcf5ef2aSThomas Huth static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
1725*fcf5ef2aSThomas Huth                                      target_ulong mask)
1726*fcf5ef2aSThomas Huth {
1727*fcf5ef2aSThomas Huth     CPUState *cs = CPU(ppc_env_get_cpu(env));
1728*fcf5ef2aSThomas Huth     target_ulong base, end, page;
1729*fcf5ef2aSThomas Huth 
1730*fcf5ef2aSThomas Huth     base = BATu & ~0x0001FFFF;
1731*fcf5ef2aSThomas Huth     end = base + mask + 0x00020000;
1732*fcf5ef2aSThomas Huth     LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
1733*fcf5ef2aSThomas Huth              TARGET_FMT_lx ")\n", base, end, mask);
1734*fcf5ef2aSThomas Huth     for (page = base; page != end; page += TARGET_PAGE_SIZE) {
1735*fcf5ef2aSThomas Huth         tlb_flush_page(cs, page);
1736*fcf5ef2aSThomas Huth     }
1737*fcf5ef2aSThomas Huth     LOG_BATS("Flush done\n");
1738*fcf5ef2aSThomas Huth }
1739*fcf5ef2aSThomas Huth #endif
1740*fcf5ef2aSThomas Huth 
1741*fcf5ef2aSThomas Huth static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
1742*fcf5ef2aSThomas Huth                                   target_ulong value)
1743*fcf5ef2aSThomas Huth {
1744*fcf5ef2aSThomas Huth     LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
1745*fcf5ef2aSThomas Huth              nr, ul == 0 ? 'u' : 'l', value, env->nip);
1746*fcf5ef2aSThomas Huth }
1747*fcf5ef2aSThomas Huth 
1748*fcf5ef2aSThomas Huth void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1749*fcf5ef2aSThomas Huth {
1750*fcf5ef2aSThomas Huth     target_ulong mask;
1751*fcf5ef2aSThomas Huth #if defined(FLUSH_ALL_TLBS)
1752*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = ppc_env_get_cpu(env);
1753*fcf5ef2aSThomas Huth #endif
1754*fcf5ef2aSThomas Huth 
1755*fcf5ef2aSThomas Huth     dump_store_bat(env, 'I', 0, nr, value);
1756*fcf5ef2aSThomas Huth     if (env->IBAT[0][nr] != value) {
1757*fcf5ef2aSThomas Huth         mask = (value << 15) & 0x0FFE0000UL;
1758*fcf5ef2aSThomas Huth #if !defined(FLUSH_ALL_TLBS)
1759*fcf5ef2aSThomas Huth         do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1760*fcf5ef2aSThomas Huth #endif
1761*fcf5ef2aSThomas Huth         /* When storing valid upper BAT, mask BEPI and BRPN
1762*fcf5ef2aSThomas Huth          * and invalidate all TLBs covered by this BAT
1763*fcf5ef2aSThomas Huth          */
1764*fcf5ef2aSThomas Huth         mask = (value << 15) & 0x0FFE0000UL;
1765*fcf5ef2aSThomas Huth         env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1766*fcf5ef2aSThomas Huth             (value & ~0x0001FFFFUL & ~mask);
1767*fcf5ef2aSThomas Huth         env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
1768*fcf5ef2aSThomas Huth             (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
1769*fcf5ef2aSThomas Huth #if !defined(FLUSH_ALL_TLBS)
1770*fcf5ef2aSThomas Huth         do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1771*fcf5ef2aSThomas Huth #else
1772*fcf5ef2aSThomas Huth         tlb_flush(CPU(cpu), 1);
1773*fcf5ef2aSThomas Huth #endif
1774*fcf5ef2aSThomas Huth     }
1775*fcf5ef2aSThomas Huth }
1776*fcf5ef2aSThomas Huth 
1777*fcf5ef2aSThomas Huth void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1778*fcf5ef2aSThomas Huth {
1779*fcf5ef2aSThomas Huth     dump_store_bat(env, 'I', 1, nr, value);
1780*fcf5ef2aSThomas Huth     env->IBAT[1][nr] = value;
1781*fcf5ef2aSThomas Huth }
1782*fcf5ef2aSThomas Huth 
1783*fcf5ef2aSThomas Huth void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1784*fcf5ef2aSThomas Huth {
1785*fcf5ef2aSThomas Huth     target_ulong mask;
1786*fcf5ef2aSThomas Huth #if defined(FLUSH_ALL_TLBS)
1787*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = ppc_env_get_cpu(env);
1788*fcf5ef2aSThomas Huth #endif
1789*fcf5ef2aSThomas Huth 
1790*fcf5ef2aSThomas Huth     dump_store_bat(env, 'D', 0, nr, value);
1791*fcf5ef2aSThomas Huth     if (env->DBAT[0][nr] != value) {
1792*fcf5ef2aSThomas Huth         /* When storing valid upper BAT, mask BEPI and BRPN
1793*fcf5ef2aSThomas Huth          * and invalidate all TLBs covered by this BAT
1794*fcf5ef2aSThomas Huth          */
1795*fcf5ef2aSThomas Huth         mask = (value << 15) & 0x0FFE0000UL;
1796*fcf5ef2aSThomas Huth #if !defined(FLUSH_ALL_TLBS)
1797*fcf5ef2aSThomas Huth         do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1798*fcf5ef2aSThomas Huth #endif
1799*fcf5ef2aSThomas Huth         mask = (value << 15) & 0x0FFE0000UL;
1800*fcf5ef2aSThomas Huth         env->DBAT[0][nr] = (value & 0x00001FFFUL) |
1801*fcf5ef2aSThomas Huth             (value & ~0x0001FFFFUL & ~mask);
1802*fcf5ef2aSThomas Huth         env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
1803*fcf5ef2aSThomas Huth             (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
1804*fcf5ef2aSThomas Huth #if !defined(FLUSH_ALL_TLBS)
1805*fcf5ef2aSThomas Huth         do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1806*fcf5ef2aSThomas Huth #else
1807*fcf5ef2aSThomas Huth         tlb_flush(CPU(cpu), 1);
1808*fcf5ef2aSThomas Huth #endif
1809*fcf5ef2aSThomas Huth     }
1810*fcf5ef2aSThomas Huth }
1811*fcf5ef2aSThomas Huth 
1812*fcf5ef2aSThomas Huth void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1813*fcf5ef2aSThomas Huth {
1814*fcf5ef2aSThomas Huth     dump_store_bat(env, 'D', 1, nr, value);
1815*fcf5ef2aSThomas Huth     env->DBAT[1][nr] = value;
1816*fcf5ef2aSThomas Huth }
1817*fcf5ef2aSThomas Huth 
1818*fcf5ef2aSThomas Huth void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value)
1819*fcf5ef2aSThomas Huth {
1820*fcf5ef2aSThomas Huth     target_ulong mask;
1821*fcf5ef2aSThomas Huth #if defined(FLUSH_ALL_TLBS)
1822*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = ppc_env_get_cpu(env);
1823*fcf5ef2aSThomas Huth     int do_inval;
1824*fcf5ef2aSThomas Huth #endif
1825*fcf5ef2aSThomas Huth 
1826*fcf5ef2aSThomas Huth     dump_store_bat(env, 'I', 0, nr, value);
1827*fcf5ef2aSThomas Huth     if (env->IBAT[0][nr] != value) {
1828*fcf5ef2aSThomas Huth #if defined(FLUSH_ALL_TLBS)
1829*fcf5ef2aSThomas Huth         do_inval = 0;
1830*fcf5ef2aSThomas Huth #endif
1831*fcf5ef2aSThomas Huth         mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1832*fcf5ef2aSThomas Huth         if (env->IBAT[1][nr] & 0x40) {
1833*fcf5ef2aSThomas Huth             /* Invalidate BAT only if it is valid */
1834*fcf5ef2aSThomas Huth #if !defined(FLUSH_ALL_TLBS)
1835*fcf5ef2aSThomas Huth             do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1836*fcf5ef2aSThomas Huth #else
1837*fcf5ef2aSThomas Huth             do_inval = 1;
1838*fcf5ef2aSThomas Huth #endif
1839*fcf5ef2aSThomas Huth         }
1840*fcf5ef2aSThomas Huth         /* When storing valid upper BAT, mask BEPI and BRPN
1841*fcf5ef2aSThomas Huth          * and invalidate all TLBs covered by this BAT
1842*fcf5ef2aSThomas Huth          */
1843*fcf5ef2aSThomas Huth         env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1844*fcf5ef2aSThomas Huth             (value & ~0x0001FFFFUL & ~mask);
1845*fcf5ef2aSThomas Huth         env->DBAT[0][nr] = env->IBAT[0][nr];
1846*fcf5ef2aSThomas Huth         if (env->IBAT[1][nr] & 0x40) {
1847*fcf5ef2aSThomas Huth #if !defined(FLUSH_ALL_TLBS)
1848*fcf5ef2aSThomas Huth             do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1849*fcf5ef2aSThomas Huth #else
1850*fcf5ef2aSThomas Huth             do_inval = 1;
1851*fcf5ef2aSThomas Huth #endif
1852*fcf5ef2aSThomas Huth         }
1853*fcf5ef2aSThomas Huth #if defined(FLUSH_ALL_TLBS)
1854*fcf5ef2aSThomas Huth         if (do_inval) {
1855*fcf5ef2aSThomas Huth             tlb_flush(CPU(cpu), 1);
1856*fcf5ef2aSThomas Huth         }
1857*fcf5ef2aSThomas Huth #endif
1858*fcf5ef2aSThomas Huth     }
1859*fcf5ef2aSThomas Huth }
1860*fcf5ef2aSThomas Huth 
1861*fcf5ef2aSThomas Huth void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value)
1862*fcf5ef2aSThomas Huth {
1863*fcf5ef2aSThomas Huth #if !defined(FLUSH_ALL_TLBS)
1864*fcf5ef2aSThomas Huth     target_ulong mask;
1865*fcf5ef2aSThomas Huth #else
1866*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = ppc_env_get_cpu(env);
1867*fcf5ef2aSThomas Huth     int do_inval;
1868*fcf5ef2aSThomas Huth #endif
1869*fcf5ef2aSThomas Huth 
1870*fcf5ef2aSThomas Huth     dump_store_bat(env, 'I', 1, nr, value);
1871*fcf5ef2aSThomas Huth     if (env->IBAT[1][nr] != value) {
1872*fcf5ef2aSThomas Huth #if defined(FLUSH_ALL_TLBS)
1873*fcf5ef2aSThomas Huth         do_inval = 0;
1874*fcf5ef2aSThomas Huth #endif
1875*fcf5ef2aSThomas Huth         if (env->IBAT[1][nr] & 0x40) {
1876*fcf5ef2aSThomas Huth #if !defined(FLUSH_ALL_TLBS)
1877*fcf5ef2aSThomas Huth             mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1878*fcf5ef2aSThomas Huth             do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1879*fcf5ef2aSThomas Huth #else
1880*fcf5ef2aSThomas Huth             do_inval = 1;
1881*fcf5ef2aSThomas Huth #endif
1882*fcf5ef2aSThomas Huth         }
1883*fcf5ef2aSThomas Huth         if (value & 0x40) {
1884*fcf5ef2aSThomas Huth #if !defined(FLUSH_ALL_TLBS)
1885*fcf5ef2aSThomas Huth             mask = (value << 17) & 0x0FFE0000UL;
1886*fcf5ef2aSThomas Huth             do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1887*fcf5ef2aSThomas Huth #else
1888*fcf5ef2aSThomas Huth             do_inval = 1;
1889*fcf5ef2aSThomas Huth #endif
1890*fcf5ef2aSThomas Huth         }
1891*fcf5ef2aSThomas Huth         env->IBAT[1][nr] = value;
1892*fcf5ef2aSThomas Huth         env->DBAT[1][nr] = value;
1893*fcf5ef2aSThomas Huth #if defined(FLUSH_ALL_TLBS)
1894*fcf5ef2aSThomas Huth         if (do_inval) {
1895*fcf5ef2aSThomas Huth             tlb_flush(CPU(cpu), 1);
1896*fcf5ef2aSThomas Huth         }
1897*fcf5ef2aSThomas Huth #endif
1898*fcf5ef2aSThomas Huth     }
1899*fcf5ef2aSThomas Huth }
1900*fcf5ef2aSThomas Huth 
1901*fcf5ef2aSThomas Huth /*****************************************************************************/
1902*fcf5ef2aSThomas Huth /* TLB management */
1903*fcf5ef2aSThomas Huth void ppc_tlb_invalidate_all(CPUPPCState *env)
1904*fcf5ef2aSThomas Huth {
1905*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = ppc_env_get_cpu(env);
1906*fcf5ef2aSThomas Huth 
1907*fcf5ef2aSThomas Huth     switch (env->mmu_model) {
1908*fcf5ef2aSThomas Huth     case POWERPC_MMU_SOFT_6xx:
1909*fcf5ef2aSThomas Huth     case POWERPC_MMU_SOFT_74xx:
1910*fcf5ef2aSThomas Huth         ppc6xx_tlb_invalidate_all(env);
1911*fcf5ef2aSThomas Huth         break;
1912*fcf5ef2aSThomas Huth     case POWERPC_MMU_SOFT_4xx:
1913*fcf5ef2aSThomas Huth     case POWERPC_MMU_SOFT_4xx_Z:
1914*fcf5ef2aSThomas Huth         ppc4xx_tlb_invalidate_all(env);
1915*fcf5ef2aSThomas Huth         break;
1916*fcf5ef2aSThomas Huth     case POWERPC_MMU_REAL:
1917*fcf5ef2aSThomas Huth         cpu_abort(CPU(cpu), "No TLB for PowerPC 4xx in real mode\n");
1918*fcf5ef2aSThomas Huth         break;
1919*fcf5ef2aSThomas Huth     case POWERPC_MMU_MPC8xx:
1920*fcf5ef2aSThomas Huth         /* XXX: TODO */
1921*fcf5ef2aSThomas Huth         cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1922*fcf5ef2aSThomas Huth         break;
1923*fcf5ef2aSThomas Huth     case POWERPC_MMU_BOOKE:
1924*fcf5ef2aSThomas Huth         tlb_flush(CPU(cpu), 1);
1925*fcf5ef2aSThomas Huth         break;
1926*fcf5ef2aSThomas Huth     case POWERPC_MMU_BOOKE206:
1927*fcf5ef2aSThomas Huth         booke206_flush_tlb(env, -1, 0);
1928*fcf5ef2aSThomas Huth         break;
1929*fcf5ef2aSThomas Huth     case POWERPC_MMU_32B:
1930*fcf5ef2aSThomas Huth     case POWERPC_MMU_601:
1931*fcf5ef2aSThomas Huth #if defined(TARGET_PPC64)
1932*fcf5ef2aSThomas Huth     case POWERPC_MMU_64B:
1933*fcf5ef2aSThomas Huth     case POWERPC_MMU_2_03:
1934*fcf5ef2aSThomas Huth     case POWERPC_MMU_2_06:
1935*fcf5ef2aSThomas Huth     case POWERPC_MMU_2_06a:
1936*fcf5ef2aSThomas Huth     case POWERPC_MMU_2_07:
1937*fcf5ef2aSThomas Huth     case POWERPC_MMU_2_07a:
1938*fcf5ef2aSThomas Huth #endif /* defined(TARGET_PPC64) */
1939*fcf5ef2aSThomas Huth         env->tlb_need_flush = 0;
1940*fcf5ef2aSThomas Huth         tlb_flush(CPU(cpu), 1);
1941*fcf5ef2aSThomas Huth         break;
1942*fcf5ef2aSThomas Huth     default:
1943*fcf5ef2aSThomas Huth         /* XXX: TODO */
1944*fcf5ef2aSThomas Huth         cpu_abort(CPU(cpu), "Unknown MMU model %d\n", env->mmu_model);
1945*fcf5ef2aSThomas Huth         break;
1946*fcf5ef2aSThomas Huth     }
1947*fcf5ef2aSThomas Huth }
1948*fcf5ef2aSThomas Huth 
1949*fcf5ef2aSThomas Huth void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
1950*fcf5ef2aSThomas Huth {
1951*fcf5ef2aSThomas Huth #if !defined(FLUSH_ALL_TLBS)
1952*fcf5ef2aSThomas Huth     addr &= TARGET_PAGE_MASK;
1953*fcf5ef2aSThomas Huth     switch (env->mmu_model) {
1954*fcf5ef2aSThomas Huth     case POWERPC_MMU_SOFT_6xx:
1955*fcf5ef2aSThomas Huth     case POWERPC_MMU_SOFT_74xx:
1956*fcf5ef2aSThomas Huth         ppc6xx_tlb_invalidate_virt(env, addr, 0);
1957*fcf5ef2aSThomas Huth         if (env->id_tlbs == 1) {
1958*fcf5ef2aSThomas Huth             ppc6xx_tlb_invalidate_virt(env, addr, 1);
1959*fcf5ef2aSThomas Huth         }
1960*fcf5ef2aSThomas Huth         break;
1961*fcf5ef2aSThomas Huth     case POWERPC_MMU_32B:
1962*fcf5ef2aSThomas Huth     case POWERPC_MMU_601:
1963*fcf5ef2aSThomas Huth         /* Actual CPUs invalidate entire congruence classes based on the
1964*fcf5ef2aSThomas Huth          * geometry of their TLBs and some OSes take that into account,
1965*fcf5ef2aSThomas Huth          * we just mark the TLB to be flushed later (context synchronizing
1966*fcf5ef2aSThomas Huth          * event or sync instruction on 32-bit).
1967*fcf5ef2aSThomas Huth          */
1968*fcf5ef2aSThomas Huth         env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
1969*fcf5ef2aSThomas Huth         break;
1970*fcf5ef2aSThomas Huth #if defined(TARGET_PPC64)
1971*fcf5ef2aSThomas Huth     case POWERPC_MMU_64B:
1972*fcf5ef2aSThomas Huth     case POWERPC_MMU_2_03:
1973*fcf5ef2aSThomas Huth     case POWERPC_MMU_2_06:
1974*fcf5ef2aSThomas Huth     case POWERPC_MMU_2_06a:
1975*fcf5ef2aSThomas Huth     case POWERPC_MMU_2_07:
1976*fcf5ef2aSThomas Huth     case POWERPC_MMU_2_07a:
1977*fcf5ef2aSThomas Huth         /* tlbie invalidate TLBs for all segments */
1978*fcf5ef2aSThomas Huth         /* XXX: given the fact that there are too many segments to invalidate,
1979*fcf5ef2aSThomas Huth          *      and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
1980*fcf5ef2aSThomas Huth          *      we just invalidate all TLBs
1981*fcf5ef2aSThomas Huth          */
1982*fcf5ef2aSThomas Huth         env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
1983*fcf5ef2aSThomas Huth         break;
1984*fcf5ef2aSThomas Huth #endif /* defined(TARGET_PPC64) */
1985*fcf5ef2aSThomas Huth     default:
1986*fcf5ef2aSThomas Huth         /* Should never reach here with other MMU models */
1987*fcf5ef2aSThomas Huth         assert(0);
1988*fcf5ef2aSThomas Huth     }
1989*fcf5ef2aSThomas Huth #else
1990*fcf5ef2aSThomas Huth     ppc_tlb_invalidate_all(env);
1991*fcf5ef2aSThomas Huth #endif
1992*fcf5ef2aSThomas Huth }
1993*fcf5ef2aSThomas Huth 
1994*fcf5ef2aSThomas Huth /*****************************************************************************/
1995*fcf5ef2aSThomas Huth /* Special registers manipulation */
1996*fcf5ef2aSThomas Huth void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
1997*fcf5ef2aSThomas Huth {
1998*fcf5ef2aSThomas Huth     qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
1999*fcf5ef2aSThomas Huth     assert(!env->external_htab);
2000*fcf5ef2aSThomas Huth     env->spr[SPR_SDR1] = value;
2001*fcf5ef2aSThomas Huth #if defined(TARGET_PPC64)
2002*fcf5ef2aSThomas Huth     if (env->mmu_model & POWERPC_MMU_64) {
2003*fcf5ef2aSThomas Huth         PowerPCCPU *cpu = ppc_env_get_cpu(env);
2004*fcf5ef2aSThomas Huth         Error *local_err = NULL;
2005*fcf5ef2aSThomas Huth 
2006*fcf5ef2aSThomas Huth         ppc_hash64_set_sdr1(cpu, value, &local_err);
2007*fcf5ef2aSThomas Huth         if (local_err) {
2008*fcf5ef2aSThomas Huth             error_report_err(local_err);
2009*fcf5ef2aSThomas Huth             error_free(local_err);
2010*fcf5ef2aSThomas Huth         }
2011*fcf5ef2aSThomas Huth     } else
2012*fcf5ef2aSThomas Huth #endif /* defined(TARGET_PPC64) */
2013*fcf5ef2aSThomas Huth     {
2014*fcf5ef2aSThomas Huth         /* FIXME: Should check for valid HTABMASK values */
2015*fcf5ef2aSThomas Huth         env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
2016*fcf5ef2aSThomas Huth         env->htab_base = value & SDR_32_HTABORG;
2017*fcf5ef2aSThomas Huth     }
2018*fcf5ef2aSThomas Huth }
2019*fcf5ef2aSThomas Huth 
2020*fcf5ef2aSThomas Huth /* Segment registers load and store */
2021*fcf5ef2aSThomas Huth target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
2022*fcf5ef2aSThomas Huth {
2023*fcf5ef2aSThomas Huth #if defined(TARGET_PPC64)
2024*fcf5ef2aSThomas Huth     if (env->mmu_model & POWERPC_MMU_64) {
2025*fcf5ef2aSThomas Huth         /* XXX */
2026*fcf5ef2aSThomas Huth         return 0;
2027*fcf5ef2aSThomas Huth     }
2028*fcf5ef2aSThomas Huth #endif
2029*fcf5ef2aSThomas Huth     return env->sr[sr_num];
2030*fcf5ef2aSThomas Huth }
2031*fcf5ef2aSThomas Huth 
2032*fcf5ef2aSThomas Huth void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
2033*fcf5ef2aSThomas Huth {
2034*fcf5ef2aSThomas Huth     qemu_log_mask(CPU_LOG_MMU,
2035*fcf5ef2aSThomas Huth             "%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
2036*fcf5ef2aSThomas Huth             (int)srnum, value, env->sr[srnum]);
2037*fcf5ef2aSThomas Huth #if defined(TARGET_PPC64)
2038*fcf5ef2aSThomas Huth     if (env->mmu_model & POWERPC_MMU_64) {
2039*fcf5ef2aSThomas Huth         PowerPCCPU *cpu = ppc_env_get_cpu(env);
2040*fcf5ef2aSThomas Huth         uint64_t esid, vsid;
2041*fcf5ef2aSThomas Huth 
2042*fcf5ef2aSThomas Huth         /* ESID = srnum */
2043*fcf5ef2aSThomas Huth         esid = ((uint64_t)(srnum & 0xf) << 28) | SLB_ESID_V;
2044*fcf5ef2aSThomas Huth 
2045*fcf5ef2aSThomas Huth         /* VSID = VSID */
2046*fcf5ef2aSThomas Huth         vsid = (value & 0xfffffff) << 12;
2047*fcf5ef2aSThomas Huth         /* flags = flags */
2048*fcf5ef2aSThomas Huth         vsid |= ((value >> 27) & 0xf) << 8;
2049*fcf5ef2aSThomas Huth 
2050*fcf5ef2aSThomas Huth         ppc_store_slb(cpu, srnum, esid, vsid);
2051*fcf5ef2aSThomas Huth     } else
2052*fcf5ef2aSThomas Huth #endif
2053*fcf5ef2aSThomas Huth     if (env->sr[srnum] != value) {
2054*fcf5ef2aSThomas Huth         env->sr[srnum] = value;
2055*fcf5ef2aSThomas Huth /* Invalidating 256MB of virtual memory in 4kB pages is way longer than
2056*fcf5ef2aSThomas Huth    flusing the whole TLB. */
2057*fcf5ef2aSThomas Huth #if !defined(FLUSH_ALL_TLBS) && 0
2058*fcf5ef2aSThomas Huth         {
2059*fcf5ef2aSThomas Huth             target_ulong page, end;
2060*fcf5ef2aSThomas Huth             /* Invalidate 256 MB of virtual memory */
2061*fcf5ef2aSThomas Huth             page = (16 << 20) * srnum;
2062*fcf5ef2aSThomas Huth             end = page + (16 << 20);
2063*fcf5ef2aSThomas Huth             for (; page != end; page += TARGET_PAGE_SIZE) {
2064*fcf5ef2aSThomas Huth                 tlb_flush_page(CPU(cpu), page);
2065*fcf5ef2aSThomas Huth             }
2066*fcf5ef2aSThomas Huth         }
2067*fcf5ef2aSThomas Huth #else
2068*fcf5ef2aSThomas Huth         env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
2069*fcf5ef2aSThomas Huth #endif
2070*fcf5ef2aSThomas Huth     }
2071*fcf5ef2aSThomas Huth }
2072*fcf5ef2aSThomas Huth 
2073*fcf5ef2aSThomas Huth /* TLB management */
2074*fcf5ef2aSThomas Huth void helper_tlbia(CPUPPCState *env)
2075*fcf5ef2aSThomas Huth {
2076*fcf5ef2aSThomas Huth     ppc_tlb_invalidate_all(env);
2077*fcf5ef2aSThomas Huth }
2078*fcf5ef2aSThomas Huth 
2079*fcf5ef2aSThomas Huth void helper_tlbie(CPUPPCState *env, target_ulong addr)
2080*fcf5ef2aSThomas Huth {
2081*fcf5ef2aSThomas Huth     ppc_tlb_invalidate_one(env, addr);
2082*fcf5ef2aSThomas Huth }
2083*fcf5ef2aSThomas Huth 
2084*fcf5ef2aSThomas Huth void helper_tlbiva(CPUPPCState *env, target_ulong addr)
2085*fcf5ef2aSThomas Huth {
2086*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = ppc_env_get_cpu(env);
2087*fcf5ef2aSThomas Huth 
2088*fcf5ef2aSThomas Huth     /* tlbiva instruction only exists on BookE */
2089*fcf5ef2aSThomas Huth     assert(env->mmu_model == POWERPC_MMU_BOOKE);
2090*fcf5ef2aSThomas Huth     /* XXX: TODO */
2091*fcf5ef2aSThomas Huth     cpu_abort(CPU(cpu), "BookE MMU model is not implemented\n");
2092*fcf5ef2aSThomas Huth }
2093*fcf5ef2aSThomas Huth 
2094*fcf5ef2aSThomas Huth /* Software driven TLBs management */
2095*fcf5ef2aSThomas Huth /* PowerPC 602/603 software TLB load instructions helpers */
2096*fcf5ef2aSThomas Huth static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2097*fcf5ef2aSThomas Huth {
2098*fcf5ef2aSThomas Huth     target_ulong RPN, CMP, EPN;
2099*fcf5ef2aSThomas Huth     int way;
2100*fcf5ef2aSThomas Huth 
2101*fcf5ef2aSThomas Huth     RPN = env->spr[SPR_RPA];
2102*fcf5ef2aSThomas Huth     if (is_code) {
2103*fcf5ef2aSThomas Huth         CMP = env->spr[SPR_ICMP];
2104*fcf5ef2aSThomas Huth         EPN = env->spr[SPR_IMISS];
2105*fcf5ef2aSThomas Huth     } else {
2106*fcf5ef2aSThomas Huth         CMP = env->spr[SPR_DCMP];
2107*fcf5ef2aSThomas Huth         EPN = env->spr[SPR_DMISS];
2108*fcf5ef2aSThomas Huth     }
2109*fcf5ef2aSThomas Huth     way = (env->spr[SPR_SRR1] >> 17) & 1;
2110*fcf5ef2aSThomas Huth     (void)EPN; /* avoid a compiler warning */
2111*fcf5ef2aSThomas Huth     LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2112*fcf5ef2aSThomas Huth               " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2113*fcf5ef2aSThomas Huth               RPN, way);
2114*fcf5ef2aSThomas Huth     /* Store this TLB */
2115*fcf5ef2aSThomas Huth     ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2116*fcf5ef2aSThomas Huth                      way, is_code, CMP, RPN);
2117*fcf5ef2aSThomas Huth }
2118*fcf5ef2aSThomas Huth 
2119*fcf5ef2aSThomas Huth void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN)
2120*fcf5ef2aSThomas Huth {
2121*fcf5ef2aSThomas Huth     do_6xx_tlb(env, EPN, 0);
2122*fcf5ef2aSThomas Huth }
2123*fcf5ef2aSThomas Huth 
2124*fcf5ef2aSThomas Huth void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
2125*fcf5ef2aSThomas Huth {
2126*fcf5ef2aSThomas Huth     do_6xx_tlb(env, EPN, 1);
2127*fcf5ef2aSThomas Huth }
2128*fcf5ef2aSThomas Huth 
2129*fcf5ef2aSThomas Huth /* PowerPC 74xx software TLB load instructions helpers */
2130*fcf5ef2aSThomas Huth static void do_74xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2131*fcf5ef2aSThomas Huth {
2132*fcf5ef2aSThomas Huth     target_ulong RPN, CMP, EPN;
2133*fcf5ef2aSThomas Huth     int way;
2134*fcf5ef2aSThomas Huth 
2135*fcf5ef2aSThomas Huth     RPN = env->spr[SPR_PTELO];
2136*fcf5ef2aSThomas Huth     CMP = env->spr[SPR_PTEHI];
2137*fcf5ef2aSThomas Huth     EPN = env->spr[SPR_TLBMISS] & ~0x3;
2138*fcf5ef2aSThomas Huth     way = env->spr[SPR_TLBMISS] & 0x3;
2139*fcf5ef2aSThomas Huth     (void)EPN; /* avoid a compiler warning */
2140*fcf5ef2aSThomas Huth     LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2141*fcf5ef2aSThomas Huth               " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2142*fcf5ef2aSThomas Huth               RPN, way);
2143*fcf5ef2aSThomas Huth     /* Store this TLB */
2144*fcf5ef2aSThomas Huth     ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2145*fcf5ef2aSThomas Huth                      way, is_code, CMP, RPN);
2146*fcf5ef2aSThomas Huth }
2147*fcf5ef2aSThomas Huth 
2148*fcf5ef2aSThomas Huth void helper_74xx_tlbd(CPUPPCState *env, target_ulong EPN)
2149*fcf5ef2aSThomas Huth {
2150*fcf5ef2aSThomas Huth     do_74xx_tlb(env, EPN, 0);
2151*fcf5ef2aSThomas Huth }
2152*fcf5ef2aSThomas Huth 
2153*fcf5ef2aSThomas Huth void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN)
2154*fcf5ef2aSThomas Huth {
2155*fcf5ef2aSThomas Huth     do_74xx_tlb(env, EPN, 1);
2156*fcf5ef2aSThomas Huth }
2157*fcf5ef2aSThomas Huth 
2158*fcf5ef2aSThomas Huth /*****************************************************************************/
2159*fcf5ef2aSThomas Huth /* PowerPC 601 specific instructions (POWER bridge) */
2160*fcf5ef2aSThomas Huth 
2161*fcf5ef2aSThomas Huth target_ulong helper_rac(CPUPPCState *env, target_ulong addr)
2162*fcf5ef2aSThomas Huth {
2163*fcf5ef2aSThomas Huth     mmu_ctx_t ctx;
2164*fcf5ef2aSThomas Huth     int nb_BATs;
2165*fcf5ef2aSThomas Huth     target_ulong ret = 0;
2166*fcf5ef2aSThomas Huth 
2167*fcf5ef2aSThomas Huth     /* We don't have to generate many instances of this instruction,
2168*fcf5ef2aSThomas Huth      * as rac is supervisor only.
2169*fcf5ef2aSThomas Huth      */
2170*fcf5ef2aSThomas Huth     /* XXX: FIX THIS: Pretend we have no BAT */
2171*fcf5ef2aSThomas Huth     nb_BATs = env->nb_BATs;
2172*fcf5ef2aSThomas Huth     env->nb_BATs = 0;
2173*fcf5ef2aSThomas Huth     if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
2174*fcf5ef2aSThomas Huth         ret = ctx.raddr;
2175*fcf5ef2aSThomas Huth     }
2176*fcf5ef2aSThomas Huth     env->nb_BATs = nb_BATs;
2177*fcf5ef2aSThomas Huth     return ret;
2178*fcf5ef2aSThomas Huth }
2179*fcf5ef2aSThomas Huth 
2180*fcf5ef2aSThomas Huth static inline target_ulong booke_tlb_to_page_size(int size)
2181*fcf5ef2aSThomas Huth {
2182*fcf5ef2aSThomas Huth     return 1024 << (2 * size);
2183*fcf5ef2aSThomas Huth }
2184*fcf5ef2aSThomas Huth 
2185*fcf5ef2aSThomas Huth static inline int booke_page_size_to_tlb(target_ulong page_size)
2186*fcf5ef2aSThomas Huth {
2187*fcf5ef2aSThomas Huth     int size;
2188*fcf5ef2aSThomas Huth 
2189*fcf5ef2aSThomas Huth     switch (page_size) {
2190*fcf5ef2aSThomas Huth     case 0x00000400UL:
2191*fcf5ef2aSThomas Huth         size = 0x0;
2192*fcf5ef2aSThomas Huth         break;
2193*fcf5ef2aSThomas Huth     case 0x00001000UL:
2194*fcf5ef2aSThomas Huth         size = 0x1;
2195*fcf5ef2aSThomas Huth         break;
2196*fcf5ef2aSThomas Huth     case 0x00004000UL:
2197*fcf5ef2aSThomas Huth         size = 0x2;
2198*fcf5ef2aSThomas Huth         break;
2199*fcf5ef2aSThomas Huth     case 0x00010000UL:
2200*fcf5ef2aSThomas Huth         size = 0x3;
2201*fcf5ef2aSThomas Huth         break;
2202*fcf5ef2aSThomas Huth     case 0x00040000UL:
2203*fcf5ef2aSThomas Huth         size = 0x4;
2204*fcf5ef2aSThomas Huth         break;
2205*fcf5ef2aSThomas Huth     case 0x00100000UL:
2206*fcf5ef2aSThomas Huth         size = 0x5;
2207*fcf5ef2aSThomas Huth         break;
2208*fcf5ef2aSThomas Huth     case 0x00400000UL:
2209*fcf5ef2aSThomas Huth         size = 0x6;
2210*fcf5ef2aSThomas Huth         break;
2211*fcf5ef2aSThomas Huth     case 0x01000000UL:
2212*fcf5ef2aSThomas Huth         size = 0x7;
2213*fcf5ef2aSThomas Huth         break;
2214*fcf5ef2aSThomas Huth     case 0x04000000UL:
2215*fcf5ef2aSThomas Huth         size = 0x8;
2216*fcf5ef2aSThomas Huth         break;
2217*fcf5ef2aSThomas Huth     case 0x10000000UL:
2218*fcf5ef2aSThomas Huth         size = 0x9;
2219*fcf5ef2aSThomas Huth         break;
2220*fcf5ef2aSThomas Huth     case 0x40000000UL:
2221*fcf5ef2aSThomas Huth         size = 0xA;
2222*fcf5ef2aSThomas Huth         break;
2223*fcf5ef2aSThomas Huth #if defined(TARGET_PPC64)
2224*fcf5ef2aSThomas Huth     case 0x000100000000ULL:
2225*fcf5ef2aSThomas Huth         size = 0xB;
2226*fcf5ef2aSThomas Huth         break;
2227*fcf5ef2aSThomas Huth     case 0x000400000000ULL:
2228*fcf5ef2aSThomas Huth         size = 0xC;
2229*fcf5ef2aSThomas Huth         break;
2230*fcf5ef2aSThomas Huth     case 0x001000000000ULL:
2231*fcf5ef2aSThomas Huth         size = 0xD;
2232*fcf5ef2aSThomas Huth         break;
2233*fcf5ef2aSThomas Huth     case 0x004000000000ULL:
2234*fcf5ef2aSThomas Huth         size = 0xE;
2235*fcf5ef2aSThomas Huth         break;
2236*fcf5ef2aSThomas Huth     case 0x010000000000ULL:
2237*fcf5ef2aSThomas Huth         size = 0xF;
2238*fcf5ef2aSThomas Huth         break;
2239*fcf5ef2aSThomas Huth #endif
2240*fcf5ef2aSThomas Huth     default:
2241*fcf5ef2aSThomas Huth         size = -1;
2242*fcf5ef2aSThomas Huth         break;
2243*fcf5ef2aSThomas Huth     }
2244*fcf5ef2aSThomas Huth 
2245*fcf5ef2aSThomas Huth     return size;
2246*fcf5ef2aSThomas Huth }
2247*fcf5ef2aSThomas Huth 
2248*fcf5ef2aSThomas Huth /* Helpers for 4xx TLB management */
2249*fcf5ef2aSThomas Huth #define PPC4XX_TLB_ENTRY_MASK       0x0000003f  /* Mask for 64 TLB entries */
2250*fcf5ef2aSThomas Huth 
2251*fcf5ef2aSThomas Huth #define PPC4XX_TLBHI_V              0x00000040
2252*fcf5ef2aSThomas Huth #define PPC4XX_TLBHI_E              0x00000020
2253*fcf5ef2aSThomas Huth #define PPC4XX_TLBHI_SIZE_MIN       0
2254*fcf5ef2aSThomas Huth #define PPC4XX_TLBHI_SIZE_MAX       7
2255*fcf5ef2aSThomas Huth #define PPC4XX_TLBHI_SIZE_DEFAULT   1
2256*fcf5ef2aSThomas Huth #define PPC4XX_TLBHI_SIZE_SHIFT     7
2257*fcf5ef2aSThomas Huth #define PPC4XX_TLBHI_SIZE_MASK      0x00000007
2258*fcf5ef2aSThomas Huth 
2259*fcf5ef2aSThomas Huth #define PPC4XX_TLBLO_EX             0x00000200
2260*fcf5ef2aSThomas Huth #define PPC4XX_TLBLO_WR             0x00000100
2261*fcf5ef2aSThomas Huth #define PPC4XX_TLBLO_ATTR_MASK      0x000000FF
2262*fcf5ef2aSThomas Huth #define PPC4XX_TLBLO_RPN_MASK       0xFFFFFC00
2263*fcf5ef2aSThomas Huth 
2264*fcf5ef2aSThomas Huth target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
2265*fcf5ef2aSThomas Huth {
2266*fcf5ef2aSThomas Huth     ppcemb_tlb_t *tlb;
2267*fcf5ef2aSThomas Huth     target_ulong ret;
2268*fcf5ef2aSThomas Huth     int size;
2269*fcf5ef2aSThomas Huth 
2270*fcf5ef2aSThomas Huth     entry &= PPC4XX_TLB_ENTRY_MASK;
2271*fcf5ef2aSThomas Huth     tlb = &env->tlb.tlbe[entry];
2272*fcf5ef2aSThomas Huth     ret = tlb->EPN;
2273*fcf5ef2aSThomas Huth     if (tlb->prot & PAGE_VALID) {
2274*fcf5ef2aSThomas Huth         ret |= PPC4XX_TLBHI_V;
2275*fcf5ef2aSThomas Huth     }
2276*fcf5ef2aSThomas Huth     size = booke_page_size_to_tlb(tlb->size);
2277*fcf5ef2aSThomas Huth     if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
2278*fcf5ef2aSThomas Huth         size = PPC4XX_TLBHI_SIZE_DEFAULT;
2279*fcf5ef2aSThomas Huth     }
2280*fcf5ef2aSThomas Huth     ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
2281*fcf5ef2aSThomas Huth     env->spr[SPR_40x_PID] = tlb->PID;
2282*fcf5ef2aSThomas Huth     return ret;
2283*fcf5ef2aSThomas Huth }
2284*fcf5ef2aSThomas Huth 
2285*fcf5ef2aSThomas Huth target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry)
2286*fcf5ef2aSThomas Huth {
2287*fcf5ef2aSThomas Huth     ppcemb_tlb_t *tlb;
2288*fcf5ef2aSThomas Huth     target_ulong ret;
2289*fcf5ef2aSThomas Huth 
2290*fcf5ef2aSThomas Huth     entry &= PPC4XX_TLB_ENTRY_MASK;
2291*fcf5ef2aSThomas Huth     tlb = &env->tlb.tlbe[entry];
2292*fcf5ef2aSThomas Huth     ret = tlb->RPN;
2293*fcf5ef2aSThomas Huth     if (tlb->prot & PAGE_EXEC) {
2294*fcf5ef2aSThomas Huth         ret |= PPC4XX_TLBLO_EX;
2295*fcf5ef2aSThomas Huth     }
2296*fcf5ef2aSThomas Huth     if (tlb->prot & PAGE_WRITE) {
2297*fcf5ef2aSThomas Huth         ret |= PPC4XX_TLBLO_WR;
2298*fcf5ef2aSThomas Huth     }
2299*fcf5ef2aSThomas Huth     return ret;
2300*fcf5ef2aSThomas Huth }
2301*fcf5ef2aSThomas Huth 
2302*fcf5ef2aSThomas Huth void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
2303*fcf5ef2aSThomas Huth                          target_ulong val)
2304*fcf5ef2aSThomas Huth {
2305*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = ppc_env_get_cpu(env);
2306*fcf5ef2aSThomas Huth     CPUState *cs = CPU(cpu);
2307*fcf5ef2aSThomas Huth     ppcemb_tlb_t *tlb;
2308*fcf5ef2aSThomas Huth     target_ulong page, end;
2309*fcf5ef2aSThomas Huth 
2310*fcf5ef2aSThomas Huth     LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
2311*fcf5ef2aSThomas Huth               val);
2312*fcf5ef2aSThomas Huth     entry &= PPC4XX_TLB_ENTRY_MASK;
2313*fcf5ef2aSThomas Huth     tlb = &env->tlb.tlbe[entry];
2314*fcf5ef2aSThomas Huth     /* Invalidate previous TLB (if it's valid) */
2315*fcf5ef2aSThomas Huth     if (tlb->prot & PAGE_VALID) {
2316*fcf5ef2aSThomas Huth         end = tlb->EPN + tlb->size;
2317*fcf5ef2aSThomas Huth         LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
2318*fcf5ef2aSThomas Huth                   TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2319*fcf5ef2aSThomas Huth         for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2320*fcf5ef2aSThomas Huth             tlb_flush_page(cs, page);
2321*fcf5ef2aSThomas Huth         }
2322*fcf5ef2aSThomas Huth     }
2323*fcf5ef2aSThomas Huth     tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
2324*fcf5ef2aSThomas Huth                                        & PPC4XX_TLBHI_SIZE_MASK);
2325*fcf5ef2aSThomas Huth     /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2326*fcf5ef2aSThomas Huth      * If this ever occurs, one should use the ppcemb target instead
2327*fcf5ef2aSThomas Huth      * of the ppc or ppc64 one
2328*fcf5ef2aSThomas Huth      */
2329*fcf5ef2aSThomas Huth     if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
2330*fcf5ef2aSThomas Huth         cpu_abort(cs, "TLB size " TARGET_FMT_lu " < %u "
2331*fcf5ef2aSThomas Huth                   "are not supported (%d)\n",
2332*fcf5ef2aSThomas Huth                   tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
2333*fcf5ef2aSThomas Huth     }
2334*fcf5ef2aSThomas Huth     tlb->EPN = val & ~(tlb->size - 1);
2335*fcf5ef2aSThomas Huth     if (val & PPC4XX_TLBHI_V) {
2336*fcf5ef2aSThomas Huth         tlb->prot |= PAGE_VALID;
2337*fcf5ef2aSThomas Huth         if (val & PPC4XX_TLBHI_E) {
2338*fcf5ef2aSThomas Huth             /* XXX: TO BE FIXED */
2339*fcf5ef2aSThomas Huth             cpu_abort(cs,
2340*fcf5ef2aSThomas Huth                       "Little-endian TLB entries are not supported by now\n");
2341*fcf5ef2aSThomas Huth         }
2342*fcf5ef2aSThomas Huth     } else {
2343*fcf5ef2aSThomas Huth         tlb->prot &= ~PAGE_VALID;
2344*fcf5ef2aSThomas Huth     }
2345*fcf5ef2aSThomas Huth     tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2346*fcf5ef2aSThomas Huth     LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2347*fcf5ef2aSThomas Huth               " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2348*fcf5ef2aSThomas Huth               (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2349*fcf5ef2aSThomas Huth               tlb->prot & PAGE_READ ? 'r' : '-',
2350*fcf5ef2aSThomas Huth               tlb->prot & PAGE_WRITE ? 'w' : '-',
2351*fcf5ef2aSThomas Huth               tlb->prot & PAGE_EXEC ? 'x' : '-',
2352*fcf5ef2aSThomas Huth               tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2353*fcf5ef2aSThomas Huth     /* Invalidate new TLB (if valid) */
2354*fcf5ef2aSThomas Huth     if (tlb->prot & PAGE_VALID) {
2355*fcf5ef2aSThomas Huth         end = tlb->EPN + tlb->size;
2356*fcf5ef2aSThomas Huth         LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
2357*fcf5ef2aSThomas Huth                   TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2358*fcf5ef2aSThomas Huth         for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2359*fcf5ef2aSThomas Huth             tlb_flush_page(cs, page);
2360*fcf5ef2aSThomas Huth         }
2361*fcf5ef2aSThomas Huth     }
2362*fcf5ef2aSThomas Huth }
2363*fcf5ef2aSThomas Huth 
2364*fcf5ef2aSThomas Huth void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
2365*fcf5ef2aSThomas Huth                          target_ulong val)
2366*fcf5ef2aSThomas Huth {
2367*fcf5ef2aSThomas Huth     ppcemb_tlb_t *tlb;
2368*fcf5ef2aSThomas Huth 
2369*fcf5ef2aSThomas Huth     LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
2370*fcf5ef2aSThomas Huth               val);
2371*fcf5ef2aSThomas Huth     entry &= PPC4XX_TLB_ENTRY_MASK;
2372*fcf5ef2aSThomas Huth     tlb = &env->tlb.tlbe[entry];
2373*fcf5ef2aSThomas Huth     tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
2374*fcf5ef2aSThomas Huth     tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
2375*fcf5ef2aSThomas Huth     tlb->prot = PAGE_READ;
2376*fcf5ef2aSThomas Huth     if (val & PPC4XX_TLBLO_EX) {
2377*fcf5ef2aSThomas Huth         tlb->prot |= PAGE_EXEC;
2378*fcf5ef2aSThomas Huth     }
2379*fcf5ef2aSThomas Huth     if (val & PPC4XX_TLBLO_WR) {
2380*fcf5ef2aSThomas Huth         tlb->prot |= PAGE_WRITE;
2381*fcf5ef2aSThomas Huth     }
2382*fcf5ef2aSThomas Huth     LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2383*fcf5ef2aSThomas Huth               " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2384*fcf5ef2aSThomas Huth               (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2385*fcf5ef2aSThomas Huth               tlb->prot & PAGE_READ ? 'r' : '-',
2386*fcf5ef2aSThomas Huth               tlb->prot & PAGE_WRITE ? 'w' : '-',
2387*fcf5ef2aSThomas Huth               tlb->prot & PAGE_EXEC ? 'x' : '-',
2388*fcf5ef2aSThomas Huth               tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2389*fcf5ef2aSThomas Huth }
2390*fcf5ef2aSThomas Huth 
2391*fcf5ef2aSThomas Huth target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
2392*fcf5ef2aSThomas Huth {
2393*fcf5ef2aSThomas Huth     return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
2394*fcf5ef2aSThomas Huth }
2395*fcf5ef2aSThomas Huth 
2396*fcf5ef2aSThomas Huth /* PowerPC 440 TLB management */
2397*fcf5ef2aSThomas Huth void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry,
2398*fcf5ef2aSThomas Huth                       target_ulong value)
2399*fcf5ef2aSThomas Huth {
2400*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = ppc_env_get_cpu(env);
2401*fcf5ef2aSThomas Huth     ppcemb_tlb_t *tlb;
2402*fcf5ef2aSThomas Huth     target_ulong EPN, RPN, size;
2403*fcf5ef2aSThomas Huth     int do_flush_tlbs;
2404*fcf5ef2aSThomas Huth 
2405*fcf5ef2aSThomas Huth     LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
2406*fcf5ef2aSThomas Huth               __func__, word, (int)entry, value);
2407*fcf5ef2aSThomas Huth     do_flush_tlbs = 0;
2408*fcf5ef2aSThomas Huth     entry &= 0x3F;
2409*fcf5ef2aSThomas Huth     tlb = &env->tlb.tlbe[entry];
2410*fcf5ef2aSThomas Huth     switch (word) {
2411*fcf5ef2aSThomas Huth     default:
2412*fcf5ef2aSThomas Huth         /* Just here to please gcc */
2413*fcf5ef2aSThomas Huth     case 0:
2414*fcf5ef2aSThomas Huth         EPN = value & 0xFFFFFC00;
2415*fcf5ef2aSThomas Huth         if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
2416*fcf5ef2aSThomas Huth             do_flush_tlbs = 1;
2417*fcf5ef2aSThomas Huth         }
2418*fcf5ef2aSThomas Huth         tlb->EPN = EPN;
2419*fcf5ef2aSThomas Huth         size = booke_tlb_to_page_size((value >> 4) & 0xF);
2420*fcf5ef2aSThomas Huth         if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
2421*fcf5ef2aSThomas Huth             do_flush_tlbs = 1;
2422*fcf5ef2aSThomas Huth         }
2423*fcf5ef2aSThomas Huth         tlb->size = size;
2424*fcf5ef2aSThomas Huth         tlb->attr &= ~0x1;
2425*fcf5ef2aSThomas Huth         tlb->attr |= (value >> 8) & 1;
2426*fcf5ef2aSThomas Huth         if (value & 0x200) {
2427*fcf5ef2aSThomas Huth             tlb->prot |= PAGE_VALID;
2428*fcf5ef2aSThomas Huth         } else {
2429*fcf5ef2aSThomas Huth             if (tlb->prot & PAGE_VALID) {
2430*fcf5ef2aSThomas Huth                 tlb->prot &= ~PAGE_VALID;
2431*fcf5ef2aSThomas Huth                 do_flush_tlbs = 1;
2432*fcf5ef2aSThomas Huth             }
2433*fcf5ef2aSThomas Huth         }
2434*fcf5ef2aSThomas Huth         tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
2435*fcf5ef2aSThomas Huth         if (do_flush_tlbs) {
2436*fcf5ef2aSThomas Huth             tlb_flush(CPU(cpu), 1);
2437*fcf5ef2aSThomas Huth         }
2438*fcf5ef2aSThomas Huth         break;
2439*fcf5ef2aSThomas Huth     case 1:
2440*fcf5ef2aSThomas Huth         RPN = value & 0xFFFFFC0F;
2441*fcf5ef2aSThomas Huth         if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
2442*fcf5ef2aSThomas Huth             tlb_flush(CPU(cpu), 1);
2443*fcf5ef2aSThomas Huth         }
2444*fcf5ef2aSThomas Huth         tlb->RPN = RPN;
2445*fcf5ef2aSThomas Huth         break;
2446*fcf5ef2aSThomas Huth     case 2:
2447*fcf5ef2aSThomas Huth         tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
2448*fcf5ef2aSThomas Huth         tlb->prot = tlb->prot & PAGE_VALID;
2449*fcf5ef2aSThomas Huth         if (value & 0x1) {
2450*fcf5ef2aSThomas Huth             tlb->prot |= PAGE_READ << 4;
2451*fcf5ef2aSThomas Huth         }
2452*fcf5ef2aSThomas Huth         if (value & 0x2) {
2453*fcf5ef2aSThomas Huth             tlb->prot |= PAGE_WRITE << 4;
2454*fcf5ef2aSThomas Huth         }
2455*fcf5ef2aSThomas Huth         if (value & 0x4) {
2456*fcf5ef2aSThomas Huth             tlb->prot |= PAGE_EXEC << 4;
2457*fcf5ef2aSThomas Huth         }
2458*fcf5ef2aSThomas Huth         if (value & 0x8) {
2459*fcf5ef2aSThomas Huth             tlb->prot |= PAGE_READ;
2460*fcf5ef2aSThomas Huth         }
2461*fcf5ef2aSThomas Huth         if (value & 0x10) {
2462*fcf5ef2aSThomas Huth             tlb->prot |= PAGE_WRITE;
2463*fcf5ef2aSThomas Huth         }
2464*fcf5ef2aSThomas Huth         if (value & 0x20) {
2465*fcf5ef2aSThomas Huth             tlb->prot |= PAGE_EXEC;
2466*fcf5ef2aSThomas Huth         }
2467*fcf5ef2aSThomas Huth         break;
2468*fcf5ef2aSThomas Huth     }
2469*fcf5ef2aSThomas Huth }
2470*fcf5ef2aSThomas Huth 
2471*fcf5ef2aSThomas Huth target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word,
2472*fcf5ef2aSThomas Huth                               target_ulong entry)
2473*fcf5ef2aSThomas Huth {
2474*fcf5ef2aSThomas Huth     ppcemb_tlb_t *tlb;
2475*fcf5ef2aSThomas Huth     target_ulong ret;
2476*fcf5ef2aSThomas Huth     int size;
2477*fcf5ef2aSThomas Huth 
2478*fcf5ef2aSThomas Huth     entry &= 0x3F;
2479*fcf5ef2aSThomas Huth     tlb = &env->tlb.tlbe[entry];
2480*fcf5ef2aSThomas Huth     switch (word) {
2481*fcf5ef2aSThomas Huth     default:
2482*fcf5ef2aSThomas Huth         /* Just here to please gcc */
2483*fcf5ef2aSThomas Huth     case 0:
2484*fcf5ef2aSThomas Huth         ret = tlb->EPN;
2485*fcf5ef2aSThomas Huth         size = booke_page_size_to_tlb(tlb->size);
2486*fcf5ef2aSThomas Huth         if (size < 0 || size > 0xF) {
2487*fcf5ef2aSThomas Huth             size = 1;
2488*fcf5ef2aSThomas Huth         }
2489*fcf5ef2aSThomas Huth         ret |= size << 4;
2490*fcf5ef2aSThomas Huth         if (tlb->attr & 0x1) {
2491*fcf5ef2aSThomas Huth             ret |= 0x100;
2492*fcf5ef2aSThomas Huth         }
2493*fcf5ef2aSThomas Huth         if (tlb->prot & PAGE_VALID) {
2494*fcf5ef2aSThomas Huth             ret |= 0x200;
2495*fcf5ef2aSThomas Huth         }
2496*fcf5ef2aSThomas Huth         env->spr[SPR_440_MMUCR] &= ~0x000000FF;
2497*fcf5ef2aSThomas Huth         env->spr[SPR_440_MMUCR] |= tlb->PID;
2498*fcf5ef2aSThomas Huth         break;
2499*fcf5ef2aSThomas Huth     case 1:
2500*fcf5ef2aSThomas Huth         ret = tlb->RPN;
2501*fcf5ef2aSThomas Huth         break;
2502*fcf5ef2aSThomas Huth     case 2:
2503*fcf5ef2aSThomas Huth         ret = tlb->attr & ~0x1;
2504*fcf5ef2aSThomas Huth         if (tlb->prot & (PAGE_READ << 4)) {
2505*fcf5ef2aSThomas Huth             ret |= 0x1;
2506*fcf5ef2aSThomas Huth         }
2507*fcf5ef2aSThomas Huth         if (tlb->prot & (PAGE_WRITE << 4)) {
2508*fcf5ef2aSThomas Huth             ret |= 0x2;
2509*fcf5ef2aSThomas Huth         }
2510*fcf5ef2aSThomas Huth         if (tlb->prot & (PAGE_EXEC << 4)) {
2511*fcf5ef2aSThomas Huth             ret |= 0x4;
2512*fcf5ef2aSThomas Huth         }
2513*fcf5ef2aSThomas Huth         if (tlb->prot & PAGE_READ) {
2514*fcf5ef2aSThomas Huth             ret |= 0x8;
2515*fcf5ef2aSThomas Huth         }
2516*fcf5ef2aSThomas Huth         if (tlb->prot & PAGE_WRITE) {
2517*fcf5ef2aSThomas Huth             ret |= 0x10;
2518*fcf5ef2aSThomas Huth         }
2519*fcf5ef2aSThomas Huth         if (tlb->prot & PAGE_EXEC) {
2520*fcf5ef2aSThomas Huth             ret |= 0x20;
2521*fcf5ef2aSThomas Huth         }
2522*fcf5ef2aSThomas Huth         break;
2523*fcf5ef2aSThomas Huth     }
2524*fcf5ef2aSThomas Huth     return ret;
2525*fcf5ef2aSThomas Huth }
2526*fcf5ef2aSThomas Huth 
2527*fcf5ef2aSThomas Huth target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address)
2528*fcf5ef2aSThomas Huth {
2529*fcf5ef2aSThomas Huth     return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
2530*fcf5ef2aSThomas Huth }
2531*fcf5ef2aSThomas Huth 
2532*fcf5ef2aSThomas Huth /* PowerPC BookE 2.06 TLB management */
2533*fcf5ef2aSThomas Huth 
2534*fcf5ef2aSThomas Huth static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
2535*fcf5ef2aSThomas Huth {
2536*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = ppc_env_get_cpu(env);
2537*fcf5ef2aSThomas Huth     uint32_t tlbncfg = 0;
2538*fcf5ef2aSThomas Huth     int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
2539*fcf5ef2aSThomas Huth     int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
2540*fcf5ef2aSThomas Huth     int tlb;
2541*fcf5ef2aSThomas Huth 
2542*fcf5ef2aSThomas Huth     tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2543*fcf5ef2aSThomas Huth     tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
2544*fcf5ef2aSThomas Huth 
2545*fcf5ef2aSThomas Huth     if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
2546*fcf5ef2aSThomas Huth         cpu_abort(CPU(cpu), "we don't support HES yet\n");
2547*fcf5ef2aSThomas Huth     }
2548*fcf5ef2aSThomas Huth 
2549*fcf5ef2aSThomas Huth     return booke206_get_tlbm(env, tlb, ea, esel);
2550*fcf5ef2aSThomas Huth }
2551*fcf5ef2aSThomas Huth 
2552*fcf5ef2aSThomas Huth void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid)
2553*fcf5ef2aSThomas Huth {
2554*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = ppc_env_get_cpu(env);
2555*fcf5ef2aSThomas Huth 
2556*fcf5ef2aSThomas Huth     env->spr[pidn] = pid;
2557*fcf5ef2aSThomas Huth     /* changing PIDs mean we're in a different address space now */
2558*fcf5ef2aSThomas Huth     tlb_flush(CPU(cpu), 1);
2559*fcf5ef2aSThomas Huth }
2560*fcf5ef2aSThomas Huth 
2561*fcf5ef2aSThomas Huth void helper_booke206_tlbwe(CPUPPCState *env)
2562*fcf5ef2aSThomas Huth {
2563*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = ppc_env_get_cpu(env);
2564*fcf5ef2aSThomas Huth     uint32_t tlbncfg, tlbn;
2565*fcf5ef2aSThomas Huth     ppcmas_tlb_t *tlb;
2566*fcf5ef2aSThomas Huth     uint32_t size_tlb, size_ps;
2567*fcf5ef2aSThomas Huth     target_ulong mask;
2568*fcf5ef2aSThomas Huth 
2569*fcf5ef2aSThomas Huth 
2570*fcf5ef2aSThomas Huth     switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
2571*fcf5ef2aSThomas Huth     case MAS0_WQ_ALWAYS:
2572*fcf5ef2aSThomas Huth         /* good to go, write that entry */
2573*fcf5ef2aSThomas Huth         break;
2574*fcf5ef2aSThomas Huth     case MAS0_WQ_COND:
2575*fcf5ef2aSThomas Huth         /* XXX check if reserved */
2576*fcf5ef2aSThomas Huth         if (0) {
2577*fcf5ef2aSThomas Huth             return;
2578*fcf5ef2aSThomas Huth         }
2579*fcf5ef2aSThomas Huth         break;
2580*fcf5ef2aSThomas Huth     case MAS0_WQ_CLR_RSRV:
2581*fcf5ef2aSThomas Huth         /* XXX clear entry */
2582*fcf5ef2aSThomas Huth         return;
2583*fcf5ef2aSThomas Huth     default:
2584*fcf5ef2aSThomas Huth         /* no idea what to do */
2585*fcf5ef2aSThomas Huth         return;
2586*fcf5ef2aSThomas Huth     }
2587*fcf5ef2aSThomas Huth 
2588*fcf5ef2aSThomas Huth     if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
2589*fcf5ef2aSThomas Huth         !msr_gs) {
2590*fcf5ef2aSThomas Huth         /* XXX we don't support direct LRAT setting yet */
2591*fcf5ef2aSThomas Huth         fprintf(stderr, "cpu: don't support LRAT setting yet\n");
2592*fcf5ef2aSThomas Huth         return;
2593*fcf5ef2aSThomas Huth     }
2594*fcf5ef2aSThomas Huth 
2595*fcf5ef2aSThomas Huth     tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2596*fcf5ef2aSThomas Huth     tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
2597*fcf5ef2aSThomas Huth 
2598*fcf5ef2aSThomas Huth     tlb = booke206_cur_tlb(env);
2599*fcf5ef2aSThomas Huth 
2600*fcf5ef2aSThomas Huth     if (!tlb) {
2601*fcf5ef2aSThomas Huth         raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
2602*fcf5ef2aSThomas Huth                                POWERPC_EXCP_INVAL |
2603*fcf5ef2aSThomas Huth                                POWERPC_EXCP_INVAL_INVAL, GETPC());
2604*fcf5ef2aSThomas Huth     }
2605*fcf5ef2aSThomas Huth 
2606*fcf5ef2aSThomas Huth     /* check that we support the targeted size */
2607*fcf5ef2aSThomas Huth     size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
2608*fcf5ef2aSThomas Huth     size_ps = booke206_tlbnps(env, tlbn);
2609*fcf5ef2aSThomas Huth     if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
2610*fcf5ef2aSThomas Huth         !(size_ps & (1 << size_tlb))) {
2611*fcf5ef2aSThomas Huth         raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
2612*fcf5ef2aSThomas Huth                                POWERPC_EXCP_INVAL |
2613*fcf5ef2aSThomas Huth                                POWERPC_EXCP_INVAL_INVAL, GETPC());
2614*fcf5ef2aSThomas Huth     }
2615*fcf5ef2aSThomas Huth 
2616*fcf5ef2aSThomas Huth     if (msr_gs) {
2617*fcf5ef2aSThomas Huth         cpu_abort(CPU(cpu), "missing HV implementation\n");
2618*fcf5ef2aSThomas Huth     }
2619*fcf5ef2aSThomas Huth     tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
2620*fcf5ef2aSThomas Huth         env->spr[SPR_BOOKE_MAS3];
2621*fcf5ef2aSThomas Huth     tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
2622*fcf5ef2aSThomas Huth 
2623*fcf5ef2aSThomas Huth     /* MAV 1.0 only */
2624*fcf5ef2aSThomas Huth     if (!(tlbncfg & TLBnCFG_AVAIL)) {
2625*fcf5ef2aSThomas Huth         /* force !AVAIL TLB entries to correct page size */
2626*fcf5ef2aSThomas Huth         tlb->mas1 &= ~MAS1_TSIZE_MASK;
2627*fcf5ef2aSThomas Huth         /* XXX can be configured in MMUCSR0 */
2628*fcf5ef2aSThomas Huth         tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
2629*fcf5ef2aSThomas Huth     }
2630*fcf5ef2aSThomas Huth 
2631*fcf5ef2aSThomas Huth     /* Make a mask from TLB size to discard invalid bits in EPN field */
2632*fcf5ef2aSThomas Huth     mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2633*fcf5ef2aSThomas Huth     /* Add a mask for page attributes */
2634*fcf5ef2aSThomas Huth     mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E;
2635*fcf5ef2aSThomas Huth 
2636*fcf5ef2aSThomas Huth     if (!msr_cm) {
2637*fcf5ef2aSThomas Huth         /* Executing a tlbwe instruction in 32-bit mode will set
2638*fcf5ef2aSThomas Huth          * bits 0:31 of the TLB EPN field to zero.
2639*fcf5ef2aSThomas Huth          */
2640*fcf5ef2aSThomas Huth         mask &= 0xffffffff;
2641*fcf5ef2aSThomas Huth     }
2642*fcf5ef2aSThomas Huth 
2643*fcf5ef2aSThomas Huth     tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & mask;
2644*fcf5ef2aSThomas Huth 
2645*fcf5ef2aSThomas Huth     if (!(tlbncfg & TLBnCFG_IPROT)) {
2646*fcf5ef2aSThomas Huth         /* no IPROT supported by TLB */
2647*fcf5ef2aSThomas Huth         tlb->mas1 &= ~MAS1_IPROT;
2648*fcf5ef2aSThomas Huth     }
2649*fcf5ef2aSThomas Huth 
2650*fcf5ef2aSThomas Huth     if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
2651*fcf5ef2aSThomas Huth         tlb_flush_page(CPU(cpu), tlb->mas2 & MAS2_EPN_MASK);
2652*fcf5ef2aSThomas Huth     } else {
2653*fcf5ef2aSThomas Huth         tlb_flush(CPU(cpu), 1);
2654*fcf5ef2aSThomas Huth     }
2655*fcf5ef2aSThomas Huth }
2656*fcf5ef2aSThomas Huth 
2657*fcf5ef2aSThomas Huth static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
2658*fcf5ef2aSThomas Huth {
2659*fcf5ef2aSThomas Huth     int tlbn = booke206_tlbm_to_tlbn(env, tlb);
2660*fcf5ef2aSThomas Huth     int way = booke206_tlbm_to_way(env, tlb);
2661*fcf5ef2aSThomas Huth 
2662*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
2663*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
2664*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2665*fcf5ef2aSThomas Huth 
2666*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
2667*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
2668*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
2669*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
2670*fcf5ef2aSThomas Huth }
2671*fcf5ef2aSThomas Huth 
2672*fcf5ef2aSThomas Huth void helper_booke206_tlbre(CPUPPCState *env)
2673*fcf5ef2aSThomas Huth {
2674*fcf5ef2aSThomas Huth     ppcmas_tlb_t *tlb = NULL;
2675*fcf5ef2aSThomas Huth 
2676*fcf5ef2aSThomas Huth     tlb = booke206_cur_tlb(env);
2677*fcf5ef2aSThomas Huth     if (!tlb) {
2678*fcf5ef2aSThomas Huth         env->spr[SPR_BOOKE_MAS1] = 0;
2679*fcf5ef2aSThomas Huth     } else {
2680*fcf5ef2aSThomas Huth         booke206_tlb_to_mas(env, tlb);
2681*fcf5ef2aSThomas Huth     }
2682*fcf5ef2aSThomas Huth }
2683*fcf5ef2aSThomas Huth 
2684*fcf5ef2aSThomas Huth void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address)
2685*fcf5ef2aSThomas Huth {
2686*fcf5ef2aSThomas Huth     ppcmas_tlb_t *tlb = NULL;
2687*fcf5ef2aSThomas Huth     int i, j;
2688*fcf5ef2aSThomas Huth     hwaddr raddr;
2689*fcf5ef2aSThomas Huth     uint32_t spid, sas;
2690*fcf5ef2aSThomas Huth 
2691*fcf5ef2aSThomas Huth     spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
2692*fcf5ef2aSThomas Huth     sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
2693*fcf5ef2aSThomas Huth 
2694*fcf5ef2aSThomas Huth     for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2695*fcf5ef2aSThomas Huth         int ways = booke206_tlb_ways(env, i);
2696*fcf5ef2aSThomas Huth 
2697*fcf5ef2aSThomas Huth         for (j = 0; j < ways; j++) {
2698*fcf5ef2aSThomas Huth             tlb = booke206_get_tlbm(env, i, address, j);
2699*fcf5ef2aSThomas Huth 
2700*fcf5ef2aSThomas Huth             if (!tlb) {
2701*fcf5ef2aSThomas Huth                 continue;
2702*fcf5ef2aSThomas Huth             }
2703*fcf5ef2aSThomas Huth 
2704*fcf5ef2aSThomas Huth             if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
2705*fcf5ef2aSThomas Huth                 continue;
2706*fcf5ef2aSThomas Huth             }
2707*fcf5ef2aSThomas Huth 
2708*fcf5ef2aSThomas Huth             if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
2709*fcf5ef2aSThomas Huth                 continue;
2710*fcf5ef2aSThomas Huth             }
2711*fcf5ef2aSThomas Huth 
2712*fcf5ef2aSThomas Huth             booke206_tlb_to_mas(env, tlb);
2713*fcf5ef2aSThomas Huth             return;
2714*fcf5ef2aSThomas Huth         }
2715*fcf5ef2aSThomas Huth     }
2716*fcf5ef2aSThomas Huth 
2717*fcf5ef2aSThomas Huth     /* no entry found, fill with defaults */
2718*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
2719*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
2720*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
2721*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS3] = 0;
2722*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS7] = 0;
2723*fcf5ef2aSThomas Huth 
2724*fcf5ef2aSThomas Huth     if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
2725*fcf5ef2aSThomas Huth         env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
2726*fcf5ef2aSThomas Huth     }
2727*fcf5ef2aSThomas Huth 
2728*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
2729*fcf5ef2aSThomas Huth         << MAS1_TID_SHIFT;
2730*fcf5ef2aSThomas Huth 
2731*fcf5ef2aSThomas Huth     /* next victim logic */
2732*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
2733*fcf5ef2aSThomas Huth     env->last_way++;
2734*fcf5ef2aSThomas Huth     env->last_way &= booke206_tlb_ways(env, 0) - 1;
2735*fcf5ef2aSThomas Huth     env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2736*fcf5ef2aSThomas Huth }
2737*fcf5ef2aSThomas Huth 
2738*fcf5ef2aSThomas Huth static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
2739*fcf5ef2aSThomas Huth                                               uint32_t ea)
2740*fcf5ef2aSThomas Huth {
2741*fcf5ef2aSThomas Huth     int i;
2742*fcf5ef2aSThomas Huth     int ways = booke206_tlb_ways(env, tlbn);
2743*fcf5ef2aSThomas Huth     target_ulong mask;
2744*fcf5ef2aSThomas Huth 
2745*fcf5ef2aSThomas Huth     for (i = 0; i < ways; i++) {
2746*fcf5ef2aSThomas Huth         ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
2747*fcf5ef2aSThomas Huth         if (!tlb) {
2748*fcf5ef2aSThomas Huth             continue;
2749*fcf5ef2aSThomas Huth         }
2750*fcf5ef2aSThomas Huth         mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2751*fcf5ef2aSThomas Huth         if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
2752*fcf5ef2aSThomas Huth             !(tlb->mas1 & MAS1_IPROT)) {
2753*fcf5ef2aSThomas Huth             tlb->mas1 &= ~MAS1_VALID;
2754*fcf5ef2aSThomas Huth         }
2755*fcf5ef2aSThomas Huth     }
2756*fcf5ef2aSThomas Huth }
2757*fcf5ef2aSThomas Huth 
2758*fcf5ef2aSThomas Huth void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address)
2759*fcf5ef2aSThomas Huth {
2760*fcf5ef2aSThomas Huth     CPUState *cs;
2761*fcf5ef2aSThomas Huth 
2762*fcf5ef2aSThomas Huth     if (address & 0x4) {
2763*fcf5ef2aSThomas Huth         /* flush all entries */
2764*fcf5ef2aSThomas Huth         if (address & 0x8) {
2765*fcf5ef2aSThomas Huth             /* flush all of TLB1 */
2766*fcf5ef2aSThomas Huth             booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
2767*fcf5ef2aSThomas Huth         } else {
2768*fcf5ef2aSThomas Huth             /* flush all of TLB0 */
2769*fcf5ef2aSThomas Huth             booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
2770*fcf5ef2aSThomas Huth         }
2771*fcf5ef2aSThomas Huth         return;
2772*fcf5ef2aSThomas Huth     }
2773*fcf5ef2aSThomas Huth 
2774*fcf5ef2aSThomas Huth     if (address & 0x8) {
2775*fcf5ef2aSThomas Huth         /* flush TLB1 entries */
2776*fcf5ef2aSThomas Huth         booke206_invalidate_ea_tlb(env, 1, address);
2777*fcf5ef2aSThomas Huth         CPU_FOREACH(cs) {
2778*fcf5ef2aSThomas Huth             tlb_flush(cs, 1);
2779*fcf5ef2aSThomas Huth         }
2780*fcf5ef2aSThomas Huth     } else {
2781*fcf5ef2aSThomas Huth         /* flush TLB0 entries */
2782*fcf5ef2aSThomas Huth         booke206_invalidate_ea_tlb(env, 0, address);
2783*fcf5ef2aSThomas Huth         CPU_FOREACH(cs) {
2784*fcf5ef2aSThomas Huth             tlb_flush_page(cs, address & MAS2_EPN_MASK);
2785*fcf5ef2aSThomas Huth         }
2786*fcf5ef2aSThomas Huth     }
2787*fcf5ef2aSThomas Huth }
2788*fcf5ef2aSThomas Huth 
2789*fcf5ef2aSThomas Huth void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address)
2790*fcf5ef2aSThomas Huth {
2791*fcf5ef2aSThomas Huth     /* XXX missing LPID handling */
2792*fcf5ef2aSThomas Huth     booke206_flush_tlb(env, -1, 1);
2793*fcf5ef2aSThomas Huth }
2794*fcf5ef2aSThomas Huth 
2795*fcf5ef2aSThomas Huth void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address)
2796*fcf5ef2aSThomas Huth {
2797*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = ppc_env_get_cpu(env);
2798*fcf5ef2aSThomas Huth     int i, j;
2799*fcf5ef2aSThomas Huth     int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2800*fcf5ef2aSThomas Huth     ppcmas_tlb_t *tlb = env->tlb.tlbm;
2801*fcf5ef2aSThomas Huth     int tlb_size;
2802*fcf5ef2aSThomas Huth 
2803*fcf5ef2aSThomas Huth     /* XXX missing LPID handling */
2804*fcf5ef2aSThomas Huth     for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2805*fcf5ef2aSThomas Huth         tlb_size = booke206_tlb_size(env, i);
2806*fcf5ef2aSThomas Huth         for (j = 0; j < tlb_size; j++) {
2807*fcf5ef2aSThomas Huth             if (!(tlb[j].mas1 & MAS1_IPROT) &&
2808*fcf5ef2aSThomas Huth                 ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
2809*fcf5ef2aSThomas Huth                 tlb[j].mas1 &= ~MAS1_VALID;
2810*fcf5ef2aSThomas Huth             }
2811*fcf5ef2aSThomas Huth         }
2812*fcf5ef2aSThomas Huth         tlb += booke206_tlb_size(env, i);
2813*fcf5ef2aSThomas Huth     }
2814*fcf5ef2aSThomas Huth     tlb_flush(CPU(cpu), 1);
2815*fcf5ef2aSThomas Huth }
2816*fcf5ef2aSThomas Huth 
2817*fcf5ef2aSThomas Huth void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
2818*fcf5ef2aSThomas Huth {
2819*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = ppc_env_get_cpu(env);
2820*fcf5ef2aSThomas Huth     int i, j;
2821*fcf5ef2aSThomas Huth     ppcmas_tlb_t *tlb;
2822*fcf5ef2aSThomas Huth     int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2823*fcf5ef2aSThomas Huth     int pid = tid >> MAS6_SPID_SHIFT;
2824*fcf5ef2aSThomas Huth     int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
2825*fcf5ef2aSThomas Huth     int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
2826*fcf5ef2aSThomas Huth     /* XXX check for unsupported isize and raise an invalid opcode then */
2827*fcf5ef2aSThomas Huth     int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
2828*fcf5ef2aSThomas Huth     /* XXX implement MAV2 handling */
2829*fcf5ef2aSThomas Huth     bool mav2 = false;
2830*fcf5ef2aSThomas Huth 
2831*fcf5ef2aSThomas Huth     /* XXX missing LPID handling */
2832*fcf5ef2aSThomas Huth     /* flush by pid and ea */
2833*fcf5ef2aSThomas Huth     for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2834*fcf5ef2aSThomas Huth         int ways = booke206_tlb_ways(env, i);
2835*fcf5ef2aSThomas Huth 
2836*fcf5ef2aSThomas Huth         for (j = 0; j < ways; j++) {
2837*fcf5ef2aSThomas Huth             tlb = booke206_get_tlbm(env, i, address, j);
2838*fcf5ef2aSThomas Huth             if (!tlb) {
2839*fcf5ef2aSThomas Huth                 continue;
2840*fcf5ef2aSThomas Huth             }
2841*fcf5ef2aSThomas Huth             if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
2842*fcf5ef2aSThomas Huth                 (tlb->mas1 & MAS1_IPROT) ||
2843*fcf5ef2aSThomas Huth                 ((tlb->mas1 & MAS1_IND) != ind) ||
2844*fcf5ef2aSThomas Huth                 ((tlb->mas8 & MAS8_TGS) != sgs)) {
2845*fcf5ef2aSThomas Huth                 continue;
2846*fcf5ef2aSThomas Huth             }
2847*fcf5ef2aSThomas Huth             if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
2848*fcf5ef2aSThomas Huth                 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
2849*fcf5ef2aSThomas Huth                 continue;
2850*fcf5ef2aSThomas Huth             }
2851*fcf5ef2aSThomas Huth             /* XXX e500mc doesn't match SAS, but other cores might */
2852*fcf5ef2aSThomas Huth             tlb->mas1 &= ~MAS1_VALID;
2853*fcf5ef2aSThomas Huth         }
2854*fcf5ef2aSThomas Huth     }
2855*fcf5ef2aSThomas Huth     tlb_flush(CPU(cpu), 1);
2856*fcf5ef2aSThomas Huth }
2857*fcf5ef2aSThomas Huth 
2858*fcf5ef2aSThomas Huth void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type)
2859*fcf5ef2aSThomas Huth {
2860*fcf5ef2aSThomas Huth     int flags = 0;
2861*fcf5ef2aSThomas Huth 
2862*fcf5ef2aSThomas Huth     if (type & 2) {
2863*fcf5ef2aSThomas Huth         flags |= BOOKE206_FLUSH_TLB1;
2864*fcf5ef2aSThomas Huth     }
2865*fcf5ef2aSThomas Huth 
2866*fcf5ef2aSThomas Huth     if (type & 4) {
2867*fcf5ef2aSThomas Huth         flags |= BOOKE206_FLUSH_TLB0;
2868*fcf5ef2aSThomas Huth     }
2869*fcf5ef2aSThomas Huth 
2870*fcf5ef2aSThomas Huth     booke206_flush_tlb(env, flags, 1);
2871*fcf5ef2aSThomas Huth }
2872*fcf5ef2aSThomas Huth 
2873*fcf5ef2aSThomas Huth 
2874*fcf5ef2aSThomas Huth void helper_check_tlb_flush_local(CPUPPCState *env)
2875*fcf5ef2aSThomas Huth {
2876*fcf5ef2aSThomas Huth     check_tlb_flush(env, false);
2877*fcf5ef2aSThomas Huth }
2878*fcf5ef2aSThomas Huth 
2879*fcf5ef2aSThomas Huth void helper_check_tlb_flush_global(CPUPPCState *env)
2880*fcf5ef2aSThomas Huth {
2881*fcf5ef2aSThomas Huth     check_tlb_flush(env, true);
2882*fcf5ef2aSThomas Huth }
2883*fcf5ef2aSThomas Huth 
2884*fcf5ef2aSThomas Huth /*****************************************************************************/
2885*fcf5ef2aSThomas Huth 
2886*fcf5ef2aSThomas Huth /* try to fill the TLB and return an exception if error. If retaddr is
2887*fcf5ef2aSThomas Huth    NULL, it means that the function was called in C code (i.e. not
2888*fcf5ef2aSThomas Huth    from generated code or from helper.c) */
2889*fcf5ef2aSThomas Huth /* XXX: fix it to restore all registers */
2890*fcf5ef2aSThomas Huth void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type,
2891*fcf5ef2aSThomas Huth               int mmu_idx, uintptr_t retaddr)
2892*fcf5ef2aSThomas Huth {
2893*fcf5ef2aSThomas Huth     PowerPCCPU *cpu = POWERPC_CPU(cs);
2894*fcf5ef2aSThomas Huth     PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
2895*fcf5ef2aSThomas Huth     CPUPPCState *env = &cpu->env;
2896*fcf5ef2aSThomas Huth     int ret;
2897*fcf5ef2aSThomas Huth 
2898*fcf5ef2aSThomas Huth     if (pcc->handle_mmu_fault) {
2899*fcf5ef2aSThomas Huth         ret = pcc->handle_mmu_fault(cpu, addr, access_type, mmu_idx);
2900*fcf5ef2aSThomas Huth     } else {
2901*fcf5ef2aSThomas Huth         ret = cpu_ppc_handle_mmu_fault(env, addr, access_type, mmu_idx);
2902*fcf5ef2aSThomas Huth     }
2903*fcf5ef2aSThomas Huth     if (unlikely(ret != 0)) {
2904*fcf5ef2aSThomas Huth         raise_exception_err_ra(env, cs->exception_index, env->error_code,
2905*fcf5ef2aSThomas Huth                                retaddr);
2906*fcf5ef2aSThomas Huth     }
2907*fcf5ef2aSThomas Huth }
2908