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