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