target-ppc: Rework get_physical_address()
[qemu/agraf.git] / target-ppc / mmu_helper.c
blob5b82731133f4cc1788a896a199fa94c61479335d
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 "sysemu/kvm.h"
22 #include "kvm_ppc.h"
23 #include "mmu-hash64.h"
24 #include "mmu-hash32.h"
26 //#define DEBUG_MMU
27 //#define DEBUG_BATS
28 //#define DEBUG_SOFTWARE_TLB
29 //#define DUMP_PAGE_TABLES
30 //#define DEBUG_SOFTWARE_TLB
31 //#define FLUSH_ALL_TLBS
33 #ifdef DEBUG_MMU
34 # define LOG_MMU(...) qemu_log(__VA_ARGS__)
35 # define LOG_MMU_STATE(env) log_cpu_state((env), 0)
36 #else
37 # define LOG_MMU(...) do { } while (0)
38 # define LOG_MMU_STATE(...) do { } while (0)
39 #endif
41 #ifdef DEBUG_SOFTWARE_TLB
42 # define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
43 #else
44 # define LOG_SWTLB(...) do { } while (0)
45 #endif
47 #ifdef DEBUG_BATS
48 # define LOG_BATS(...) qemu_log(__VA_ARGS__)
49 #else
50 # define LOG_BATS(...) do { } while (0)
51 #endif
53 /*****************************************************************************/
54 /* PowerPC MMU emulation */
55 #if defined(CONFIG_USER_ONLY)
56 int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
57 int mmu_idx)
59 int exception, error_code;
61 if (rw == 2) {
62 exception = POWERPC_EXCP_ISI;
63 error_code = 0x40000000;
64 } else {
65 exception = POWERPC_EXCP_DSI;
66 error_code = 0x40000000;
67 if (rw) {
68 error_code |= 0x02000000;
70 env->spr[SPR_DAR] = address;
71 env->spr[SPR_DSISR] = error_code;
73 env->exception_index = exception;
74 env->error_code = error_code;
76 return 1;
79 #else
80 /* Common routines used by software and hardware TLBs emulation */
81 static inline int pte_is_valid(target_ulong pte0)
83 return pte0 & 0x80000000 ? 1 : 0;
86 static inline void pte_invalidate(target_ulong *pte0)
88 *pte0 &= ~0x80000000;
91 #define PTE_PTEM_MASK 0x7FFFFFBF
92 #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
94 int pp_check(int key, int pp, int nx)
96 int access;
98 /* Compute access rights */
99 /* When pp is 3/7, the result is undefined. Set it to noaccess */
100 access = 0;
101 if (key == 0) {
102 switch (pp) {
103 case 0x0:
104 case 0x1:
105 case 0x2:
106 access |= PAGE_WRITE;
107 /* No break here */
108 case 0x3:
109 case 0x6:
110 access |= PAGE_READ;
111 break;
113 } else {
114 switch (pp) {
115 case 0x0:
116 case 0x6:
117 access = 0;
118 break;
119 case 0x1:
120 case 0x3:
121 access = PAGE_READ;
122 break;
123 case 0x2:
124 access = PAGE_READ | PAGE_WRITE;
125 break;
128 if (nx == 0) {
129 access |= PAGE_EXEC;
132 return access;
135 int check_prot(int prot, int rw, int access_type)
137 int ret;
139 if (access_type == ACCESS_CODE) {
140 if (prot & PAGE_EXEC) {
141 ret = 0;
142 } else {
143 ret = -2;
145 } else if (rw) {
146 if (prot & PAGE_WRITE) {
147 ret = 0;
148 } else {
149 ret = -2;
151 } else {
152 if (prot & PAGE_READ) {
153 ret = 0;
154 } else {
155 ret = -2;
159 return ret;
162 static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
163 target_ulong pte1, int h, int rw, int type)
165 target_ulong ptem, mmask;
166 int access, ret, pteh, ptev, pp;
168 ret = -1;
169 /* Check validity and table match */
170 ptev = pte_is_valid(pte0);
171 pteh = (pte0 >> 6) & 1;
172 if (ptev && h == pteh) {
173 /* Check vsid & api */
174 ptem = pte0 & PTE_PTEM_MASK;
175 mmask = PTE_CHECK_MASK;
176 pp = pte1 & 0x00000003;
177 if (ptem == ctx->ptem) {
178 if (ctx->raddr != (hwaddr)-1ULL) {
179 /* all matches should have equal RPN, WIMG & PP */
180 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
181 qemu_log("Bad RPN/WIMG/PP\n");
182 return -3;
185 /* Compute access rights */
186 access = pp_check(ctx->key, pp, ctx->nx);
187 /* Keep the matching PTE informations */
188 ctx->raddr = pte1;
189 ctx->prot = access;
190 ret = check_prot(ctx->prot, rw, type);
191 if (ret == 0) {
192 /* Access granted */
193 LOG_MMU("PTE access granted !\n");
194 } else {
195 /* Access right violation */
196 LOG_MMU("PTE access rejected\n");
201 return ret;
204 int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
205 int ret, int rw)
207 int store = 0;
209 /* Update page flags */
210 if (!(*pte1p & 0x00000100)) {
211 /* Update accessed flag */
212 *pte1p |= 0x00000100;
213 store = 1;
215 if (!(*pte1p & 0x00000080)) {
216 if (rw == 1 && ret == 0) {
217 /* Update changed flag */
218 *pte1p |= 0x00000080;
219 store = 1;
220 } else {
221 /* Force page fault for first write access */
222 ctx->prot &= ~PAGE_WRITE;
226 return store;
229 /* Software driven TLB helpers */
230 static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
231 int way, int is_code)
233 int nr;
235 /* Select TLB num in a way from address */
236 nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
237 /* Select TLB way */
238 nr += env->tlb_per_way * way;
239 /* 6xx have separate TLBs for instructions and data */
240 if (is_code && env->id_tlbs == 1) {
241 nr += env->nb_tlb;
244 return nr;
247 static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
249 ppc6xx_tlb_t *tlb;
250 int nr, max;
252 /* LOG_SWTLB("Invalidate all TLBs\n"); */
253 /* Invalidate all defined software TLB */
254 max = env->nb_tlb;
255 if (env->id_tlbs == 1) {
256 max *= 2;
258 for (nr = 0; nr < max; nr++) {
259 tlb = &env->tlb.tlb6[nr];
260 pte_invalidate(&tlb->pte0);
262 tlb_flush(env, 1);
265 static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env,
266 target_ulong eaddr,
267 int is_code, int match_epn)
269 #if !defined(FLUSH_ALL_TLBS)
270 ppc6xx_tlb_t *tlb;
271 int way, nr;
273 /* Invalidate ITLB + DTLB, all ways */
274 for (way = 0; way < env->nb_ways; way++) {
275 nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
276 tlb = &env->tlb.tlb6[nr];
277 if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
278 LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
279 env->nb_tlb, eaddr);
280 pte_invalidate(&tlb->pte0);
281 tlb_flush_page(env, tlb->EPN);
284 #else
285 /* XXX: PowerPC specification say this is valid as well */
286 ppc6xx_tlb_invalidate_all(env);
287 #endif
290 static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
291 target_ulong eaddr, int is_code)
293 ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0);
296 static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way,
297 int is_code, target_ulong pte0, target_ulong pte1)
299 ppc6xx_tlb_t *tlb;
300 int nr;
302 nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
303 tlb = &env->tlb.tlb6[nr];
304 LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
305 " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
306 /* Invalidate any pending reference in QEMU for this virtual address */
307 ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1);
308 tlb->pte0 = pte0;
309 tlb->pte1 = pte1;
310 tlb->EPN = EPN;
311 /* Store last way for LRU mechanism */
312 env->last_way = way;
315 static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
316 target_ulong eaddr, int rw, int access_type)
318 ppc6xx_tlb_t *tlb;
319 int nr, best, way;
320 int ret;
322 best = -1;
323 ret = -1; /* No TLB found */
324 for (way = 0; way < env->nb_ways; way++) {
325 nr = ppc6xx_tlb_getnum(env, eaddr, way,
326 access_type == ACCESS_CODE ? 1 : 0);
327 tlb = &env->tlb.tlb6[nr];
328 /* This test "emulates" the PTE index match for hardware TLBs */
329 if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
330 LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
331 "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
332 pte_is_valid(tlb->pte0) ? "valid" : "inval",
333 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
334 continue;
336 LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
337 TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
338 pte_is_valid(tlb->pte0) ? "valid" : "inval",
339 tlb->EPN, eaddr, tlb->pte1,
340 rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
341 switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
342 case -3:
343 /* TLB inconsistency */
344 return -1;
345 case -2:
346 /* Access violation */
347 ret = -2;
348 best = nr;
349 break;
350 case -1:
351 default:
352 /* No match */
353 break;
354 case 0:
355 /* access granted */
356 /* XXX: we should go on looping to check all TLBs consistency
357 * but we can speed-up the whole thing as the
358 * result would be undefined if TLBs are not consistent.
360 ret = 0;
361 best = nr;
362 goto done;
365 if (best != -1) {
366 done:
367 LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
368 ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
369 /* Update page flags */
370 pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
373 return ret;
376 /* Perform BAT hit & translation */
377 static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
378 int *validp, int *protp, target_ulong *BATu,
379 target_ulong *BATl)
381 target_ulong bl;
382 int pp, valid, prot;
384 bl = (*BATu & 0x00001FFC) << 15;
385 valid = 0;
386 prot = 0;
387 if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
388 ((msr_pr != 0) && (*BATu & 0x00000001))) {
389 valid = 1;
390 pp = *BATl & 0x00000003;
391 if (pp != 0) {
392 prot = PAGE_READ | PAGE_EXEC;
393 if (pp == 0x2) {
394 prot |= PAGE_WRITE;
398 *blp = bl;
399 *validp = valid;
400 *protp = prot;
403 static inline void bat_601_size_prot(CPUPPCState *env, target_ulong *blp,
404 int *validp, int *protp,
405 target_ulong *BATu, target_ulong *BATl)
407 target_ulong bl;
408 int key, pp, valid, prot;
410 bl = (*BATl & 0x0000003F) << 17;
411 LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n",
412 (uint8_t)(*BATl & 0x0000003F), bl, ~bl);
413 prot = 0;
414 valid = (*BATl >> 6) & 1;
415 if (valid) {
416 pp = *BATu & 0x00000003;
417 if (msr_pr == 0) {
418 key = (*BATu >> 3) & 1;
419 } else {
420 key = (*BATu >> 2) & 1;
422 prot = pp_check(key, pp, 0);
424 *blp = bl;
425 *validp = valid;
426 *protp = prot;
429 static inline int get_bat(CPUPPCState *env, mmu_ctx_t *ctx,
430 target_ulong virtual, int rw, int type)
432 target_ulong *BATlt, *BATut, *BATu, *BATl;
433 target_ulong BEPIl, BEPIu, bl;
434 int i, valid, prot;
435 int ret = -1;
437 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
438 type == ACCESS_CODE ? 'I' : 'D', virtual);
439 switch (type) {
440 case ACCESS_CODE:
441 BATlt = env->IBAT[1];
442 BATut = env->IBAT[0];
443 break;
444 default:
445 BATlt = env->DBAT[1];
446 BATut = env->DBAT[0];
447 break;
449 for (i = 0; i < env->nb_BATs; i++) {
450 BATu = &BATut[i];
451 BATl = &BATlt[i];
452 BEPIu = *BATu & 0xF0000000;
453 BEPIl = *BATu & 0x0FFE0000;
454 if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
455 bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl);
456 } else {
457 bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
459 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
460 " BATl " TARGET_FMT_lx "\n", __func__,
461 type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
462 if ((virtual & 0xF0000000) == BEPIu &&
463 ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
464 /* BAT matches */
465 if (valid != 0) {
466 /* Get physical address */
467 ctx->raddr = (*BATl & 0xF0000000) |
468 ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
469 (virtual & 0x0001F000);
470 /* Compute access rights */
471 ctx->prot = prot;
472 ret = check_prot(ctx->prot, rw, type);
473 if (ret == 0) {
474 LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
475 i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
476 ctx->prot & PAGE_WRITE ? 'W' : '-');
478 break;
482 if (ret < 0) {
483 #if defined(DEBUG_BATS)
484 if (qemu_log_enabled()) {
485 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
486 for (i = 0; i < 4; i++) {
487 BATu = &BATut[i];
488 BATl = &BATlt[i];
489 BEPIu = *BATu & 0xF0000000;
490 BEPIl = *BATu & 0x0FFE0000;
491 bl = (*BATu & 0x00001FFC) << 15;
492 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
493 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
494 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
495 __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
496 *BATu, *BATl, BEPIu, BEPIl, bl);
499 #endif
501 /* No hit */
502 return ret;
505 hwaddr get_pteg_offset(CPUPPCState *env, hwaddr hash, int pte_size)
507 return (hash * pte_size * 8) & env->htab_mask;
510 /* Perform segment based translation */
511 static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
512 target_ulong eaddr, int rw, int type)
514 hwaddr hash;
515 target_ulong vsid;
516 int ds, pr, target_page_bits;
517 int ret;
518 target_ulong sr, pgidx;
520 pr = msr_pr;
521 ctx->eaddr = eaddr;
523 sr = env->sr[eaddr >> 28];
524 ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
525 ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
526 ds = sr & 0x80000000 ? 1 : 0;
527 ctx->nx = sr & 0x10000000 ? 1 : 0;
528 vsid = sr & 0x00FFFFFF;
529 target_page_bits = TARGET_PAGE_BITS;
530 LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
531 TARGET_FMT_lx " lr=" TARGET_FMT_lx
532 " ir=%d dr=%d pr=%d %d t=%d\n",
533 eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
534 (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
535 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
536 hash = vsid ^ pgidx;
537 ctx->ptem = (vsid << 7) | (pgidx >> 10);
539 LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
540 ctx->key, ds, ctx->nx, vsid);
541 ret = -1;
542 if (!ds) {
543 /* Check if instruction fetch is allowed, if needed */
544 if (type != ACCESS_CODE || ctx->nx == 0) {
545 /* Page address translation */
546 LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
547 " hash " TARGET_FMT_plx "\n",
548 env->htab_base, env->htab_mask, hash);
549 ctx->hash[0] = hash;
550 ctx->hash[1] = ~hash;
552 /* Initialize real address with an invalid value */
553 ctx->raddr = (hwaddr)-1ULL;
554 /* Software TLB search */
555 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
556 #if defined(DUMP_PAGE_TABLES)
557 if (qemu_log_enabled()) {
558 hwaddr curaddr;
559 uint32_t a0, a1, a2, a3;
561 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
562 "\n", sdr, mask + 0x80);
563 for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
564 curaddr += 16) {
565 a0 = ldl_phys(curaddr);
566 a1 = ldl_phys(curaddr + 4);
567 a2 = ldl_phys(curaddr + 8);
568 a3 = ldl_phys(curaddr + 12);
569 if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
570 qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
571 curaddr, a0, a1, a2, a3);
575 #endif
576 } else {
577 LOG_MMU("No access allowed\n");
578 ret = -3;
580 } else {
581 target_ulong sr;
583 LOG_MMU("direct store...\n");
584 /* Direct-store segment : absolutely *BUGGY* for now */
586 /* Direct-store implies a 32-bit MMU.
587 * Check the Segment Register's bus unit ID (BUID).
589 sr = env->sr[eaddr >> 28];
590 if ((sr & 0x1FF00000) >> 20 == 0x07f) {
591 /* Memory-forced I/O controller interface access */
592 /* If T=1 and BUID=x'07F', the 601 performs a memory access
593 * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
595 ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
596 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
597 return 0;
600 switch (type) {
601 case ACCESS_INT:
602 /* Integer load/store : only access allowed */
603 break;
604 case ACCESS_CODE:
605 /* No code fetch is allowed in direct-store areas */
606 return -4;
607 case ACCESS_FLOAT:
608 /* Floating point load/store */
609 return -4;
610 case ACCESS_RES:
611 /* lwarx, ldarx or srwcx. */
612 return -4;
613 case ACCESS_CACHE:
614 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
615 /* Should make the instruction do no-op.
616 * As it already do no-op, it's quite easy :-)
618 ctx->raddr = eaddr;
619 return 0;
620 case ACCESS_EXT:
621 /* eciwx or ecowx */
622 return -4;
623 default:
624 qemu_log("ERROR: instruction should not need "
625 "address translation\n");
626 return -4;
628 if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
629 ctx->raddr = eaddr;
630 ret = 2;
631 } else {
632 ret = -2;
636 return ret;
639 /* Generic TLB check function for embedded PowerPC implementations */
640 static int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
641 hwaddr *raddrp,
642 target_ulong address, uint32_t pid, int ext,
643 int i)
645 target_ulong mask;
647 /* Check valid flag */
648 if (!(tlb->prot & PAGE_VALID)) {
649 return -1;
651 mask = ~(tlb->size - 1);
652 LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
653 " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
654 mask, (uint32_t)tlb->PID, tlb->prot);
655 /* Check PID */
656 if (tlb->PID != 0 && tlb->PID != pid) {
657 return -1;
659 /* Check effective address */
660 if ((address & mask) != tlb->EPN) {
661 return -1;
663 *raddrp = (tlb->RPN & mask) | (address & ~mask);
664 if (ext) {
665 /* Extend the physical address to 36 bits */
666 *raddrp |= (uint64_t)(tlb->RPN & 0xF) << 32;
669 return 0;
672 /* Generic TLB search function for PowerPC embedded implementations */
673 static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address,
674 uint32_t pid)
676 ppcemb_tlb_t *tlb;
677 hwaddr raddr;
678 int i, ret;
680 /* Default return value is no match */
681 ret = -1;
682 for (i = 0; i < env->nb_tlb; i++) {
683 tlb = &env->tlb.tlbe[i];
684 if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
685 ret = i;
686 break;
690 return ret;
693 /* Helpers specific to PowerPC 40x implementations */
694 static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
696 ppcemb_tlb_t *tlb;
697 int i;
699 for (i = 0; i < env->nb_tlb; i++) {
700 tlb = &env->tlb.tlbe[i];
701 tlb->prot &= ~PAGE_VALID;
703 tlb_flush(env, 1);
706 static inline void ppc4xx_tlb_invalidate_virt(CPUPPCState *env,
707 target_ulong eaddr, uint32_t pid)
709 #if !defined(FLUSH_ALL_TLBS)
710 ppcemb_tlb_t *tlb;
711 hwaddr raddr;
712 target_ulong page, end;
713 int i;
715 for (i = 0; i < env->nb_tlb; i++) {
716 tlb = &env->tlb.tlbe[i];
717 if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
718 end = tlb->EPN + tlb->size;
719 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
720 tlb_flush_page(env, page);
722 tlb->prot &= ~PAGE_VALID;
723 break;
726 #else
727 ppc4xx_tlb_invalidate_all(env);
728 #endif
731 static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
732 target_ulong address, int rw,
733 int access_type)
735 ppcemb_tlb_t *tlb;
736 hwaddr raddr;
737 int i, ret, zsel, zpr, pr;
739 ret = -1;
740 raddr = (hwaddr)-1ULL;
741 pr = msr_pr;
742 for (i = 0; i < env->nb_tlb; i++) {
743 tlb = &env->tlb.tlbe[i];
744 if (ppcemb_tlb_check(env, tlb, &raddr, address,
745 env->spr[SPR_40x_PID], 0, i) < 0) {
746 continue;
748 zsel = (tlb->attr >> 4) & 0xF;
749 zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
750 LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
751 __func__, i, zsel, zpr, rw, tlb->attr);
752 /* Check execute enable bit */
753 switch (zpr) {
754 case 0x2:
755 if (pr != 0) {
756 goto check_perms;
758 /* No break here */
759 case 0x3:
760 /* All accesses granted */
761 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
762 ret = 0;
763 break;
764 case 0x0:
765 if (pr != 0) {
766 /* Raise Zone protection fault. */
767 env->spr[SPR_40x_ESR] = 1 << 22;
768 ctx->prot = 0;
769 ret = -2;
770 break;
772 /* No break here */
773 case 0x1:
774 check_perms:
775 /* Check from TLB entry */
776 ctx->prot = tlb->prot;
777 ret = check_prot(ctx->prot, rw, access_type);
778 if (ret == -2) {
779 env->spr[SPR_40x_ESR] = 0;
781 break;
783 if (ret >= 0) {
784 ctx->raddr = raddr;
785 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
786 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
787 ret);
788 return 0;
791 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
792 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
794 return ret;
797 void store_40x_sler(CPUPPCState *env, uint32_t val)
799 /* XXX: TO BE FIXED */
800 if (val != 0x00000000) {
801 cpu_abort(env, "Little-endian regions are not supported by now\n");
803 env->spr[SPR_405_SLER] = val;
806 static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
807 hwaddr *raddr, int *prot,
808 target_ulong address, int rw,
809 int access_type, int i)
811 int ret, prot2;
813 if (ppcemb_tlb_check(env, tlb, raddr, address,
814 env->spr[SPR_BOOKE_PID],
815 !env->nb_pids, i) >= 0) {
816 goto found_tlb;
819 if (env->spr[SPR_BOOKE_PID1] &&
820 ppcemb_tlb_check(env, tlb, raddr, address,
821 env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
822 goto found_tlb;
825 if (env->spr[SPR_BOOKE_PID2] &&
826 ppcemb_tlb_check(env, tlb, raddr, address,
827 env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
828 goto found_tlb;
831 LOG_SWTLB("%s: TLB entry not found\n", __func__);
832 return -1;
834 found_tlb:
836 if (msr_pr != 0) {
837 prot2 = tlb->prot & 0xF;
838 } else {
839 prot2 = (tlb->prot >> 4) & 0xF;
842 /* Check the address space */
843 if (access_type == ACCESS_CODE) {
844 if (msr_ir != (tlb->attr & 1)) {
845 LOG_SWTLB("%s: AS doesn't match\n", __func__);
846 return -1;
849 *prot = prot2;
850 if (prot2 & PAGE_EXEC) {
851 LOG_SWTLB("%s: good TLB!\n", __func__);
852 return 0;
855 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
856 ret = -3;
857 } else {
858 if (msr_dr != (tlb->attr & 1)) {
859 LOG_SWTLB("%s: AS doesn't match\n", __func__);
860 return -1;
863 *prot = prot2;
864 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
865 LOG_SWTLB("%s: found TLB!\n", __func__);
866 return 0;
869 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
870 ret = -2;
873 return ret;
876 static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
877 target_ulong address, int rw,
878 int access_type)
880 ppcemb_tlb_t *tlb;
881 hwaddr raddr;
882 int i, ret;
884 ret = -1;
885 raddr = (hwaddr)-1ULL;
886 for (i = 0; i < env->nb_tlb; i++) {
887 tlb = &env->tlb.tlbe[i];
888 ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
889 access_type, i);
890 if (!ret) {
891 break;
895 if (ret >= 0) {
896 ctx->raddr = raddr;
897 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
898 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
899 ret);
900 } else {
901 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
902 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
905 return ret;
908 static void booke206_flush_tlb(CPUPPCState *env, int flags,
909 const int check_iprot)
911 int tlb_size;
912 int i, j;
913 ppcmas_tlb_t *tlb = env->tlb.tlbm;
915 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
916 if (flags & (1 << i)) {
917 tlb_size = booke206_tlb_size(env, i);
918 for (j = 0; j < tlb_size; j++) {
919 if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
920 tlb[j].mas1 &= ~MAS1_VALID;
924 tlb += booke206_tlb_size(env, i);
927 tlb_flush(env, 1);
930 static hwaddr booke206_tlb_to_page_size(CPUPPCState *env,
931 ppcmas_tlb_t *tlb)
933 int tlbm_size;
935 tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
937 return 1024ULL << tlbm_size;
940 /* TLB check function for MAS based SoftTLBs */
941 static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
942 hwaddr *raddrp,
943 target_ulong address, uint32_t pid)
945 target_ulong mask;
946 uint32_t tlb_pid;
948 /* Check valid flag */
949 if (!(tlb->mas1 & MAS1_VALID)) {
950 return -1;
953 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
954 LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
955 PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n",
956 __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3,
957 tlb->mas8);
959 /* Check PID */
960 tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
961 if (tlb_pid != 0 && tlb_pid != pid) {
962 return -1;
965 /* Check effective address */
966 if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
967 return -1;
970 if (raddrp) {
971 *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
974 return 0;
977 static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
978 hwaddr *raddr, int *prot,
979 target_ulong address, int rw,
980 int access_type)
982 int ret;
983 int prot2 = 0;
985 if (ppcmas_tlb_check(env, tlb, raddr, address,
986 env->spr[SPR_BOOKE_PID]) >= 0) {
987 goto found_tlb;
990 if (env->spr[SPR_BOOKE_PID1] &&
991 ppcmas_tlb_check(env, tlb, raddr, address,
992 env->spr[SPR_BOOKE_PID1]) >= 0) {
993 goto found_tlb;
996 if (env->spr[SPR_BOOKE_PID2] &&
997 ppcmas_tlb_check(env, tlb, raddr, address,
998 env->spr[SPR_BOOKE_PID2]) >= 0) {
999 goto found_tlb;
1002 LOG_SWTLB("%s: TLB entry not found\n", __func__);
1003 return -1;
1005 found_tlb:
1007 if (msr_pr != 0) {
1008 if (tlb->mas7_3 & MAS3_UR) {
1009 prot2 |= PAGE_READ;
1011 if (tlb->mas7_3 & MAS3_UW) {
1012 prot2 |= PAGE_WRITE;
1014 if (tlb->mas7_3 & MAS3_UX) {
1015 prot2 |= PAGE_EXEC;
1017 } else {
1018 if (tlb->mas7_3 & MAS3_SR) {
1019 prot2 |= PAGE_READ;
1021 if (tlb->mas7_3 & MAS3_SW) {
1022 prot2 |= PAGE_WRITE;
1024 if (tlb->mas7_3 & MAS3_SX) {
1025 prot2 |= PAGE_EXEC;
1029 /* Check the address space and permissions */
1030 if (access_type == ACCESS_CODE) {
1031 if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
1032 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1033 return -1;
1036 *prot = prot2;
1037 if (prot2 & PAGE_EXEC) {
1038 LOG_SWTLB("%s: good TLB!\n", __func__);
1039 return 0;
1042 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
1043 ret = -3;
1044 } else {
1045 if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
1046 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1047 return -1;
1050 *prot = prot2;
1051 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
1052 LOG_SWTLB("%s: found TLB!\n", __func__);
1053 return 0;
1056 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
1057 ret = -2;
1060 return ret;
1063 static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1064 target_ulong address, int rw,
1065 int access_type)
1067 ppcmas_tlb_t *tlb;
1068 hwaddr raddr;
1069 int i, j, ret;
1071 ret = -1;
1072 raddr = (hwaddr)-1ULL;
1074 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1075 int ways = booke206_tlb_ways(env, i);
1077 for (j = 0; j < ways; j++) {
1078 tlb = booke206_get_tlbm(env, i, address, j);
1079 if (!tlb) {
1080 continue;
1082 ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
1083 rw, access_type);
1084 if (ret != -1) {
1085 goto found_tlb;
1090 found_tlb:
1092 if (ret >= 0) {
1093 ctx->raddr = raddr;
1094 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1095 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1096 ret);
1097 } else {
1098 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1099 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1102 return ret;
1105 static const char *book3e_tsize_to_str[32] = {
1106 "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
1107 "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
1108 "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
1109 "1T", "2T"
1112 static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1113 CPUPPCState *env)
1115 ppcemb_tlb_t *entry;
1116 int i;
1118 if (kvm_enabled() && !env->kvm_sw_tlb) {
1119 cpu_fprintf(f, "Cannot access KVM TLB\n");
1120 return;
1123 cpu_fprintf(f, "\nTLB:\n");
1124 cpu_fprintf(f, "Effective Physical Size PID Prot "
1125 "Attr\n");
1127 entry = &env->tlb.tlbe[0];
1128 for (i = 0; i < env->nb_tlb; i++, entry++) {
1129 hwaddr ea, pa;
1130 target_ulong mask;
1131 uint64_t size = (uint64_t)entry->size;
1132 char size_buf[20];
1134 /* Check valid flag */
1135 if (!(entry->prot & PAGE_VALID)) {
1136 continue;
1139 mask = ~(entry->size - 1);
1140 ea = entry->EPN & mask;
1141 pa = entry->RPN & mask;
1142 /* Extend the physical address to 36 bits */
1143 pa |= (hwaddr)(entry->RPN & 0xF) << 32;
1144 size /= 1024;
1145 if (size >= 1024) {
1146 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024);
1147 } else {
1148 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size);
1150 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
1151 (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
1152 entry->prot, entry->attr);
1157 static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
1158 CPUPPCState *env, int tlbn, int offset,
1159 int tlbsize)
1161 ppcmas_tlb_t *entry;
1162 int i;
1164 cpu_fprintf(f, "\nTLB%d:\n", tlbn);
1165 cpu_fprintf(f, "Effective Physical Size TID TS SRWX"
1166 " URWX WIMGE U0123\n");
1168 entry = &env->tlb.tlbm[offset];
1169 for (i = 0; i < tlbsize; i++, entry++) {
1170 hwaddr ea, pa, size;
1171 int tsize;
1173 if (!(entry->mas1 & MAS1_VALID)) {
1174 continue;
1177 tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1178 size = 1024ULL << tsize;
1179 ea = entry->mas2 & ~(size - 1);
1180 pa = entry->mas7_3 & ~(size - 1);
1182 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c"
1183 "U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
1184 (uint64_t)ea, (uint64_t)pa,
1185 book3e_tsize_to_str[tsize],
1186 (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
1187 (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
1188 entry->mas7_3 & MAS3_SR ? 'R' : '-',
1189 entry->mas7_3 & MAS3_SW ? 'W' : '-',
1190 entry->mas7_3 & MAS3_SX ? 'X' : '-',
1191 entry->mas7_3 & MAS3_UR ? 'R' : '-',
1192 entry->mas7_3 & MAS3_UW ? 'W' : '-',
1193 entry->mas7_3 & MAS3_UX ? 'X' : '-',
1194 entry->mas2 & MAS2_W ? 'W' : '-',
1195 entry->mas2 & MAS2_I ? 'I' : '-',
1196 entry->mas2 & MAS2_M ? 'M' : '-',
1197 entry->mas2 & MAS2_G ? 'G' : '-',
1198 entry->mas2 & MAS2_E ? 'E' : '-',
1199 entry->mas7_3 & MAS3_U0 ? '0' : '-',
1200 entry->mas7_3 & MAS3_U1 ? '1' : '-',
1201 entry->mas7_3 & MAS3_U2 ? '2' : '-',
1202 entry->mas7_3 & MAS3_U3 ? '3' : '-');
1206 static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1207 CPUPPCState *env)
1209 int offset = 0;
1210 int i;
1212 if (kvm_enabled() && !env->kvm_sw_tlb) {
1213 cpu_fprintf(f, "Cannot access KVM TLB\n");
1214 return;
1217 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1218 int size = booke206_tlb_size(env, i);
1220 if (size == 0) {
1221 continue;
1224 mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size);
1225 offset += size;
1229 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
1231 switch (env->mmu_model) {
1232 case POWERPC_MMU_BOOKE:
1233 mmubooke_dump_mmu(f, cpu_fprintf, env);
1234 break;
1235 case POWERPC_MMU_BOOKE206:
1236 mmubooke206_dump_mmu(f, cpu_fprintf, env);
1237 break;
1238 #if defined(TARGET_PPC64)
1239 case POWERPC_MMU_64B:
1240 case POWERPC_MMU_2_06:
1241 case POWERPC_MMU_2_06d:
1242 dump_slb(f, cpu_fprintf, env);
1243 break;
1244 #endif
1245 default:
1246 qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
1250 static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
1251 target_ulong eaddr, int rw)
1253 int in_plb, ret;
1255 ctx->raddr = eaddr;
1256 ctx->prot = PAGE_READ | PAGE_EXEC;
1257 ret = 0;
1258 switch (env->mmu_model) {
1259 case POWERPC_MMU_32B:
1260 case POWERPC_MMU_601:
1261 case POWERPC_MMU_SOFT_6xx:
1262 case POWERPC_MMU_SOFT_74xx:
1263 case POWERPC_MMU_SOFT_4xx:
1264 case POWERPC_MMU_REAL:
1265 case POWERPC_MMU_BOOKE:
1266 ctx->prot |= PAGE_WRITE;
1267 break;
1268 #if defined(TARGET_PPC64)
1269 case POWERPC_MMU_64B:
1270 case POWERPC_MMU_2_06:
1271 case POWERPC_MMU_2_06d:
1272 /* Real address are 60 bits long */
1273 ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL;
1274 ctx->prot |= PAGE_WRITE;
1275 break;
1276 #endif
1277 case POWERPC_MMU_SOFT_4xx_Z:
1278 if (unlikely(msr_pe != 0)) {
1279 /* 403 family add some particular protections,
1280 * using PBL/PBU registers for accesses with no translation.
1282 in_plb =
1283 /* Check PLB validity */
1284 (env->pb[0] < env->pb[1] &&
1285 /* and address in plb area */
1286 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
1287 (env->pb[2] < env->pb[3] &&
1288 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
1289 if (in_plb ^ msr_px) {
1290 /* Access in protected area */
1291 if (rw == 1) {
1292 /* Access is not allowed */
1293 ret = -2;
1295 } else {
1296 /* Read-write access is allowed */
1297 ctx->prot |= PAGE_WRITE;
1300 break;
1301 case POWERPC_MMU_MPC8xx:
1302 /* XXX: TODO */
1303 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1304 break;
1305 case POWERPC_MMU_BOOKE206:
1306 cpu_abort(env, "BookE 2.06 MMU doesn't have physical real mode\n");
1307 break;
1308 default:
1309 cpu_abort(env, "Unknown or invalid MMU model\n");
1310 return -1;
1313 return ret;
1316 static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1317 target_ulong eaddr, int rw, int access_type)
1319 int ret = -1;
1320 bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
1321 || (access_type != ACCESS_CODE && msr_dr == 0);
1323 #if 0
1324 qemu_log("%s\n", __func__);
1325 #endif
1327 switch (env->mmu_model) {
1328 case POWERPC_MMU_32B:
1329 case POWERPC_MMU_601:
1330 if (real_mode) {
1331 ret = check_physical(env, ctx, eaddr, rw);
1332 } else {
1333 /* Try to find a BAT */
1334 if (env->nb_BATs != 0) {
1335 ret = get_bat(env, ctx, eaddr, rw, access_type);
1337 if (ret < 0) {
1338 /* We didn't match any BAT entry or don't have BATs */
1339 ret = get_segment32(env, ctx, eaddr, rw, access_type);
1342 break;
1344 case POWERPC_MMU_SOFT_6xx:
1345 case POWERPC_MMU_SOFT_74xx:
1346 if (real_mode) {
1347 ret = check_physical(env, ctx, eaddr, rw);
1348 } else {
1349 /* Try to find a BAT */
1350 if (env->nb_BATs != 0) {
1351 ret = get_bat(env, ctx, eaddr, rw, access_type);
1353 if (ret < 0) {
1354 /* We didn't match any BAT entry or don't have BATs */
1355 ret = get_segment_6xx_tlb(env, ctx, eaddr, rw, access_type);
1358 break;
1360 #if defined(TARGET_PPC64)
1361 case POWERPC_MMU_64B:
1362 case POWERPC_MMU_2_06:
1363 case POWERPC_MMU_2_06d:
1364 if (real_mode) {
1365 ret = check_physical(env, ctx, eaddr, rw);
1366 } else {
1367 ret = get_segment64(env, ctx, eaddr, rw, access_type);
1369 break;
1370 #endif
1372 case POWERPC_MMU_SOFT_4xx:
1373 case POWERPC_MMU_SOFT_4xx_Z:
1374 if (real_mode) {
1375 ret = check_physical(env, ctx, eaddr, rw);
1376 } else {
1377 ret = mmu40x_get_physical_address(env, ctx, eaddr,
1378 rw, access_type);
1380 break;
1381 case POWERPC_MMU_BOOKE:
1382 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1383 rw, access_type);
1384 break;
1385 case POWERPC_MMU_BOOKE206:
1386 ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
1387 access_type);
1388 break;
1389 case POWERPC_MMU_MPC8xx:
1390 /* XXX: TODO */
1391 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1392 break;
1393 case POWERPC_MMU_REAL:
1394 if (real_mode) {
1395 ret = check_physical(env, ctx, eaddr, rw);
1396 } else {
1397 cpu_abort(env, "PowerPC in real mode do not do any translation\n");
1399 return -1;
1400 default:
1401 cpu_abort(env, "Unknown or invalid MMU model\n");
1402 return -1;
1404 #if 0
1405 qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
1406 __func__, eaddr, ret, ctx->raddr);
1407 #endif
1409 return ret;
1412 hwaddr cpu_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
1414 mmu_ctx_t ctx;
1416 if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {
1417 return -1;
1420 return ctx.raddr & TARGET_PAGE_MASK;
1423 static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
1424 int rw)
1426 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
1427 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
1428 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
1429 env->spr[SPR_BOOKE_MAS3] = 0;
1430 env->spr[SPR_BOOKE_MAS6] = 0;
1431 env->spr[SPR_BOOKE_MAS7] = 0;
1433 /* AS */
1434 if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
1435 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
1436 env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
1439 env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
1440 env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
1442 switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
1443 case MAS4_TIDSELD_PID0:
1444 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
1445 break;
1446 case MAS4_TIDSELD_PID1:
1447 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
1448 break;
1449 case MAS4_TIDSELD_PID2:
1450 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
1451 break;
1454 env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
1456 /* next victim logic */
1457 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
1458 env->last_way++;
1459 env->last_way &= booke206_tlb_ways(env, 0) - 1;
1460 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
1463 /* Perform address translation */
1464 int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
1465 int mmu_idx)
1467 mmu_ctx_t ctx;
1468 int access_type;
1469 int ret = 0;
1471 if (rw == 2) {
1472 /* code access */
1473 rw = 0;
1474 access_type = ACCESS_CODE;
1475 } else {
1476 /* data access */
1477 access_type = env->access_type;
1479 ret = get_physical_address(env, &ctx, address, rw, access_type);
1480 if (ret == 0) {
1481 tlb_set_page(env, address & TARGET_PAGE_MASK,
1482 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
1483 mmu_idx, TARGET_PAGE_SIZE);
1484 ret = 0;
1485 } else if (ret < 0) {
1486 LOG_MMU_STATE(env);
1487 if (access_type == ACCESS_CODE) {
1488 switch (ret) {
1489 case -1:
1490 /* No matches in page tables or TLB */
1491 switch (env->mmu_model) {
1492 case POWERPC_MMU_SOFT_6xx:
1493 env->exception_index = POWERPC_EXCP_IFTLB;
1494 env->error_code = 1 << 18;
1495 env->spr[SPR_IMISS] = address;
1496 env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
1497 goto tlb_miss;
1498 case POWERPC_MMU_SOFT_74xx:
1499 env->exception_index = POWERPC_EXCP_IFTLB;
1500 goto tlb_miss_74xx;
1501 case POWERPC_MMU_SOFT_4xx:
1502 case POWERPC_MMU_SOFT_4xx_Z:
1503 env->exception_index = POWERPC_EXCP_ITLB;
1504 env->error_code = 0;
1505 env->spr[SPR_40x_DEAR] = address;
1506 env->spr[SPR_40x_ESR] = 0x00000000;
1507 break;
1508 case POWERPC_MMU_32B:
1509 case POWERPC_MMU_601:
1510 #if defined(TARGET_PPC64)
1511 case POWERPC_MMU_64B:
1512 case POWERPC_MMU_2_06:
1513 case POWERPC_MMU_2_06d:
1514 #endif
1515 env->exception_index = POWERPC_EXCP_ISI;
1516 env->error_code = 0x40000000;
1517 break;
1518 case POWERPC_MMU_BOOKE206:
1519 booke206_update_mas_tlb_miss(env, address, rw);
1520 /* fall through */
1521 case POWERPC_MMU_BOOKE:
1522 env->exception_index = POWERPC_EXCP_ITLB;
1523 env->error_code = 0;
1524 env->spr[SPR_BOOKE_DEAR] = address;
1525 return -1;
1526 case POWERPC_MMU_MPC8xx:
1527 /* XXX: TODO */
1528 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1529 break;
1530 case POWERPC_MMU_REAL:
1531 cpu_abort(env, "PowerPC in real mode should never raise "
1532 "any MMU exceptions\n");
1533 return -1;
1534 default:
1535 cpu_abort(env, "Unknown or invalid MMU model\n");
1536 return -1;
1538 break;
1539 case -2:
1540 /* Access rights violation */
1541 env->exception_index = POWERPC_EXCP_ISI;
1542 env->error_code = 0x08000000;
1543 break;
1544 case -3:
1545 /* No execute protection violation */
1546 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1547 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1548 env->spr[SPR_BOOKE_ESR] = 0x00000000;
1550 env->exception_index = POWERPC_EXCP_ISI;
1551 env->error_code = 0x10000000;
1552 break;
1553 case -4:
1554 /* Direct store exception */
1555 /* No code fetch is allowed in direct-store areas */
1556 env->exception_index = POWERPC_EXCP_ISI;
1557 env->error_code = 0x10000000;
1558 break;
1559 #if defined(TARGET_PPC64)
1560 case -5:
1561 /* No match in segment table */
1562 env->exception_index = POWERPC_EXCP_ISEG;
1563 env->error_code = 0;
1564 break;
1565 #endif
1567 } else {
1568 switch (ret) {
1569 case -1:
1570 /* No matches in page tables or TLB */
1571 switch (env->mmu_model) {
1572 case POWERPC_MMU_SOFT_6xx:
1573 if (rw == 1) {
1574 env->exception_index = POWERPC_EXCP_DSTLB;
1575 env->error_code = 1 << 16;
1576 } else {
1577 env->exception_index = POWERPC_EXCP_DLTLB;
1578 env->error_code = 0;
1580 env->spr[SPR_DMISS] = address;
1581 env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
1582 tlb_miss:
1583 env->error_code |= ctx.key << 19;
1584 env->spr[SPR_HASH1] = env->htab_base +
1585 get_pteg_offset(env, ctx.hash[0], HASH_PTE_SIZE_32);
1586 env->spr[SPR_HASH2] = env->htab_base +
1587 get_pteg_offset(env, ctx.hash[1], HASH_PTE_SIZE_32);
1588 break;
1589 case POWERPC_MMU_SOFT_74xx:
1590 if (rw == 1) {
1591 env->exception_index = POWERPC_EXCP_DSTLB;
1592 } else {
1593 env->exception_index = POWERPC_EXCP_DLTLB;
1595 tlb_miss_74xx:
1596 /* Implement LRU algorithm */
1597 env->error_code = ctx.key << 19;
1598 env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
1599 ((env->last_way + 1) & (env->nb_ways - 1));
1600 env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
1601 break;
1602 case POWERPC_MMU_SOFT_4xx:
1603 case POWERPC_MMU_SOFT_4xx_Z:
1604 env->exception_index = POWERPC_EXCP_DTLB;
1605 env->error_code = 0;
1606 env->spr[SPR_40x_DEAR] = address;
1607 if (rw) {
1608 env->spr[SPR_40x_ESR] = 0x00800000;
1609 } else {
1610 env->spr[SPR_40x_ESR] = 0x00000000;
1612 break;
1613 case POWERPC_MMU_32B:
1614 case POWERPC_MMU_601:
1615 #if defined(TARGET_PPC64)
1616 case POWERPC_MMU_64B:
1617 case POWERPC_MMU_2_06:
1618 case POWERPC_MMU_2_06d:
1619 #endif
1620 env->exception_index = POWERPC_EXCP_DSI;
1621 env->error_code = 0;
1622 env->spr[SPR_DAR] = address;
1623 if (rw == 1) {
1624 env->spr[SPR_DSISR] = 0x42000000;
1625 } else {
1626 env->spr[SPR_DSISR] = 0x40000000;
1628 break;
1629 case POWERPC_MMU_MPC8xx:
1630 /* XXX: TODO */
1631 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1632 break;
1633 case POWERPC_MMU_BOOKE206:
1634 booke206_update_mas_tlb_miss(env, address, rw);
1635 /* fall through */
1636 case POWERPC_MMU_BOOKE:
1637 env->exception_index = POWERPC_EXCP_DTLB;
1638 env->error_code = 0;
1639 env->spr[SPR_BOOKE_DEAR] = address;
1640 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1641 return -1;
1642 case POWERPC_MMU_REAL:
1643 cpu_abort(env, "PowerPC in real mode should never raise "
1644 "any MMU exceptions\n");
1645 return -1;
1646 default:
1647 cpu_abort(env, "Unknown or invalid MMU model\n");
1648 return -1;
1650 break;
1651 case -2:
1652 /* Access rights violation */
1653 env->exception_index = POWERPC_EXCP_DSI;
1654 env->error_code = 0;
1655 if (env->mmu_model == POWERPC_MMU_SOFT_4xx
1656 || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
1657 env->spr[SPR_40x_DEAR] = address;
1658 if (rw) {
1659 env->spr[SPR_40x_ESR] |= 0x00800000;
1661 } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1662 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1663 env->spr[SPR_BOOKE_DEAR] = address;
1664 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1665 } else {
1666 env->spr[SPR_DAR] = address;
1667 if (rw == 1) {
1668 env->spr[SPR_DSISR] = 0x0A000000;
1669 } else {
1670 env->spr[SPR_DSISR] = 0x08000000;
1673 break;
1674 case -4:
1675 /* Direct store exception */
1676 switch (access_type) {
1677 case ACCESS_FLOAT:
1678 /* Floating point load/store */
1679 env->exception_index = POWERPC_EXCP_ALIGN;
1680 env->error_code = POWERPC_EXCP_ALIGN_FP;
1681 env->spr[SPR_DAR] = address;
1682 break;
1683 case ACCESS_RES:
1684 /* lwarx, ldarx or stwcx. */
1685 env->exception_index = POWERPC_EXCP_DSI;
1686 env->error_code = 0;
1687 env->spr[SPR_DAR] = address;
1688 if (rw == 1) {
1689 env->spr[SPR_DSISR] = 0x06000000;
1690 } else {
1691 env->spr[SPR_DSISR] = 0x04000000;
1693 break;
1694 case ACCESS_EXT:
1695 /* eciwx or ecowx */
1696 env->exception_index = POWERPC_EXCP_DSI;
1697 env->error_code = 0;
1698 env->spr[SPR_DAR] = address;
1699 if (rw == 1) {
1700 env->spr[SPR_DSISR] = 0x06100000;
1701 } else {
1702 env->spr[SPR_DSISR] = 0x04100000;
1704 break;
1705 default:
1706 printf("DSI: invalid exception (%d)\n", ret);
1707 env->exception_index = POWERPC_EXCP_PROGRAM;
1708 env->error_code =
1709 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
1710 env->spr[SPR_DAR] = address;
1711 break;
1713 break;
1714 #if defined(TARGET_PPC64)
1715 case -5:
1716 /* No match in segment table */
1717 env->exception_index = POWERPC_EXCP_DSEG;
1718 env->error_code = 0;
1719 env->spr[SPR_DAR] = address;
1720 break;
1721 #endif
1724 #if 0
1725 printf("%s: set exception to %d %02x\n", __func__,
1726 env->exception, env->error_code);
1727 #endif
1728 ret = 1;
1731 return ret;
1734 /*****************************************************************************/
1735 /* BATs management */
1736 #if !defined(FLUSH_ALL_TLBS)
1737 static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
1738 target_ulong mask)
1740 target_ulong base, end, page;
1742 base = BATu & ~0x0001FFFF;
1743 end = base + mask + 0x00020000;
1744 LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
1745 TARGET_FMT_lx ")\n", base, end, mask);
1746 for (page = base; page != end; page += TARGET_PAGE_SIZE) {
1747 tlb_flush_page(env, page);
1749 LOG_BATS("Flush done\n");
1751 #endif
1753 static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
1754 target_ulong value)
1756 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
1757 nr, ul == 0 ? 'u' : 'l', value, env->nip);
1760 void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1762 target_ulong mask;
1764 dump_store_bat(env, 'I', 0, nr, value);
1765 if (env->IBAT[0][nr] != value) {
1766 mask = (value << 15) & 0x0FFE0000UL;
1767 #if !defined(FLUSH_ALL_TLBS)
1768 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1769 #endif
1770 /* When storing valid upper BAT, mask BEPI and BRPN
1771 * and invalidate all TLBs covered by this BAT
1773 mask = (value << 15) & 0x0FFE0000UL;
1774 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1775 (value & ~0x0001FFFFUL & ~mask);
1776 env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
1777 (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
1778 #if !defined(FLUSH_ALL_TLBS)
1779 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1780 #else
1781 tlb_flush(env, 1);
1782 #endif
1786 void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1788 dump_store_bat(env, 'I', 1, nr, value);
1789 env->IBAT[1][nr] = value;
1792 void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1794 target_ulong mask;
1796 dump_store_bat(env, 'D', 0, nr, value);
1797 if (env->DBAT[0][nr] != value) {
1798 /* When storing valid upper BAT, mask BEPI and BRPN
1799 * and invalidate all TLBs covered by this BAT
1801 mask = (value << 15) & 0x0FFE0000UL;
1802 #if !defined(FLUSH_ALL_TLBS)
1803 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1804 #endif
1805 mask = (value << 15) & 0x0FFE0000UL;
1806 env->DBAT[0][nr] = (value & 0x00001FFFUL) |
1807 (value & ~0x0001FFFFUL & ~mask);
1808 env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
1809 (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
1810 #if !defined(FLUSH_ALL_TLBS)
1811 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1812 #else
1813 tlb_flush(env, 1);
1814 #endif
1818 void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1820 dump_store_bat(env, 'D', 1, nr, value);
1821 env->DBAT[1][nr] = value;
1824 void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value)
1826 target_ulong mask;
1827 #if defined(FLUSH_ALL_TLBS)
1828 int do_inval;
1829 #endif
1831 dump_store_bat(env, 'I', 0, nr, value);
1832 if (env->IBAT[0][nr] != value) {
1833 #if defined(FLUSH_ALL_TLBS)
1834 do_inval = 0;
1835 #endif
1836 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1837 if (env->IBAT[1][nr] & 0x40) {
1838 /* Invalidate BAT only if it is valid */
1839 #if !defined(FLUSH_ALL_TLBS)
1840 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1841 #else
1842 do_inval = 1;
1843 #endif
1845 /* When storing valid upper BAT, mask BEPI and BRPN
1846 * and invalidate all TLBs covered by this BAT
1848 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1849 (value & ~0x0001FFFFUL & ~mask);
1850 env->DBAT[0][nr] = env->IBAT[0][nr];
1851 if (env->IBAT[1][nr] & 0x40) {
1852 #if !defined(FLUSH_ALL_TLBS)
1853 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1854 #else
1855 do_inval = 1;
1856 #endif
1858 #if defined(FLUSH_ALL_TLBS)
1859 if (do_inval) {
1860 tlb_flush(env, 1);
1862 #endif
1866 void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value)
1868 #if !defined(FLUSH_ALL_TLBS)
1869 target_ulong mask;
1870 #else
1871 int do_inval;
1872 #endif
1874 dump_store_bat(env, 'I', 1, nr, value);
1875 if (env->IBAT[1][nr] != value) {
1876 #if defined(FLUSH_ALL_TLBS)
1877 do_inval = 0;
1878 #endif
1879 if (env->IBAT[1][nr] & 0x40) {
1880 #if !defined(FLUSH_ALL_TLBS)
1881 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1882 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1883 #else
1884 do_inval = 1;
1885 #endif
1887 if (value & 0x40) {
1888 #if !defined(FLUSH_ALL_TLBS)
1889 mask = (value << 17) & 0x0FFE0000UL;
1890 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1891 #else
1892 do_inval = 1;
1893 #endif
1895 env->IBAT[1][nr] = value;
1896 env->DBAT[1][nr] = value;
1897 #if defined(FLUSH_ALL_TLBS)
1898 if (do_inval) {
1899 tlb_flush(env, 1);
1901 #endif
1905 /*****************************************************************************/
1906 /* TLB management */
1907 void ppc_tlb_invalidate_all(CPUPPCState *env)
1909 switch (env->mmu_model) {
1910 case POWERPC_MMU_SOFT_6xx:
1911 case POWERPC_MMU_SOFT_74xx:
1912 ppc6xx_tlb_invalidate_all(env);
1913 break;
1914 case POWERPC_MMU_SOFT_4xx:
1915 case POWERPC_MMU_SOFT_4xx_Z:
1916 ppc4xx_tlb_invalidate_all(env);
1917 break;
1918 case POWERPC_MMU_REAL:
1919 cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
1920 break;
1921 case POWERPC_MMU_MPC8xx:
1922 /* XXX: TODO */
1923 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1924 break;
1925 case POWERPC_MMU_BOOKE:
1926 tlb_flush(env, 1);
1927 break;
1928 case POWERPC_MMU_BOOKE206:
1929 booke206_flush_tlb(env, -1, 0);
1930 break;
1931 case POWERPC_MMU_32B:
1932 case POWERPC_MMU_601:
1933 #if defined(TARGET_PPC64)
1934 case POWERPC_MMU_64B:
1935 case POWERPC_MMU_2_06:
1936 case POWERPC_MMU_2_06d:
1937 #endif /* defined(TARGET_PPC64) */
1938 tlb_flush(env, 1);
1939 break;
1940 default:
1941 /* XXX: TODO */
1942 cpu_abort(env, "Unknown MMU model\n");
1943 break;
1947 void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
1949 #if !defined(FLUSH_ALL_TLBS)
1950 addr &= TARGET_PAGE_MASK;
1951 switch (env->mmu_model) {
1952 case POWERPC_MMU_SOFT_6xx:
1953 case POWERPC_MMU_SOFT_74xx:
1954 ppc6xx_tlb_invalidate_virt(env, addr, 0);
1955 if (env->id_tlbs == 1) {
1956 ppc6xx_tlb_invalidate_virt(env, addr, 1);
1958 break;
1959 case POWERPC_MMU_SOFT_4xx:
1960 case POWERPC_MMU_SOFT_4xx_Z:
1961 ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
1962 break;
1963 case POWERPC_MMU_REAL:
1964 cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
1965 break;
1966 case POWERPC_MMU_MPC8xx:
1967 /* XXX: TODO */
1968 cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1969 break;
1970 case POWERPC_MMU_BOOKE:
1971 /* XXX: TODO */
1972 cpu_abort(env, "BookE MMU model is not implemented\n");
1973 break;
1974 case POWERPC_MMU_BOOKE206:
1975 /* XXX: TODO */
1976 cpu_abort(env, "BookE 2.06 MMU model is not implemented\n");
1977 break;
1978 case POWERPC_MMU_32B:
1979 case POWERPC_MMU_601:
1980 /* tlbie invalidate TLBs for all segments */
1981 addr &= ~((target_ulong)-1ULL << 28);
1982 /* XXX: this case should be optimized,
1983 * giving a mask to tlb_flush_page
1985 tlb_flush_page(env, addr | (0x0 << 28));
1986 tlb_flush_page(env, addr | (0x1 << 28));
1987 tlb_flush_page(env, addr | (0x2 << 28));
1988 tlb_flush_page(env, addr | (0x3 << 28));
1989 tlb_flush_page(env, addr | (0x4 << 28));
1990 tlb_flush_page(env, addr | (0x5 << 28));
1991 tlb_flush_page(env, addr | (0x6 << 28));
1992 tlb_flush_page(env, addr | (0x7 << 28));
1993 tlb_flush_page(env, addr | (0x8 << 28));
1994 tlb_flush_page(env, addr | (0x9 << 28));
1995 tlb_flush_page(env, addr | (0xA << 28));
1996 tlb_flush_page(env, addr | (0xB << 28));
1997 tlb_flush_page(env, addr | (0xC << 28));
1998 tlb_flush_page(env, addr | (0xD << 28));
1999 tlb_flush_page(env, addr | (0xE << 28));
2000 tlb_flush_page(env, addr | (0xF << 28));
2001 break;
2002 #if defined(TARGET_PPC64)
2003 case POWERPC_MMU_64B:
2004 case POWERPC_MMU_2_06:
2005 case POWERPC_MMU_2_06d:
2006 /* tlbie invalidate TLBs for all segments */
2007 /* XXX: given the fact that there are too many segments to invalidate,
2008 * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
2009 * we just invalidate all TLBs
2011 tlb_flush(env, 1);
2012 break;
2013 #endif /* defined(TARGET_PPC64) */
2014 default:
2015 /* XXX: TODO */
2016 cpu_abort(env, "Unknown MMU model\n");
2017 break;
2019 #else
2020 ppc_tlb_invalidate_all(env);
2021 #endif
2024 /*****************************************************************************/
2025 /* Special registers manipulation */
2026 void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
2028 LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value);
2029 if (env->spr[SPR_SDR1] != value) {
2030 env->spr[SPR_SDR1] = value;
2031 #if defined(TARGET_PPC64)
2032 if (env->mmu_model & POWERPC_MMU_64) {
2033 target_ulong htabsize = value & SDR_64_HTABSIZE;
2035 if (htabsize > 28) {
2036 fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx
2037 " stored in SDR1\n", htabsize);
2038 htabsize = 28;
2040 env->htab_mask = (1ULL << (htabsize + 18)) - 1;
2041 env->htab_base = value & SDR_64_HTABORG;
2042 } else
2043 #endif /* defined(TARGET_PPC64) */
2045 /* FIXME: Should check for valid HTABMASK values */
2046 env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
2047 env->htab_base = value & SDR_32_HTABORG;
2049 tlb_flush(env, 1);
2053 /* Segment registers load and store */
2054 target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
2056 #if defined(TARGET_PPC64)
2057 if (env->mmu_model & POWERPC_MMU_64) {
2058 /* XXX */
2059 return 0;
2061 #endif
2062 return env->sr[sr_num];
2065 void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
2067 LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
2068 (int)srnum, value, env->sr[srnum]);
2069 #if defined(TARGET_PPC64)
2070 if (env->mmu_model & POWERPC_MMU_64) {
2071 uint64_t rb = 0, rs = 0;
2073 /* ESID = srnum */
2074 rb |= ((uint32_t)srnum & 0xf) << 28;
2075 /* Set the valid bit */
2076 rb |= 1 << 27;
2077 /* Index = ESID */
2078 rb |= (uint32_t)srnum;
2080 /* VSID = VSID */
2081 rs |= (value & 0xfffffff) << 12;
2082 /* flags = flags */
2083 rs |= ((value >> 27) & 0xf) << 8;
2085 ppc_store_slb(env, rb, rs);
2086 } else
2087 #endif
2088 if (env->sr[srnum] != value) {
2089 env->sr[srnum] = value;
2090 /* Invalidating 256MB of virtual memory in 4kB pages is way longer than
2091 flusing the whole TLB. */
2092 #if !defined(FLUSH_ALL_TLBS) && 0
2094 target_ulong page, end;
2095 /* Invalidate 256 MB of virtual memory */
2096 page = (16 << 20) * srnum;
2097 end = page + (16 << 20);
2098 for (; page != end; page += TARGET_PAGE_SIZE) {
2099 tlb_flush_page(env, page);
2102 #else
2103 tlb_flush(env, 1);
2104 #endif
2107 #endif /* !defined(CONFIG_USER_ONLY) */
2109 #if !defined(CONFIG_USER_ONLY)
2110 /* TLB management */
2111 void helper_tlbia(CPUPPCState *env)
2113 ppc_tlb_invalidate_all(env);
2116 void helper_tlbie(CPUPPCState *env, target_ulong addr)
2118 ppc_tlb_invalidate_one(env, addr);
2121 /* Software driven TLBs management */
2122 /* PowerPC 602/603 software TLB load instructions helpers */
2123 static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2125 target_ulong RPN, CMP, EPN;
2126 int way;
2128 RPN = env->spr[SPR_RPA];
2129 if (is_code) {
2130 CMP = env->spr[SPR_ICMP];
2131 EPN = env->spr[SPR_IMISS];
2132 } else {
2133 CMP = env->spr[SPR_DCMP];
2134 EPN = env->spr[SPR_DMISS];
2136 way = (env->spr[SPR_SRR1] >> 17) & 1;
2137 (void)EPN; /* avoid a compiler warning */
2138 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2139 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2140 RPN, way);
2141 /* Store this TLB */
2142 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2143 way, is_code, CMP, RPN);
2146 void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN)
2148 do_6xx_tlb(env, EPN, 0);
2151 void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
2153 do_6xx_tlb(env, EPN, 1);
2156 /* PowerPC 74xx software TLB load instructions helpers */
2157 static void do_74xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2159 target_ulong RPN, CMP, EPN;
2160 int way;
2162 RPN = env->spr[SPR_PTELO];
2163 CMP = env->spr[SPR_PTEHI];
2164 EPN = env->spr[SPR_TLBMISS] & ~0x3;
2165 way = env->spr[SPR_TLBMISS] & 0x3;
2166 (void)EPN; /* avoid a compiler warning */
2167 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2168 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2169 RPN, way);
2170 /* Store this TLB */
2171 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2172 way, is_code, CMP, RPN);
2175 void helper_74xx_tlbd(CPUPPCState *env, target_ulong EPN)
2177 do_74xx_tlb(env, EPN, 0);
2180 void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN)
2182 do_74xx_tlb(env, EPN, 1);
2185 /*****************************************************************************/
2186 /* PowerPC 601 specific instructions (POWER bridge) */
2188 target_ulong helper_rac(CPUPPCState *env, target_ulong addr)
2190 mmu_ctx_t ctx;
2191 int nb_BATs;
2192 target_ulong ret = 0;
2194 /* We don't have to generate many instances of this instruction,
2195 * as rac is supervisor only.
2197 /* XXX: FIX THIS: Pretend we have no BAT */
2198 nb_BATs = env->nb_BATs;
2199 env->nb_BATs = 0;
2200 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
2201 ret = ctx.raddr;
2203 env->nb_BATs = nb_BATs;
2204 return ret;
2207 static inline target_ulong booke_tlb_to_page_size(int size)
2209 return 1024 << (2 * size);
2212 static inline int booke_page_size_to_tlb(target_ulong page_size)
2214 int size;
2216 switch (page_size) {
2217 case 0x00000400UL:
2218 size = 0x0;
2219 break;
2220 case 0x00001000UL:
2221 size = 0x1;
2222 break;
2223 case 0x00004000UL:
2224 size = 0x2;
2225 break;
2226 case 0x00010000UL:
2227 size = 0x3;
2228 break;
2229 case 0x00040000UL:
2230 size = 0x4;
2231 break;
2232 case 0x00100000UL:
2233 size = 0x5;
2234 break;
2235 case 0x00400000UL:
2236 size = 0x6;
2237 break;
2238 case 0x01000000UL:
2239 size = 0x7;
2240 break;
2241 case 0x04000000UL:
2242 size = 0x8;
2243 break;
2244 case 0x10000000UL:
2245 size = 0x9;
2246 break;
2247 case 0x40000000UL:
2248 size = 0xA;
2249 break;
2250 #if defined(TARGET_PPC64)
2251 case 0x000100000000ULL:
2252 size = 0xB;
2253 break;
2254 case 0x000400000000ULL:
2255 size = 0xC;
2256 break;
2257 case 0x001000000000ULL:
2258 size = 0xD;
2259 break;
2260 case 0x004000000000ULL:
2261 size = 0xE;
2262 break;
2263 case 0x010000000000ULL:
2264 size = 0xF;
2265 break;
2266 #endif
2267 default:
2268 size = -1;
2269 break;
2272 return size;
2275 /* Helpers for 4xx TLB management */
2276 #define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
2278 #define PPC4XX_TLBHI_V 0x00000040
2279 #define PPC4XX_TLBHI_E 0x00000020
2280 #define PPC4XX_TLBHI_SIZE_MIN 0
2281 #define PPC4XX_TLBHI_SIZE_MAX 7
2282 #define PPC4XX_TLBHI_SIZE_DEFAULT 1
2283 #define PPC4XX_TLBHI_SIZE_SHIFT 7
2284 #define PPC4XX_TLBHI_SIZE_MASK 0x00000007
2286 #define PPC4XX_TLBLO_EX 0x00000200
2287 #define PPC4XX_TLBLO_WR 0x00000100
2288 #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
2289 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
2291 target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
2293 ppcemb_tlb_t *tlb;
2294 target_ulong ret;
2295 int size;
2297 entry &= PPC4XX_TLB_ENTRY_MASK;
2298 tlb = &env->tlb.tlbe[entry];
2299 ret = tlb->EPN;
2300 if (tlb->prot & PAGE_VALID) {
2301 ret |= PPC4XX_TLBHI_V;
2303 size = booke_page_size_to_tlb(tlb->size);
2304 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
2305 size = PPC4XX_TLBHI_SIZE_DEFAULT;
2307 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
2308 env->spr[SPR_40x_PID] = tlb->PID;
2309 return ret;
2312 target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry)
2314 ppcemb_tlb_t *tlb;
2315 target_ulong ret;
2317 entry &= PPC4XX_TLB_ENTRY_MASK;
2318 tlb = &env->tlb.tlbe[entry];
2319 ret = tlb->RPN;
2320 if (tlb->prot & PAGE_EXEC) {
2321 ret |= PPC4XX_TLBLO_EX;
2323 if (tlb->prot & PAGE_WRITE) {
2324 ret |= PPC4XX_TLBLO_WR;
2326 return ret;
2329 void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
2330 target_ulong val)
2332 ppcemb_tlb_t *tlb;
2333 target_ulong page, end;
2335 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
2336 val);
2337 entry &= PPC4XX_TLB_ENTRY_MASK;
2338 tlb = &env->tlb.tlbe[entry];
2339 /* Invalidate previous TLB (if it's valid) */
2340 if (tlb->prot & PAGE_VALID) {
2341 end = tlb->EPN + tlb->size;
2342 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
2343 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2344 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2345 tlb_flush_page(env, page);
2348 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
2349 & PPC4XX_TLBHI_SIZE_MASK);
2350 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2351 * If this ever occurs, one should use the ppcemb target instead
2352 * of the ppc or ppc64 one
2354 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
2355 cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
2356 "are not supported (%d)\n",
2357 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
2359 tlb->EPN = val & ~(tlb->size - 1);
2360 if (val & PPC4XX_TLBHI_V) {
2361 tlb->prot |= PAGE_VALID;
2362 if (val & PPC4XX_TLBHI_E) {
2363 /* XXX: TO BE FIXED */
2364 cpu_abort(env,
2365 "Little-endian TLB entries are not supported by now\n");
2367 } else {
2368 tlb->prot &= ~PAGE_VALID;
2370 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2371 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2372 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2373 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2374 tlb->prot & PAGE_READ ? 'r' : '-',
2375 tlb->prot & PAGE_WRITE ? 'w' : '-',
2376 tlb->prot & PAGE_EXEC ? 'x' : '-',
2377 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2378 /* Invalidate new TLB (if valid) */
2379 if (tlb->prot & PAGE_VALID) {
2380 end = tlb->EPN + tlb->size;
2381 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
2382 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2383 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2384 tlb_flush_page(env, page);
2389 void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
2390 target_ulong val)
2392 ppcemb_tlb_t *tlb;
2394 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
2395 val);
2396 entry &= PPC4XX_TLB_ENTRY_MASK;
2397 tlb = &env->tlb.tlbe[entry];
2398 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
2399 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
2400 tlb->prot = PAGE_READ;
2401 if (val & PPC4XX_TLBLO_EX) {
2402 tlb->prot |= PAGE_EXEC;
2404 if (val & PPC4XX_TLBLO_WR) {
2405 tlb->prot |= PAGE_WRITE;
2407 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2408 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2409 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2410 tlb->prot & PAGE_READ ? 'r' : '-',
2411 tlb->prot & PAGE_WRITE ? 'w' : '-',
2412 tlb->prot & PAGE_EXEC ? 'x' : '-',
2413 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2416 target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
2418 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
2421 /* PowerPC 440 TLB management */
2422 void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry,
2423 target_ulong value)
2425 ppcemb_tlb_t *tlb;
2426 target_ulong EPN, RPN, size;
2427 int do_flush_tlbs;
2429 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
2430 __func__, word, (int)entry, value);
2431 do_flush_tlbs = 0;
2432 entry &= 0x3F;
2433 tlb = &env->tlb.tlbe[entry];
2434 switch (word) {
2435 default:
2436 /* Just here to please gcc */
2437 case 0:
2438 EPN = value & 0xFFFFFC00;
2439 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
2440 do_flush_tlbs = 1;
2442 tlb->EPN = EPN;
2443 size = booke_tlb_to_page_size((value >> 4) & 0xF);
2444 if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
2445 do_flush_tlbs = 1;
2447 tlb->size = size;
2448 tlb->attr &= ~0x1;
2449 tlb->attr |= (value >> 8) & 1;
2450 if (value & 0x200) {
2451 tlb->prot |= PAGE_VALID;
2452 } else {
2453 if (tlb->prot & PAGE_VALID) {
2454 tlb->prot &= ~PAGE_VALID;
2455 do_flush_tlbs = 1;
2458 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
2459 if (do_flush_tlbs) {
2460 tlb_flush(env, 1);
2462 break;
2463 case 1:
2464 RPN = value & 0xFFFFFC0F;
2465 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
2466 tlb_flush(env, 1);
2468 tlb->RPN = RPN;
2469 break;
2470 case 2:
2471 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
2472 tlb->prot = tlb->prot & PAGE_VALID;
2473 if (value & 0x1) {
2474 tlb->prot |= PAGE_READ << 4;
2476 if (value & 0x2) {
2477 tlb->prot |= PAGE_WRITE << 4;
2479 if (value & 0x4) {
2480 tlb->prot |= PAGE_EXEC << 4;
2482 if (value & 0x8) {
2483 tlb->prot |= PAGE_READ;
2485 if (value & 0x10) {
2486 tlb->prot |= PAGE_WRITE;
2488 if (value & 0x20) {
2489 tlb->prot |= PAGE_EXEC;
2491 break;
2495 target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word,
2496 target_ulong entry)
2498 ppcemb_tlb_t *tlb;
2499 target_ulong ret;
2500 int size;
2502 entry &= 0x3F;
2503 tlb = &env->tlb.tlbe[entry];
2504 switch (word) {
2505 default:
2506 /* Just here to please gcc */
2507 case 0:
2508 ret = tlb->EPN;
2509 size = booke_page_size_to_tlb(tlb->size);
2510 if (size < 0 || size > 0xF) {
2511 size = 1;
2513 ret |= size << 4;
2514 if (tlb->attr & 0x1) {
2515 ret |= 0x100;
2517 if (tlb->prot & PAGE_VALID) {
2518 ret |= 0x200;
2520 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
2521 env->spr[SPR_440_MMUCR] |= tlb->PID;
2522 break;
2523 case 1:
2524 ret = tlb->RPN;
2525 break;
2526 case 2:
2527 ret = tlb->attr & ~0x1;
2528 if (tlb->prot & (PAGE_READ << 4)) {
2529 ret |= 0x1;
2531 if (tlb->prot & (PAGE_WRITE << 4)) {
2532 ret |= 0x2;
2534 if (tlb->prot & (PAGE_EXEC << 4)) {
2535 ret |= 0x4;
2537 if (tlb->prot & PAGE_READ) {
2538 ret |= 0x8;
2540 if (tlb->prot & PAGE_WRITE) {
2541 ret |= 0x10;
2543 if (tlb->prot & PAGE_EXEC) {
2544 ret |= 0x20;
2546 break;
2548 return ret;
2551 target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address)
2553 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
2556 /* PowerPC BookE 2.06 TLB management */
2558 static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
2560 uint32_t tlbncfg = 0;
2561 int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
2562 int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
2563 int tlb;
2565 tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2566 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
2568 if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
2569 cpu_abort(env, "we don't support HES yet\n");
2572 return booke206_get_tlbm(env, tlb, ea, esel);
2575 void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid)
2577 env->spr[pidn] = pid;
2578 /* changing PIDs mean we're in a different address space now */
2579 tlb_flush(env, 1);
2582 void helper_booke206_tlbwe(CPUPPCState *env)
2584 uint32_t tlbncfg, tlbn;
2585 ppcmas_tlb_t *tlb;
2586 uint32_t size_tlb, size_ps;
2587 target_ulong mask;
2590 switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
2591 case MAS0_WQ_ALWAYS:
2592 /* good to go, write that entry */
2593 break;
2594 case MAS0_WQ_COND:
2595 /* XXX check if reserved */
2596 if (0) {
2597 return;
2599 break;
2600 case MAS0_WQ_CLR_RSRV:
2601 /* XXX clear entry */
2602 return;
2603 default:
2604 /* no idea what to do */
2605 return;
2608 if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
2609 !msr_gs) {
2610 /* XXX we don't support direct LRAT setting yet */
2611 fprintf(stderr, "cpu: don't support LRAT setting yet\n");
2612 return;
2615 tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2616 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
2618 tlb = booke206_cur_tlb(env);
2620 if (!tlb) {
2621 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2622 POWERPC_EXCP_INVAL |
2623 POWERPC_EXCP_INVAL_INVAL);
2626 /* check that we support the targeted size */
2627 size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
2628 size_ps = booke206_tlbnps(env, tlbn);
2629 if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
2630 !(size_ps & (1 << size_tlb))) {
2631 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2632 POWERPC_EXCP_INVAL |
2633 POWERPC_EXCP_INVAL_INVAL);
2636 if (msr_gs) {
2637 cpu_abort(env, "missing HV implementation\n");
2639 tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
2640 env->spr[SPR_BOOKE_MAS3];
2641 tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
2643 /* MAV 1.0 only */
2644 if (!(tlbncfg & TLBnCFG_AVAIL)) {
2645 /* force !AVAIL TLB entries to correct page size */
2646 tlb->mas1 &= ~MAS1_TSIZE_MASK;
2647 /* XXX can be configured in MMUCSR0 */
2648 tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
2651 /* Make a mask from TLB size to discard invalid bits in EPN field */
2652 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2653 /* Add a mask for page attributes */
2654 mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E;
2656 if (!msr_cm) {
2657 /* Executing a tlbwe instruction in 32-bit mode will set
2658 * bits 0:31 of the TLB EPN field to zero.
2660 mask &= 0xffffffff;
2663 tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & mask;
2665 if (!(tlbncfg & TLBnCFG_IPROT)) {
2666 /* no IPROT supported by TLB */
2667 tlb->mas1 &= ~MAS1_IPROT;
2670 if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
2671 tlb_flush_page(env, tlb->mas2 & MAS2_EPN_MASK);
2672 } else {
2673 tlb_flush(env, 1);
2677 static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
2679 int tlbn = booke206_tlbm_to_tlbn(env, tlb);
2680 int way = booke206_tlbm_to_way(env, tlb);
2682 env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
2683 env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
2684 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2686 env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
2687 env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
2688 env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
2689 env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
2692 void helper_booke206_tlbre(CPUPPCState *env)
2694 ppcmas_tlb_t *tlb = NULL;
2696 tlb = booke206_cur_tlb(env);
2697 if (!tlb) {
2698 env->spr[SPR_BOOKE_MAS1] = 0;
2699 } else {
2700 booke206_tlb_to_mas(env, tlb);
2704 void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address)
2706 ppcmas_tlb_t *tlb = NULL;
2707 int i, j;
2708 hwaddr raddr;
2709 uint32_t spid, sas;
2711 spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
2712 sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
2714 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2715 int ways = booke206_tlb_ways(env, i);
2717 for (j = 0; j < ways; j++) {
2718 tlb = booke206_get_tlbm(env, i, address, j);
2720 if (!tlb) {
2721 continue;
2724 if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
2725 continue;
2728 if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
2729 continue;
2732 booke206_tlb_to_mas(env, tlb);
2733 return;
2737 /* no entry found, fill with defaults */
2738 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
2739 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
2740 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
2741 env->spr[SPR_BOOKE_MAS3] = 0;
2742 env->spr[SPR_BOOKE_MAS7] = 0;
2744 if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
2745 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
2748 env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
2749 << MAS1_TID_SHIFT;
2751 /* next victim logic */
2752 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
2753 env->last_way++;
2754 env->last_way &= booke206_tlb_ways(env, 0) - 1;
2755 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2758 static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
2759 uint32_t ea)
2761 int i;
2762 int ways = booke206_tlb_ways(env, tlbn);
2763 target_ulong mask;
2765 for (i = 0; i < ways; i++) {
2766 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
2767 if (!tlb) {
2768 continue;
2770 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2771 if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
2772 !(tlb->mas1 & MAS1_IPROT)) {
2773 tlb->mas1 &= ~MAS1_VALID;
2778 void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address)
2780 if (address & 0x4) {
2781 /* flush all entries */
2782 if (address & 0x8) {
2783 /* flush all of TLB1 */
2784 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
2785 } else {
2786 /* flush all of TLB0 */
2787 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
2789 return;
2792 if (address & 0x8) {
2793 /* flush TLB1 entries */
2794 booke206_invalidate_ea_tlb(env, 1, address);
2795 tlb_flush(env, 1);
2796 } else {
2797 /* flush TLB0 entries */
2798 booke206_invalidate_ea_tlb(env, 0, address);
2799 tlb_flush_page(env, address & MAS2_EPN_MASK);
2803 void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address)
2805 /* XXX missing LPID handling */
2806 booke206_flush_tlb(env, -1, 1);
2809 void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address)
2811 int i, j;
2812 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2813 ppcmas_tlb_t *tlb = env->tlb.tlbm;
2814 int tlb_size;
2816 /* XXX missing LPID handling */
2817 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2818 tlb_size = booke206_tlb_size(env, i);
2819 for (j = 0; j < tlb_size; j++) {
2820 if (!(tlb[j].mas1 & MAS1_IPROT) &&
2821 ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
2822 tlb[j].mas1 &= ~MAS1_VALID;
2825 tlb += booke206_tlb_size(env, i);
2827 tlb_flush(env, 1);
2830 void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
2832 int i, j;
2833 ppcmas_tlb_t *tlb;
2834 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2835 int pid = tid >> MAS6_SPID_SHIFT;
2836 int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
2837 int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
2838 /* XXX check for unsupported isize and raise an invalid opcode then */
2839 int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
2840 /* XXX implement MAV2 handling */
2841 bool mav2 = false;
2843 /* XXX missing LPID handling */
2844 /* flush by pid and ea */
2845 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2846 int ways = booke206_tlb_ways(env, i);
2848 for (j = 0; j < ways; j++) {
2849 tlb = booke206_get_tlbm(env, i, address, j);
2850 if (!tlb) {
2851 continue;
2853 if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
2854 (tlb->mas1 & MAS1_IPROT) ||
2855 ((tlb->mas1 & MAS1_IND) != ind) ||
2856 ((tlb->mas8 & MAS8_TGS) != sgs)) {
2857 continue;
2859 if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
2860 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
2861 continue;
2863 /* XXX e500mc doesn't match SAS, but other cores might */
2864 tlb->mas1 &= ~MAS1_VALID;
2867 tlb_flush(env, 1);
2870 void helper_booke206_tlbflush(CPUPPCState *env, uint32_t type)
2872 int flags = 0;
2874 if (type & 2) {
2875 flags |= BOOKE206_FLUSH_TLB1;
2878 if (type & 4) {
2879 flags |= BOOKE206_FLUSH_TLB0;
2882 booke206_flush_tlb(env, flags, 1);
2884 #endif