xref: /openbmc/qemu/target/ppc/mmu-booke.c (revision ffdd099a782556b9ead26551a6f1d070a595306d)
1*e7baac64SBALATON Zoltan /*
2*e7baac64SBALATON Zoltan  *  PowerPC BookE MMU, TLB emulation helpers for QEMU.
3*e7baac64SBALATON Zoltan  *
4*e7baac64SBALATON Zoltan  *  Copyright (c) 2003-2007 Jocelyn Mayer
5*e7baac64SBALATON Zoltan  *
6*e7baac64SBALATON Zoltan  * This library is free software; you can redistribute it and/or
7*e7baac64SBALATON Zoltan  * modify it under the terms of the GNU Lesser General Public
8*e7baac64SBALATON Zoltan  * License as published by the Free Software Foundation; either
9*e7baac64SBALATON Zoltan  * version 2.1 of the License, or (at your option) any later version.
10*e7baac64SBALATON Zoltan  *
11*e7baac64SBALATON Zoltan  * This library is distributed in the hope that it will be useful,
12*e7baac64SBALATON Zoltan  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*e7baac64SBALATON Zoltan  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14*e7baac64SBALATON Zoltan  * Lesser General Public License for more details.
15*e7baac64SBALATON Zoltan  *
16*e7baac64SBALATON Zoltan  * You should have received a copy of the GNU Lesser General Public
17*e7baac64SBALATON Zoltan  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18*e7baac64SBALATON Zoltan  */
19*e7baac64SBALATON Zoltan 
20*e7baac64SBALATON Zoltan #include "qemu/osdep.h"
21*e7baac64SBALATON Zoltan #include "exec/page-protection.h"
22*e7baac64SBALATON Zoltan #include "exec/log.h"
23*e7baac64SBALATON Zoltan #include "cpu.h"
24*e7baac64SBALATON Zoltan #include "internal.h"
25*e7baac64SBALATON Zoltan #include "mmu-booke.h"
26*e7baac64SBALATON Zoltan 
27*e7baac64SBALATON Zoltan /* Generic TLB check function for embedded PowerPC implementations */
ppcemb_tlb_check(CPUPPCState * env,ppcemb_tlb_t * tlb,hwaddr * raddrp,target_ulong address,uint32_t pid,int i)28*e7baac64SBALATON Zoltan static bool ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
29*e7baac64SBALATON Zoltan                              hwaddr *raddrp,
30*e7baac64SBALATON Zoltan                              target_ulong address, uint32_t pid, int i)
31*e7baac64SBALATON Zoltan {
32*e7baac64SBALATON Zoltan     target_ulong mask;
33*e7baac64SBALATON Zoltan 
34*e7baac64SBALATON Zoltan     /* Check valid flag */
35*e7baac64SBALATON Zoltan     if (!(tlb->prot & PAGE_VALID)) {
36*e7baac64SBALATON Zoltan         return false;
37*e7baac64SBALATON Zoltan     }
38*e7baac64SBALATON Zoltan     mask = ~(tlb->size - 1);
39*e7baac64SBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "%s: TLB %d address " TARGET_FMT_lx
40*e7baac64SBALATON Zoltan                   " PID %u <=> " TARGET_FMT_lx " " TARGET_FMT_lx " %u %x\n",
41*e7baac64SBALATON Zoltan                   __func__, i, address, pid, tlb->EPN,
42*e7baac64SBALATON Zoltan                   mask, (uint32_t)tlb->PID, tlb->prot);
43*e7baac64SBALATON Zoltan     /* Check PID */
44*e7baac64SBALATON Zoltan     if (tlb->PID != 0 && tlb->PID != pid) {
45*e7baac64SBALATON Zoltan         return false;
46*e7baac64SBALATON Zoltan     }
47*e7baac64SBALATON Zoltan     /* Check effective address */
48*e7baac64SBALATON Zoltan     if ((address & mask) != tlb->EPN) {
49*e7baac64SBALATON Zoltan         return false;
50*e7baac64SBALATON Zoltan     }
51*e7baac64SBALATON Zoltan     *raddrp = (tlb->RPN & mask) | (address & ~mask);
52*e7baac64SBALATON Zoltan     return true;
53*e7baac64SBALATON Zoltan }
54*e7baac64SBALATON Zoltan 
55*e7baac64SBALATON Zoltan /* Generic TLB search function for PowerPC embedded implementations */
ppcemb_tlb_search(CPUPPCState * env,target_ulong address,uint32_t pid)56*e7baac64SBALATON Zoltan int ppcemb_tlb_search(CPUPPCState *env, target_ulong address, uint32_t pid)
57*e7baac64SBALATON Zoltan {
58*e7baac64SBALATON Zoltan     ppcemb_tlb_t *tlb;
59*e7baac64SBALATON Zoltan     hwaddr raddr;
60*e7baac64SBALATON Zoltan     int i;
61*e7baac64SBALATON Zoltan 
62*e7baac64SBALATON Zoltan     for (i = 0; i < env->nb_tlb; i++) {
63*e7baac64SBALATON Zoltan         tlb = &env->tlb.tlbe[i];
64*e7baac64SBALATON Zoltan         if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, i)) {
65*e7baac64SBALATON Zoltan             return i;
66*e7baac64SBALATON Zoltan         }
67*e7baac64SBALATON Zoltan     }
68*e7baac64SBALATON Zoltan     return -1;
69*e7baac64SBALATON Zoltan }
70*e7baac64SBALATON Zoltan 
mmu40x_get_physical_address(CPUPPCState * env,hwaddr * raddr,int * prot,target_ulong address,MMUAccessType access_type)71*e7baac64SBALATON Zoltan int mmu40x_get_physical_address(CPUPPCState *env, hwaddr *raddr, int *prot,
72*e7baac64SBALATON Zoltan                                 target_ulong address,
73*e7baac64SBALATON Zoltan                                 MMUAccessType access_type)
74*e7baac64SBALATON Zoltan {
75*e7baac64SBALATON Zoltan     ppcemb_tlb_t *tlb;
76*e7baac64SBALATON Zoltan     int i, ret, zsel, zpr, pr;
77*e7baac64SBALATON Zoltan 
78*e7baac64SBALATON Zoltan     ret = -1;
79*e7baac64SBALATON Zoltan     pr = FIELD_EX64(env->msr, MSR, PR);
80*e7baac64SBALATON Zoltan     for (i = 0; i < env->nb_tlb; i++) {
81*e7baac64SBALATON Zoltan         tlb = &env->tlb.tlbe[i];
82*e7baac64SBALATON Zoltan         if (!ppcemb_tlb_check(env, tlb, raddr, address,
83*e7baac64SBALATON Zoltan                               env->spr[SPR_40x_PID], i)) {
84*e7baac64SBALATON Zoltan             continue;
85*e7baac64SBALATON Zoltan         }
86*e7baac64SBALATON Zoltan         zsel = (tlb->attr >> 4) & 0xF;
87*e7baac64SBALATON Zoltan         zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
88*e7baac64SBALATON Zoltan         qemu_log_mask(CPU_LOG_MMU,
89*e7baac64SBALATON Zoltan                       "%s: TLB %d zsel %d zpr %d ty %d attr %08x\n",
90*e7baac64SBALATON Zoltan                       __func__, i, zsel, zpr, access_type, tlb->attr);
91*e7baac64SBALATON Zoltan         /* Check execute enable bit */
92*e7baac64SBALATON Zoltan         switch (zpr) {
93*e7baac64SBALATON Zoltan         case 0x2:
94*e7baac64SBALATON Zoltan             if (pr != 0) {
95*e7baac64SBALATON Zoltan                 goto check_perms;
96*e7baac64SBALATON Zoltan             }
97*e7baac64SBALATON Zoltan             /* fall through */
98*e7baac64SBALATON Zoltan         case 0x3:
99*e7baac64SBALATON Zoltan             /* All accesses granted */
100*e7baac64SBALATON Zoltan             *prot = PAGE_RWX;
101*e7baac64SBALATON Zoltan             ret = 0;
102*e7baac64SBALATON Zoltan             break;
103*e7baac64SBALATON Zoltan 
104*e7baac64SBALATON Zoltan         case 0x0:
105*e7baac64SBALATON Zoltan             if (pr != 0) {
106*e7baac64SBALATON Zoltan                 /* Raise Zone protection fault.  */
107*e7baac64SBALATON Zoltan                 env->spr[SPR_40x_ESR] = 1 << 22;
108*e7baac64SBALATON Zoltan                 *prot = 0;
109*e7baac64SBALATON Zoltan                 ret = -2;
110*e7baac64SBALATON Zoltan                 break;
111*e7baac64SBALATON Zoltan             }
112*e7baac64SBALATON Zoltan             /* fall through */
113*e7baac64SBALATON Zoltan         case 0x1:
114*e7baac64SBALATON Zoltan check_perms:
115*e7baac64SBALATON Zoltan             /* Check from TLB entry */
116*e7baac64SBALATON Zoltan             *prot = tlb->prot;
117*e7baac64SBALATON Zoltan             if (check_prot_access_type(*prot, access_type)) {
118*e7baac64SBALATON Zoltan                 ret = 0;
119*e7baac64SBALATON Zoltan             } else {
120*e7baac64SBALATON Zoltan                 env->spr[SPR_40x_ESR] = 0;
121*e7baac64SBALATON Zoltan                 ret = -2;
122*e7baac64SBALATON Zoltan             }
123*e7baac64SBALATON Zoltan             break;
124*e7baac64SBALATON Zoltan         }
125*e7baac64SBALATON Zoltan     }
126*e7baac64SBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "%s: access %s " TARGET_FMT_lx " => "
127*e7baac64SBALATON Zoltan                   HWADDR_FMT_plx " %d %d\n",  __func__,
128*e7baac64SBALATON Zoltan                   ret < 0 ? "refused" : "granted", address,
129*e7baac64SBALATON Zoltan                   ret < 0 ? 0 : *raddr, *prot, ret);
130*e7baac64SBALATON Zoltan 
131*e7baac64SBALATON Zoltan     return ret;
132*e7baac64SBALATON Zoltan }
133*e7baac64SBALATON Zoltan 
mmubooke_check_pid(CPUPPCState * env,ppcemb_tlb_t * tlb,hwaddr * raddr,target_ulong addr,int i)134*e7baac64SBALATON Zoltan static bool mmubooke_check_pid(CPUPPCState *env, ppcemb_tlb_t *tlb,
135*e7baac64SBALATON Zoltan                                hwaddr *raddr, target_ulong addr, int i)
136*e7baac64SBALATON Zoltan {
137*e7baac64SBALATON Zoltan     if (ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID], i)) {
138*e7baac64SBALATON Zoltan         if (!env->nb_pids) {
139*e7baac64SBALATON Zoltan             /* Extend the physical address to 36 bits */
140*e7baac64SBALATON Zoltan             *raddr |= (uint64_t)(tlb->RPN & 0xF) << 32;
141*e7baac64SBALATON Zoltan         }
142*e7baac64SBALATON Zoltan         return true;
143*e7baac64SBALATON Zoltan     } else if (!env->nb_pids) {
144*e7baac64SBALATON Zoltan         return false;
145*e7baac64SBALATON Zoltan     }
146*e7baac64SBALATON Zoltan     if (env->spr[SPR_BOOKE_PID1] &&
147*e7baac64SBALATON Zoltan         ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID1], i)) {
148*e7baac64SBALATON Zoltan         return true;
149*e7baac64SBALATON Zoltan     }
150*e7baac64SBALATON Zoltan     if (env->spr[SPR_BOOKE_PID2] &&
151*e7baac64SBALATON Zoltan         ppcemb_tlb_check(env, tlb, raddr, addr, env->spr[SPR_BOOKE_PID2], i)) {
152*e7baac64SBALATON Zoltan         return true;
153*e7baac64SBALATON Zoltan     }
154*e7baac64SBALATON Zoltan     return false;
155*e7baac64SBALATON Zoltan }
156*e7baac64SBALATON Zoltan 
mmubooke_check_tlb(CPUPPCState * env,ppcemb_tlb_t * tlb,hwaddr * raddr,int * prot,target_ulong address,MMUAccessType access_type,int i)157*e7baac64SBALATON Zoltan static int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
158*e7baac64SBALATON Zoltan                               hwaddr *raddr, int *prot, target_ulong address,
159*e7baac64SBALATON Zoltan                               MMUAccessType access_type, int i)
160*e7baac64SBALATON Zoltan {
161*e7baac64SBALATON Zoltan     if (!mmubooke_check_pid(env, tlb, raddr, address, i)) {
162*e7baac64SBALATON Zoltan         qemu_log_mask(CPU_LOG_MMU, "%s: TLB entry not found\n", __func__);
163*e7baac64SBALATON Zoltan         return -1;
164*e7baac64SBALATON Zoltan     }
165*e7baac64SBALATON Zoltan 
166*e7baac64SBALATON Zoltan     /* Check the address space */
167*e7baac64SBALATON Zoltan     if ((access_type == MMU_INST_FETCH ?
168*e7baac64SBALATON Zoltan         FIELD_EX64(env->msr, MSR, IR) :
169*e7baac64SBALATON Zoltan         FIELD_EX64(env->msr, MSR, DR)) != (tlb->attr & 1)) {
170*e7baac64SBALATON Zoltan         qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__);
171*e7baac64SBALATON Zoltan         return -1;
172*e7baac64SBALATON Zoltan     }
173*e7baac64SBALATON Zoltan 
174*e7baac64SBALATON Zoltan     if (FIELD_EX64(env->msr, MSR, PR)) {
175*e7baac64SBALATON Zoltan         *prot = tlb->prot & 0xF;
176*e7baac64SBALATON Zoltan     } else {
177*e7baac64SBALATON Zoltan         *prot = (tlb->prot >> 4) & 0xF;
178*e7baac64SBALATON Zoltan     }
179*e7baac64SBALATON Zoltan     if (check_prot_access_type(*prot, access_type)) {
180*e7baac64SBALATON Zoltan         qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
181*e7baac64SBALATON Zoltan         return 0;
182*e7baac64SBALATON Zoltan     }
183*e7baac64SBALATON Zoltan 
184*e7baac64SBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "%s: no prot match: %x\n", __func__, *prot);
185*e7baac64SBALATON Zoltan     return access_type == MMU_INST_FETCH ? -3 : -2;
186*e7baac64SBALATON Zoltan }
187*e7baac64SBALATON Zoltan 
mmubooke_get_physical_address(CPUPPCState * env,hwaddr * raddr,int * prot,target_ulong address,MMUAccessType access_type)188*e7baac64SBALATON Zoltan static int mmubooke_get_physical_address(CPUPPCState *env, hwaddr *raddr,
189*e7baac64SBALATON Zoltan                                          int *prot, target_ulong address,
190*e7baac64SBALATON Zoltan                                          MMUAccessType access_type)
191*e7baac64SBALATON Zoltan {
192*e7baac64SBALATON Zoltan     ppcemb_tlb_t *tlb;
193*e7baac64SBALATON Zoltan     int i, ret = -1;
194*e7baac64SBALATON Zoltan 
195*e7baac64SBALATON Zoltan     for (i = 0; i < env->nb_tlb; i++) {
196*e7baac64SBALATON Zoltan         tlb = &env->tlb.tlbe[i];
197*e7baac64SBALATON Zoltan         ret = mmubooke_check_tlb(env, tlb, raddr, prot, address,
198*e7baac64SBALATON Zoltan                                  access_type, i);
199*e7baac64SBALATON Zoltan         if (ret != -1) {
200*e7baac64SBALATON Zoltan             break;
201*e7baac64SBALATON Zoltan         }
202*e7baac64SBALATON Zoltan     }
203*e7baac64SBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU,
204*e7baac64SBALATON Zoltan                   "%s: access %s " TARGET_FMT_lx " => " HWADDR_FMT_plx
205*e7baac64SBALATON Zoltan                   " %d %d\n", __func__, ret < 0 ? "refused" : "granted",
206*e7baac64SBALATON Zoltan                   address, ret < 0 ? -1 : *raddr, ret == -1 ? 0 : *prot, ret);
207*e7baac64SBALATON Zoltan     return ret;
208*e7baac64SBALATON Zoltan }
209*e7baac64SBALATON Zoltan 
booke206_tlb_to_page_size(CPUPPCState * env,ppcmas_tlb_t * tlb)210*e7baac64SBALATON Zoltan hwaddr booke206_tlb_to_page_size(CPUPPCState *env, ppcmas_tlb_t *tlb)
211*e7baac64SBALATON Zoltan {
212*e7baac64SBALATON Zoltan     int tlbm_size;
213*e7baac64SBALATON Zoltan 
214*e7baac64SBALATON Zoltan     tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
215*e7baac64SBALATON Zoltan 
216*e7baac64SBALATON Zoltan     return 1024ULL << tlbm_size;
217*e7baac64SBALATON Zoltan }
218*e7baac64SBALATON Zoltan 
219*e7baac64SBALATON Zoltan /* TLB check function for MAS based SoftTLBs */
ppcmas_tlb_check(CPUPPCState * env,ppcmas_tlb_t * tlb,hwaddr * raddrp,target_ulong address,uint32_t pid)220*e7baac64SBALATON Zoltan int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb, hwaddr *raddrp,
221*e7baac64SBALATON Zoltan                      target_ulong address, uint32_t pid)
222*e7baac64SBALATON Zoltan {
223*e7baac64SBALATON Zoltan     hwaddr mask;
224*e7baac64SBALATON Zoltan     uint32_t tlb_pid;
225*e7baac64SBALATON Zoltan 
226*e7baac64SBALATON Zoltan     if (!FIELD_EX64(env->msr, MSR, CM)) {
227*e7baac64SBALATON Zoltan         /* In 32bit mode we can only address 32bit EAs */
228*e7baac64SBALATON Zoltan         address = (uint32_t)address;
229*e7baac64SBALATON Zoltan     }
230*e7baac64SBALATON Zoltan 
231*e7baac64SBALATON Zoltan     /* Check valid flag */
232*e7baac64SBALATON Zoltan     if (!(tlb->mas1 & MAS1_VALID)) {
233*e7baac64SBALATON Zoltan         return -1;
234*e7baac64SBALATON Zoltan     }
235*e7baac64SBALATON Zoltan 
236*e7baac64SBALATON Zoltan     mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
237*e7baac64SBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "%s: TLB ADDR=0x" TARGET_FMT_lx
238*e7baac64SBALATON Zoltan                   " PID=0x%x MAS1=0x%x MAS2=0x%" PRIx64 " mask=0x%"
239*e7baac64SBALATON Zoltan                   HWADDR_PRIx " MAS7_3=0x%" PRIx64 " MAS8=0x%" PRIx32 "\n",
240*e7baac64SBALATON Zoltan                   __func__, address, pid, tlb->mas1, tlb->mas2, mask,
241*e7baac64SBALATON Zoltan                   tlb->mas7_3, tlb->mas8);
242*e7baac64SBALATON Zoltan 
243*e7baac64SBALATON Zoltan     /* Check PID */
244*e7baac64SBALATON Zoltan     tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
245*e7baac64SBALATON Zoltan     if (tlb_pid != 0 && tlb_pid != pid) {
246*e7baac64SBALATON Zoltan         return -1;
247*e7baac64SBALATON Zoltan     }
248*e7baac64SBALATON Zoltan 
249*e7baac64SBALATON Zoltan     /* Check effective address */
250*e7baac64SBALATON Zoltan     if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
251*e7baac64SBALATON Zoltan         return -1;
252*e7baac64SBALATON Zoltan     }
253*e7baac64SBALATON Zoltan 
254*e7baac64SBALATON Zoltan     if (raddrp) {
255*e7baac64SBALATON Zoltan         *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
256*e7baac64SBALATON Zoltan     }
257*e7baac64SBALATON Zoltan 
258*e7baac64SBALATON Zoltan     return 0;
259*e7baac64SBALATON Zoltan }
260*e7baac64SBALATON Zoltan 
is_epid_mmu(int mmu_idx)261*e7baac64SBALATON Zoltan static bool is_epid_mmu(int mmu_idx)
262*e7baac64SBALATON Zoltan {
263*e7baac64SBALATON Zoltan     return mmu_idx == PPC_TLB_EPID_STORE || mmu_idx == PPC_TLB_EPID_LOAD;
264*e7baac64SBALATON Zoltan }
265*e7baac64SBALATON Zoltan 
mmubooke206_esr(int mmu_idx,MMUAccessType access_type)266*e7baac64SBALATON Zoltan static uint32_t mmubooke206_esr(int mmu_idx, MMUAccessType access_type)
267*e7baac64SBALATON Zoltan {
268*e7baac64SBALATON Zoltan     uint32_t esr = 0;
269*e7baac64SBALATON Zoltan     if (access_type == MMU_DATA_STORE) {
270*e7baac64SBALATON Zoltan         esr |= ESR_ST;
271*e7baac64SBALATON Zoltan     }
272*e7baac64SBALATON Zoltan     if (is_epid_mmu(mmu_idx)) {
273*e7baac64SBALATON Zoltan         esr |= ESR_EPID;
274*e7baac64SBALATON Zoltan     }
275*e7baac64SBALATON Zoltan     return esr;
276*e7baac64SBALATON Zoltan }
277*e7baac64SBALATON Zoltan 
278*e7baac64SBALATON Zoltan /*
279*e7baac64SBALATON Zoltan  * Get EPID register given the mmu_idx. If this is regular load,
280*e7baac64SBALATON Zoltan  * construct the EPID access bits from current processor state
281*e7baac64SBALATON Zoltan  *
282*e7baac64SBALATON Zoltan  * Get the effective AS and PR bits and the PID. The PID is returned
283*e7baac64SBALATON Zoltan  * only if EPID load is requested, otherwise the caller must detect
284*e7baac64SBALATON Zoltan  * the correct EPID.  Return true if valid EPID is returned.
285*e7baac64SBALATON Zoltan  */
mmubooke206_get_as(CPUPPCState * env,int mmu_idx,uint32_t * epid_out,bool * as_out,bool * pr_out)286*e7baac64SBALATON Zoltan static bool mmubooke206_get_as(CPUPPCState *env,
287*e7baac64SBALATON Zoltan                                int mmu_idx, uint32_t *epid_out,
288*e7baac64SBALATON Zoltan                                bool *as_out, bool *pr_out)
289*e7baac64SBALATON Zoltan {
290*e7baac64SBALATON Zoltan     if (is_epid_mmu(mmu_idx)) {
291*e7baac64SBALATON Zoltan         uint32_t epidr;
292*e7baac64SBALATON Zoltan         if (mmu_idx == PPC_TLB_EPID_STORE) {
293*e7baac64SBALATON Zoltan             epidr = env->spr[SPR_BOOKE_EPSC];
294*e7baac64SBALATON Zoltan         } else {
295*e7baac64SBALATON Zoltan             epidr = env->spr[SPR_BOOKE_EPLC];
296*e7baac64SBALATON Zoltan         }
297*e7baac64SBALATON Zoltan         *epid_out = (epidr & EPID_EPID) >> EPID_EPID_SHIFT;
298*e7baac64SBALATON Zoltan         *as_out = !!(epidr & EPID_EAS);
299*e7baac64SBALATON Zoltan         *pr_out = !!(epidr & EPID_EPR);
300*e7baac64SBALATON Zoltan         return true;
301*e7baac64SBALATON Zoltan     } else {
302*e7baac64SBALATON Zoltan         *as_out = FIELD_EX64(env->msr, MSR, DS);
303*e7baac64SBALATON Zoltan         *pr_out = FIELD_EX64(env->msr, MSR, PR);
304*e7baac64SBALATON Zoltan         return false;
305*e7baac64SBALATON Zoltan     }
306*e7baac64SBALATON Zoltan }
307*e7baac64SBALATON Zoltan 
308*e7baac64SBALATON Zoltan /* Check if the tlb found by hashing really matches */
mmubooke206_check_tlb(CPUPPCState * env,ppcmas_tlb_t * tlb,hwaddr * raddr,int * prot,target_ulong address,MMUAccessType access_type,int mmu_idx)309*e7baac64SBALATON Zoltan static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
310*e7baac64SBALATON Zoltan                                  hwaddr *raddr, int *prot,
311*e7baac64SBALATON Zoltan                                  target_ulong address,
312*e7baac64SBALATON Zoltan                                  MMUAccessType access_type, int mmu_idx)
313*e7baac64SBALATON Zoltan {
314*e7baac64SBALATON Zoltan     uint32_t epid;
315*e7baac64SBALATON Zoltan     bool as, pr;
316*e7baac64SBALATON Zoltan     bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr);
317*e7baac64SBALATON Zoltan 
318*e7baac64SBALATON Zoltan     if (!use_epid) {
319*e7baac64SBALATON Zoltan         if (ppcmas_tlb_check(env, tlb, raddr, address,
320*e7baac64SBALATON Zoltan                              env->spr[SPR_BOOKE_PID]) >= 0) {
321*e7baac64SBALATON Zoltan             goto found_tlb;
322*e7baac64SBALATON Zoltan         }
323*e7baac64SBALATON Zoltan 
324*e7baac64SBALATON Zoltan         if (env->spr[SPR_BOOKE_PID1] &&
325*e7baac64SBALATON Zoltan             ppcmas_tlb_check(env, tlb, raddr, address,
326*e7baac64SBALATON Zoltan                              env->spr[SPR_BOOKE_PID1]) >= 0) {
327*e7baac64SBALATON Zoltan             goto found_tlb;
328*e7baac64SBALATON Zoltan         }
329*e7baac64SBALATON Zoltan 
330*e7baac64SBALATON Zoltan         if (env->spr[SPR_BOOKE_PID2] &&
331*e7baac64SBALATON Zoltan             ppcmas_tlb_check(env, tlb, raddr, address,
332*e7baac64SBALATON Zoltan                              env->spr[SPR_BOOKE_PID2]) >= 0) {
333*e7baac64SBALATON Zoltan             goto found_tlb;
334*e7baac64SBALATON Zoltan         }
335*e7baac64SBALATON Zoltan     } else {
336*e7baac64SBALATON Zoltan         if (ppcmas_tlb_check(env, tlb, raddr, address, epid) >= 0) {
337*e7baac64SBALATON Zoltan             goto found_tlb;
338*e7baac64SBALATON Zoltan         }
339*e7baac64SBALATON Zoltan     }
340*e7baac64SBALATON Zoltan 
341*e7baac64SBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "%s: No TLB entry found for effective address "
342*e7baac64SBALATON Zoltan                   "0x" TARGET_FMT_lx "\n", __func__, address);
343*e7baac64SBALATON Zoltan     return -1;
344*e7baac64SBALATON Zoltan 
345*e7baac64SBALATON Zoltan found_tlb:
346*e7baac64SBALATON Zoltan 
347*e7baac64SBALATON Zoltan     /* Check the address space and permissions */
348*e7baac64SBALATON Zoltan     if (access_type == MMU_INST_FETCH) {
349*e7baac64SBALATON Zoltan         /* There is no way to fetch code using epid load */
350*e7baac64SBALATON Zoltan         assert(!use_epid);
351*e7baac64SBALATON Zoltan         as = FIELD_EX64(env->msr, MSR, IR);
352*e7baac64SBALATON Zoltan     }
353*e7baac64SBALATON Zoltan 
354*e7baac64SBALATON Zoltan     if (as != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
355*e7baac64SBALATON Zoltan         qemu_log_mask(CPU_LOG_MMU, "%s: AS doesn't match\n", __func__);
356*e7baac64SBALATON Zoltan         return -1;
357*e7baac64SBALATON Zoltan     }
358*e7baac64SBALATON Zoltan 
359*e7baac64SBALATON Zoltan     *prot = 0;
360*e7baac64SBALATON Zoltan     if (pr) {
361*e7baac64SBALATON Zoltan         if (tlb->mas7_3 & MAS3_UR) {
362*e7baac64SBALATON Zoltan             *prot |= PAGE_READ;
363*e7baac64SBALATON Zoltan         }
364*e7baac64SBALATON Zoltan         if (tlb->mas7_3 & MAS3_UW) {
365*e7baac64SBALATON Zoltan             *prot |= PAGE_WRITE;
366*e7baac64SBALATON Zoltan         }
367*e7baac64SBALATON Zoltan         if (tlb->mas7_3 & MAS3_UX) {
368*e7baac64SBALATON Zoltan             *prot |= PAGE_EXEC;
369*e7baac64SBALATON Zoltan         }
370*e7baac64SBALATON Zoltan     } else {
371*e7baac64SBALATON Zoltan         if (tlb->mas7_3 & MAS3_SR) {
372*e7baac64SBALATON Zoltan             *prot |= PAGE_READ;
373*e7baac64SBALATON Zoltan         }
374*e7baac64SBALATON Zoltan         if (tlb->mas7_3 & MAS3_SW) {
375*e7baac64SBALATON Zoltan             *prot |= PAGE_WRITE;
376*e7baac64SBALATON Zoltan         }
377*e7baac64SBALATON Zoltan         if (tlb->mas7_3 & MAS3_SX) {
378*e7baac64SBALATON Zoltan             *prot |= PAGE_EXEC;
379*e7baac64SBALATON Zoltan         }
380*e7baac64SBALATON Zoltan     }
381*e7baac64SBALATON Zoltan     if (check_prot_access_type(*prot, access_type)) {
382*e7baac64SBALATON Zoltan         qemu_log_mask(CPU_LOG_MMU, "%s: good TLB!\n", __func__);
383*e7baac64SBALATON Zoltan         return 0;
384*e7baac64SBALATON Zoltan     }
385*e7baac64SBALATON Zoltan 
386*e7baac64SBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "%s: no prot match: %x\n", __func__, *prot);
387*e7baac64SBALATON Zoltan     return access_type == MMU_INST_FETCH ? -3 : -2;
388*e7baac64SBALATON Zoltan }
389*e7baac64SBALATON Zoltan 
mmubooke206_get_physical_address(CPUPPCState * env,hwaddr * raddr,int * prot,target_ulong address,MMUAccessType access_type,int mmu_idx)390*e7baac64SBALATON Zoltan static int mmubooke206_get_physical_address(CPUPPCState *env, hwaddr *raddr,
391*e7baac64SBALATON Zoltan                                             int *prot, target_ulong address,
392*e7baac64SBALATON Zoltan                                             MMUAccessType access_type,
393*e7baac64SBALATON Zoltan                                             int mmu_idx)
394*e7baac64SBALATON Zoltan {
395*e7baac64SBALATON Zoltan     ppcmas_tlb_t *tlb;
396*e7baac64SBALATON Zoltan     int i, j, ret = -1;
397*e7baac64SBALATON Zoltan 
398*e7baac64SBALATON Zoltan     for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
399*e7baac64SBALATON Zoltan         int ways = booke206_tlb_ways(env, i);
400*e7baac64SBALATON Zoltan         for (j = 0; j < ways; j++) {
401*e7baac64SBALATON Zoltan             tlb = booke206_get_tlbm(env, i, address, j);
402*e7baac64SBALATON Zoltan             if (!tlb) {
403*e7baac64SBALATON Zoltan                 continue;
404*e7baac64SBALATON Zoltan             }
405*e7baac64SBALATON Zoltan             ret = mmubooke206_check_tlb(env, tlb, raddr, prot, address,
406*e7baac64SBALATON Zoltan                                         access_type, mmu_idx);
407*e7baac64SBALATON Zoltan             if (ret != -1) {
408*e7baac64SBALATON Zoltan                 goto found_tlb;
409*e7baac64SBALATON Zoltan             }
410*e7baac64SBALATON Zoltan         }
411*e7baac64SBALATON Zoltan     }
412*e7baac64SBALATON Zoltan 
413*e7baac64SBALATON Zoltan found_tlb:
414*e7baac64SBALATON Zoltan 
415*e7baac64SBALATON Zoltan     qemu_log_mask(CPU_LOG_MMU, "%s: access %s " TARGET_FMT_lx " => "
416*e7baac64SBALATON Zoltan                   HWADDR_FMT_plx " %d %d\n", __func__,
417*e7baac64SBALATON Zoltan                   ret < 0 ? "refused" : "granted", address,
418*e7baac64SBALATON Zoltan                   ret < 0 ? -1 : *raddr, ret == -1 ? 0 : *prot, ret);
419*e7baac64SBALATON Zoltan     return ret;
420*e7baac64SBALATON Zoltan }
421*e7baac64SBALATON Zoltan 
booke206_update_mas_tlb_miss(CPUPPCState * env,target_ulong address,MMUAccessType access_type,int mmu_idx)422*e7baac64SBALATON Zoltan static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
423*e7baac64SBALATON Zoltan                                          MMUAccessType access_type, int mmu_idx)
424*e7baac64SBALATON Zoltan {
425*e7baac64SBALATON Zoltan     uint32_t epid;
426*e7baac64SBALATON Zoltan     bool as, pr;
427*e7baac64SBALATON Zoltan     uint32_t missed_tid = 0;
428*e7baac64SBALATON Zoltan     bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr);
429*e7baac64SBALATON Zoltan 
430*e7baac64SBALATON Zoltan     if (access_type == MMU_INST_FETCH) {
431*e7baac64SBALATON Zoltan         as = FIELD_EX64(env->msr, MSR, IR);
432*e7baac64SBALATON Zoltan     }
433*e7baac64SBALATON Zoltan     env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
434*e7baac64SBALATON Zoltan     env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
435*e7baac64SBALATON Zoltan     env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
436*e7baac64SBALATON Zoltan     env->spr[SPR_BOOKE_MAS3] = 0;
437*e7baac64SBALATON Zoltan     env->spr[SPR_BOOKE_MAS6] = 0;
438*e7baac64SBALATON Zoltan     env->spr[SPR_BOOKE_MAS7] = 0;
439*e7baac64SBALATON Zoltan 
440*e7baac64SBALATON Zoltan     /* AS */
441*e7baac64SBALATON Zoltan     if (as) {
442*e7baac64SBALATON Zoltan         env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
443*e7baac64SBALATON Zoltan         env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
444*e7baac64SBALATON Zoltan     }
445*e7baac64SBALATON Zoltan 
446*e7baac64SBALATON Zoltan     env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
447*e7baac64SBALATON Zoltan     env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
448*e7baac64SBALATON Zoltan 
449*e7baac64SBALATON Zoltan     if (!use_epid) {
450*e7baac64SBALATON Zoltan         switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
451*e7baac64SBALATON Zoltan         case MAS4_TIDSELD_PID0:
452*e7baac64SBALATON Zoltan             missed_tid = env->spr[SPR_BOOKE_PID];
453*e7baac64SBALATON Zoltan             break;
454*e7baac64SBALATON Zoltan         case MAS4_TIDSELD_PID1:
455*e7baac64SBALATON Zoltan             missed_tid = env->spr[SPR_BOOKE_PID1];
456*e7baac64SBALATON Zoltan             break;
457*e7baac64SBALATON Zoltan         case MAS4_TIDSELD_PID2:
458*e7baac64SBALATON Zoltan             missed_tid = env->spr[SPR_BOOKE_PID2];
459*e7baac64SBALATON Zoltan             break;
460*e7baac64SBALATON Zoltan         }
461*e7baac64SBALATON Zoltan         env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
462*e7baac64SBALATON Zoltan     } else {
463*e7baac64SBALATON Zoltan         missed_tid = epid;
464*e7baac64SBALATON Zoltan         env->spr[SPR_BOOKE_MAS6] |= missed_tid << 16;
465*e7baac64SBALATON Zoltan     }
466*e7baac64SBALATON Zoltan     env->spr[SPR_BOOKE_MAS1] |= (missed_tid << MAS1_TID_SHIFT);
467*e7baac64SBALATON Zoltan 
468*e7baac64SBALATON Zoltan 
469*e7baac64SBALATON Zoltan     /* next victim logic */
470*e7baac64SBALATON Zoltan     env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
471*e7baac64SBALATON Zoltan     env->last_way++;
472*e7baac64SBALATON Zoltan     env->last_way &= booke206_tlb_ways(env, 0) - 1;
473*e7baac64SBALATON Zoltan     env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
474*e7baac64SBALATON Zoltan }
475*e7baac64SBALATON Zoltan 
ppc_booke_xlate(PowerPCCPU * cpu,vaddr eaddr,MMUAccessType access_type,hwaddr * raddrp,int * psizep,int * protp,int mmu_idx,bool guest_visible)476*e7baac64SBALATON Zoltan bool ppc_booke_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
477*e7baac64SBALATON Zoltan                      hwaddr *raddrp, int *psizep, int *protp, int mmu_idx,
478*e7baac64SBALATON Zoltan                      bool guest_visible)
479*e7baac64SBALATON Zoltan {
480*e7baac64SBALATON Zoltan     CPUState *cs = CPU(cpu);
481*e7baac64SBALATON Zoltan     CPUPPCState *env = &cpu->env;
482*e7baac64SBALATON Zoltan     hwaddr raddr;
483*e7baac64SBALATON Zoltan     int prot, ret;
484*e7baac64SBALATON Zoltan 
485*e7baac64SBALATON Zoltan     if (env->mmu_model == POWERPC_MMU_BOOKE206) {
486*e7baac64SBALATON Zoltan         ret = mmubooke206_get_physical_address(env, &raddr, &prot, eaddr,
487*e7baac64SBALATON Zoltan                                                access_type, mmu_idx);
488*e7baac64SBALATON Zoltan     } else {
489*e7baac64SBALATON Zoltan         ret = mmubooke_get_physical_address(env, &raddr, &prot, eaddr,
490*e7baac64SBALATON Zoltan                                             access_type);
491*e7baac64SBALATON Zoltan     }
492*e7baac64SBALATON Zoltan     if (ret == 0) {
493*e7baac64SBALATON Zoltan         *raddrp = raddr;
494*e7baac64SBALATON Zoltan         *protp = prot;
495*e7baac64SBALATON Zoltan         *psizep = TARGET_PAGE_BITS;
496*e7baac64SBALATON Zoltan         return true;
497*e7baac64SBALATON Zoltan     } else if (!guest_visible) {
498*e7baac64SBALATON Zoltan         return false;
499*e7baac64SBALATON Zoltan     }
500*e7baac64SBALATON Zoltan 
501*e7baac64SBALATON Zoltan     log_cpu_state_mask(CPU_LOG_MMU, cs, 0);
502*e7baac64SBALATON Zoltan     env->error_code = 0;
503*e7baac64SBALATON Zoltan     switch (ret) {
504*e7baac64SBALATON Zoltan     case -1:
505*e7baac64SBALATON Zoltan         /* No matches in page tables or TLB */
506*e7baac64SBALATON Zoltan         if (env->mmu_model == POWERPC_MMU_BOOKE206) {
507*e7baac64SBALATON Zoltan             booke206_update_mas_tlb_miss(env, eaddr, access_type, mmu_idx);
508*e7baac64SBALATON Zoltan         }
509*e7baac64SBALATON Zoltan         cs->exception_index = (access_type == MMU_INST_FETCH) ?
510*e7baac64SBALATON Zoltan                               POWERPC_EXCP_ITLB : POWERPC_EXCP_DTLB;
511*e7baac64SBALATON Zoltan         env->spr[SPR_BOOKE_DEAR] = eaddr;
512*e7baac64SBALATON Zoltan         env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
513*e7baac64SBALATON Zoltan         break;
514*e7baac64SBALATON Zoltan     case -2:
515*e7baac64SBALATON Zoltan         /* Access rights violation */
516*e7baac64SBALATON Zoltan         cs->exception_index = (access_type == MMU_INST_FETCH) ?
517*e7baac64SBALATON Zoltan                               POWERPC_EXCP_ISI : POWERPC_EXCP_DSI;
518*e7baac64SBALATON Zoltan         if (access_type != MMU_INST_FETCH) {
519*e7baac64SBALATON Zoltan             env->spr[SPR_BOOKE_DEAR] = eaddr;
520*e7baac64SBALATON Zoltan             env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, access_type);
521*e7baac64SBALATON Zoltan         }
522*e7baac64SBALATON Zoltan         break;
523*e7baac64SBALATON Zoltan     case -3:
524*e7baac64SBALATON Zoltan         /* No execute protection violation */
525*e7baac64SBALATON Zoltan         cs->exception_index = POWERPC_EXCP_ISI;
526*e7baac64SBALATON Zoltan         env->spr[SPR_BOOKE_ESR] = 0;
527*e7baac64SBALATON Zoltan         break;
528*e7baac64SBALATON Zoltan     }
529*e7baac64SBALATON Zoltan 
530*e7baac64SBALATON Zoltan     return false;
531*e7baac64SBALATON Zoltan }
532