Merge branch 's390-for-upstream' of git://repo.or.cz/qemu/agraf
[qemu.git] / target-ppc / mmu_helper.c
blobd2664acef01df6f48fd7462cf3eade4554218848
1 /*
2 * PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU.
4 * Copyright (c) 2003-2007 Jocelyn Mayer
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 of the License, or (at your option) any later version.
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.
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/>.
19 #include "cpu.h"
20 #include "helper.h"
21 #include "kvm.h"
22 #include "kvm_ppc.h"
24 //#define DEBUG_MMU
25 //#define DEBUG_BATS
26 //#define DEBUG_SLB
27 //#define DEBUG_SOFTWARE_TLB
28 //#define DUMP_PAGE_TABLES
29 //#define DEBUG_SOFTWARE_TLB
30 //#define FLUSH_ALL_TLBS
32 #ifdef DEBUG_MMU
33 # define LOG_MMU(...) qemu_log(__VA_ARGS__)
34 # define LOG_MMU_STATE(env) log_cpu_state((env), 0)
35 #else
36 # define LOG_MMU(...) do { } while (0)
37 # define LOG_MMU_STATE(...) do { } while (0)
38 #endif
40 #ifdef DEBUG_SOFTWARE_TLB
41 # define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
42 #else
43 # define LOG_SWTLB(...) do { } while (0)
44 #endif
46 #ifdef DEBUG_BATS
47 # define LOG_BATS(...) qemu_log(__VA_ARGS__)
48 #else
49 # define LOG_BATS(...) do { } while (0)
50 #endif
52 #ifdef DEBUG_SLB
53 # define LOG_SLB(...) qemu_log(__VA_ARGS__)
54 #else
55 # define LOG_SLB(...) do { } while (0)
56 #endif
58 /*****************************************************************************/
59 /* PowerPC MMU emulation */
60 #if defined(CONFIG_USER_ONLY)
61 int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
62 int mmu_idx)
64 int exception, error_code;
66 if (rw == 2) {
67 exception = POWERPC_EXCP_ISI;
68 error_code = 0x40000000;
69 } else {
70 exception = POWERPC_EXCP_DSI;
71 error_code = 0x40000000;
72 if (rw) {
73 error_code |= 0x02000000;
75 env->spr[SPR_DAR] = address;
76 env->spr[SPR_DSISR] = error_code;
78 env->exception_index = exception;
79 env->error_code = error_code;
81 return 1;
84 #else
85 /* Common routines used by software and hardware TLBs emulation */
86 static inline int pte_is_valid(target_ulong pte0)
88 return pte0 & 0x80000000 ? 1 : 0;
91 static inline void pte_invalidate(target_ulong *pte0)
93 *pte0 &= ~0x80000000;
96 #if defined(TARGET_PPC64)
97 static inline int pte64_is_valid(target_ulong pte0)
99 return pte0 & 0x0000000000000001ULL ? 1 : 0;
102 static inline void pte64_invalidate(target_ulong *pte0)
104 *pte0 &= ~0x0000000000000001ULL;
106 #endif
108 #define PTE_PTEM_MASK 0x7FFFFFBF
109 #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
110 #if defined(TARGET_PPC64)
111 #define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL
112 #define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F)
113 #endif
115 static inline int pp_check(int key, int pp, int nx)
117 int access;
119 /* Compute access rights */
120 /* When pp is 3/7, the result is undefined. Set it to noaccess */
121 access = 0;
122 if (key == 0) {
123 switch (pp) {
124 case 0x0:
125 case 0x1:
126 case 0x2:
127 access |= PAGE_WRITE;
128 /* No break here */
129 case 0x3:
130 case 0x6:
131 access |= PAGE_READ;
132 break;
134 } else {
135 switch (pp) {
136 case 0x0:
137 case 0x6:
138 access = 0;
139 break;
140 case 0x1:
141 case 0x3:
142 access = PAGE_READ;
143 break;
144 case 0x2:
145 access = PAGE_READ | PAGE_WRITE;
146 break;
149 if (nx == 0) {
150 access |= PAGE_EXEC;
153 return access;
156 static inline int check_prot(int prot, int rw, int access_type)
158 int ret;
160 if (access_type == ACCESS_CODE) {
161 if (prot & PAGE_EXEC) {
162 ret = 0;
163 } else {
164 ret = -2;
166 } else if (rw) {
167 if (prot & PAGE_WRITE) {
168 ret = 0;
169 } else {
170 ret = -2;
172 } else {
173 if (prot & PAGE_READ) {
174 ret = 0;
175 } else {
176 ret = -2;
180 return ret;
183 static inline int pte_check(mmu_ctx_t *ctx, int is_64b, target_ulong pte0,
184 target_ulong pte1, int h, int rw, int type)
186 target_ulong ptem, mmask;
187 int access, ret, pteh, ptev, pp;
189 ret = -1;
190 /* Check validity and table match */
191 #if defined(TARGET_PPC64)
192 if (is_64b) {
193 ptev = pte64_is_valid(pte0);
194 pteh = (pte0 >> 1) & 1;
195 } else
196 #endif
198 ptev = pte_is_valid(pte0);
199 pteh = (pte0 >> 6) & 1;
201 if (ptev && h == pteh) {
202 /* Check vsid & api */
203 #if defined(TARGET_PPC64)
204 if (is_64b) {
205 ptem = pte0 & PTE64_PTEM_MASK;
206 mmask = PTE64_CHECK_MASK;
207 pp = (pte1 & 0x00000003) | ((pte1 >> 61) & 0x00000004);
208 ctx->nx = (pte1 >> 2) & 1; /* No execute bit */
209 ctx->nx |= (pte1 >> 3) & 1; /* Guarded bit */
210 } else
211 #endif
213 ptem = pte0 & PTE_PTEM_MASK;
214 mmask = PTE_CHECK_MASK;
215 pp = pte1 & 0x00000003;
217 if (ptem == ctx->ptem) {
218 if (ctx->raddr != (target_phys_addr_t)-1ULL) {
219 /* all matches should have equal RPN, WIMG & PP */
220 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
221 qemu_log("Bad RPN/WIMG/PP\n");
222 return -3;
225 /* Compute access rights */
226 access = pp_check(ctx->key, pp, ctx->nx);
227 /* Keep the matching PTE informations */
228 ctx->raddr = pte1;
229 ctx->prot = access;
230 ret = check_prot(ctx->prot, rw, type);
231 if (ret == 0) {
232 /* Access granted */
233 LOG_MMU("PTE access granted !\n");
234 } else {
235 /* Access right violation */
236 LOG_MMU("PTE access rejected\n");
241 return ret;
244 static inline int pte32_check(mmu_ctx_t *ctx, target_ulong pte0,
245 target_ulong pte1, int h, int rw, int type)
247 return pte_check(ctx, 0, pte0, pte1, h, rw, type);
250 #if defined(TARGET_PPC64)
251 static inline int pte64_check(mmu_ctx_t *ctx, target_ulong pte0,
252 target_ulong pte1, int h, int rw, int type)
254 return pte_check(ctx, 1, pte0, pte1, h, rw, type);
256 #endif
258 static inline int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
259 int ret, int rw)
261 int store = 0;
263 /* Update page flags */
264 if (!(*pte1p & 0x00000100)) {
265 /* Update accessed flag */
266 *pte1p |= 0x00000100;
267 store = 1;
269 if (!(*pte1p & 0x00000080)) {
270 if (rw == 1 && ret == 0) {
271 /* Update changed flag */
272 *pte1p |= 0x00000080;
273 store = 1;
274 } else {
275 /* Force page fault for first write access */
276 ctx->prot &= ~PAGE_WRITE;
280 return store;
283 /* Software driven TLB helpers */
284 static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
285 int way, int is_code)
287 int nr;
289 /* Select TLB num in a way from address */
290 nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
291 /* Select TLB way */
292 nr += env->tlb_per_way * way;
293 /* 6xx have separate TLBs for instructions and data */
294 if (is_code && env->id_tlbs == 1) {
295 nr += env->nb_tlb;
298 return nr;
301 static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
303 ppc6xx_tlb_t *tlb;
304 int nr, max;
306 /* LOG_SWTLB("Invalidate all TLBs\n"); */
307 /* Invalidate all defined software TLB */
308 max = env->nb_tlb;
309 if (env->id_tlbs == 1) {
310 max *= 2;
312 for (nr = 0; nr < max; nr++) {
313 tlb = &env->tlb.tlb6[nr];
314 pte_invalidate(&tlb->pte0);
316 tlb_flush(env, 1);
319 static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env,
320 target_ulong eaddr,
321 int is_code, int match_epn)
323 #if !defined(FLUSH_ALL_TLBS)
324 ppc6xx_tlb_t *tlb;
325 int way, nr;
327 /* Invalidate ITLB + DTLB, all ways */
328 for (way = 0; way < env->nb_ways; way++) {
329 nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
330 tlb = &env->tlb.tlb6[nr];
331 if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
332 LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
333 env->nb_tlb, eaddr);
334 pte_invalidate(&tlb->pte0);
335 tlb_flush_page(env, tlb->EPN);
338 #else
339 /* XXX: PowerPC specification say this is valid as well */
340 ppc6xx_tlb_invalidate_all(env);
341 #endif
344 static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
345 target_ulong eaddr, int is_code)
347 ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0);
350 static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way,
351 int is_code, target_ulong pte0, target_ulong pte1)
353 ppc6xx_tlb_t *tlb;
354 int nr;
356 nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
357 tlb = &env->tlb.tlb6[nr];
358 LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
359 " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
360 /* Invalidate any pending reference in QEMU for this virtual address */
361 ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1);
362 tlb->pte0 = pte0;
363 tlb->pte1 = pte1;
364 tlb->EPN = EPN;
365 /* Store last way for LRU mechanism */
366 env->last_way = way;
369 static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
370 target_ulong eaddr, int rw, int access_type)
372 ppc6xx_tlb_t *tlb;
373 int nr, best, way;
374 int ret;
376 best = -1;
377 ret = -1; /* No TLB found */
378 for (way = 0; way < env->nb_ways; way++) {
379 nr = ppc6xx_tlb_getnum(env, eaddr, way,
380 access_type == ACCESS_CODE ? 1 : 0);
381 tlb = &env->tlb.tlb6[nr];
382 /* This test "emulates" the PTE index match for hardware TLBs */
383 if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
384 LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
385 "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
386 pte_is_valid(tlb->pte0) ? "valid" : "inval",
387 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
388 continue;
390 LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
391 TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
392 pte_is_valid(tlb->pte0) ? "valid" : "inval",
393 tlb->EPN, eaddr, tlb->pte1,
394 rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
395 switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
396 case -3:
397 /* TLB inconsistency */
398 return -1;
399 case -2:
400 /* Access violation */
401 ret = -2;
402 best = nr;
403 break;
404 case -1:
405 default:
406 /* No match */
407 break;
408 case 0:
409 /* access granted */
410 /* XXX: we should go on looping to check all TLBs consistency
411 * but we can speed-up the whole thing as the
412 * result would be undefined if TLBs are not consistent.
414 ret = 0;
415 best = nr;
416 goto done;
419 if (best != -1) {
420 done:
421 LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
422 ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
423 /* Update page flags */
424 pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
427 return ret;
430 /* Perform BAT hit & translation */
431 static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
432 int *validp, int *protp, target_ulong *BATu,
433 target_ulong *BATl)
435 target_ulong bl;
436 int pp, valid, prot;
438 bl = (*BATu & 0x00001FFC) << 15;
439 valid = 0;
440 prot = 0;
441 if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
442 ((msr_pr != 0) && (*BATu & 0x00000001))) {
443 valid = 1;
444 pp = *BATl & 0x00000003;
445 if (pp != 0) {
446 prot = PAGE_READ | PAGE_EXEC;
447 if (pp == 0x2) {
448 prot |= PAGE_WRITE;
452 *blp = bl;
453 *validp = valid;
454 *protp = prot;
457 static inline void bat_601_size_prot(CPUPPCState *env, target_ulong *blp,
458 int *validp, int *protp,
459 target_ulong *BATu, target_ulong *BATl)
461 target_ulong bl;
462 int key, pp, valid, prot;
464 bl = (*BATl & 0x0000003F) << 17;
465 LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n",
466 (uint8_t)(*BATl & 0x0000003F), bl, ~bl);
467 prot = 0;
468 valid = (*BATl >> 6) & 1;
469 if (valid) {
470 pp = *BATu & 0x00000003;
471 if (msr_pr == 0) {
472 key = (*BATu >> 3) & 1;
473 } else {
474 key = (*BATu >> 2) & 1;
476 prot = pp_check(key, pp, 0);
478 *blp = bl;
479 *validp = valid;
480 *protp = prot;
483 static inline int get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
484 target_ulong virtual, int rw, int type)
486 target_ulong *BATlt, *BATut, *BATu, *BATl;
487 target_ulong BEPIl, BEPIu, bl;
488 int i, valid, prot;
489 int ret = -1;
491 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
492 type == ACCESS_CODE ? 'I' : 'D', virtual);
493 switch (type) {
494 case ACCESS_CODE:
495 BATlt = env->IBAT[1];
496 BATut = env->IBAT[0];
497 break;
498 default:
499 BATlt = env->DBAT[1];
500 BATut = env->DBAT[0];
501 break;
503 for (i = 0; i < env->nb_BATs; i++) {
504 BATu = &BATut[i];
505 BATl = &BATlt[i];
506 BEPIu = *BATu & 0xF0000000;
507 BEPIl = *BATu & 0x0FFE0000;
508 if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
509 bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl);
510 } else {
511 bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
513 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
514 " BATl " TARGET_FMT_lx "\n", __func__,
515 type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
516 if ((virtual & 0xF0000000) == BEPIu &&
517 ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
518 /* BAT matches */
519 if (valid != 0) {
520 /* Get physical address */
521 ctx->raddr = (*BATl & 0xF0000000) |
522 ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
523 (virtual & 0x0001F000);
524 /* Compute access rights */
525 ctx->prot = prot;
526 ret = check_prot(ctx->prot, rw, type);
527 if (ret == 0) {
528 LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
529 i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
530 ctx->prot & PAGE_WRITE ? 'W' : '-');
532 break;
536 if (ret < 0) {
537 #if defined(DEBUG_BATS)
538 if (qemu_log_enabled()) {
539 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
540 for (i = 0; i < 4; i++) {
541 BATu = &BATut[i];
542 BATl = &BATlt[i];
543 BEPIu = *BATu & 0xF0000000;
544 BEPIl = *BATu & 0x0FFE0000;
545 bl = (*BATu & 0x00001FFC) << 15;
546 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
547 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
548 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
549 __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
550 *BATu, *BATl, BEPIu, BEPIl, bl);
553 #endif
555 /* No hit */
556 return ret;
559 static inline target_phys_addr_t get_pteg_offset(CPUPPCState *env,
560 target_phys_addr_t hash,
561 int pte_size)
563 return (hash * pte_size * 8) & env->htab_mask;
566 /* PTE table lookup */
567 static inline int find_pte2(CPUPPCState *env, mmu_ctx_t *ctx, int is_64b, int h,
568 int rw, int type, int target_page_bits)
570 target_phys_addr_t pteg_off;
571 target_ulong pte0, pte1;
572 int i, good = -1;
573 int ret, r;
575 ret = -1; /* No entry found */
576 pteg_off = get_pteg_offset(env, ctx->hash[h],
577 is_64b ? HASH_PTE_SIZE_64 : HASH_PTE_SIZE_32);
578 for (i = 0; i < 8; i++) {
579 #if defined(TARGET_PPC64)
580 if (is_64b) {
581 if (env->external_htab) {
582 pte0 = ldq_p(env->external_htab + pteg_off + (i * 16));
583 pte1 = ldq_p(env->external_htab + pteg_off + (i * 16) + 8);
584 } else {
585 pte0 = ldq_phys(env->htab_base + pteg_off + (i * 16));
586 pte1 = ldq_phys(env->htab_base + pteg_off + (i * 16) + 8);
589 r = pte64_check(ctx, pte0, pte1, h, rw, type);
590 LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
591 TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
592 pteg_off + (i * 16), pte0, pte1, (int)(pte0 & 1), h,
593 (int)((pte0 >> 1) & 1), ctx->ptem);
594 } else
595 #endif
597 if (env->external_htab) {
598 pte0 = ldl_p(env->external_htab + pteg_off + (i * 8));
599 pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4);
600 } else {
601 pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8));
602 pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4);
604 r = pte32_check(ctx, pte0, pte1, h, rw, type);
605 LOG_MMU("Load pte from " TARGET_FMT_lx " => " TARGET_FMT_lx " "
606 TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
607 pteg_off + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
608 (int)((pte0 >> 6) & 1), ctx->ptem);
610 switch (r) {
611 case -3:
612 /* PTE inconsistency */
613 return -1;
614 case -2:
615 /* Access violation */
616 ret = -2;
617 good = i;
618 break;
619 case -1:
620 default:
621 /* No PTE match */
622 break;
623 case 0:
624 /* access granted */
625 /* XXX: we should go on looping to check all PTEs consistency
626 * but if we can speed-up the whole thing as the
627 * result would be undefined if PTEs are not consistent.
629 ret = 0;
630 good = i;
631 goto done;
634 if (good != -1) {
635 done:
636 LOG_MMU("found PTE at addr " TARGET_FMT_lx " prot=%01x ret=%d\n",
637 ctx->raddr, ctx->prot, ret);
638 /* Update page flags */
639 pte1 = ctx->raddr;
640 if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {
641 #if defined(TARGET_PPC64)
642 if (is_64b) {
643 if (env->external_htab) {
644 stq_p(env->external_htab + pteg_off + (good * 16) + 8,
645 pte1);
646 } else {
647 stq_phys_notdirty(env->htab_base + pteg_off +
648 (good * 16) + 8, pte1);
650 } else
651 #endif
653 if (env->external_htab) {
654 stl_p(env->external_htab + pteg_off + (good * 8) + 4,
655 pte1);
656 } else {
657 stl_phys_notdirty(env->htab_base + pteg_off +
658 (good * 8) + 4, pte1);
664 /* We have a TLB that saves 4K pages, so let's
665 * split a huge page to 4k chunks */
666 if (target_page_bits != TARGET_PAGE_BITS) {
667 ctx->raddr |= (ctx->eaddr & ((1 << target_page_bits) - 1))
668 & TARGET_PAGE_MASK;
670 return ret;
673 static inline int find_pte(CPUPPCState *env, mmu_ctx_t *ctx, int h, int rw,
674 int type, int target_page_bits)
676 #if defined(TARGET_PPC64)
677 if (env->mmu_model & POWERPC_MMU_64) {
678 return find_pte2(env, ctx, 1, h, rw, type, target_page_bits);
680 #endif
682 return find_pte2(env, ctx, 0, h, rw, type, target_page_bits);
685 #if defined(TARGET_PPC64)
686 static inline ppc_slb_t *slb_lookup(CPUPPCState *env, target_ulong eaddr)
688 uint64_t esid_256M, esid_1T;
689 int n;
691 LOG_SLB("%s: eaddr " TARGET_FMT_lx "\n", __func__, eaddr);
693 esid_256M = (eaddr & SEGMENT_MASK_256M) | SLB_ESID_V;
694 esid_1T = (eaddr & SEGMENT_MASK_1T) | SLB_ESID_V;
696 for (n = 0; n < env->slb_nr; n++) {
697 ppc_slb_t *slb = &env->slb[n];
699 LOG_SLB("%s: slot %d %016" PRIx64 " %016"
700 PRIx64 "\n", __func__, n, slb->esid, slb->vsid);
701 /* We check for 1T matches on all MMUs here - if the MMU
702 * doesn't have 1T segment support, we will have prevented 1T
703 * entries from being inserted in the slbmte code. */
704 if (((slb->esid == esid_256M) &&
705 ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_256M))
706 || ((slb->esid == esid_1T) &&
707 ((slb->vsid & SLB_VSID_B) == SLB_VSID_B_1T))) {
708 return slb;
712 return NULL;
715 /*****************************************************************************/
716 /* SPR accesses */
718 void helper_slbia(CPUPPCState *env)
720 int n, do_invalidate;
722 do_invalidate = 0;
723 /* XXX: Warning: slbia never invalidates the first segment */
724 for (n = 1; n < env->slb_nr; n++) {
725 ppc_slb_t *slb = &env->slb[n];
727 if (slb->esid & SLB_ESID_V) {
728 slb->esid &= ~SLB_ESID_V;
729 /* XXX: given the fact that segment size is 256 MB or 1TB,
730 * and we still don't have a tlb_flush_mask(env, n, mask)
731 * in QEMU, we just invalidate all TLBs
733 do_invalidate = 1;
736 if (do_invalidate) {
737 tlb_flush(env, 1);
741 void helper_slbie(CPUPPCState *env, target_ulong addr)
743 ppc_slb_t *slb;
745 slb = slb_lookup(env, addr);
746 if (!slb) {
747 return;
750 if (slb->esid & SLB_ESID_V) {
751 slb->esid &= ~SLB_ESID_V;
753 /* XXX: given the fact that segment size is 256 MB or 1TB,
754 * and we still don't have a tlb_flush_mask(env, n, mask)
755 * in QEMU, we just invalidate all TLBs
757 tlb_flush(env, 1);
761 int ppc_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
763 int slot = rb & 0xfff;
764 ppc_slb_t *slb = &env->slb[slot];
766 if (rb & (0x1000 - env->slb_nr)) {
767 return -1; /* Reserved bits set or slot too high */
769 if (rs & (SLB_VSID_B & ~SLB_VSID_B_1T)) {
770 return -1; /* Bad segment size */
772 if ((rs & SLB_VSID_B) && !(env->mmu_model & POWERPC_MMU_1TSEG)) {
773 return -1; /* 1T segment on MMU that doesn't support it */
776 /* Mask out the slot number as we store the entry */
777 slb->esid = rb & (SLB_ESID_ESID | SLB_ESID_V);
778 slb->vsid = rs;
780 LOG_SLB("%s: %d " TARGET_FMT_lx " - " TARGET_FMT_lx " => %016" PRIx64
781 " %016" PRIx64 "\n", __func__, slot, rb, rs,
782 slb->esid, slb->vsid);
784 return 0;
787 static int ppc_load_slb_esid(CPUPPCState *env, target_ulong rb,
788 target_ulong *rt)
790 int slot = rb & 0xfff;
791 ppc_slb_t *slb = &env->slb[slot];
793 if (slot >= env->slb_nr) {
794 return -1;
797 *rt = slb->esid;
798 return 0;
801 static int ppc_load_slb_vsid(CPUPPCState *env, target_ulong rb,
802 target_ulong *rt)
804 int slot = rb & 0xfff;
805 ppc_slb_t *slb = &env->slb[slot];
807 if (slot >= env->slb_nr) {
808 return -1;
811 *rt = slb->vsid;
812 return 0;
814 #endif /* defined(TARGET_PPC64) */
816 /* Perform segment based translation */
817 static inline int get_segment(CPUPPCState *env, mmu_ctx_t *ctx,
818 target_ulong eaddr, int rw, int type)
820 target_phys_addr_t hash;
821 target_ulong vsid;
822 int ds, pr, target_page_bits;
823 int ret, ret2;
825 pr = msr_pr;
826 ctx->eaddr = eaddr;
827 #if defined(TARGET_PPC64)
828 if (env->mmu_model & POWERPC_MMU_64) {
829 ppc_slb_t *slb;
830 target_ulong pageaddr;
831 int segment_bits;
833 LOG_MMU("Check SLBs\n");
834 slb = slb_lookup(env, eaddr);
835 if (!slb) {
836 return -5;
839 if (slb->vsid & SLB_VSID_B) {
840 vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT_1T;
841 segment_bits = 40;
842 } else {
843 vsid = (slb->vsid & SLB_VSID_VSID) >> SLB_VSID_SHIFT;
844 segment_bits = 28;
847 target_page_bits = (slb->vsid & SLB_VSID_L)
848 ? TARGET_PAGE_BITS_16M : TARGET_PAGE_BITS;
849 ctx->key = !!(pr ? (slb->vsid & SLB_VSID_KP)
850 : (slb->vsid & SLB_VSID_KS));
851 ds = 0;
852 ctx->nx = !!(slb->vsid & SLB_VSID_N);
854 pageaddr = eaddr & ((1ULL << segment_bits)
855 - (1ULL << target_page_bits));
856 if (slb->vsid & SLB_VSID_B) {
857 hash = vsid ^ (vsid << 25) ^ (pageaddr >> target_page_bits);
858 } else {
859 hash = vsid ^ (pageaddr >> target_page_bits);
861 /* Only 5 bits of the page index are used in the AVPN */
862 ctx->ptem = (slb->vsid & SLB_VSID_PTEM) |
863 ((pageaddr >> 16) & ((1ULL << segment_bits) - 0x80));
864 } else
865 #endif /* defined(TARGET_PPC64) */
867 target_ulong sr, pgidx;
869 sr = env->sr[eaddr >> 28];
870 ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
871 ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
872 ds = sr & 0x80000000 ? 1 : 0;
873 ctx->nx = sr & 0x10000000 ? 1 : 0;
874 vsid = sr & 0x00FFFFFF;
875 target_page_bits = TARGET_PAGE_BITS;
876 LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
877 TARGET_FMT_lx " lr=" TARGET_FMT_lx
878 " ir=%d dr=%d pr=%d %d t=%d\n",
879 eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
880 (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
881 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
882 hash = vsid ^ pgidx;
883 ctx->ptem = (vsid << 7) | (pgidx >> 10);
885 LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
886 ctx->key, ds, ctx->nx, vsid);
887 ret = -1;
888 if (!ds) {
889 /* Check if instruction fetch is allowed, if needed */
890 if (type != ACCESS_CODE || ctx->nx == 0) {
891 /* Page address translation */
892 LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
893 " hash " TARGET_FMT_plx "\n",
894 env->htab_base, env->htab_mask, hash);
895 ctx->hash[0] = hash;
896 ctx->hash[1] = ~hash;
898 /* Initialize real address with an invalid value */
899 ctx->raddr = (target_phys_addr_t)-1ULL;
900 if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx ||
901 env->mmu_model == POWERPC_MMU_SOFT_74xx)) {
902 /* Software TLB search */
903 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
904 } else {
905 LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
906 " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
907 " hash=" TARGET_FMT_plx "\n",
908 env->htab_base, env->htab_mask, vsid, ctx->ptem,
909 ctx->hash[0]);
910 /* Primary table lookup */
911 ret = find_pte(env, ctx, 0, rw, type, target_page_bits);
912 if (ret < 0) {
913 /* Secondary table lookup */
914 if (eaddr != 0xEFFFFFFF) {
915 LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
916 " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
917 " hash=" TARGET_FMT_plx "\n", env->htab_base,
918 env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
920 ret2 = find_pte(env, ctx, 1, rw, type,
921 target_page_bits);
922 if (ret2 != -1) {
923 ret = ret2;
927 #if defined(DUMP_PAGE_TABLES)
928 if (qemu_log_enabled()) {
929 target_phys_addr_t curaddr;
930 uint32_t a0, a1, a2, a3;
932 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
933 "\n", sdr, mask + 0x80);
934 for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
935 curaddr += 16) {
936 a0 = ldl_phys(curaddr);
937 a1 = ldl_phys(curaddr + 4);
938 a2 = ldl_phys(curaddr + 8);
939 a3 = ldl_phys(curaddr + 12);
940 if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
941 qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
942 curaddr, a0, a1, a2, a3);
946 #endif
947 } else {
948 LOG_MMU("No access allowed\n");
949 ret = -3;
951 } else {
952 target_ulong sr;
954 LOG_MMU("direct store...\n");
955 /* Direct-store segment : absolutely *BUGGY* for now */
957 /* Direct-store implies a 32-bit MMU.
958 * Check the Segment Register's bus unit ID (BUID).
960 sr = env->sr[eaddr >> 28];
961 if ((sr & 0x1FF00000) >> 20 == 0x07f) {
962 /* Memory-forced I/O controller interface access */
963 /* If T=1 and BUID=x'07F', the 601 performs a memory access
964 * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
966 ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
967 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
968 return 0;
971 switch (type) {
972 case ACCESS_INT:
973 /* Integer load/store : only access allowed */
974 break;
975 case ACCESS_CODE:
976 /* No code fetch is allowed in direct-store areas */
977 return -4;
978 case ACCESS_FLOAT:
979 /* Floating point load/store */
980 return -4;
981 case ACCESS_RES:
982 /* lwarx, ldarx or srwcx. */
983 return -4;
984 case ACCESS_CACHE:
985 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
986 /* Should make the instruction do no-op.
987 * As it already do no-op, it's quite easy :-)
989 ctx->raddr = eaddr;
990 return 0;
991 case ACCESS_EXT:
992 /* eciwx or ecowx */
993 return -4;
994 default:
995 qemu_log("ERROR: instruction should not need "
996 "address translation\n");
997 return -4;
999 if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
1000 ctx->raddr = eaddr;
1001 ret = 2;
1002 } else {
1003 ret = -2;
1007 return ret;
1010 /* Generic TLB check function for embedded PowerPC implementations */
1011 static int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
1012 target_phys_addr_t *raddrp,
1013 target_ulong address, uint32_t pid, int ext,
1014 int i)
1016 target_ulong mask;
1018 /* Check valid flag */
1019 if (!(tlb->prot & PAGE_VALID)) {
1020 return -1;
1022 mask = ~(tlb->size - 1);
1023 LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
1024 " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
1025 mask, (uint32_t)tlb->PID, tlb->prot);
1026 /* Check PID */
1027 if (tlb->PID != 0 && tlb->PID != pid) {
1028 return -1;
1030 /* Check effective address */
1031 if ((address & mask) != tlb->EPN) {
1032 return -1;
1034 *raddrp = (tlb->RPN & mask) | (address & ~mask);
1035 #if (TARGET_PHYS_ADDR_BITS >= 36)
1036 if (ext) {
1037 /* Extend the physical address to 36 bits */
1038 *raddrp |= (target_phys_addr_t)(tlb->RPN & 0xF) << 32;
1040 #endif
1042 return 0;
1045 /* Generic TLB search function for PowerPC embedded implementations */
1046 static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address,
1047 uint32_t pid)
1049 ppcemb_tlb_t *tlb;
1050 target_phys_addr_t raddr;
1051 int i, ret;
1053 /* Default return value is no match */
1054 ret = -1;
1055 for (i = 0; i < env->nb_tlb; i++) {
1056 tlb = &env->tlb.tlbe[i];
1057 if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
1058 ret = i;
1059 break;
1063 return ret;
1066 /* Helpers specific to PowerPC 40x implementations */
1067 static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
1069 ppcemb_tlb_t *tlb;
1070 int i;
1072 for (i = 0; i < env->nb_tlb; i++) {
1073 tlb = &env->tlb.tlbe[i];
1074 tlb->prot &= ~PAGE_VALID;
1076 tlb_flush(env, 1);
1079 static inline void ppc4xx_tlb_invalidate_virt(CPUPPCState *env,
1080 target_ulong eaddr, uint32_t pid)
1082 #if !defined(FLUSH_ALL_TLBS)
1083 ppcemb_tlb_t *tlb;
1084 target_phys_addr_t raddr;
1085 target_ulong page, end;
1086 int i;
1088 for (i = 0; i < env->nb_tlb; i++) {
1089 tlb = &env->tlb.tlbe[i];
1090 if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
1091 end = tlb->EPN + tlb->size;
1092 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
1093 tlb_flush_page(env, page);
1095 tlb->prot &= ~PAGE_VALID;
1096 break;
1099 #else
1100 ppc4xx_tlb_invalidate_all(env);
1101 #endif
1104 static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1105 target_ulong address, int rw,
1106 int access_type)
1108 ppcemb_tlb_t *tlb;
1109 target_phys_addr_t raddr;
1110 int i, ret, zsel, zpr, pr;
1112 ret = -1;
1113 raddr = (target_phys_addr_t)-1ULL;
1114 pr = msr_pr;
1115 for (i = 0; i < env->nb_tlb; i++) {
1116 tlb = &env->tlb.tlbe[i];
1117 if (ppcemb_tlb_check(env, tlb, &raddr, address,
1118 env->spr[SPR_40x_PID], 0, i) < 0) {
1119 continue;
1121 zsel = (tlb->attr >> 4) & 0xF;
1122 zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
1123 LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
1124 __func__, i, zsel, zpr, rw, tlb->attr);
1125 /* Check execute enable bit */
1126 switch (zpr) {
1127 case 0x2:
1128 if (pr != 0) {
1129 goto check_perms;
1131 /* No break here */
1132 case 0x3:
1133 /* All accesses granted */
1134 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
1135 ret = 0;
1136 break;
1137 case 0x0:
1138 if (pr != 0) {
1139 /* Raise Zone protection fault. */
1140 env->spr[SPR_40x_ESR] = 1 << 22;
1141 ctx->prot = 0;
1142 ret = -2;
1143 break;
1145 /* No break here */
1146 case 0x1:
1147 check_perms:
1148 /* Check from TLB entry */
1149 ctx->prot = tlb->prot;
1150 ret = check_prot(ctx->prot, rw, access_type);
1151 if (ret == -2) {
1152 env->spr[SPR_40x_ESR] = 0;
1154 break;
1156 if (ret >= 0) {
1157 ctx->raddr = raddr;
1158 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1159 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1160 ret);
1161 return 0;
1164 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1165 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1167 return ret;
1170 void store_40x_sler(CPUPPCState *env, uint32_t val)
1172 /* XXX: TO BE FIXED */
1173 if (val != 0x00000000) {
1174 cpu_abort(env, "Little-endian regions are not supported by now\n");
1176 env->spr[SPR_405_SLER] = val;
1179 static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
1180 target_phys_addr_t *raddr, int *prot,
1181 target_ulong address, int rw,
1182 int access_type, int i)
1184 int ret, prot2;
1186 if (ppcemb_tlb_check(env, tlb, raddr, address,
1187 env->spr[SPR_BOOKE_PID],
1188 !env->nb_pids, i) >= 0) {
1189 goto found_tlb;
1192 if (env->spr[SPR_BOOKE_PID1] &&
1193 ppcemb_tlb_check(env, tlb, raddr, address,
1194 env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
1195 goto found_tlb;
1198 if (env->spr[SPR_BOOKE_PID2] &&
1199 ppcemb_tlb_check(env, tlb, raddr, address,
1200 env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
1201 goto found_tlb;
1204 LOG_SWTLB("%s: TLB entry not found\n", __func__);
1205 return -1;
1207 found_tlb:
1209 if (msr_pr != 0) {
1210 prot2 = tlb->prot & 0xF;
1211 } else {
1212 prot2 = (tlb->prot >> 4) & 0xF;
1215 /* Check the address space */
1216 if (access_type == ACCESS_CODE) {
1217 if (msr_ir != (tlb->attr & 1)) {
1218 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1219 return -1;
1222 *prot = prot2;
1223 if (prot2 & PAGE_EXEC) {
1224 LOG_SWTLB("%s: good TLB!\n", __func__);
1225 return 0;
1228 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
1229 ret = -3;
1230 } else {
1231 if (msr_dr != (tlb->attr & 1)) {
1232 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1233 return -1;
1236 *prot = prot2;
1237 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
1238 LOG_SWTLB("%s: found TLB!\n", __func__);
1239 return 0;
1242 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
1243 ret = -2;
1246 return ret;
1249 static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1250 target_ulong address, int rw,
1251 int access_type)
1253 ppcemb_tlb_t *tlb;
1254 target_phys_addr_t raddr;
1255 int i, ret;
1257 ret = -1;
1258 raddr = (target_phys_addr_t)-1ULL;
1259 for (i = 0; i < env->nb_tlb; i++) {
1260 tlb = &env->tlb.tlbe[i];
1261 ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
1262 access_type, i);
1263 if (!ret) {
1264 break;
1268 if (ret >= 0) {
1269 ctx->raddr = raddr;
1270 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1271 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1272 ret);
1273 } else {
1274 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1275 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1278 return ret;
1281 void booke206_flush_tlb(CPUPPCState *env, int flags, const int check_iprot)
1283 int tlb_size;
1284 int i, j;
1285 ppcmas_tlb_t *tlb = env->tlb.tlbm;
1287 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1288 if (flags & (1 << i)) {
1289 tlb_size = booke206_tlb_size(env, i);
1290 for (j = 0; j < tlb_size; j++) {
1291 if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
1292 tlb[j].mas1 &= ~MAS1_VALID;
1296 tlb += booke206_tlb_size(env, i);
1299 tlb_flush(env, 1);
1302 target_phys_addr_t booke206_tlb_to_page_size(CPUPPCState *env,
1303 ppcmas_tlb_t *tlb)
1305 int tlbm_size;
1307 tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1309 return 1024ULL << tlbm_size;
1312 /* TLB check function for MAS based SoftTLBs */
1313 int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
1314 target_phys_addr_t *raddrp,
1315 target_ulong address, uint32_t pid)
1317 target_ulong mask;
1318 uint32_t tlb_pid;
1320 /* Check valid flag */
1321 if (!(tlb->mas1 & MAS1_VALID)) {
1322 return -1;
1325 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
1326 LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
1327 PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n",
1328 __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3,
1329 tlb->mas8);
1331 /* Check PID */
1332 tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
1333 if (tlb_pid != 0 && tlb_pid != pid) {
1334 return -1;
1337 /* Check effective address */
1338 if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
1339 return -1;
1342 if (raddrp) {
1343 *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
1346 return 0;
1349 static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
1350 target_phys_addr_t *raddr, int *prot,
1351 target_ulong address, int rw,
1352 int access_type)
1354 int ret;
1355 int prot2 = 0;
1357 if (ppcmas_tlb_check(env, tlb, raddr, address,
1358 env->spr[SPR_BOOKE_PID]) >= 0) {
1359 goto found_tlb;
1362 if (env->spr[SPR_BOOKE_PID1] &&
1363 ppcmas_tlb_check(env, tlb, raddr, address,
1364 env->spr[SPR_BOOKE_PID1]) >= 0) {
1365 goto found_tlb;
1368 if (env->spr[SPR_BOOKE_PID2] &&
1369 ppcmas_tlb_check(env, tlb, raddr, address,
1370 env->spr[SPR_BOOKE_PID2]) >= 0) {
1371 goto found_tlb;
1374 LOG_SWTLB("%s: TLB entry not found\n", __func__);
1375 return -1;
1377 found_tlb:
1379 if (msr_pr != 0) {
1380 if (tlb->mas7_3 & MAS3_UR) {
1381 prot2 |= PAGE_READ;
1383 if (tlb->mas7_3 & MAS3_UW) {
1384 prot2 |= PAGE_WRITE;
1386 if (tlb->mas7_3 & MAS3_UX) {
1387 prot2 |= PAGE_EXEC;
1389 } else {
1390 if (tlb->mas7_3 & MAS3_SR) {
1391 prot2 |= PAGE_READ;
1393 if (tlb->mas7_3 & MAS3_SW) {
1394 prot2 |= PAGE_WRITE;
1396 if (tlb->mas7_3 & MAS3_SX) {
1397 prot2 |= PAGE_EXEC;
1401 /* Check the address space and permissions */
1402 if (access_type == ACCESS_CODE) {
1403 if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
1404 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1405 return -1;
1408 *prot = prot2;
1409 if (prot2 & PAGE_EXEC) {
1410 LOG_SWTLB("%s: good TLB!\n", __func__);
1411 return 0;
1414 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
1415 ret = -3;
1416 } else {
1417 if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
1418 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1419 return -1;
1422 *prot = prot2;
1423 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
1424 LOG_SWTLB("%s: found TLB!\n", __func__);
1425 return 0;
1428 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
1429 ret = -2;
1432 return ret;
1435 static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1436 target_ulong address, int rw,
1437 int access_type)
1439 ppcmas_tlb_t *tlb;
1440 target_phys_addr_t raddr;
1441 int i, j, ret;
1443 ret = -1;
1444 raddr = (target_phys_addr_t)-1ULL;
1446 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1447 int ways = booke206_tlb_ways(env, i);
1449 for (j = 0; j < ways; j++) {
1450 tlb = booke206_get_tlbm(env, i, address, j);
1451 if (!tlb) {
1452 continue;
1454 ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
1455 rw, access_type);
1456 if (ret != -1) {
1457 goto found_tlb;
1462 found_tlb:
1464 if (ret >= 0) {
1465 ctx->raddr = raddr;
1466 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1467 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1468 ret);
1469 } else {
1470 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1471 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1474 return ret;
1477 static const char *book3e_tsize_to_str[32] = {
1478 "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
1479 "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
1480 "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
1481 "1T", "2T"
1484 static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1485 CPUPPCState *env)
1487 ppcemb_tlb_t *entry;
1488 int i;
1490 if (kvm_enabled() && !env->kvm_sw_tlb) {
1491 cpu_fprintf(f, "Cannot access KVM TLB\n");
1492 return;
1495 cpu_fprintf(f, "\nTLB:\n");
1496 cpu_fprintf(f, "Effective Physical Size PID Prot "
1497 "Attr\n");
1499 entry = &env->tlb.tlbe[0];
1500 for (i = 0; i < env->nb_tlb; i++, entry++) {
1501 target_phys_addr_t ea, pa;
1502 target_ulong mask;
1503 uint64_t size = (uint64_t)entry->size;
1504 char size_buf[20];
1506 /* Check valid flag */
1507 if (!(entry->prot & PAGE_VALID)) {
1508 continue;
1511 mask = ~(entry->size - 1);
1512 ea = entry->EPN & mask;
1513 pa = entry->RPN & mask;
1514 #if (TARGET_PHYS_ADDR_BITS >= 36)
1515 /* Extend the physical address to 36 bits */
1516 pa |= (target_phys_addr_t)(entry->RPN & 0xF) << 32;
1517 #endif
1518 size /= 1024;
1519 if (size >= 1024) {
1520 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024);
1521 } else {
1522 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size);
1524 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
1525 (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
1526 entry->prot, entry->attr);
1531 static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
1532 CPUPPCState *env, int tlbn, int offset,
1533 int tlbsize)
1535 ppcmas_tlb_t *entry;
1536 int i;
1538 cpu_fprintf(f, "\nTLB%d:\n", tlbn);
1539 cpu_fprintf(f, "Effective Physical Size TID TS SRWX"
1540 " URWX WIMGE U0123\n");
1542 entry = &env->tlb.tlbm[offset];
1543 for (i = 0; i < tlbsize; i++, entry++) {
1544 target_phys_addr_t ea, pa, size;
1545 int tsize;
1547 if (!(entry->mas1 & MAS1_VALID)) {
1548 continue;
1551 tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1552 size = 1024ULL << tsize;
1553 ea = entry->mas2 & ~(size - 1);
1554 pa = entry->mas7_3 & ~(size - 1);
1556 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c"
1557 "U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
1558 (uint64_t)ea, (uint64_t)pa,
1559 book3e_tsize_to_str[tsize],
1560 (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
1561 (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
1562 entry->mas7_3 & MAS3_SR ? 'R' : '-',
1563 entry->mas7_3 & MAS3_SW ? 'W' : '-',
1564 entry->mas7_3 & MAS3_SX ? 'X' : '-',
1565 entry->mas7_3 & MAS3_UR ? 'R' : '-',
1566 entry->mas7_3 & MAS3_UW ? 'W' : '-',
1567 entry->mas7_3 & MAS3_UX ? 'X' : '-',
1568 entry->mas2 & MAS2_W ? 'W' : '-',
1569 entry->mas2 & MAS2_I ? 'I' : '-',
1570 entry->mas2 & MAS2_M ? 'M' : '-',
1571 entry->mas2 & MAS2_G ? 'G' : '-',
1572 entry->mas2 & MAS2_E ? 'E' : '-',
1573 entry->mas7_3 & MAS3_U0 ? '0' : '-',
1574 entry->mas7_3 & MAS3_U1 ? '1' : '-',
1575 entry->mas7_3 & MAS3_U2 ? '2' : '-',
1576 entry->mas7_3 & MAS3_U3 ? '3' : '-');
1580 static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1581 CPUPPCState *env)
1583 int offset = 0;
1584 int i;
1586 if (kvm_enabled() && !env->kvm_sw_tlb) {
1587 cpu_fprintf(f, "Cannot access KVM TLB\n");
1588 return;
1591 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1592 int size = booke206_tlb_size(env, i);
1594 if (size == 0) {
1595 continue;
1598 mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size);
1599 offset += size;
1603 #if defined(TARGET_PPC64)
1604 static void mmubooks_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1605 CPUPPCState *env)
1607 int i;
1608 uint64_t slbe, slbv;
1610 cpu_synchronize_state(env);
1612 cpu_fprintf(f, "SLB\tESID\t\t\tVSID\n");
1613 for (i = 0; i < env->slb_nr; i++) {
1614 slbe = env->slb[i].esid;
1615 slbv = env->slb[i].vsid;
1616 if (slbe == 0 && slbv == 0) {
1617 continue;
1619 cpu_fprintf(f, "%d\t0x%016" PRIx64 "\t0x%016" PRIx64 "\n",
1620 i, slbe, slbv);
1623 #endif
1625 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
1627 switch (env->mmu_model) {
1628 case POWERPC_MMU_BOOKE:
1629 mmubooke_dump_mmu(f, cpu_fprintf, env);
1630 break;
1631 case POWERPC_MMU_BOOKE206:
1632 mmubooke206_dump_mmu(f, cpu_fprintf, env);
1633 break;
1634 #if defined(TARGET_PPC64)
1635 case POWERPC_MMU_64B:
1636 case POWERPC_MMU_2_06:
1637 case POWERPC_MMU_2_06d:
1638 mmubooks_dump_mmu(f, cpu_fprintf, env);
1639 break;
1640 #endif
1641 default:
1642 qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
1646 static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
1647 target_ulong eaddr, int rw)
1649 int in_plb, ret;
1651 ctx->raddr = eaddr;
1652 ctx->prot = PAGE_READ | PAGE_EXEC;
1653 ret = 0;
1654 switch (env->mmu_model) {
1655 case POWERPC_MMU_32B:
1656 case POWERPC_MMU_601:
1657 case POWERPC_MMU_SOFT_6xx:
1658 case POWERPC_MMU_SOFT_74xx:
1659 case POWERPC_MMU_SOFT_4xx:
1660 case POWERPC_MMU_REAL:
1661 case POWERPC_MMU_BOOKE:
1662 ctx->prot |= PAGE_WRITE;
1663 break;
1664 #if defined(TARGET_PPC64)
1665 case POWERPC_MMU_620:
1666 case POWERPC_MMU_64B:
1667 case POWERPC_MMU_2_06:
1668 case POWERPC_MMU_2_06d:
1669 /* Real address are 60 bits long */
1670 ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL;
1671 ctx->prot |= PAGE_WRITE;
1672 break;
1673 #endif
1674 case POWERPC_MMU_SOFT_4xx_Z:
1675 if (unlikely(msr_pe != 0)) {
1676 /* 403 family add some particular protections,
1677 * using PBL/PBU registers for accesses with no translation.
1679 in_plb =
1680 /* Check PLB validity */
1681 (env->pb[0] < env->pb[1] &&
1682 /* and address in plb area */
1683 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
1684 (env->pb[2] < env->pb[3] &&
1685 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
1686 if (in_plb ^ msr_px) {
1687 /* Access in protected area */
1688 if (rw == 1) {
1689 /* Access is not allowed */
1690 ret = -2;
1692 } else {
1693 /* Read-write access is allowed */
1694 ctx->prot |= PAGE_WRITE;
1697 break;
1698 case POWERPC_MMU_MPC8xx:
1699 /* XXX: TODO */
1700 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1701 break;
1702 case POWERPC_MMU_BOOKE206:
1703 cpu_abort(env, "BookE 2.06 MMU doesn't have physical real mode\n");
1704 break;
1705 default:
1706 cpu_abort(env, "Unknown or invalid MMU model\n");
1707 return -1;
1710 return ret;
1713 int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx, target_ulong eaddr,
1714 int rw, int access_type)
1716 int ret;
1718 #if 0
1719 qemu_log("%s\n", __func__);
1720 #endif
1721 if ((access_type == ACCESS_CODE && msr_ir == 0) ||
1722 (access_type != ACCESS_CODE && msr_dr == 0)) {
1723 if (env->mmu_model == POWERPC_MMU_BOOKE) {
1724 /* The BookE MMU always performs address translation. The
1725 IS and DS bits only affect the address space. */
1726 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1727 rw, access_type);
1728 } else if (env->mmu_model == POWERPC_MMU_BOOKE206) {
1729 ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
1730 access_type);
1731 } else {
1732 /* No address translation. */
1733 ret = check_physical(env, ctx, eaddr, rw);
1735 } else {
1736 ret = -1;
1737 switch (env->mmu_model) {
1738 case POWERPC_MMU_32B:
1739 case POWERPC_MMU_601:
1740 case POWERPC_MMU_SOFT_6xx:
1741 case POWERPC_MMU_SOFT_74xx:
1742 /* Try to find a BAT */
1743 if (env->nb_BATs != 0) {
1744 ret = get_bat(env, ctx, eaddr, rw, access_type);
1746 #if defined(TARGET_PPC64)
1747 case POWERPC_MMU_620:
1748 case POWERPC_MMU_64B:
1749 case POWERPC_MMU_2_06:
1750 case POWERPC_MMU_2_06d:
1751 #endif
1752 if (ret < 0) {
1753 /* We didn't match any BAT entry or don't have BATs */
1754 ret = get_segment(env, ctx, eaddr, rw, access_type);
1756 break;
1757 case POWERPC_MMU_SOFT_4xx:
1758 case POWERPC_MMU_SOFT_4xx_Z:
1759 ret = mmu40x_get_physical_address(env, ctx, eaddr,
1760 rw, access_type);
1761 break;
1762 case POWERPC_MMU_BOOKE:
1763 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1764 rw, access_type);
1765 break;
1766 case POWERPC_MMU_BOOKE206:
1767 ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
1768 access_type);
1769 break;
1770 case POWERPC_MMU_MPC8xx:
1771 /* XXX: TODO */
1772 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1773 break;
1774 case POWERPC_MMU_REAL:
1775 cpu_abort(env, "PowerPC in real mode do not do any translation\n");
1776 return -1;
1777 default:
1778 cpu_abort(env, "Unknown or invalid MMU model\n");
1779 return -1;
1782 #if 0
1783 qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
1784 __func__, eaddr, ret, ctx->raddr);
1785 #endif
1787 return ret;
1790 target_phys_addr_t cpu_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
1792 mmu_ctx_t ctx;
1794 if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {
1795 return -1;
1798 return ctx.raddr & TARGET_PAGE_MASK;
1801 static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
1802 int rw)
1804 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
1805 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
1806 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
1807 env->spr[SPR_BOOKE_MAS3] = 0;
1808 env->spr[SPR_BOOKE_MAS6] = 0;
1809 env->spr[SPR_BOOKE_MAS7] = 0;
1811 /* AS */
1812 if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
1813 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
1814 env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
1817 env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
1818 env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
1820 switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
1821 case MAS4_TIDSELD_PID0:
1822 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
1823 break;
1824 case MAS4_TIDSELD_PID1:
1825 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
1826 break;
1827 case MAS4_TIDSELD_PID2:
1828 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
1829 break;
1832 env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
1834 /* next victim logic */
1835 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
1836 env->last_way++;
1837 env->last_way &= booke206_tlb_ways(env, 0) - 1;
1838 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
1841 /* Perform address translation */
1842 int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
1843 int mmu_idx)
1845 mmu_ctx_t ctx;
1846 int access_type;
1847 int ret = 0;
1849 if (rw == 2) {
1850 /* code access */
1851 rw = 0;
1852 access_type = ACCESS_CODE;
1853 } else {
1854 /* data access */
1855 access_type = env->access_type;
1857 ret = get_physical_address(env, &ctx, address, rw, access_type);
1858 if (ret == 0) {
1859 tlb_set_page(env, address & TARGET_PAGE_MASK,
1860 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
1861 mmu_idx, TARGET_PAGE_SIZE);
1862 ret = 0;
1863 } else if (ret < 0) {
1864 LOG_MMU_STATE(env);
1865 if (access_type == ACCESS_CODE) {
1866 switch (ret) {
1867 case -1:
1868 /* No matches in page tables or TLB */
1869 switch (env->mmu_model) {
1870 case POWERPC_MMU_SOFT_6xx:
1871 env->exception_index = POWERPC_EXCP_IFTLB;
1872 env->error_code = 1 << 18;
1873 env->spr[SPR_IMISS] = address;
1874 env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
1875 goto tlb_miss;
1876 case POWERPC_MMU_SOFT_74xx:
1877 env->exception_index = POWERPC_EXCP_IFTLB;
1878 goto tlb_miss_74xx;
1879 case POWERPC_MMU_SOFT_4xx:
1880 case POWERPC_MMU_SOFT_4xx_Z:
1881 env->exception_index = POWERPC_EXCP_ITLB;
1882 env->error_code = 0;
1883 env->spr[SPR_40x_DEAR] = address;
1884 env->spr[SPR_40x_ESR] = 0x00000000;
1885 break;
1886 case POWERPC_MMU_32B:
1887 case POWERPC_MMU_601:
1888 #if defined(TARGET_PPC64)
1889 case POWERPC_MMU_620:
1890 case POWERPC_MMU_64B:
1891 case POWERPC_MMU_2_06:
1892 case POWERPC_MMU_2_06d:
1893 #endif
1894 env->exception_index = POWERPC_EXCP_ISI;
1895 env->error_code = 0x40000000;
1896 break;
1897 case POWERPC_MMU_BOOKE206:
1898 booke206_update_mas_tlb_miss(env, address, rw);
1899 /* fall through */
1900 case POWERPC_MMU_BOOKE:
1901 env->exception_index = POWERPC_EXCP_ITLB;
1902 env->error_code = 0;
1903 env->spr[SPR_BOOKE_DEAR] = address;
1904 return -1;
1905 case POWERPC_MMU_MPC8xx:
1906 /* XXX: TODO */
1907 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1908 break;
1909 case POWERPC_MMU_REAL:
1910 cpu_abort(env, "PowerPC in real mode should never raise "
1911 "any MMU exceptions\n");
1912 return -1;
1913 default:
1914 cpu_abort(env, "Unknown or invalid MMU model\n");
1915 return -1;
1917 break;
1918 case -2:
1919 /* Access rights violation */
1920 env->exception_index = POWERPC_EXCP_ISI;
1921 env->error_code = 0x08000000;
1922 break;
1923 case -3:
1924 /* No execute protection violation */
1925 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1926 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1927 env->spr[SPR_BOOKE_ESR] = 0x00000000;
1929 env->exception_index = POWERPC_EXCP_ISI;
1930 env->error_code = 0x10000000;
1931 break;
1932 case -4:
1933 /* Direct store exception */
1934 /* No code fetch is allowed in direct-store areas */
1935 env->exception_index = POWERPC_EXCP_ISI;
1936 env->error_code = 0x10000000;
1937 break;
1938 #if defined(TARGET_PPC64)
1939 case -5:
1940 /* No match in segment table */
1941 if (env->mmu_model == POWERPC_MMU_620) {
1942 env->exception_index = POWERPC_EXCP_ISI;
1943 /* XXX: this might be incorrect */
1944 env->error_code = 0x40000000;
1945 } else {
1946 env->exception_index = POWERPC_EXCP_ISEG;
1947 env->error_code = 0;
1949 break;
1950 #endif
1952 } else {
1953 switch (ret) {
1954 case -1:
1955 /* No matches in page tables or TLB */
1956 switch (env->mmu_model) {
1957 case POWERPC_MMU_SOFT_6xx:
1958 if (rw == 1) {
1959 env->exception_index = POWERPC_EXCP_DSTLB;
1960 env->error_code = 1 << 16;
1961 } else {
1962 env->exception_index = POWERPC_EXCP_DLTLB;
1963 env->error_code = 0;
1965 env->spr[SPR_DMISS] = address;
1966 env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
1967 tlb_miss:
1968 env->error_code |= ctx.key << 19;
1969 env->spr[SPR_HASH1] = env->htab_base +
1970 get_pteg_offset(env, ctx.hash[0], HASH_PTE_SIZE_32);
1971 env->spr[SPR_HASH2] = env->htab_base +
1972 get_pteg_offset(env, ctx.hash[1], HASH_PTE_SIZE_32);
1973 break;
1974 case POWERPC_MMU_SOFT_74xx:
1975 if (rw == 1) {
1976 env->exception_index = POWERPC_EXCP_DSTLB;
1977 } else {
1978 env->exception_index = POWERPC_EXCP_DLTLB;
1980 tlb_miss_74xx:
1981 /* Implement LRU algorithm */
1982 env->error_code = ctx.key << 19;
1983 env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
1984 ((env->last_way + 1) & (env->nb_ways - 1));
1985 env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
1986 break;
1987 case POWERPC_MMU_SOFT_4xx:
1988 case POWERPC_MMU_SOFT_4xx_Z:
1989 env->exception_index = POWERPC_EXCP_DTLB;
1990 env->error_code = 0;
1991 env->spr[SPR_40x_DEAR] = address;
1992 if (rw) {
1993 env->spr[SPR_40x_ESR] = 0x00800000;
1994 } else {
1995 env->spr[SPR_40x_ESR] = 0x00000000;
1997 break;
1998 case POWERPC_MMU_32B:
1999 case POWERPC_MMU_601:
2000 #if defined(TARGET_PPC64)
2001 case POWERPC_MMU_620:
2002 case POWERPC_MMU_64B:
2003 case POWERPC_MMU_2_06:
2004 case POWERPC_MMU_2_06d:
2005 #endif
2006 env->exception_index = POWERPC_EXCP_DSI;
2007 env->error_code = 0;
2008 env->spr[SPR_DAR] = address;
2009 if (rw == 1) {
2010 env->spr[SPR_DSISR] = 0x42000000;
2011 } else {
2012 env->spr[SPR_DSISR] = 0x40000000;
2014 break;
2015 case POWERPC_MMU_MPC8xx:
2016 /* XXX: TODO */
2017 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
2018 break;
2019 case POWERPC_MMU_BOOKE206:
2020 booke206_update_mas_tlb_miss(env, address, rw);
2021 /* fall through */
2022 case POWERPC_MMU_BOOKE:
2023 env->exception_index = POWERPC_EXCP_DTLB;
2024 env->error_code = 0;
2025 env->spr[SPR_BOOKE_DEAR] = address;
2026 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
2027 return -1;
2028 case POWERPC_MMU_REAL:
2029 cpu_abort(env, "PowerPC in real mode should never raise "
2030 "any MMU exceptions\n");
2031 return -1;
2032 default:
2033 cpu_abort(env, "Unknown or invalid MMU model\n");
2034 return -1;
2036 break;
2037 case -2:
2038 /* Access rights violation */
2039 env->exception_index = POWERPC_EXCP_DSI;
2040 env->error_code = 0;
2041 if (env->mmu_model == POWERPC_MMU_SOFT_4xx
2042 || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
2043 env->spr[SPR_40x_DEAR] = address;
2044 if (rw) {
2045 env->spr[SPR_40x_ESR] |= 0x00800000;
2047 } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
2048 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
2049 env->spr[SPR_BOOKE_DEAR] = address;
2050 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
2051 } else {
2052 env->spr[SPR_DAR] = address;
2053 if (rw == 1) {
2054 env->spr[SPR_DSISR] = 0x0A000000;
2055 } else {
2056 env->spr[SPR_DSISR] = 0x08000000;
2059 break;
2060 case -4:
2061 /* Direct store exception */
2062 switch (access_type) {
2063 case ACCESS_FLOAT:
2064 /* Floating point load/store */
2065 env->exception_index = POWERPC_EXCP_ALIGN;
2066 env->error_code = POWERPC_EXCP_ALIGN_FP;
2067 env->spr[SPR_DAR] = address;
2068 break;
2069 case ACCESS_RES:
2070 /* lwarx, ldarx or stwcx. */
2071 env->exception_index = POWERPC_EXCP_DSI;
2072 env->error_code = 0;
2073 env->spr[SPR_DAR] = address;
2074 if (rw == 1) {
2075 env->spr[SPR_DSISR] = 0x06000000;
2076 } else {
2077 env->spr[SPR_DSISR] = 0x04000000;
2079 break;
2080 case ACCESS_EXT:
2081 /* eciwx or ecowx */
2082 env->exception_index = POWERPC_EXCP_DSI;
2083 env->error_code = 0;
2084 env->spr[SPR_DAR] = address;
2085 if (rw == 1) {
2086 env->spr[SPR_DSISR] = 0x06100000;
2087 } else {
2088 env->spr[SPR_DSISR] = 0x04100000;
2090 break;
2091 default:
2092 printf("DSI: invalid exception (%d)\n", ret);
2093 env->exception_index = POWERPC_EXCP_PROGRAM;
2094 env->error_code =
2095 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
2096 env->spr[SPR_DAR] = address;
2097 break;
2099 break;
2100 #if defined(TARGET_PPC64)
2101 case -5:
2102 /* No match in segment table */
2103 if (env->mmu_model == POWERPC_MMU_620) {
2104 env->exception_index = POWERPC_EXCP_DSI;
2105 env->error_code = 0;
2106 env->spr[SPR_DAR] = address;
2107 /* XXX: this might be incorrect */
2108 if (rw == 1) {
2109 env->spr[SPR_DSISR] = 0x42000000;
2110 } else {
2111 env->spr[SPR_DSISR] = 0x40000000;
2113 } else {
2114 env->exception_index = POWERPC_EXCP_DSEG;
2115 env->error_code = 0;
2116 env->spr[SPR_DAR] = address;
2118 break;
2119 #endif
2122 #if 0
2123 printf("%s: set exception to %d %02x\n", __func__,
2124 env->exception, env->error_code);
2125 #endif
2126 ret = 1;
2129 return ret;
2132 /*****************************************************************************/
2133 /* BATs management */
2134 #if !defined(FLUSH_ALL_TLBS)
2135 static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
2136 target_ulong mask)
2138 target_ulong base, end, page;
2140 base = BATu & ~0x0001FFFF;
2141 end = base + mask + 0x00020000;
2142 LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
2143 TARGET_FMT_lx ")\n", base, end, mask);
2144 for (page = base; page != end; page += TARGET_PAGE_SIZE) {
2145 tlb_flush_page(env, page);
2147 LOG_BATS("Flush done\n");
2149 #endif
2151 static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
2152 target_ulong value)
2154 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
2155 nr, ul == 0 ? 'u' : 'l', value, env->nip);
2158 void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value)
2160 target_ulong mask;
2162 dump_store_bat(env, 'I', 0, nr, value);
2163 if (env->IBAT[0][nr] != value) {
2164 mask = (value << 15) & 0x0FFE0000UL;
2165 #if !defined(FLUSH_ALL_TLBS)
2166 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2167 #endif
2168 /* When storing valid upper BAT, mask BEPI and BRPN
2169 * and invalidate all TLBs covered by this BAT
2171 mask = (value << 15) & 0x0FFE0000UL;
2172 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
2173 (value & ~0x0001FFFFUL & ~mask);
2174 env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
2175 (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
2176 #if !defined(FLUSH_ALL_TLBS)
2177 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2178 #else
2179 tlb_flush(env, 1);
2180 #endif
2184 void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong value)
2186 dump_store_bat(env, 'I', 1, nr, value);
2187 env->IBAT[1][nr] = value;
2190 void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong value)
2192 target_ulong mask;
2194 dump_store_bat(env, 'D', 0, nr, value);
2195 if (env->DBAT[0][nr] != value) {
2196 /* When storing valid upper BAT, mask BEPI and BRPN
2197 * and invalidate all TLBs covered by this BAT
2199 mask = (value << 15) & 0x0FFE0000UL;
2200 #if !defined(FLUSH_ALL_TLBS)
2201 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
2202 #endif
2203 mask = (value << 15) & 0x0FFE0000UL;
2204 env->DBAT[0][nr] = (value & 0x00001FFFUL) |
2205 (value & ~0x0001FFFFUL & ~mask);
2206 env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
2207 (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
2208 #if !defined(FLUSH_ALL_TLBS)
2209 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
2210 #else
2211 tlb_flush(env, 1);
2212 #endif
2216 void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong value)
2218 dump_store_bat(env, 'D', 1, nr, value);
2219 env->DBAT[1][nr] = value;
2222 void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value)
2224 target_ulong mask;
2225 #if defined(FLUSH_ALL_TLBS)
2226 int do_inval;
2227 #endif
2229 dump_store_bat(env, 'I', 0, nr, value);
2230 if (env->IBAT[0][nr] != value) {
2231 #if defined(FLUSH_ALL_TLBS)
2232 do_inval = 0;
2233 #endif
2234 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
2235 if (env->IBAT[1][nr] & 0x40) {
2236 /* Invalidate BAT only if it is valid */
2237 #if !defined(FLUSH_ALL_TLBS)
2238 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2239 #else
2240 do_inval = 1;
2241 #endif
2243 /* When storing valid upper BAT, mask BEPI and BRPN
2244 * and invalidate all TLBs covered by this BAT
2246 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
2247 (value & ~0x0001FFFFUL & ~mask);
2248 env->DBAT[0][nr] = env->IBAT[0][nr];
2249 if (env->IBAT[1][nr] & 0x40) {
2250 #if !defined(FLUSH_ALL_TLBS)
2251 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2252 #else
2253 do_inval = 1;
2254 #endif
2256 #if defined(FLUSH_ALL_TLBS)
2257 if (do_inval) {
2258 tlb_flush(env, 1);
2260 #endif
2264 void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value)
2266 target_ulong mask;
2267 #if defined(FLUSH_ALL_TLBS)
2268 int do_inval;
2269 #endif
2271 dump_store_bat(env, 'I', 1, nr, value);
2272 if (env->IBAT[1][nr] != value) {
2273 #if defined(FLUSH_ALL_TLBS)
2274 do_inval = 0;
2275 #endif
2276 if (env->IBAT[1][nr] & 0x40) {
2277 #if !defined(FLUSH_ALL_TLBS)
2278 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
2279 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2280 #else
2281 do_inval = 1;
2282 #endif
2284 if (value & 0x40) {
2285 #if !defined(FLUSH_ALL_TLBS)
2286 mask = (value << 17) & 0x0FFE0000UL;
2287 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
2288 #else
2289 do_inval = 1;
2290 #endif
2292 env->IBAT[1][nr] = value;
2293 env->DBAT[1][nr] = value;
2294 #if defined(FLUSH_ALL_TLBS)
2295 if (do_inval) {
2296 tlb_flush(env, 1);
2298 #endif
2302 /*****************************************************************************/
2303 /* TLB management */
2304 void ppc_tlb_invalidate_all(CPUPPCState *env)
2306 switch (env->mmu_model) {
2307 case POWERPC_MMU_SOFT_6xx:
2308 case POWERPC_MMU_SOFT_74xx:
2309 ppc6xx_tlb_invalidate_all(env);
2310 break;
2311 case POWERPC_MMU_SOFT_4xx:
2312 case POWERPC_MMU_SOFT_4xx_Z:
2313 ppc4xx_tlb_invalidate_all(env);
2314 break;
2315 case POWERPC_MMU_REAL:
2316 cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
2317 break;
2318 case POWERPC_MMU_MPC8xx:
2319 /* XXX: TODO */
2320 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
2321 break;
2322 case POWERPC_MMU_BOOKE:
2323 tlb_flush(env, 1);
2324 break;
2325 case POWERPC_MMU_BOOKE206:
2326 booke206_flush_tlb(env, -1, 0);
2327 break;
2328 case POWERPC_MMU_32B:
2329 case POWERPC_MMU_601:
2330 #if defined(TARGET_PPC64)
2331 case POWERPC_MMU_620:
2332 case POWERPC_MMU_64B:
2333 case POWERPC_MMU_2_06:
2334 case POWERPC_MMU_2_06d:
2335 #endif /* defined(TARGET_PPC64) */
2336 tlb_flush(env, 1);
2337 break;
2338 default:
2339 /* XXX: TODO */
2340 cpu_abort(env, "Unknown MMU model\n");
2341 break;
2345 void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
2347 #if !defined(FLUSH_ALL_TLBS)
2348 addr &= TARGET_PAGE_MASK;
2349 switch (env->mmu_model) {
2350 case POWERPC_MMU_SOFT_6xx:
2351 case POWERPC_MMU_SOFT_74xx:
2352 ppc6xx_tlb_invalidate_virt(env, addr, 0);
2353 if (env->id_tlbs == 1) {
2354 ppc6xx_tlb_invalidate_virt(env, addr, 1);
2356 break;
2357 case POWERPC_MMU_SOFT_4xx:
2358 case POWERPC_MMU_SOFT_4xx_Z:
2359 ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
2360 break;
2361 case POWERPC_MMU_REAL:
2362 cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
2363 break;
2364 case POWERPC_MMU_MPC8xx:
2365 /* XXX: TODO */
2366 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
2367 break;
2368 case POWERPC_MMU_BOOKE:
2369 /* XXX: TODO */
2370 cpu_abort(env, "BookE MMU model is not implemented\n");
2371 break;
2372 case POWERPC_MMU_BOOKE206:
2373 /* XXX: TODO */
2374 cpu_abort(env, "BookE 2.06 MMU model is not implemented\n");
2375 break;
2376 case POWERPC_MMU_32B:
2377 case POWERPC_MMU_601:
2378 /* tlbie invalidate TLBs for all segments */
2379 addr &= ~((target_ulong)-1ULL << 28);
2380 /* XXX: this case should be optimized,
2381 * giving a mask to tlb_flush_page
2383 tlb_flush_page(env, addr | (0x0 << 28));
2384 tlb_flush_page(env, addr | (0x1 << 28));
2385 tlb_flush_page(env, addr | (0x2 << 28));
2386 tlb_flush_page(env, addr | (0x3 << 28));
2387 tlb_flush_page(env, addr | (0x4 << 28));
2388 tlb_flush_page(env, addr | (0x5 << 28));
2389 tlb_flush_page(env, addr | (0x6 << 28));
2390 tlb_flush_page(env, addr | (0x7 << 28));
2391 tlb_flush_page(env, addr | (0x8 << 28));
2392 tlb_flush_page(env, addr | (0x9 << 28));
2393 tlb_flush_page(env, addr | (0xA << 28));
2394 tlb_flush_page(env, addr | (0xB << 28));
2395 tlb_flush_page(env, addr | (0xC << 28));
2396 tlb_flush_page(env, addr | (0xD << 28));
2397 tlb_flush_page(env, addr | (0xE << 28));
2398 tlb_flush_page(env, addr | (0xF << 28));
2399 break;
2400 #if defined(TARGET_PPC64)
2401 case POWERPC_MMU_620:
2402 case POWERPC_MMU_64B:
2403 case POWERPC_MMU_2_06:
2404 case POWERPC_MMU_2_06d:
2405 /* tlbie invalidate TLBs for all segments */
2406 /* XXX: given the fact that there are too many segments to invalidate,
2407 * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
2408 * we just invalidate all TLBs
2410 tlb_flush(env, 1);
2411 break;
2412 #endif /* defined(TARGET_PPC64) */
2413 default:
2414 /* XXX: TODO */
2415 cpu_abort(env, "Unknown MMU model\n");
2416 break;
2418 #else
2419 ppc_tlb_invalidate_all(env);
2420 #endif
2423 /*****************************************************************************/
2424 /* Special registers manipulation */
2425 #if defined(TARGET_PPC64)
2426 void ppc_store_asr(CPUPPCState *env, target_ulong value)
2428 if (env->asr != value) {
2429 env->asr = value;
2430 tlb_flush(env, 1);
2433 #endif
2435 void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
2437 LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value);
2438 if (env->spr[SPR_SDR1] != value) {
2439 env->spr[SPR_SDR1] = value;
2440 #if defined(TARGET_PPC64)
2441 if (env->mmu_model & POWERPC_MMU_64) {
2442 target_ulong htabsize = value & SDR_64_HTABSIZE;
2444 if (htabsize > 28) {
2445 fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx
2446 " stored in SDR1\n", htabsize);
2447 htabsize = 28;
2449 env->htab_mask = (1ULL << (htabsize + 18)) - 1;
2450 env->htab_base = value & SDR_64_HTABORG;
2451 } else
2452 #endif /* defined(TARGET_PPC64) */
2454 /* FIXME: Should check for valid HTABMASK values */
2455 env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
2456 env->htab_base = value & SDR_32_HTABORG;
2458 tlb_flush(env, 1);
2462 /* Segment registers load and store */
2463 target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
2465 #if defined(TARGET_PPC64)
2466 if (env->mmu_model & POWERPC_MMU_64) {
2467 /* XXX */
2468 return 0;
2470 #endif
2471 return env->sr[sr_num];
2474 void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
2476 LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
2477 (int)srnum, value, env->sr[srnum]);
2478 #if defined(TARGET_PPC64)
2479 if (env->mmu_model & POWERPC_MMU_64) {
2480 uint64_t rb = 0, rs = 0;
2482 /* ESID = srnum */
2483 rb |= ((uint32_t)srnum & 0xf) << 28;
2484 /* Set the valid bit */
2485 rb |= 1 << 27;
2486 /* Index = ESID */
2487 rb |= (uint32_t)srnum;
2489 /* VSID = VSID */
2490 rs |= (value & 0xfffffff) << 12;
2491 /* flags = flags */
2492 rs |= ((value >> 27) & 0xf) << 8;
2494 ppc_store_slb(env, rb, rs);
2495 } else
2496 #endif
2497 if (env->sr[srnum] != value) {
2498 env->sr[srnum] = value;
2499 /* Invalidating 256MB of virtual memory in 4kB pages is way longer than
2500 flusing the whole TLB. */
2501 #if !defined(FLUSH_ALL_TLBS) && 0
2503 target_ulong page, end;
2504 /* Invalidate 256 MB of virtual memory */
2505 page = (16 << 20) * srnum;
2506 end = page + (16 << 20);
2507 for (; page != end; page += TARGET_PAGE_SIZE) {
2508 tlb_flush_page(env, page);
2511 #else
2512 tlb_flush(env, 1);
2513 #endif
2516 #endif /* !defined(CONFIG_USER_ONLY) */
2518 #if !defined(CONFIG_USER_ONLY)
2519 /* SLB management */
2520 #if defined(TARGET_PPC64)
2521 void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
2523 if (ppc_store_slb(env, rb, rs) < 0) {
2524 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2525 POWERPC_EXCP_INVAL);
2529 target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
2531 target_ulong rt = 0;
2533 if (ppc_load_slb_esid(env, rb, &rt) < 0) {
2534 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2535 POWERPC_EXCP_INVAL);
2537 return rt;
2540 target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
2542 target_ulong rt = 0;
2544 if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
2545 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2546 POWERPC_EXCP_INVAL);
2548 return rt;
2550 #endif /* defined(TARGET_PPC64) */
2552 /* TLB management */
2553 void helper_tlbia(CPUPPCState *env)
2555 ppc_tlb_invalidate_all(env);
2558 void helper_tlbie(CPUPPCState *env, target_ulong addr)
2560 ppc_tlb_invalidate_one(env, addr);
2563 /* Software driven TLBs management */
2564 /* PowerPC 602/603 software TLB load instructions helpers */
2565 static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2567 target_ulong RPN, CMP, EPN;
2568 int way;
2570 RPN = env->spr[SPR_RPA];
2571 if (is_code) {
2572 CMP = env->spr[SPR_ICMP];
2573 EPN = env->spr[SPR_IMISS];
2574 } else {
2575 CMP = env->spr[SPR_DCMP];
2576 EPN = env->spr[SPR_DMISS];
2578 way = (env->spr[SPR_SRR1] >> 17) & 1;
2579 (void)EPN; /* avoid a compiler warning */
2580 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2581 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2582 RPN, way);
2583 /* Store this TLB */
2584 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2585 way, is_code, CMP, RPN);
2588 void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN)
2590 do_6xx_tlb(env, EPN, 0);
2593 void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
2595 do_6xx_tlb(env, EPN, 1);
2598 /* PowerPC 74xx software TLB load instructions helpers */
2599 static void do_74xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2601 target_ulong RPN, CMP, EPN;
2602 int way;
2604 RPN = env->spr[SPR_PTELO];
2605 CMP = env->spr[SPR_PTEHI];
2606 EPN = env->spr[SPR_TLBMISS] & ~0x3;
2607 way = env->spr[SPR_TLBMISS] & 0x3;
2608 (void)EPN; /* avoid a compiler warning */
2609 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2610 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2611 RPN, way);
2612 /* Store this TLB */
2613 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2614 way, is_code, CMP, RPN);
2617 void helper_74xx_tlbd(CPUPPCState *env, target_ulong EPN)
2619 do_74xx_tlb(env, EPN, 0);
2622 void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN)
2624 do_74xx_tlb(env, EPN, 1);
2627 /*****************************************************************************/
2628 /* PowerPC 601 specific instructions (POWER bridge) */
2630 target_ulong helper_rac(CPUPPCState *env, target_ulong addr)
2632 mmu_ctx_t ctx;
2633 int nb_BATs;
2634 target_ulong ret = 0;
2636 /* We don't have to generate many instances of this instruction,
2637 * as rac is supervisor only.
2639 /* XXX: FIX THIS: Pretend we have no BAT */
2640 nb_BATs = env->nb_BATs;
2641 env->nb_BATs = 0;
2642 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
2643 ret = ctx.raddr;
2645 env->nb_BATs = nb_BATs;
2646 return ret;
2649 static inline target_ulong booke_tlb_to_page_size(int size)
2651 return 1024 << (2 * size);
2654 static inline int booke_page_size_to_tlb(target_ulong page_size)
2656 int size;
2658 switch (page_size) {
2659 case 0x00000400UL:
2660 size = 0x0;
2661 break;
2662 case 0x00001000UL:
2663 size = 0x1;
2664 break;
2665 case 0x00004000UL:
2666 size = 0x2;
2667 break;
2668 case 0x00010000UL:
2669 size = 0x3;
2670 break;
2671 case 0x00040000UL:
2672 size = 0x4;
2673 break;
2674 case 0x00100000UL:
2675 size = 0x5;
2676 break;
2677 case 0x00400000UL:
2678 size = 0x6;
2679 break;
2680 case 0x01000000UL:
2681 size = 0x7;
2682 break;
2683 case 0x04000000UL:
2684 size = 0x8;
2685 break;
2686 case 0x10000000UL:
2687 size = 0x9;
2688 break;
2689 case 0x40000000UL:
2690 size = 0xA;
2691 break;
2692 #if defined(TARGET_PPC64)
2693 case 0x000100000000ULL:
2694 size = 0xB;
2695 break;
2696 case 0x000400000000ULL:
2697 size = 0xC;
2698 break;
2699 case 0x001000000000ULL:
2700 size = 0xD;
2701 break;
2702 case 0x004000000000ULL:
2703 size = 0xE;
2704 break;
2705 case 0x010000000000ULL:
2706 size = 0xF;
2707 break;
2708 #endif
2709 default:
2710 size = -1;
2711 break;
2714 return size;
2717 /* Helpers for 4xx TLB management */
2718 #define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
2720 #define PPC4XX_TLBHI_V 0x00000040
2721 #define PPC4XX_TLBHI_E 0x00000020
2722 #define PPC4XX_TLBHI_SIZE_MIN 0
2723 #define PPC4XX_TLBHI_SIZE_MAX 7
2724 #define PPC4XX_TLBHI_SIZE_DEFAULT 1
2725 #define PPC4XX_TLBHI_SIZE_SHIFT 7
2726 #define PPC4XX_TLBHI_SIZE_MASK 0x00000007
2728 #define PPC4XX_TLBLO_EX 0x00000200
2729 #define PPC4XX_TLBLO_WR 0x00000100
2730 #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
2731 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
2733 target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
2735 ppcemb_tlb_t *tlb;
2736 target_ulong ret;
2737 int size;
2739 entry &= PPC4XX_TLB_ENTRY_MASK;
2740 tlb = &env->tlb.tlbe[entry];
2741 ret = tlb->EPN;
2742 if (tlb->prot & PAGE_VALID) {
2743 ret |= PPC4XX_TLBHI_V;
2745 size = booke_page_size_to_tlb(tlb->size);
2746 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
2747 size = PPC4XX_TLBHI_SIZE_DEFAULT;
2749 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
2750 env->spr[SPR_40x_PID] = tlb->PID;
2751 return ret;
2754 target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry)
2756 ppcemb_tlb_t *tlb;
2757 target_ulong ret;
2759 entry &= PPC4XX_TLB_ENTRY_MASK;
2760 tlb = &env->tlb.tlbe[entry];
2761 ret = tlb->RPN;
2762 if (tlb->prot & PAGE_EXEC) {
2763 ret |= PPC4XX_TLBLO_EX;
2765 if (tlb->prot & PAGE_WRITE) {
2766 ret |= PPC4XX_TLBLO_WR;
2768 return ret;
2771 void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
2772 target_ulong val)
2774 ppcemb_tlb_t *tlb;
2775 target_ulong page, end;
2777 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
2778 val);
2779 entry &= PPC4XX_TLB_ENTRY_MASK;
2780 tlb = &env->tlb.tlbe[entry];
2781 /* Invalidate previous TLB (if it's valid) */
2782 if (tlb->prot & PAGE_VALID) {
2783 end = tlb->EPN + tlb->size;
2784 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
2785 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2786 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2787 tlb_flush_page(env, page);
2790 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
2791 & PPC4XX_TLBHI_SIZE_MASK);
2792 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2793 * If this ever occurs, one should use the ppcemb target instead
2794 * of the ppc or ppc64 one
2796 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
2797 cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
2798 "are not supported (%d)\n",
2799 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
2801 tlb->EPN = val & ~(tlb->size - 1);
2802 if (val & PPC4XX_TLBHI_V) {
2803 tlb->prot |= PAGE_VALID;
2804 if (val & PPC4XX_TLBHI_E) {
2805 /* XXX: TO BE FIXED */
2806 cpu_abort(env,
2807 "Little-endian TLB entries are not supported by now\n");
2809 } else {
2810 tlb->prot &= ~PAGE_VALID;
2812 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2813 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2814 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2815 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2816 tlb->prot & PAGE_READ ? 'r' : '-',
2817 tlb->prot & PAGE_WRITE ? 'w' : '-',
2818 tlb->prot & PAGE_EXEC ? 'x' : '-',
2819 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2820 /* Invalidate new TLB (if valid) */
2821 if (tlb->prot & PAGE_VALID) {
2822 end = tlb->EPN + tlb->size;
2823 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
2824 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2825 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2826 tlb_flush_page(env, page);
2831 void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
2832 target_ulong val)
2834 ppcemb_tlb_t *tlb;
2836 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
2837 val);
2838 entry &= PPC4XX_TLB_ENTRY_MASK;
2839 tlb = &env->tlb.tlbe[entry];
2840 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
2841 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
2842 tlb->prot = PAGE_READ;
2843 if (val & PPC4XX_TLBLO_EX) {
2844 tlb->prot |= PAGE_EXEC;
2846 if (val & PPC4XX_TLBLO_WR) {
2847 tlb->prot |= PAGE_WRITE;
2849 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2850 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2851 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2852 tlb->prot & PAGE_READ ? 'r' : '-',
2853 tlb->prot & PAGE_WRITE ? 'w' : '-',
2854 tlb->prot & PAGE_EXEC ? 'x' : '-',
2855 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2858 target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
2860 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
2863 /* PowerPC 440 TLB management */
2864 void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry,
2865 target_ulong value)
2867 ppcemb_tlb_t *tlb;
2868 target_ulong EPN, RPN, size;
2869 int do_flush_tlbs;
2871 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
2872 __func__, word, (int)entry, value);
2873 do_flush_tlbs = 0;
2874 entry &= 0x3F;
2875 tlb = &env->tlb.tlbe[entry];
2876 switch (word) {
2877 default:
2878 /* Just here to please gcc */
2879 case 0:
2880 EPN = value & 0xFFFFFC00;
2881 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
2882 do_flush_tlbs = 1;
2884 tlb->EPN = EPN;
2885 size = booke_tlb_to_page_size((value >> 4) & 0xF);
2886 if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
2887 do_flush_tlbs = 1;
2889 tlb->size = size;
2890 tlb->attr &= ~0x1;
2891 tlb->attr |= (value >> 8) & 1;
2892 if (value & 0x200) {
2893 tlb->prot |= PAGE_VALID;
2894 } else {
2895 if (tlb->prot & PAGE_VALID) {
2896 tlb->prot &= ~PAGE_VALID;
2897 do_flush_tlbs = 1;
2900 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
2901 if (do_flush_tlbs) {
2902 tlb_flush(env, 1);
2904 break;
2905 case 1:
2906 RPN = value & 0xFFFFFC0F;
2907 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
2908 tlb_flush(env, 1);
2910 tlb->RPN = RPN;
2911 break;
2912 case 2:
2913 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
2914 tlb->prot = tlb->prot & PAGE_VALID;
2915 if (value & 0x1) {
2916 tlb->prot |= PAGE_READ << 4;
2918 if (value & 0x2) {
2919 tlb->prot |= PAGE_WRITE << 4;
2921 if (value & 0x4) {
2922 tlb->prot |= PAGE_EXEC << 4;
2924 if (value & 0x8) {
2925 tlb->prot |= PAGE_READ;
2927 if (value & 0x10) {
2928 tlb->prot |= PAGE_WRITE;
2930 if (value & 0x20) {
2931 tlb->prot |= PAGE_EXEC;
2933 break;
2937 target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word,
2938 target_ulong entry)
2940 ppcemb_tlb_t *tlb;
2941 target_ulong ret;
2942 int size;
2944 entry &= 0x3F;
2945 tlb = &env->tlb.tlbe[entry];
2946 switch (word) {
2947 default:
2948 /* Just here to please gcc */
2949 case 0:
2950 ret = tlb->EPN;
2951 size = booke_page_size_to_tlb(tlb->size);
2952 if (size < 0 || size > 0xF) {
2953 size = 1;
2955 ret |= size << 4;
2956 if (tlb->attr & 0x1) {
2957 ret |= 0x100;
2959 if (tlb->prot & PAGE_VALID) {
2960 ret |= 0x200;
2962 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
2963 env->spr[SPR_440_MMUCR] |= tlb->PID;
2964 break;
2965 case 1:
2966 ret = tlb->RPN;
2967 break;
2968 case 2:
2969 ret = tlb->attr & ~0x1;
2970 if (tlb->prot & (PAGE_READ << 4)) {
2971 ret |= 0x1;
2973 if (tlb->prot & (PAGE_WRITE << 4)) {
2974 ret |= 0x2;
2976 if (tlb->prot & (PAGE_EXEC << 4)) {
2977 ret |= 0x4;
2979 if (tlb->prot & PAGE_READ) {
2980 ret |= 0x8;
2982 if (tlb->prot & PAGE_WRITE) {
2983 ret |= 0x10;
2985 if (tlb->prot & PAGE_EXEC) {
2986 ret |= 0x20;
2988 break;
2990 return ret;
2993 target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address)
2995 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
2998 /* PowerPC BookE 2.06 TLB management */
3000 static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
3002 uint32_t tlbncfg = 0;
3003 int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
3004 int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
3005 int tlb;
3007 tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
3008 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
3010 if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
3011 cpu_abort(env, "we don't support HES yet\n");
3014 return booke206_get_tlbm(env, tlb, ea, esel);
3017 void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid)
3019 env->spr[pidn] = pid;
3020 /* changing PIDs mean we're in a different address space now */
3021 tlb_flush(env, 1);
3024 void helper_booke206_tlbwe(CPUPPCState *env)
3026 uint32_t tlbncfg, tlbn;
3027 ppcmas_tlb_t *tlb;
3028 uint32_t size_tlb, size_ps;
3029 target_ulong mask;
3032 switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
3033 case MAS0_WQ_ALWAYS:
3034 /* good to go, write that entry */
3035 break;
3036 case MAS0_WQ_COND:
3037 /* XXX check if reserved */
3038 if (0) {
3039 return;
3041 break;
3042 case MAS0_WQ_CLR_RSRV:
3043 /* XXX clear entry */
3044 return;
3045 default:
3046 /* no idea what to do */
3047 return;
3050 if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
3051 !msr_gs) {
3052 /* XXX we don't support direct LRAT setting yet */
3053 fprintf(stderr, "cpu: don't support LRAT setting yet\n");
3054 return;
3057 tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
3058 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
3060 tlb = booke206_cur_tlb(env);
3062 if (!tlb) {
3063 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
3064 POWERPC_EXCP_INVAL |
3065 POWERPC_EXCP_INVAL_INVAL);
3068 /* check that we support the targeted size */
3069 size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
3070 size_ps = booke206_tlbnps(env, tlbn);
3071 if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
3072 !(size_ps & (1 << size_tlb))) {
3073 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
3074 POWERPC_EXCP_INVAL |
3075 POWERPC_EXCP_INVAL_INVAL);
3078 if (msr_gs) {
3079 cpu_abort(env, "missing HV implementation\n");
3081 tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
3082 env->spr[SPR_BOOKE_MAS3];
3083 tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
3085 /* MAV 1.0 only */
3086 if (!(tlbncfg & TLBnCFG_AVAIL)) {
3087 /* force !AVAIL TLB entries to correct page size */
3088 tlb->mas1 &= ~MAS1_TSIZE_MASK;
3089 /* XXX can be configured in MMUCSR0 */
3090 tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
3093 /* Make a mask from TLB size to discard invalid bits in EPN field */
3094 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
3095 /* Add a mask for page attributes */
3096 mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E;
3098 if (!msr_cm) {
3099 /* Executing a tlbwe instruction in 32-bit mode will set
3100 * bits 0:31 of the TLB EPN field to zero.
3102 mask &= 0xffffffff;
3105 tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & mask;
3107 if (!(tlbncfg & TLBnCFG_IPROT)) {
3108 /* no IPROT supported by TLB */
3109 tlb->mas1 &= ~MAS1_IPROT;
3112 if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
3113 tlb_flush_page(env, tlb->mas2 & MAS2_EPN_MASK);
3114 } else {
3115 tlb_flush(env, 1);
3119 static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
3121 int tlbn = booke206_tlbm_to_tlbn(env, tlb);
3122 int way = booke206_tlbm_to_way(env, tlb);
3124 env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
3125 env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
3126 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
3128 env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
3129 env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
3130 env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
3131 env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
3134 void helper_booke206_tlbre(CPUPPCState *env)
3136 ppcmas_tlb_t *tlb = NULL;
3138 tlb = booke206_cur_tlb(env);
3139 if (!tlb) {
3140 env->spr[SPR_BOOKE_MAS1] = 0;
3141 } else {
3142 booke206_tlb_to_mas(env, tlb);
3146 void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address)
3148 ppcmas_tlb_t *tlb = NULL;
3149 int i, j;
3150 target_phys_addr_t raddr;
3151 uint32_t spid, sas;
3153 spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
3154 sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
3156 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
3157 int ways = booke206_tlb_ways(env, i);
3159 for (j = 0; j < ways; j++) {
3160 tlb = booke206_get_tlbm(env, i, address, j);
3162 if (!tlb) {
3163 continue;
3166 if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
3167 continue;
3170 if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
3171 continue;
3174 booke206_tlb_to_mas(env, tlb);
3175 return;
3179 /* no entry found, fill with defaults */
3180 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
3181 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
3182 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
3183 env->spr[SPR_BOOKE_MAS3] = 0;
3184 env->spr[SPR_BOOKE_MAS7] = 0;
3186 if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
3187 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
3190 env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
3191 << MAS1_TID_SHIFT;
3193 /* next victim logic */
3194 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
3195 env->last_way++;
3196 env->last_way &= booke206_tlb_ways(env, 0) - 1;
3197 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
3200 static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
3201 uint32_t ea)
3203 int i;
3204 int ways = booke206_tlb_ways(env, tlbn);
3205 target_ulong mask;
3207 for (i = 0; i < ways; i++) {
3208 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
3209 if (!tlb) {
3210 continue;
3212 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
3213 if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
3214 !(tlb->mas1 & MAS1_IPROT)) {
3215 tlb->mas1 &= ~MAS1_VALID;
3220 void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address)
3222 if (address & 0x4) {
3223 /* flush all entries */
3224 if (address & 0x8) {
3225 /* flush all of TLB1 */
3226 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
3227 } else {
3228 /* flush all of TLB0 */
3229 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
3231 return;
3234 if (address & 0x8) {
3235 /* flush TLB1 entries */
3236 booke206_invalidate_ea_tlb(env, 1, address);
3237 tlb_flush(env, 1);
3238 } else {
3239 /* flush TLB0 entries */
3240 booke206_invalidate_ea_tlb(env, 0, address);
3241 tlb_flush_page(env, address & MAS2_EPN_MASK);
3245 void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address)
3247 /* XXX missing LPID handling */
3248 booke206_flush_tlb(env, -1, 1);
3251 void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address)
3253 int i, j;
3254 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
3255 ppcmas_tlb_t *tlb = env->tlb.tlbm;
3256 int tlb_size;
3258 /* XXX missing LPID handling */
3259 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
3260 tlb_size = booke206_tlb_size(env, i);
3261 for (j = 0; j < tlb_size; j++) {
3262 if (!(tlb[j].mas1 & MAS1_IPROT) &&
3263 ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
3264 tlb[j].mas1 &= ~MAS1_VALID;
3267 tlb += booke206_tlb_size(env, i);
3269 tlb_flush(env, 1);
3272 void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
3274 int i, j;
3275 ppcmas_tlb_t *tlb;
3276 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
3277 int pid = tid >> MAS6_SPID_SHIFT;
3278 int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
3279 int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
3280 /* XXX check for unsupported isize and raise an invalid opcode then */
3281 int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
3282 /* XXX implement MAV2 handling */
3283 bool mav2 = false;
3285 /* XXX missing LPID handling */
3286 /* flush by pid and ea */
3287 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
3288 int ways = booke206_tlb_ways(env, i);
3290 for (j = 0; j < ways; j++) {
3291 tlb = booke206_get_tlbm(env, i, address, j);
3292 if (!tlb) {
3293 continue;
3295 if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
3296 (tlb->mas1 & MAS1_IPROT) ||
3297 ((tlb->mas1 & MAS1_IND) != ind) ||
3298 ((tlb->mas8 & MAS8_TGS) != sgs)) {
3299 continue;
3301 if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
3302 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
3303 continue;
3305 /* XXX e500mc doesn't match SAS, but other cores might */
3306 tlb->mas1 &= ~MAS1_VALID;
3309 tlb_flush(env, 1);
3312 void helper_booke206_tlbflush(CPUPPCState *env, uint32_t type)
3314 int flags = 0;
3316 if (type & 2) {
3317 flags |= BOOKE206_FLUSH_TLB1;
3320 if (type & 4) {
3321 flags |= BOOKE206_FLUSH_TLB0;
3324 booke206_flush_tlb(env, flags, 1);
3326 #endif