target/ppc: improve performance of large BAT invalidations
[qemu/ar7.git] / target / ppc / mmu_helper.c
blob1dbc9acb75efe54ccf3c7e3a98ca8cb64a8c4ac1
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 "qemu/osdep.h"
20 #include "qemu/units.h"
21 #include "cpu.h"
22 #include "exec/helper-proto.h"
23 #include "sysemu/kvm.h"
24 #include "kvm_ppc.h"
25 #include "mmu-hash64.h"
26 #include "mmu-hash32.h"
27 #include "exec/exec-all.h"
28 #include "exec/cpu_ldst.h"
29 #include "exec/log.h"
30 #include "helper_regs.h"
31 #include "qemu/error-report.h"
32 #include "qemu/qemu-print.h"
33 #include "mmu-book3s-v3.h"
34 #include "mmu-radix64.h"
36 /* #define DEBUG_MMU */
37 /* #define DEBUG_BATS */
38 /* #define DEBUG_SOFTWARE_TLB */
39 /* #define DUMP_PAGE_TABLES */
40 /* #define FLUSH_ALL_TLBS */
42 #ifdef DEBUG_MMU
43 # define LOG_MMU_STATE(cpu) log_cpu_state_mask(CPU_LOG_MMU, (cpu), 0)
44 #else
45 # define LOG_MMU_STATE(cpu) do { } while (0)
46 #endif
48 #ifdef DEBUG_SOFTWARE_TLB
49 # define LOG_SWTLB(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
50 #else
51 # define LOG_SWTLB(...) do { } while (0)
52 #endif
54 #ifdef DEBUG_BATS
55 # define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
56 #else
57 # define LOG_BATS(...) do { } while (0)
58 #endif
60 /*****************************************************************************/
61 /* PowerPC MMU emulation */
63 /* Context used internally during MMU translations */
64 typedef struct mmu_ctx_t mmu_ctx_t;
65 struct mmu_ctx_t {
66 hwaddr raddr; /* Real address */
67 hwaddr eaddr; /* Effective address */
68 int prot; /* Protection bits */
69 hwaddr hash[2]; /* Pagetable hash values */
70 target_ulong ptem; /* Virtual segment ID | API */
71 int key; /* Access key */
72 int nx; /* Non-execute area */
75 /* Common routines used by software and hardware TLBs emulation */
76 static inline int pte_is_valid(target_ulong pte0)
78 return pte0 & 0x80000000 ? 1 : 0;
81 static inline void pte_invalidate(target_ulong *pte0)
83 *pte0 &= ~0x80000000;
86 #define PTE_PTEM_MASK 0x7FFFFFBF
87 #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
89 static int pp_check(int key, int pp, int nx)
91 int access;
93 /* Compute access rights */
94 access = 0;
95 if (key == 0) {
96 switch (pp) {
97 case 0x0:
98 case 0x1:
99 case 0x2:
100 access |= PAGE_WRITE;
101 /* No break here */
102 case 0x3:
103 access |= PAGE_READ;
104 break;
106 } else {
107 switch (pp) {
108 case 0x0:
109 access = 0;
110 break;
111 case 0x1:
112 case 0x3:
113 access = PAGE_READ;
114 break;
115 case 0x2:
116 access = PAGE_READ | PAGE_WRITE;
117 break;
120 if (nx == 0) {
121 access |= PAGE_EXEC;
124 return access;
127 static int check_prot(int prot, int rw, int access_type)
129 int ret;
131 if (access_type == ACCESS_CODE) {
132 if (prot & PAGE_EXEC) {
133 ret = 0;
134 } else {
135 ret = -2;
137 } else if (rw) {
138 if (prot & PAGE_WRITE) {
139 ret = 0;
140 } else {
141 ret = -2;
143 } else {
144 if (prot & PAGE_READ) {
145 ret = 0;
146 } else {
147 ret = -2;
151 return ret;
154 static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
155 target_ulong pte1, int h,
156 int rw, int type)
158 target_ulong ptem, mmask;
159 int access, ret, pteh, ptev, pp;
161 ret = -1;
162 /* Check validity and table match */
163 ptev = pte_is_valid(pte0);
164 pteh = (pte0 >> 6) & 1;
165 if (ptev && h == pteh) {
166 /* Check vsid & api */
167 ptem = pte0 & PTE_PTEM_MASK;
168 mmask = PTE_CHECK_MASK;
169 pp = pte1 & 0x00000003;
170 if (ptem == ctx->ptem) {
171 if (ctx->raddr != (hwaddr)-1ULL) {
172 /* all matches should have equal RPN, WIMG & PP */
173 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
174 qemu_log_mask(CPU_LOG_MMU, "Bad RPN/WIMG/PP\n");
175 return -3;
178 /* Compute access rights */
179 access = pp_check(ctx->key, pp, ctx->nx);
180 /* Keep the matching PTE informations */
181 ctx->raddr = pte1;
182 ctx->prot = access;
183 ret = check_prot(ctx->prot, rw, type);
184 if (ret == 0) {
185 /* Access granted */
186 qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
187 } else {
188 /* Access right violation */
189 qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
194 return ret;
197 static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
198 int ret, int rw)
200 int store = 0;
202 /* Update page flags */
203 if (!(*pte1p & 0x00000100)) {
204 /* Update accessed flag */
205 *pte1p |= 0x00000100;
206 store = 1;
208 if (!(*pte1p & 0x00000080)) {
209 if (rw == 1 && ret == 0) {
210 /* Update changed flag */
211 *pte1p |= 0x00000080;
212 store = 1;
213 } else {
214 /* Force page fault for first write access */
215 ctx->prot &= ~PAGE_WRITE;
219 return store;
222 /* Software driven TLB helpers */
223 static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
224 int way, int is_code)
226 int nr;
228 /* Select TLB num in a way from address */
229 nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
230 /* Select TLB way */
231 nr += env->tlb_per_way * way;
232 /* 6xx have separate TLBs for instructions and data */
233 if (is_code && env->id_tlbs == 1) {
234 nr += env->nb_tlb;
237 return nr;
240 static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
242 PowerPCCPU *cpu = ppc_env_get_cpu(env);
243 ppc6xx_tlb_t *tlb;
244 int nr, max;
246 /* LOG_SWTLB("Invalidate all TLBs\n"); */
247 /* Invalidate all defined software TLB */
248 max = env->nb_tlb;
249 if (env->id_tlbs == 1) {
250 max *= 2;
252 for (nr = 0; nr < max; nr++) {
253 tlb = &env->tlb.tlb6[nr];
254 pte_invalidate(&tlb->pte0);
256 tlb_flush(CPU(cpu));
259 static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env,
260 target_ulong eaddr,
261 int is_code, int match_epn)
263 #if !defined(FLUSH_ALL_TLBS)
264 CPUState *cs = CPU(ppc_env_get_cpu(env));
265 ppc6xx_tlb_t *tlb;
266 int way, nr;
268 /* Invalidate ITLB + DTLB, all ways */
269 for (way = 0; way < env->nb_ways; way++) {
270 nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
271 tlb = &env->tlb.tlb6[nr];
272 if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
273 LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
274 env->nb_tlb, eaddr);
275 pte_invalidate(&tlb->pte0);
276 tlb_flush_page(cs, tlb->EPN);
279 #else
280 /* XXX: PowerPC specification say this is valid as well */
281 ppc6xx_tlb_invalidate_all(env);
282 #endif
285 static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
286 target_ulong eaddr, int is_code)
288 ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0);
291 static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way,
292 int is_code, target_ulong pte0, target_ulong pte1)
294 ppc6xx_tlb_t *tlb;
295 int nr;
297 nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
298 tlb = &env->tlb.tlb6[nr];
299 LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
300 " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
301 /* Invalidate any pending reference in QEMU for this virtual address */
302 ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1);
303 tlb->pte0 = pte0;
304 tlb->pte1 = pte1;
305 tlb->EPN = EPN;
306 /* Store last way for LRU mechanism */
307 env->last_way = way;
310 static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
311 target_ulong eaddr, int rw, int access_type)
313 ppc6xx_tlb_t *tlb;
314 int nr, best, way;
315 int ret;
317 best = -1;
318 ret = -1; /* No TLB found */
319 for (way = 0; way < env->nb_ways; way++) {
320 nr = ppc6xx_tlb_getnum(env, eaddr, way,
321 access_type == ACCESS_CODE ? 1 : 0);
322 tlb = &env->tlb.tlb6[nr];
323 /* This test "emulates" the PTE index match for hardware TLBs */
324 if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
325 LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
326 "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
327 pte_is_valid(tlb->pte0) ? "valid" : "inval",
328 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
329 continue;
331 LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
332 TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
333 pte_is_valid(tlb->pte0) ? "valid" : "inval",
334 tlb->EPN, eaddr, tlb->pte1,
335 rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
336 switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1,
337 0, rw, access_type)) {
338 case -3:
339 /* TLB inconsistency */
340 return -1;
341 case -2:
342 /* Access violation */
343 ret = -2;
344 best = nr;
345 break;
346 case -1:
347 default:
348 /* No match */
349 break;
350 case 0:
351 /* access granted */
353 * XXX: we should go on looping to check all TLBs
354 * consistency but we can speed-up the whole thing as
355 * the result would be undefined if TLBs are not
356 * consistent.
358 ret = 0;
359 best = nr;
360 goto done;
363 if (best != -1) {
364 done:
365 LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
366 ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
367 /* Update page flags */
368 pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
371 return ret;
374 /* Perform BAT hit & translation */
375 static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
376 int *validp, int *protp, target_ulong *BATu,
377 target_ulong *BATl)
379 target_ulong bl;
380 int pp, valid, prot;
382 bl = (*BATu & 0x00001FFC) << 15;
383 valid = 0;
384 prot = 0;
385 if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
386 ((msr_pr != 0) && (*BATu & 0x00000001))) {
387 valid = 1;
388 pp = *BATl & 0x00000003;
389 if (pp != 0) {
390 prot = PAGE_READ | PAGE_EXEC;
391 if (pp == 0x2) {
392 prot |= PAGE_WRITE;
396 *blp = bl;
397 *validp = valid;
398 *protp = prot;
401 static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
402 target_ulong virtual, int rw, int type)
404 target_ulong *BATlt, *BATut, *BATu, *BATl;
405 target_ulong BEPIl, BEPIu, bl;
406 int i, valid, prot;
407 int ret = -1;
409 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
410 type == ACCESS_CODE ? 'I' : 'D', virtual);
411 switch (type) {
412 case ACCESS_CODE:
413 BATlt = env->IBAT[1];
414 BATut = env->IBAT[0];
415 break;
416 default:
417 BATlt = env->DBAT[1];
418 BATut = env->DBAT[0];
419 break;
421 for (i = 0; i < env->nb_BATs; i++) {
422 BATu = &BATut[i];
423 BATl = &BATlt[i];
424 BEPIu = *BATu & 0xF0000000;
425 BEPIl = *BATu & 0x0FFE0000;
426 bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
427 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
428 " BATl " TARGET_FMT_lx "\n", __func__,
429 type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
430 if ((virtual & 0xF0000000) == BEPIu &&
431 ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
432 /* BAT matches */
433 if (valid != 0) {
434 /* Get physical address */
435 ctx->raddr = (*BATl & 0xF0000000) |
436 ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
437 (virtual & 0x0001F000);
438 /* Compute access rights */
439 ctx->prot = prot;
440 ret = check_prot(ctx->prot, rw, type);
441 if (ret == 0) {
442 LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
443 i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
444 ctx->prot & PAGE_WRITE ? 'W' : '-');
446 break;
450 if (ret < 0) {
451 #if defined(DEBUG_BATS)
452 if (qemu_log_enabled()) {
453 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
454 for (i = 0; i < 4; i++) {
455 BATu = &BATut[i];
456 BATl = &BATlt[i];
457 BEPIu = *BATu & 0xF0000000;
458 BEPIl = *BATu & 0x0FFE0000;
459 bl = (*BATu & 0x00001FFC) << 15;
460 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
461 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
462 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
463 __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
464 *BATu, *BATl, BEPIu, BEPIl, bl);
467 #endif
469 /* No hit */
470 return ret;
473 /* Perform segment based translation */
474 static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
475 target_ulong eaddr, int rw, int type)
477 PowerPCCPU *cpu = ppc_env_get_cpu(env);
478 hwaddr hash;
479 target_ulong vsid;
480 int ds, pr, target_page_bits;
481 int ret;
482 target_ulong sr, pgidx;
484 pr = msr_pr;
485 ctx->eaddr = eaddr;
487 sr = env->sr[eaddr >> 28];
488 ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
489 ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
490 ds = sr & 0x80000000 ? 1 : 0;
491 ctx->nx = sr & 0x10000000 ? 1 : 0;
492 vsid = sr & 0x00FFFFFF;
493 target_page_bits = TARGET_PAGE_BITS;
494 qemu_log_mask(CPU_LOG_MMU,
495 "Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx
496 " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx
497 " ir=%d dr=%d pr=%d %d t=%d\n",
498 eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
499 (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
500 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
501 hash = vsid ^ pgidx;
502 ctx->ptem = (vsid << 7) | (pgidx >> 10);
504 qemu_log_mask(CPU_LOG_MMU,
505 "pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
506 ctx->key, ds, ctx->nx, vsid);
507 ret = -1;
508 if (!ds) {
509 /* Check if instruction fetch is allowed, if needed */
510 if (type != ACCESS_CODE || ctx->nx == 0) {
511 /* Page address translation */
512 qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
513 " htab_mask " TARGET_FMT_plx
514 " hash " TARGET_FMT_plx "\n",
515 ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
516 ctx->hash[0] = hash;
517 ctx->hash[1] = ~hash;
519 /* Initialize real address with an invalid value */
520 ctx->raddr = (hwaddr)-1ULL;
521 /* Software TLB search */
522 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
523 #if defined(DUMP_PAGE_TABLES)
524 if (qemu_loglevel_mask(CPU_LOG_MMU)) {
525 CPUState *cs = ENV_GET_CPU(env);
526 hwaddr curaddr;
527 uint32_t a0, a1, a2, a3;
529 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
530 "\n", ppc_hash32_hpt_base(cpu),
531 ppc_hash32_hpt_mask(env) + 0x80);
532 for (curaddr = ppc_hash32_hpt_base(cpu);
533 curaddr < (ppc_hash32_hpt_base(cpu)
534 + ppc_hash32_hpt_mask(cpu) + 0x80);
535 curaddr += 16) {
536 a0 = ldl_phys(cs->as, curaddr);
537 a1 = ldl_phys(cs->as, curaddr + 4);
538 a2 = ldl_phys(cs->as, curaddr + 8);
539 a3 = ldl_phys(cs->as, curaddr + 12);
540 if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
541 qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
542 curaddr, a0, a1, a2, a3);
546 #endif
547 } else {
548 qemu_log_mask(CPU_LOG_MMU, "No access allowed\n");
549 ret = -3;
551 } else {
552 target_ulong sr;
554 qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
555 /* Direct-store segment : absolutely *BUGGY* for now */
558 * Direct-store implies a 32-bit MMU.
559 * Check the Segment Register's bus unit ID (BUID).
561 sr = env->sr[eaddr >> 28];
562 if ((sr & 0x1FF00000) >> 20 == 0x07f) {
564 * Memory-forced I/O controller interface access
566 * If T=1 and BUID=x'07F', the 601 performs a memory
567 * access to SR[28-31] LA[4-31], bypassing all protection
568 * mechanisms.
570 ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
571 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
572 return 0;
575 switch (type) {
576 case ACCESS_INT:
577 /* Integer load/store : only access allowed */
578 break;
579 case ACCESS_CODE:
580 /* No code fetch is allowed in direct-store areas */
581 return -4;
582 case ACCESS_FLOAT:
583 /* Floating point load/store */
584 return -4;
585 case ACCESS_RES:
586 /* lwarx, ldarx or srwcx. */
587 return -4;
588 case ACCESS_CACHE:
590 * dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi
592 * Should make the instruction do no-op. As it already do
593 * no-op, it's quite easy :-)
595 ctx->raddr = eaddr;
596 return 0;
597 case ACCESS_EXT:
598 /* eciwx or ecowx */
599 return -4;
600 default:
601 qemu_log_mask(CPU_LOG_MMU, "ERROR: instruction should not need "
602 "address translation\n");
603 return -4;
605 if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
606 ctx->raddr = eaddr;
607 ret = 2;
608 } else {
609 ret = -2;
613 return ret;
616 /* Generic TLB check function for embedded PowerPC implementations */
617 static int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
618 hwaddr *raddrp,
619 target_ulong address, uint32_t pid, int ext,
620 int i)
622 target_ulong mask;
624 /* Check valid flag */
625 if (!(tlb->prot & PAGE_VALID)) {
626 return -1;
628 mask = ~(tlb->size - 1);
629 LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
630 " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
631 mask, (uint32_t)tlb->PID, tlb->prot);
632 /* Check PID */
633 if (tlb->PID != 0 && tlb->PID != pid) {
634 return -1;
636 /* Check effective address */
637 if ((address & mask) != tlb->EPN) {
638 return -1;
640 *raddrp = (tlb->RPN & mask) | (address & ~mask);
641 if (ext) {
642 /* Extend the physical address to 36 bits */
643 *raddrp |= (uint64_t)(tlb->RPN & 0xF) << 32;
646 return 0;
649 /* Generic TLB search function for PowerPC embedded implementations */
650 static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address,
651 uint32_t pid)
653 ppcemb_tlb_t *tlb;
654 hwaddr raddr;
655 int i, ret;
657 /* Default return value is no match */
658 ret = -1;
659 for (i = 0; i < env->nb_tlb; i++) {
660 tlb = &env->tlb.tlbe[i];
661 if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
662 ret = i;
663 break;
667 return ret;
670 /* Helpers specific to PowerPC 40x implementations */
671 static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
673 PowerPCCPU *cpu = ppc_env_get_cpu(env);
674 ppcemb_tlb_t *tlb;
675 int i;
677 for (i = 0; i < env->nb_tlb; i++) {
678 tlb = &env->tlb.tlbe[i];
679 tlb->prot &= ~PAGE_VALID;
681 tlb_flush(CPU(cpu));
684 static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
685 target_ulong address, int rw,
686 int access_type)
688 ppcemb_tlb_t *tlb;
689 hwaddr raddr;
690 int i, ret, zsel, zpr, pr;
692 ret = -1;
693 raddr = (hwaddr)-1ULL;
694 pr = msr_pr;
695 for (i = 0; i < env->nb_tlb; i++) {
696 tlb = &env->tlb.tlbe[i];
697 if (ppcemb_tlb_check(env, tlb, &raddr, address,
698 env->spr[SPR_40x_PID], 0, i) < 0) {
699 continue;
701 zsel = (tlb->attr >> 4) & 0xF;
702 zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
703 LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
704 __func__, i, zsel, zpr, rw, tlb->attr);
705 /* Check execute enable bit */
706 switch (zpr) {
707 case 0x2:
708 if (pr != 0) {
709 goto check_perms;
711 /* No break here */
712 case 0x3:
713 /* All accesses granted */
714 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
715 ret = 0;
716 break;
717 case 0x0:
718 if (pr != 0) {
719 /* Raise Zone protection fault. */
720 env->spr[SPR_40x_ESR] = 1 << 22;
721 ctx->prot = 0;
722 ret = -2;
723 break;
725 /* No break here */
726 case 0x1:
727 check_perms:
728 /* Check from TLB entry */
729 ctx->prot = tlb->prot;
730 ret = check_prot(ctx->prot, rw, access_type);
731 if (ret == -2) {
732 env->spr[SPR_40x_ESR] = 0;
734 break;
736 if (ret >= 0) {
737 ctx->raddr = raddr;
738 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
739 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
740 ret);
741 return 0;
744 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
745 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
747 return ret;
750 void store_40x_sler(CPUPPCState *env, uint32_t val)
752 PowerPCCPU *cpu = ppc_env_get_cpu(env);
754 /* XXX: TO BE FIXED */
755 if (val != 0x00000000) {
756 cpu_abort(CPU(cpu), "Little-endian regions are not supported by now\n");
758 env->spr[SPR_405_SLER] = val;
761 static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
762 hwaddr *raddr, int *prot,
763 target_ulong address, int rw,
764 int access_type, int i)
766 int ret, prot2;
768 if (ppcemb_tlb_check(env, tlb, raddr, address,
769 env->spr[SPR_BOOKE_PID],
770 !env->nb_pids, i) >= 0) {
771 goto found_tlb;
774 if (env->spr[SPR_BOOKE_PID1] &&
775 ppcemb_tlb_check(env, tlb, raddr, address,
776 env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
777 goto found_tlb;
780 if (env->spr[SPR_BOOKE_PID2] &&
781 ppcemb_tlb_check(env, tlb, raddr, address,
782 env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
783 goto found_tlb;
786 LOG_SWTLB("%s: TLB entry not found\n", __func__);
787 return -1;
789 found_tlb:
791 if (msr_pr != 0) {
792 prot2 = tlb->prot & 0xF;
793 } else {
794 prot2 = (tlb->prot >> 4) & 0xF;
797 /* Check the address space */
798 if (access_type == ACCESS_CODE) {
799 if (msr_ir != (tlb->attr & 1)) {
800 LOG_SWTLB("%s: AS doesn't match\n", __func__);
801 return -1;
804 *prot = prot2;
805 if (prot2 & PAGE_EXEC) {
806 LOG_SWTLB("%s: good TLB!\n", __func__);
807 return 0;
810 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
811 ret = -3;
812 } else {
813 if (msr_dr != (tlb->attr & 1)) {
814 LOG_SWTLB("%s: AS doesn't match\n", __func__);
815 return -1;
818 *prot = prot2;
819 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
820 LOG_SWTLB("%s: found TLB!\n", __func__);
821 return 0;
824 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
825 ret = -2;
828 return ret;
831 static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
832 target_ulong address, int rw,
833 int access_type)
835 ppcemb_tlb_t *tlb;
836 hwaddr raddr;
837 int i, ret;
839 ret = -1;
840 raddr = (hwaddr)-1ULL;
841 for (i = 0; i < env->nb_tlb; i++) {
842 tlb = &env->tlb.tlbe[i];
843 ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
844 access_type, i);
845 if (ret != -1) {
846 break;
850 if (ret >= 0) {
851 ctx->raddr = raddr;
852 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
853 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
854 ret);
855 } else {
856 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
857 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
860 return ret;
863 static void booke206_flush_tlb(CPUPPCState *env, int flags,
864 const int check_iprot)
866 PowerPCCPU *cpu = ppc_env_get_cpu(env);
867 int tlb_size;
868 int i, j;
869 ppcmas_tlb_t *tlb = env->tlb.tlbm;
871 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
872 if (flags & (1 << i)) {
873 tlb_size = booke206_tlb_size(env, i);
874 for (j = 0; j < tlb_size; j++) {
875 if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
876 tlb[j].mas1 &= ~MAS1_VALID;
880 tlb += booke206_tlb_size(env, i);
883 tlb_flush(CPU(cpu));
886 static hwaddr booke206_tlb_to_page_size(CPUPPCState *env,
887 ppcmas_tlb_t *tlb)
889 int tlbm_size;
891 tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
893 return 1024ULL << tlbm_size;
896 /* TLB check function for MAS based SoftTLBs */
897 static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
898 hwaddr *raddrp, target_ulong address,
899 uint32_t pid)
901 hwaddr mask;
902 uint32_t tlb_pid;
904 if (!msr_cm) {
905 /* In 32bit mode we can only address 32bit EAs */
906 address = (uint32_t)address;
909 /* Check valid flag */
910 if (!(tlb->mas1 & MAS1_VALID)) {
911 return -1;
914 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
915 LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
916 PRIx64 " mask=0x%" HWADDR_PRIx " MAS7_3=0x%" PRIx64 " MAS8=0x%"
917 PRIx32 "\n", __func__, address, pid, tlb->mas1, tlb->mas2, mask,
918 tlb->mas7_3, tlb->mas8);
920 /* Check PID */
921 tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
922 if (tlb_pid != 0 && tlb_pid != pid) {
923 return -1;
926 /* Check effective address */
927 if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
928 return -1;
931 if (raddrp) {
932 *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
935 return 0;
938 static bool is_epid_mmu(int mmu_idx)
940 return mmu_idx == PPC_TLB_EPID_STORE || mmu_idx == PPC_TLB_EPID_LOAD;
943 static uint32_t mmubooke206_esr(int mmu_idx, bool rw)
945 uint32_t esr = 0;
946 if (rw) {
947 esr |= ESR_ST;
949 if (is_epid_mmu(mmu_idx)) {
950 esr |= ESR_EPID;
952 return esr;
956 * Get EPID register given the mmu_idx. If this is regular load,
957 * construct the EPID access bits from current processor state
959 * Get the effective AS and PR bits and the PID. The PID is returned
960 * only if EPID load is requested, otherwise the caller must detect
961 * the correct EPID. Return true if valid EPID is returned.
963 static bool mmubooke206_get_as(CPUPPCState *env,
964 int mmu_idx, uint32_t *epid_out,
965 bool *as_out, bool *pr_out)
967 if (is_epid_mmu(mmu_idx)) {
968 uint32_t epidr;
969 if (mmu_idx == PPC_TLB_EPID_STORE) {
970 epidr = env->spr[SPR_BOOKE_EPSC];
971 } else {
972 epidr = env->spr[SPR_BOOKE_EPLC];
974 *epid_out = (epidr & EPID_EPID) >> EPID_EPID_SHIFT;
975 *as_out = !!(epidr & EPID_EAS);
976 *pr_out = !!(epidr & EPID_EPR);
977 return true;
978 } else {
979 *as_out = msr_ds;
980 *pr_out = msr_pr;
981 return false;
985 /* Check if the tlb found by hashing really matches */
986 static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
987 hwaddr *raddr, int *prot,
988 target_ulong address, int rw,
989 int access_type, int mmu_idx)
991 int ret;
992 int prot2 = 0;
993 uint32_t epid;
994 bool as, pr;
995 bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr);
997 if (!use_epid) {
998 if (ppcmas_tlb_check(env, tlb, raddr, address,
999 env->spr[SPR_BOOKE_PID]) >= 0) {
1000 goto found_tlb;
1003 if (env->spr[SPR_BOOKE_PID1] &&
1004 ppcmas_tlb_check(env, tlb, raddr, address,
1005 env->spr[SPR_BOOKE_PID1]) >= 0) {
1006 goto found_tlb;
1009 if (env->spr[SPR_BOOKE_PID2] &&
1010 ppcmas_tlb_check(env, tlb, raddr, address,
1011 env->spr[SPR_BOOKE_PID2]) >= 0) {
1012 goto found_tlb;
1014 } else {
1015 if (ppcmas_tlb_check(env, tlb, raddr, address, epid) >= 0) {
1016 goto found_tlb;
1020 LOG_SWTLB("%s: TLB entry not found\n", __func__);
1021 return -1;
1023 found_tlb:
1025 if (pr) {
1026 if (tlb->mas7_3 & MAS3_UR) {
1027 prot2 |= PAGE_READ;
1029 if (tlb->mas7_3 & MAS3_UW) {
1030 prot2 |= PAGE_WRITE;
1032 if (tlb->mas7_3 & MAS3_UX) {
1033 prot2 |= PAGE_EXEC;
1035 } else {
1036 if (tlb->mas7_3 & MAS3_SR) {
1037 prot2 |= PAGE_READ;
1039 if (tlb->mas7_3 & MAS3_SW) {
1040 prot2 |= PAGE_WRITE;
1042 if (tlb->mas7_3 & MAS3_SX) {
1043 prot2 |= PAGE_EXEC;
1047 /* Check the address space and permissions */
1048 if (access_type == ACCESS_CODE) {
1049 /* There is no way to fetch code using epid load */
1050 assert(!use_epid);
1051 if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
1052 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1053 return -1;
1056 *prot = prot2;
1057 if (prot2 & PAGE_EXEC) {
1058 LOG_SWTLB("%s: good TLB!\n", __func__);
1059 return 0;
1062 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
1063 ret = -3;
1064 } else {
1065 if (as != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
1066 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1067 return -1;
1070 *prot = prot2;
1071 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
1072 LOG_SWTLB("%s: found TLB!\n", __func__);
1073 return 0;
1076 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
1077 ret = -2;
1080 return ret;
1083 static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1084 target_ulong address, int rw,
1085 int access_type, int mmu_idx)
1087 ppcmas_tlb_t *tlb;
1088 hwaddr raddr;
1089 int i, j, ret;
1091 ret = -1;
1092 raddr = (hwaddr)-1ULL;
1094 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1095 int ways = booke206_tlb_ways(env, i);
1097 for (j = 0; j < ways; j++) {
1098 tlb = booke206_get_tlbm(env, i, address, j);
1099 if (!tlb) {
1100 continue;
1102 ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
1103 rw, access_type, mmu_idx);
1104 if (ret != -1) {
1105 goto found_tlb;
1110 found_tlb:
1112 if (ret >= 0) {
1113 ctx->raddr = raddr;
1114 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1115 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1116 ret);
1117 } else {
1118 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1119 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1122 return ret;
1125 static const char *book3e_tsize_to_str[32] = {
1126 "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
1127 "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
1128 "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
1129 "1T", "2T"
1132 static void mmubooke_dump_mmu(CPUPPCState *env)
1134 ppcemb_tlb_t *entry;
1135 int i;
1137 if (kvm_enabled() && !env->kvm_sw_tlb) {
1138 qemu_printf("Cannot access KVM TLB\n");
1139 return;
1142 qemu_printf("\nTLB:\n");
1143 qemu_printf("Effective Physical Size PID Prot "
1144 "Attr\n");
1146 entry = &env->tlb.tlbe[0];
1147 for (i = 0; i < env->nb_tlb; i++, entry++) {
1148 hwaddr ea, pa;
1149 target_ulong mask;
1150 uint64_t size = (uint64_t)entry->size;
1151 char size_buf[20];
1153 /* Check valid flag */
1154 if (!(entry->prot & PAGE_VALID)) {
1155 continue;
1158 mask = ~(entry->size - 1);
1159 ea = entry->EPN & mask;
1160 pa = entry->RPN & mask;
1161 /* Extend the physical address to 36 bits */
1162 pa |= (hwaddr)(entry->RPN & 0xF) << 32;
1163 if (size >= 1 * MiB) {
1164 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / MiB);
1165 } else {
1166 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size / KiB);
1168 qemu_printf("0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
1169 (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
1170 entry->prot, entry->attr);
1175 static void mmubooke206_dump_one_tlb(CPUPPCState *env, int tlbn, int offset,
1176 int tlbsize)
1178 ppcmas_tlb_t *entry;
1179 int i;
1181 qemu_printf("\nTLB%d:\n", tlbn);
1182 qemu_printf("Effective Physical Size TID TS SRWX"
1183 " URWX WIMGE U0123\n");
1185 entry = &env->tlb.tlbm[offset];
1186 for (i = 0; i < tlbsize; i++, entry++) {
1187 hwaddr ea, pa, size;
1188 int tsize;
1190 if (!(entry->mas1 & MAS1_VALID)) {
1191 continue;
1194 tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1195 size = 1024ULL << tsize;
1196 ea = entry->mas2 & ~(size - 1);
1197 pa = entry->mas7_3 & ~(size - 1);
1199 qemu_printf("0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c"
1200 "U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
1201 (uint64_t)ea, (uint64_t)pa,
1202 book3e_tsize_to_str[tsize],
1203 (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
1204 (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
1205 entry->mas7_3 & MAS3_SR ? 'R' : '-',
1206 entry->mas7_3 & MAS3_SW ? 'W' : '-',
1207 entry->mas7_3 & MAS3_SX ? 'X' : '-',
1208 entry->mas7_3 & MAS3_UR ? 'R' : '-',
1209 entry->mas7_3 & MAS3_UW ? 'W' : '-',
1210 entry->mas7_3 & MAS3_UX ? 'X' : '-',
1211 entry->mas2 & MAS2_W ? 'W' : '-',
1212 entry->mas2 & MAS2_I ? 'I' : '-',
1213 entry->mas2 & MAS2_M ? 'M' : '-',
1214 entry->mas2 & MAS2_G ? 'G' : '-',
1215 entry->mas2 & MAS2_E ? 'E' : '-',
1216 entry->mas7_3 & MAS3_U0 ? '0' : '-',
1217 entry->mas7_3 & MAS3_U1 ? '1' : '-',
1218 entry->mas7_3 & MAS3_U2 ? '2' : '-',
1219 entry->mas7_3 & MAS3_U3 ? '3' : '-');
1223 static void mmubooke206_dump_mmu(CPUPPCState *env)
1225 int offset = 0;
1226 int i;
1228 if (kvm_enabled() && !env->kvm_sw_tlb) {
1229 qemu_printf("Cannot access KVM TLB\n");
1230 return;
1233 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1234 int size = booke206_tlb_size(env, i);
1236 if (size == 0) {
1237 continue;
1240 mmubooke206_dump_one_tlb(env, i, offset, size);
1241 offset += size;
1245 static void mmu6xx_dump_BATs(CPUPPCState *env, int type)
1247 target_ulong *BATlt, *BATut, *BATu, *BATl;
1248 target_ulong BEPIl, BEPIu, bl;
1249 int i;
1251 switch (type) {
1252 case ACCESS_CODE:
1253 BATlt = env->IBAT[1];
1254 BATut = env->IBAT[0];
1255 break;
1256 default:
1257 BATlt = env->DBAT[1];
1258 BATut = env->DBAT[0];
1259 break;
1262 for (i = 0; i < env->nb_BATs; i++) {
1263 BATu = &BATut[i];
1264 BATl = &BATlt[i];
1265 BEPIu = *BATu & 0xF0000000;
1266 BEPIl = *BATu & 0x0FFE0000;
1267 bl = (*BATu & 0x00001FFC) << 15;
1268 qemu_printf("%s BAT%d BATu " TARGET_FMT_lx
1269 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
1270 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
1271 type == ACCESS_CODE ? "code" : "data", i,
1272 *BATu, *BATl, BEPIu, BEPIl, bl);
1276 static void mmu6xx_dump_mmu(CPUPPCState *env)
1278 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1279 ppc6xx_tlb_t *tlb;
1280 target_ulong sr;
1281 int type, way, entry, i;
1283 qemu_printf("HTAB base = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_base(cpu));
1284 qemu_printf("HTAB mask = 0x%"HWADDR_PRIx"\n", ppc_hash32_hpt_mask(cpu));
1286 qemu_printf("\nSegment registers:\n");
1287 for (i = 0; i < 32; i++) {
1288 sr = env->sr[i];
1289 if (sr & 0x80000000) {
1290 qemu_printf("%02d T=%d Ks=%d Kp=%d BUID=0x%03x "
1291 "CNTLR_SPEC=0x%05x\n", i,
1292 sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1293 sr & 0x20000000 ? 1 : 0, (uint32_t)((sr >> 20) & 0x1FF),
1294 (uint32_t)(sr & 0xFFFFF));
1295 } else {
1296 qemu_printf("%02d T=%d Ks=%d Kp=%d N=%d VSID=0x%06x\n", i,
1297 sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1298 sr & 0x20000000 ? 1 : 0, sr & 0x10000000 ? 1 : 0,
1299 (uint32_t)(sr & 0x00FFFFFF));
1303 qemu_printf("\nBATs:\n");
1304 mmu6xx_dump_BATs(env, ACCESS_INT);
1305 mmu6xx_dump_BATs(env, ACCESS_CODE);
1307 if (env->id_tlbs != 1) {
1308 qemu_printf("ERROR: 6xx MMU should have separated TLB"
1309 " for code and data\n");
1312 qemu_printf("\nTLBs [EPN EPN + SIZE]\n");
1314 for (type = 0; type < 2; type++) {
1315 for (way = 0; way < env->nb_ways; way++) {
1316 for (entry = env->nb_tlb * type + env->tlb_per_way * way;
1317 entry < (env->nb_tlb * type + env->tlb_per_way * (way + 1));
1318 entry++) {
1320 tlb = &env->tlb.tlb6[entry];
1321 qemu_printf("%s TLB %02d/%02d way:%d %s ["
1322 TARGET_FMT_lx " " TARGET_FMT_lx "]\n",
1323 type ? "code" : "data", entry % env->nb_tlb,
1324 env->nb_tlb, way,
1325 pte_is_valid(tlb->pte0) ? "valid" : "inval",
1326 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE);
1332 void dump_mmu(CPUPPCState *env)
1334 switch (env->mmu_model) {
1335 case POWERPC_MMU_BOOKE:
1336 mmubooke_dump_mmu(env);
1337 break;
1338 case POWERPC_MMU_BOOKE206:
1339 mmubooke206_dump_mmu(env);
1340 break;
1341 case POWERPC_MMU_SOFT_6xx:
1342 case POWERPC_MMU_SOFT_74xx:
1343 mmu6xx_dump_mmu(env);
1344 break;
1345 #if defined(TARGET_PPC64)
1346 case POWERPC_MMU_64B:
1347 case POWERPC_MMU_2_03:
1348 case POWERPC_MMU_2_06:
1349 case POWERPC_MMU_2_07:
1350 dump_slb(ppc_env_get_cpu(env));
1351 break;
1352 case POWERPC_MMU_3_00:
1353 if (ppc64_v3_radix(ppc_env_get_cpu(env))) {
1354 /* TODO - Unsupported */
1355 } else {
1356 dump_slb(ppc_env_get_cpu(env));
1357 break;
1359 #endif
1360 default:
1361 qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
1365 static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
1366 target_ulong eaddr, int rw)
1368 int in_plb, ret;
1370 ctx->raddr = eaddr;
1371 ctx->prot = PAGE_READ | PAGE_EXEC;
1372 ret = 0;
1373 switch (env->mmu_model) {
1374 case POWERPC_MMU_SOFT_6xx:
1375 case POWERPC_MMU_SOFT_74xx:
1376 case POWERPC_MMU_SOFT_4xx:
1377 case POWERPC_MMU_REAL:
1378 case POWERPC_MMU_BOOKE:
1379 ctx->prot |= PAGE_WRITE;
1380 break;
1382 case POWERPC_MMU_SOFT_4xx_Z:
1383 if (unlikely(msr_pe != 0)) {
1385 * 403 family add some particular protections, using
1386 * PBL/PBU registers for accesses with no translation.
1388 in_plb =
1389 /* Check PLB validity */
1390 (env->pb[0] < env->pb[1] &&
1391 /* and address in plb area */
1392 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
1393 (env->pb[2] < env->pb[3] &&
1394 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
1395 if (in_plb ^ msr_px) {
1396 /* Access in protected area */
1397 if (rw == 1) {
1398 /* Access is not allowed */
1399 ret = -2;
1401 } else {
1402 /* Read-write access is allowed */
1403 ctx->prot |= PAGE_WRITE;
1406 break;
1408 default:
1409 /* Caller's checks mean we should never get here for other models */
1410 abort();
1411 return -1;
1414 return ret;
1417 static int get_physical_address_wtlb(
1418 CPUPPCState *env, mmu_ctx_t *ctx,
1419 target_ulong eaddr, int rw, int access_type,
1420 int mmu_idx)
1422 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1423 int ret = -1;
1424 bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
1425 || (access_type != ACCESS_CODE && msr_dr == 0);
1427 switch (env->mmu_model) {
1428 case POWERPC_MMU_SOFT_6xx:
1429 case POWERPC_MMU_SOFT_74xx:
1430 if (real_mode) {
1431 ret = check_physical(env, ctx, eaddr, rw);
1432 } else {
1433 /* Try to find a BAT */
1434 if (env->nb_BATs != 0) {
1435 ret = get_bat_6xx_tlb(env, ctx, eaddr, rw, access_type);
1437 if (ret < 0) {
1438 /* We didn't match any BAT entry or don't have BATs */
1439 ret = get_segment_6xx_tlb(env, ctx, eaddr, rw, access_type);
1442 break;
1444 case POWERPC_MMU_SOFT_4xx:
1445 case POWERPC_MMU_SOFT_4xx_Z:
1446 if (real_mode) {
1447 ret = check_physical(env, ctx, eaddr, rw);
1448 } else {
1449 ret = mmu40x_get_physical_address(env, ctx, eaddr,
1450 rw, access_type);
1452 break;
1453 case POWERPC_MMU_BOOKE:
1454 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1455 rw, access_type);
1456 break;
1457 case POWERPC_MMU_BOOKE206:
1458 ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
1459 access_type, mmu_idx);
1460 break;
1461 case POWERPC_MMU_MPC8xx:
1462 /* XXX: TODO */
1463 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1464 break;
1465 case POWERPC_MMU_REAL:
1466 if (real_mode) {
1467 ret = check_physical(env, ctx, eaddr, rw);
1468 } else {
1469 cpu_abort(CPU(cpu),
1470 "PowerPC in real mode do not do any translation\n");
1472 return -1;
1473 default:
1474 cpu_abort(CPU(cpu), "Unknown or invalid MMU model\n");
1475 return -1;
1478 return ret;
1481 static int get_physical_address(
1482 CPUPPCState *env, mmu_ctx_t *ctx,
1483 target_ulong eaddr, int rw, int access_type)
1485 return get_physical_address_wtlb(env, ctx, eaddr, rw, access_type, 0);
1488 hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
1490 PowerPCCPU *cpu = POWERPC_CPU(cs);
1491 CPUPPCState *env = &cpu->env;
1492 mmu_ctx_t ctx;
1494 switch (env->mmu_model) {
1495 #if defined(TARGET_PPC64)
1496 case POWERPC_MMU_64B:
1497 case POWERPC_MMU_2_03:
1498 case POWERPC_MMU_2_06:
1499 case POWERPC_MMU_2_07:
1500 return ppc_hash64_get_phys_page_debug(cpu, addr);
1501 case POWERPC_MMU_3_00:
1502 return ppc64_v3_get_phys_page_debug(cpu, addr);
1503 #endif
1505 case POWERPC_MMU_32B:
1506 case POWERPC_MMU_601:
1507 return ppc_hash32_get_phys_page_debug(cpu, addr);
1509 default:
1513 if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {
1516 * Some MMUs have separate TLBs for code and data. If we only
1517 * try an ACCESS_INT, we may not be able to read instructions
1518 * mapped by code TLBs, so we also try a ACCESS_CODE.
1520 if (unlikely(get_physical_address(env, &ctx, addr, 0,
1521 ACCESS_CODE) != 0)) {
1522 return -1;
1526 return ctx.raddr & TARGET_PAGE_MASK;
1529 static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
1530 int rw, int mmu_idx)
1532 uint32_t epid;
1533 bool as, pr;
1534 uint32_t missed_tid = 0;
1535 bool use_epid = mmubooke206_get_as(env, mmu_idx, &epid, &as, &pr);
1536 if (rw == 2) {
1537 as = msr_ir;
1539 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
1540 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
1541 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
1542 env->spr[SPR_BOOKE_MAS3] = 0;
1543 env->spr[SPR_BOOKE_MAS6] = 0;
1544 env->spr[SPR_BOOKE_MAS7] = 0;
1546 /* AS */
1547 if (as) {
1548 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
1549 env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
1552 env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
1553 env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
1555 if (!use_epid) {
1556 switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
1557 case MAS4_TIDSELD_PID0:
1558 missed_tid = env->spr[SPR_BOOKE_PID];
1559 break;
1560 case MAS4_TIDSELD_PID1:
1561 missed_tid = env->spr[SPR_BOOKE_PID1];
1562 break;
1563 case MAS4_TIDSELD_PID2:
1564 missed_tid = env->spr[SPR_BOOKE_PID2];
1565 break;
1567 env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
1568 } else {
1569 missed_tid = epid;
1570 env->spr[SPR_BOOKE_MAS6] |= missed_tid << 16;
1572 env->spr[SPR_BOOKE_MAS1] |= (missed_tid << MAS1_TID_SHIFT);
1575 /* next victim logic */
1576 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
1577 env->last_way++;
1578 env->last_way &= booke206_tlb_ways(env, 0) - 1;
1579 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
1582 /* Perform address translation */
1583 static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
1584 int rw, int mmu_idx)
1586 CPUState *cs = CPU(ppc_env_get_cpu(env));
1587 PowerPCCPU *cpu = POWERPC_CPU(cs);
1588 mmu_ctx_t ctx;
1589 int access_type;
1590 int ret = 0;
1592 if (rw == 2) {
1593 /* code access */
1594 rw = 0;
1595 access_type = ACCESS_CODE;
1596 } else {
1597 /* data access */
1598 access_type = env->access_type;
1600 ret = get_physical_address_wtlb(env, &ctx, address, rw,
1601 access_type, mmu_idx);
1602 if (ret == 0) {
1603 tlb_set_page(cs, address & TARGET_PAGE_MASK,
1604 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
1605 mmu_idx, TARGET_PAGE_SIZE);
1606 ret = 0;
1607 } else if (ret < 0) {
1608 LOG_MMU_STATE(cs);
1609 if (access_type == ACCESS_CODE) {
1610 switch (ret) {
1611 case -1:
1612 /* No matches in page tables or TLB */
1613 switch (env->mmu_model) {
1614 case POWERPC_MMU_SOFT_6xx:
1615 cs->exception_index = POWERPC_EXCP_IFTLB;
1616 env->error_code = 1 << 18;
1617 env->spr[SPR_IMISS] = address;
1618 env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
1619 goto tlb_miss;
1620 case POWERPC_MMU_SOFT_74xx:
1621 cs->exception_index = POWERPC_EXCP_IFTLB;
1622 goto tlb_miss_74xx;
1623 case POWERPC_MMU_SOFT_4xx:
1624 case POWERPC_MMU_SOFT_4xx_Z:
1625 cs->exception_index = POWERPC_EXCP_ITLB;
1626 env->error_code = 0;
1627 env->spr[SPR_40x_DEAR] = address;
1628 env->spr[SPR_40x_ESR] = 0x00000000;
1629 break;
1630 case POWERPC_MMU_BOOKE206:
1631 booke206_update_mas_tlb_miss(env, address, 2, mmu_idx);
1632 /* fall through */
1633 case POWERPC_MMU_BOOKE:
1634 cs->exception_index = POWERPC_EXCP_ITLB;
1635 env->error_code = 0;
1636 env->spr[SPR_BOOKE_DEAR] = address;
1637 env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, 0);
1638 return -1;
1639 case POWERPC_MMU_MPC8xx:
1640 /* XXX: TODO */
1641 cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1642 break;
1643 case POWERPC_MMU_REAL:
1644 cpu_abort(cs, "PowerPC in real mode should never raise "
1645 "any MMU exceptions\n");
1646 return -1;
1647 default:
1648 cpu_abort(cs, "Unknown or invalid MMU model\n");
1649 return -1;
1651 break;
1652 case -2:
1653 /* Access rights violation */
1654 cs->exception_index = POWERPC_EXCP_ISI;
1655 env->error_code = 0x08000000;
1656 break;
1657 case -3:
1658 /* No execute protection violation */
1659 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1660 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1661 env->spr[SPR_BOOKE_ESR] = 0x00000000;
1663 cs->exception_index = POWERPC_EXCP_ISI;
1664 env->error_code = 0x10000000;
1665 break;
1666 case -4:
1667 /* Direct store exception */
1668 /* No code fetch is allowed in direct-store areas */
1669 cs->exception_index = POWERPC_EXCP_ISI;
1670 env->error_code = 0x10000000;
1671 break;
1673 } else {
1674 switch (ret) {
1675 case -1:
1676 /* No matches in page tables or TLB */
1677 switch (env->mmu_model) {
1678 case POWERPC_MMU_SOFT_6xx:
1679 if (rw == 1) {
1680 cs->exception_index = POWERPC_EXCP_DSTLB;
1681 env->error_code = 1 << 16;
1682 } else {
1683 cs->exception_index = POWERPC_EXCP_DLTLB;
1684 env->error_code = 0;
1686 env->spr[SPR_DMISS] = address;
1687 env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
1688 tlb_miss:
1689 env->error_code |= ctx.key << 19;
1690 env->spr[SPR_HASH1] = ppc_hash32_hpt_base(cpu) +
1691 get_pteg_offset32(cpu, ctx.hash[0]);
1692 env->spr[SPR_HASH2] = ppc_hash32_hpt_base(cpu) +
1693 get_pteg_offset32(cpu, ctx.hash[1]);
1694 break;
1695 case POWERPC_MMU_SOFT_74xx:
1696 if (rw == 1) {
1697 cs->exception_index = POWERPC_EXCP_DSTLB;
1698 } else {
1699 cs->exception_index = POWERPC_EXCP_DLTLB;
1701 tlb_miss_74xx:
1702 /* Implement LRU algorithm */
1703 env->error_code = ctx.key << 19;
1704 env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
1705 ((env->last_way + 1) & (env->nb_ways - 1));
1706 env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
1707 break;
1708 case POWERPC_MMU_SOFT_4xx:
1709 case POWERPC_MMU_SOFT_4xx_Z:
1710 cs->exception_index = POWERPC_EXCP_DTLB;
1711 env->error_code = 0;
1712 env->spr[SPR_40x_DEAR] = address;
1713 if (rw) {
1714 env->spr[SPR_40x_ESR] = 0x00800000;
1715 } else {
1716 env->spr[SPR_40x_ESR] = 0x00000000;
1718 break;
1719 case POWERPC_MMU_MPC8xx:
1720 /* XXX: TODO */
1721 cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1722 break;
1723 case POWERPC_MMU_BOOKE206:
1724 booke206_update_mas_tlb_miss(env, address, rw, mmu_idx);
1725 /* fall through */
1726 case POWERPC_MMU_BOOKE:
1727 cs->exception_index = POWERPC_EXCP_DTLB;
1728 env->error_code = 0;
1729 env->spr[SPR_BOOKE_DEAR] = address;
1730 env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, rw);
1731 return -1;
1732 case POWERPC_MMU_REAL:
1733 cpu_abort(cs, "PowerPC in real mode should never raise "
1734 "any MMU exceptions\n");
1735 return -1;
1736 default:
1737 cpu_abort(cs, "Unknown or invalid MMU model\n");
1738 return -1;
1740 break;
1741 case -2:
1742 /* Access rights violation */
1743 cs->exception_index = POWERPC_EXCP_DSI;
1744 env->error_code = 0;
1745 if (env->mmu_model == POWERPC_MMU_SOFT_4xx
1746 || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
1747 env->spr[SPR_40x_DEAR] = address;
1748 if (rw) {
1749 env->spr[SPR_40x_ESR] |= 0x00800000;
1751 } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1752 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1753 env->spr[SPR_BOOKE_DEAR] = address;
1754 env->spr[SPR_BOOKE_ESR] = mmubooke206_esr(mmu_idx, rw);
1755 } else {
1756 env->spr[SPR_DAR] = address;
1757 if (rw == 1) {
1758 env->spr[SPR_DSISR] = 0x0A000000;
1759 } else {
1760 env->spr[SPR_DSISR] = 0x08000000;
1763 break;
1764 case -4:
1765 /* Direct store exception */
1766 switch (access_type) {
1767 case ACCESS_FLOAT:
1768 /* Floating point load/store */
1769 cs->exception_index = POWERPC_EXCP_ALIGN;
1770 env->error_code = POWERPC_EXCP_ALIGN_FP;
1771 env->spr[SPR_DAR] = address;
1772 break;
1773 case ACCESS_RES:
1774 /* lwarx, ldarx or stwcx. */
1775 cs->exception_index = POWERPC_EXCP_DSI;
1776 env->error_code = 0;
1777 env->spr[SPR_DAR] = address;
1778 if (rw == 1) {
1779 env->spr[SPR_DSISR] = 0x06000000;
1780 } else {
1781 env->spr[SPR_DSISR] = 0x04000000;
1783 break;
1784 case ACCESS_EXT:
1785 /* eciwx or ecowx */
1786 cs->exception_index = POWERPC_EXCP_DSI;
1787 env->error_code = 0;
1788 env->spr[SPR_DAR] = address;
1789 if (rw == 1) {
1790 env->spr[SPR_DSISR] = 0x06100000;
1791 } else {
1792 env->spr[SPR_DSISR] = 0x04100000;
1794 break;
1795 default:
1796 printf("DSI: invalid exception (%d)\n", ret);
1797 cs->exception_index = POWERPC_EXCP_PROGRAM;
1798 env->error_code =
1799 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
1800 env->spr[SPR_DAR] = address;
1801 break;
1803 break;
1806 ret = 1;
1809 return ret;
1812 /*****************************************************************************/
1813 /* BATs management */
1814 #if !defined(FLUSH_ALL_TLBS)
1815 static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
1816 target_ulong mask)
1818 CPUState *cs = CPU(ppc_env_get_cpu(env));
1819 target_ulong base, end, page;
1821 base = BATu & ~0x0001FFFF;
1822 end = base + mask + 0x00020000;
1823 if (((end - base) >> TARGET_PAGE_BITS) > 1024) {
1824 /* Flushing 1024 4K pages is slower than a complete flush */
1825 LOG_BATS("Flush all BATs\n");
1826 tlb_flush(CPU(cs));
1827 LOG_BATS("Flush done\n");
1828 return;
1830 LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
1831 TARGET_FMT_lx ")\n", base, end, mask);
1832 for (page = base; page != end; page += TARGET_PAGE_SIZE) {
1833 tlb_flush_page(cs, page);
1835 LOG_BATS("Flush done\n");
1837 #endif
1839 static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
1840 target_ulong value)
1842 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
1843 nr, ul == 0 ? 'u' : 'l', value, env->nip);
1846 void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1848 target_ulong mask;
1849 #if defined(FLUSH_ALL_TLBS)
1850 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1851 #endif
1853 dump_store_bat(env, 'I', 0, nr, value);
1854 if (env->IBAT[0][nr] != value) {
1855 mask = (value << 15) & 0x0FFE0000UL;
1856 #if !defined(FLUSH_ALL_TLBS)
1857 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1858 #endif
1860 * When storing valid upper BAT, mask BEPI and BRPN and
1861 * invalidate all TLBs covered by this BAT
1863 mask = (value << 15) & 0x0FFE0000UL;
1864 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1865 (value & ~0x0001FFFFUL & ~mask);
1866 env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
1867 (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
1868 #if !defined(FLUSH_ALL_TLBS)
1869 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1870 #else
1871 tlb_flush(CPU(cpu));
1872 #endif
1876 void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1878 dump_store_bat(env, 'I', 1, nr, value);
1879 env->IBAT[1][nr] = value;
1882 void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1884 target_ulong mask;
1885 #if defined(FLUSH_ALL_TLBS)
1886 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1887 #endif
1889 dump_store_bat(env, 'D', 0, nr, value);
1890 if (env->DBAT[0][nr] != value) {
1892 * When storing valid upper BAT, mask BEPI and BRPN and
1893 * invalidate all TLBs covered by this BAT
1895 mask = (value << 15) & 0x0FFE0000UL;
1896 #if !defined(FLUSH_ALL_TLBS)
1897 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1898 #endif
1899 mask = (value << 15) & 0x0FFE0000UL;
1900 env->DBAT[0][nr] = (value & 0x00001FFFUL) |
1901 (value & ~0x0001FFFFUL & ~mask);
1902 env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
1903 (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
1904 #if !defined(FLUSH_ALL_TLBS)
1905 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1906 #else
1907 tlb_flush(CPU(cpu));
1908 #endif
1912 void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1914 dump_store_bat(env, 'D', 1, nr, value);
1915 env->DBAT[1][nr] = value;
1918 void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value)
1920 target_ulong mask;
1921 #if defined(FLUSH_ALL_TLBS)
1922 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1923 int do_inval;
1924 #endif
1926 dump_store_bat(env, 'I', 0, nr, value);
1927 if (env->IBAT[0][nr] != value) {
1928 #if defined(FLUSH_ALL_TLBS)
1929 do_inval = 0;
1930 #endif
1931 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1932 if (env->IBAT[1][nr] & 0x40) {
1933 /* Invalidate BAT only if it is valid */
1934 #if !defined(FLUSH_ALL_TLBS)
1935 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1936 #else
1937 do_inval = 1;
1938 #endif
1941 * When storing valid upper BAT, mask BEPI and BRPN and
1942 * invalidate all TLBs covered by this BAT
1944 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1945 (value & ~0x0001FFFFUL & ~mask);
1946 env->DBAT[0][nr] = env->IBAT[0][nr];
1947 if (env->IBAT[1][nr] & 0x40) {
1948 #if !defined(FLUSH_ALL_TLBS)
1949 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1950 #else
1951 do_inval = 1;
1952 #endif
1954 #if defined(FLUSH_ALL_TLBS)
1955 if (do_inval) {
1956 tlb_flush(CPU(cpu));
1958 #endif
1962 void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value)
1964 #if !defined(FLUSH_ALL_TLBS)
1965 target_ulong mask;
1966 #else
1967 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1968 int do_inval;
1969 #endif
1971 dump_store_bat(env, 'I', 1, nr, value);
1972 if (env->IBAT[1][nr] != value) {
1973 #if defined(FLUSH_ALL_TLBS)
1974 do_inval = 0;
1975 #endif
1976 if (env->IBAT[1][nr] & 0x40) {
1977 #if !defined(FLUSH_ALL_TLBS)
1978 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1979 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1980 #else
1981 do_inval = 1;
1982 #endif
1984 if (value & 0x40) {
1985 #if !defined(FLUSH_ALL_TLBS)
1986 mask = (value << 17) & 0x0FFE0000UL;
1987 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1988 #else
1989 do_inval = 1;
1990 #endif
1992 env->IBAT[1][nr] = value;
1993 env->DBAT[1][nr] = value;
1994 #if defined(FLUSH_ALL_TLBS)
1995 if (do_inval) {
1996 tlb_flush(CPU(cpu));
1998 #endif
2002 /*****************************************************************************/
2003 /* TLB management */
2004 void ppc_tlb_invalidate_all(CPUPPCState *env)
2006 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2008 #if defined(TARGET_PPC64)
2009 if (env->mmu_model & POWERPC_MMU_64) {
2010 env->tlb_need_flush = 0;
2011 tlb_flush(CPU(cpu));
2012 } else
2013 #endif /* defined(TARGET_PPC64) */
2014 switch (env->mmu_model) {
2015 case POWERPC_MMU_SOFT_6xx:
2016 case POWERPC_MMU_SOFT_74xx:
2017 ppc6xx_tlb_invalidate_all(env);
2018 break;
2019 case POWERPC_MMU_SOFT_4xx:
2020 case POWERPC_MMU_SOFT_4xx_Z:
2021 ppc4xx_tlb_invalidate_all(env);
2022 break;
2023 case POWERPC_MMU_REAL:
2024 cpu_abort(CPU(cpu), "No TLB for PowerPC 4xx in real mode\n");
2025 break;
2026 case POWERPC_MMU_MPC8xx:
2027 /* XXX: TODO */
2028 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
2029 break;
2030 case POWERPC_MMU_BOOKE:
2031 tlb_flush(CPU(cpu));
2032 break;
2033 case POWERPC_MMU_BOOKE206:
2034 booke206_flush_tlb(env, -1, 0);
2035 break;
2036 case POWERPC_MMU_32B:
2037 case POWERPC_MMU_601:
2038 env->tlb_need_flush = 0;
2039 tlb_flush(CPU(cpu));
2040 break;
2041 default:
2042 /* XXX: TODO */
2043 cpu_abort(CPU(cpu), "Unknown MMU model %x\n", env->mmu_model);
2044 break;
2048 void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
2050 #if !defined(FLUSH_ALL_TLBS)
2051 addr &= TARGET_PAGE_MASK;
2052 #if defined(TARGET_PPC64)
2053 if (env->mmu_model & POWERPC_MMU_64) {
2054 /* tlbie invalidate TLBs for all segments */
2056 * XXX: given the fact that there are too many segments to invalidate,
2057 * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
2058 * we just invalidate all TLBs
2060 env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
2061 } else
2062 #endif /* defined(TARGET_PPC64) */
2063 switch (env->mmu_model) {
2064 case POWERPC_MMU_SOFT_6xx:
2065 case POWERPC_MMU_SOFT_74xx:
2066 ppc6xx_tlb_invalidate_virt(env, addr, 0);
2067 if (env->id_tlbs == 1) {
2068 ppc6xx_tlb_invalidate_virt(env, addr, 1);
2070 break;
2071 case POWERPC_MMU_32B:
2072 case POWERPC_MMU_601:
2074 * Actual CPUs invalidate entire congruence classes based on
2075 * the geometry of their TLBs and some OSes take that into
2076 * account, we just mark the TLB to be flushed later (context
2077 * synchronizing event or sync instruction on 32-bit).
2079 env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
2080 break;
2081 default:
2082 /* Should never reach here with other MMU models */
2083 assert(0);
2085 #else
2086 ppc_tlb_invalidate_all(env);
2087 #endif
2090 /*****************************************************************************/
2091 /* Special registers manipulation */
2092 void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
2094 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2095 qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
2096 assert(!cpu->vhyp);
2097 #if defined(TARGET_PPC64)
2098 if (env->mmu_model & POWERPC_MMU_64) {
2099 target_ulong sdr_mask = SDR_64_HTABORG | SDR_64_HTABSIZE;
2100 target_ulong htabsize = value & SDR_64_HTABSIZE;
2102 if (value & ~sdr_mask) {
2103 error_report("Invalid bits 0x"TARGET_FMT_lx" set in SDR1",
2104 value & ~sdr_mask);
2105 value &= sdr_mask;
2107 if (htabsize > 28) {
2108 error_report("Invalid HTABSIZE 0x" TARGET_FMT_lx" stored in SDR1",
2109 htabsize);
2110 return;
2113 #endif /* defined(TARGET_PPC64) */
2114 /* FIXME: Should check for valid HTABMASK values in 32-bit case */
2115 env->spr[SPR_SDR1] = value;
2118 #if defined(TARGET_PPC64)
2119 void ppc_store_ptcr(CPUPPCState *env, target_ulong value)
2121 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2122 target_ulong ptcr_mask = PTCR_PATB | PTCR_PATS;
2123 target_ulong patbsize = value & PTCR_PATS;
2125 qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
2127 assert(!cpu->vhyp);
2128 assert(env->mmu_model & POWERPC_MMU_3_00);
2130 if (value & ~ptcr_mask) {
2131 error_report("Invalid bits 0x"TARGET_FMT_lx" set in PTCR",
2132 value & ~ptcr_mask);
2133 value &= ptcr_mask;
2136 if (patbsize > 24) {
2137 error_report("Invalid Partition Table size 0x" TARGET_FMT_lx
2138 " stored in PTCR", patbsize);
2139 return;
2142 env->spr[SPR_PTCR] = value;
2145 #endif /* defined(TARGET_PPC64) */
2147 /* Segment registers load and store */
2148 target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
2150 #if defined(TARGET_PPC64)
2151 if (env->mmu_model & POWERPC_MMU_64) {
2152 /* XXX */
2153 return 0;
2155 #endif
2156 return env->sr[sr_num];
2159 void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
2161 qemu_log_mask(CPU_LOG_MMU,
2162 "%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
2163 (int)srnum, value, env->sr[srnum]);
2164 #if defined(TARGET_PPC64)
2165 if (env->mmu_model & POWERPC_MMU_64) {
2166 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2167 uint64_t esid, vsid;
2169 /* ESID = srnum */
2170 esid = ((uint64_t)(srnum & 0xf) << 28) | SLB_ESID_V;
2172 /* VSID = VSID */
2173 vsid = (value & 0xfffffff) << 12;
2174 /* flags = flags */
2175 vsid |= ((value >> 27) & 0xf) << 8;
2177 ppc_store_slb(cpu, srnum, esid, vsid);
2178 } else
2179 #endif
2180 if (env->sr[srnum] != value) {
2181 env->sr[srnum] = value;
2183 * Invalidating 256MB of virtual memory in 4kB pages is way
2184 * longer than flusing the whole TLB.
2186 #if !defined(FLUSH_ALL_TLBS) && 0
2188 target_ulong page, end;
2189 /* Invalidate 256 MB of virtual memory */
2190 page = (16 << 20) * srnum;
2191 end = page + (16 << 20);
2192 for (; page != end; page += TARGET_PAGE_SIZE) {
2193 tlb_flush_page(CPU(cpu), page);
2196 #else
2197 env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
2198 #endif
2202 /* TLB management */
2203 void helper_tlbia(CPUPPCState *env)
2205 ppc_tlb_invalidate_all(env);
2208 void helper_tlbie(CPUPPCState *env, target_ulong addr)
2210 ppc_tlb_invalidate_one(env, addr);
2213 void helper_tlbiva(CPUPPCState *env, target_ulong addr)
2215 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2217 /* tlbiva instruction only exists on BookE */
2218 assert(env->mmu_model == POWERPC_MMU_BOOKE);
2219 /* XXX: TODO */
2220 cpu_abort(CPU(cpu), "BookE MMU model is not implemented\n");
2223 /* Software driven TLBs management */
2224 /* PowerPC 602/603 software TLB load instructions helpers */
2225 static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2227 target_ulong RPN, CMP, EPN;
2228 int way;
2230 RPN = env->spr[SPR_RPA];
2231 if (is_code) {
2232 CMP = env->spr[SPR_ICMP];
2233 EPN = env->spr[SPR_IMISS];
2234 } else {
2235 CMP = env->spr[SPR_DCMP];
2236 EPN = env->spr[SPR_DMISS];
2238 way = (env->spr[SPR_SRR1] >> 17) & 1;
2239 (void)EPN; /* avoid a compiler warning */
2240 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2241 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2242 RPN, way);
2243 /* Store this TLB */
2244 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2245 way, is_code, CMP, RPN);
2248 void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN)
2250 do_6xx_tlb(env, EPN, 0);
2253 void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
2255 do_6xx_tlb(env, EPN, 1);
2258 /* PowerPC 74xx software TLB load instructions helpers */
2259 static void do_74xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2261 target_ulong RPN, CMP, EPN;
2262 int way;
2264 RPN = env->spr[SPR_PTELO];
2265 CMP = env->spr[SPR_PTEHI];
2266 EPN = env->spr[SPR_TLBMISS] & ~0x3;
2267 way = env->spr[SPR_TLBMISS] & 0x3;
2268 (void)EPN; /* avoid a compiler warning */
2269 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2270 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2271 RPN, way);
2272 /* Store this TLB */
2273 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2274 way, is_code, CMP, RPN);
2277 void helper_74xx_tlbd(CPUPPCState *env, target_ulong EPN)
2279 do_74xx_tlb(env, EPN, 0);
2282 void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN)
2284 do_74xx_tlb(env, EPN, 1);
2287 /*****************************************************************************/
2288 /* PowerPC 601 specific instructions (POWER bridge) */
2290 target_ulong helper_rac(CPUPPCState *env, target_ulong addr)
2292 mmu_ctx_t ctx;
2293 int nb_BATs;
2294 target_ulong ret = 0;
2297 * We don't have to generate many instances of this instruction,
2298 * as rac is supervisor only.
2300 * XXX: FIX THIS: Pretend we have no BAT
2302 nb_BATs = env->nb_BATs;
2303 env->nb_BATs = 0;
2304 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
2305 ret = ctx.raddr;
2307 env->nb_BATs = nb_BATs;
2308 return ret;
2311 static inline target_ulong booke_tlb_to_page_size(int size)
2313 return 1024 << (2 * size);
2316 static inline int booke_page_size_to_tlb(target_ulong page_size)
2318 int size;
2320 switch (page_size) {
2321 case 0x00000400UL:
2322 size = 0x0;
2323 break;
2324 case 0x00001000UL:
2325 size = 0x1;
2326 break;
2327 case 0x00004000UL:
2328 size = 0x2;
2329 break;
2330 case 0x00010000UL:
2331 size = 0x3;
2332 break;
2333 case 0x00040000UL:
2334 size = 0x4;
2335 break;
2336 case 0x00100000UL:
2337 size = 0x5;
2338 break;
2339 case 0x00400000UL:
2340 size = 0x6;
2341 break;
2342 case 0x01000000UL:
2343 size = 0x7;
2344 break;
2345 case 0x04000000UL:
2346 size = 0x8;
2347 break;
2348 case 0x10000000UL:
2349 size = 0x9;
2350 break;
2351 case 0x40000000UL:
2352 size = 0xA;
2353 break;
2354 #if defined(TARGET_PPC64)
2355 case 0x000100000000ULL:
2356 size = 0xB;
2357 break;
2358 case 0x000400000000ULL:
2359 size = 0xC;
2360 break;
2361 case 0x001000000000ULL:
2362 size = 0xD;
2363 break;
2364 case 0x004000000000ULL:
2365 size = 0xE;
2366 break;
2367 case 0x010000000000ULL:
2368 size = 0xF;
2369 break;
2370 #endif
2371 default:
2372 size = -1;
2373 break;
2376 return size;
2379 /* Helpers for 4xx TLB management */
2380 #define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
2382 #define PPC4XX_TLBHI_V 0x00000040
2383 #define PPC4XX_TLBHI_E 0x00000020
2384 #define PPC4XX_TLBHI_SIZE_MIN 0
2385 #define PPC4XX_TLBHI_SIZE_MAX 7
2386 #define PPC4XX_TLBHI_SIZE_DEFAULT 1
2387 #define PPC4XX_TLBHI_SIZE_SHIFT 7
2388 #define PPC4XX_TLBHI_SIZE_MASK 0x00000007
2390 #define PPC4XX_TLBLO_EX 0x00000200
2391 #define PPC4XX_TLBLO_WR 0x00000100
2392 #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
2393 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
2395 target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
2397 ppcemb_tlb_t *tlb;
2398 target_ulong ret;
2399 int size;
2401 entry &= PPC4XX_TLB_ENTRY_MASK;
2402 tlb = &env->tlb.tlbe[entry];
2403 ret = tlb->EPN;
2404 if (tlb->prot & PAGE_VALID) {
2405 ret |= PPC4XX_TLBHI_V;
2407 size = booke_page_size_to_tlb(tlb->size);
2408 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
2409 size = PPC4XX_TLBHI_SIZE_DEFAULT;
2411 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
2412 env->spr[SPR_40x_PID] = tlb->PID;
2413 return ret;
2416 target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry)
2418 ppcemb_tlb_t *tlb;
2419 target_ulong ret;
2421 entry &= PPC4XX_TLB_ENTRY_MASK;
2422 tlb = &env->tlb.tlbe[entry];
2423 ret = tlb->RPN;
2424 if (tlb->prot & PAGE_EXEC) {
2425 ret |= PPC4XX_TLBLO_EX;
2427 if (tlb->prot & PAGE_WRITE) {
2428 ret |= PPC4XX_TLBLO_WR;
2430 return ret;
2433 void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
2434 target_ulong val)
2436 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2437 CPUState *cs = CPU(cpu);
2438 ppcemb_tlb_t *tlb;
2439 target_ulong page, end;
2441 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
2442 val);
2443 entry &= PPC4XX_TLB_ENTRY_MASK;
2444 tlb = &env->tlb.tlbe[entry];
2445 /* Invalidate previous TLB (if it's valid) */
2446 if (tlb->prot & PAGE_VALID) {
2447 end = tlb->EPN + tlb->size;
2448 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
2449 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2450 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2451 tlb_flush_page(cs, page);
2454 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
2455 & PPC4XX_TLBHI_SIZE_MASK);
2457 * We cannot handle TLB size < TARGET_PAGE_SIZE.
2458 * If this ever occurs, we should implement TARGET_PAGE_BITS_VARY
2460 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
2461 cpu_abort(cs, "TLB size " TARGET_FMT_lu " < %u "
2462 "are not supported (%d)\n"
2463 "Please implement TARGET_PAGE_BITS_VARY\n",
2464 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
2466 tlb->EPN = val & ~(tlb->size - 1);
2467 if (val & PPC4XX_TLBHI_V) {
2468 tlb->prot |= PAGE_VALID;
2469 if (val & PPC4XX_TLBHI_E) {
2470 /* XXX: TO BE FIXED */
2471 cpu_abort(cs,
2472 "Little-endian TLB entries are not supported by now\n");
2474 } else {
2475 tlb->prot &= ~PAGE_VALID;
2477 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2478 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2479 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2480 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2481 tlb->prot & PAGE_READ ? 'r' : '-',
2482 tlb->prot & PAGE_WRITE ? 'w' : '-',
2483 tlb->prot & PAGE_EXEC ? 'x' : '-',
2484 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2485 /* Invalidate new TLB (if valid) */
2486 if (tlb->prot & PAGE_VALID) {
2487 end = tlb->EPN + tlb->size;
2488 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
2489 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2490 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2491 tlb_flush_page(cs, page);
2496 void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
2497 target_ulong val)
2499 ppcemb_tlb_t *tlb;
2501 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
2502 val);
2503 entry &= PPC4XX_TLB_ENTRY_MASK;
2504 tlb = &env->tlb.tlbe[entry];
2505 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
2506 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
2507 tlb->prot = PAGE_READ;
2508 if (val & PPC4XX_TLBLO_EX) {
2509 tlb->prot |= PAGE_EXEC;
2511 if (val & PPC4XX_TLBLO_WR) {
2512 tlb->prot |= PAGE_WRITE;
2514 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2515 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2516 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2517 tlb->prot & PAGE_READ ? 'r' : '-',
2518 tlb->prot & PAGE_WRITE ? 'w' : '-',
2519 tlb->prot & PAGE_EXEC ? 'x' : '-',
2520 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2523 target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
2525 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
2528 /* PowerPC 440 TLB management */
2529 void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry,
2530 target_ulong value)
2532 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2533 ppcemb_tlb_t *tlb;
2534 target_ulong EPN, RPN, size;
2535 int do_flush_tlbs;
2537 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
2538 __func__, word, (int)entry, value);
2539 do_flush_tlbs = 0;
2540 entry &= 0x3F;
2541 tlb = &env->tlb.tlbe[entry];
2542 switch (word) {
2543 default:
2544 /* Just here to please gcc */
2545 case 0:
2546 EPN = value & 0xFFFFFC00;
2547 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
2548 do_flush_tlbs = 1;
2550 tlb->EPN = EPN;
2551 size = booke_tlb_to_page_size((value >> 4) & 0xF);
2552 if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
2553 do_flush_tlbs = 1;
2555 tlb->size = size;
2556 tlb->attr &= ~0x1;
2557 tlb->attr |= (value >> 8) & 1;
2558 if (value & 0x200) {
2559 tlb->prot |= PAGE_VALID;
2560 } else {
2561 if (tlb->prot & PAGE_VALID) {
2562 tlb->prot &= ~PAGE_VALID;
2563 do_flush_tlbs = 1;
2566 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
2567 if (do_flush_tlbs) {
2568 tlb_flush(CPU(cpu));
2570 break;
2571 case 1:
2572 RPN = value & 0xFFFFFC0F;
2573 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
2574 tlb_flush(CPU(cpu));
2576 tlb->RPN = RPN;
2577 break;
2578 case 2:
2579 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
2580 tlb->prot = tlb->prot & PAGE_VALID;
2581 if (value & 0x1) {
2582 tlb->prot |= PAGE_READ << 4;
2584 if (value & 0x2) {
2585 tlb->prot |= PAGE_WRITE << 4;
2587 if (value & 0x4) {
2588 tlb->prot |= PAGE_EXEC << 4;
2590 if (value & 0x8) {
2591 tlb->prot |= PAGE_READ;
2593 if (value & 0x10) {
2594 tlb->prot |= PAGE_WRITE;
2596 if (value & 0x20) {
2597 tlb->prot |= PAGE_EXEC;
2599 break;
2603 target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word,
2604 target_ulong entry)
2606 ppcemb_tlb_t *tlb;
2607 target_ulong ret;
2608 int size;
2610 entry &= 0x3F;
2611 tlb = &env->tlb.tlbe[entry];
2612 switch (word) {
2613 default:
2614 /* Just here to please gcc */
2615 case 0:
2616 ret = tlb->EPN;
2617 size = booke_page_size_to_tlb(tlb->size);
2618 if (size < 0 || size > 0xF) {
2619 size = 1;
2621 ret |= size << 4;
2622 if (tlb->attr & 0x1) {
2623 ret |= 0x100;
2625 if (tlb->prot & PAGE_VALID) {
2626 ret |= 0x200;
2628 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
2629 env->spr[SPR_440_MMUCR] |= tlb->PID;
2630 break;
2631 case 1:
2632 ret = tlb->RPN;
2633 break;
2634 case 2:
2635 ret = tlb->attr & ~0x1;
2636 if (tlb->prot & (PAGE_READ << 4)) {
2637 ret |= 0x1;
2639 if (tlb->prot & (PAGE_WRITE << 4)) {
2640 ret |= 0x2;
2642 if (tlb->prot & (PAGE_EXEC << 4)) {
2643 ret |= 0x4;
2645 if (tlb->prot & PAGE_READ) {
2646 ret |= 0x8;
2648 if (tlb->prot & PAGE_WRITE) {
2649 ret |= 0x10;
2651 if (tlb->prot & PAGE_EXEC) {
2652 ret |= 0x20;
2654 break;
2656 return ret;
2659 target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address)
2661 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
2664 /* PowerPC BookE 2.06 TLB management */
2666 static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
2668 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2669 uint32_t tlbncfg = 0;
2670 int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
2671 int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
2672 int tlb;
2674 tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2675 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
2677 if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
2678 cpu_abort(CPU(cpu), "we don't support HES yet\n");
2681 return booke206_get_tlbm(env, tlb, ea, esel);
2684 void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid)
2686 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2688 env->spr[pidn] = pid;
2689 /* changing PIDs mean we're in a different address space now */
2690 tlb_flush(CPU(cpu));
2693 void helper_booke_set_eplc(CPUPPCState *env, target_ulong val)
2695 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2696 env->spr[SPR_BOOKE_EPLC] = val & EPID_MASK;
2697 tlb_flush_by_mmuidx(CPU(cpu), 1 << PPC_TLB_EPID_LOAD);
2699 void helper_booke_set_epsc(CPUPPCState *env, target_ulong val)
2701 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2702 env->spr[SPR_BOOKE_EPSC] = val & EPID_MASK;
2703 tlb_flush_by_mmuidx(CPU(cpu), 1 << PPC_TLB_EPID_STORE);
2706 static inline void flush_page(CPUPPCState *env, ppcmas_tlb_t *tlb)
2708 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2710 if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
2711 tlb_flush_page(CPU(cpu), tlb->mas2 & MAS2_EPN_MASK);
2712 } else {
2713 tlb_flush(CPU(cpu));
2717 void helper_booke206_tlbwe(CPUPPCState *env)
2719 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2720 uint32_t tlbncfg, tlbn;
2721 ppcmas_tlb_t *tlb;
2722 uint32_t size_tlb, size_ps;
2723 target_ulong mask;
2726 switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
2727 case MAS0_WQ_ALWAYS:
2728 /* good to go, write that entry */
2729 break;
2730 case MAS0_WQ_COND:
2731 /* XXX check if reserved */
2732 if (0) {
2733 return;
2735 break;
2736 case MAS0_WQ_CLR_RSRV:
2737 /* XXX clear entry */
2738 return;
2739 default:
2740 /* no idea what to do */
2741 return;
2744 if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
2745 !msr_gs) {
2746 /* XXX we don't support direct LRAT setting yet */
2747 fprintf(stderr, "cpu: don't support LRAT setting yet\n");
2748 return;
2751 tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2752 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
2754 tlb = booke206_cur_tlb(env);
2756 if (!tlb) {
2757 raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
2758 POWERPC_EXCP_INVAL |
2759 POWERPC_EXCP_INVAL_INVAL, GETPC());
2762 /* check that we support the targeted size */
2763 size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
2764 size_ps = booke206_tlbnps(env, tlbn);
2765 if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
2766 !(size_ps & (1 << size_tlb))) {
2767 raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
2768 POWERPC_EXCP_INVAL |
2769 POWERPC_EXCP_INVAL_INVAL, GETPC());
2772 if (msr_gs) {
2773 cpu_abort(CPU(cpu), "missing HV implementation\n");
2776 if (tlb->mas1 & MAS1_VALID) {
2778 * Invalidate the page in QEMU TLB if it was a valid entry.
2780 * In "PowerPC e500 Core Family Reference Manual, Rev. 1",
2781 * Section "12.4.2 TLB Write Entry (tlbwe) Instruction":
2782 * (https://www.nxp.com/docs/en/reference-manual/E500CORERM.pdf)
2784 * "Note that when an L2 TLB entry is written, it may be displacing an
2785 * already valid entry in the same L2 TLB location (a victim). If a
2786 * valid L1 TLB entry corresponds to the L2 MMU victim entry, that L1
2787 * TLB entry is automatically invalidated."
2789 flush_page(env, tlb);
2792 tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
2793 env->spr[SPR_BOOKE_MAS3];
2794 tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
2796 if ((env->spr[SPR_MMUCFG] & MMUCFG_MAVN) == MMUCFG_MAVN_V2) {
2797 /* For TLB which has a fixed size TSIZE is ignored with MAV2 */
2798 booke206_fixed_size_tlbn(env, tlbn, tlb);
2799 } else {
2800 if (!(tlbncfg & TLBnCFG_AVAIL)) {
2801 /* force !AVAIL TLB entries to correct page size */
2802 tlb->mas1 &= ~MAS1_TSIZE_MASK;
2803 /* XXX can be configured in MMUCSR0 */
2804 tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
2808 /* Make a mask from TLB size to discard invalid bits in EPN field */
2809 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2810 /* Add a mask for page attributes */
2811 mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E;
2813 if (!msr_cm) {
2815 * Executing a tlbwe instruction in 32-bit mode will set bits
2816 * 0:31 of the TLB EPN field to zero.
2818 mask &= 0xffffffff;
2821 tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & mask;
2823 if (!(tlbncfg & TLBnCFG_IPROT)) {
2824 /* no IPROT supported by TLB */
2825 tlb->mas1 &= ~MAS1_IPROT;
2828 flush_page(env, tlb);
2831 static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
2833 int tlbn = booke206_tlbm_to_tlbn(env, tlb);
2834 int way = booke206_tlbm_to_way(env, tlb);
2836 env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
2837 env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
2838 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2840 env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
2841 env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
2842 env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
2843 env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
2846 void helper_booke206_tlbre(CPUPPCState *env)
2848 ppcmas_tlb_t *tlb = NULL;
2850 tlb = booke206_cur_tlb(env);
2851 if (!tlb) {
2852 env->spr[SPR_BOOKE_MAS1] = 0;
2853 } else {
2854 booke206_tlb_to_mas(env, tlb);
2858 void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address)
2860 ppcmas_tlb_t *tlb = NULL;
2861 int i, j;
2862 hwaddr raddr;
2863 uint32_t spid, sas;
2865 spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
2866 sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
2868 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2869 int ways = booke206_tlb_ways(env, i);
2871 for (j = 0; j < ways; j++) {
2872 tlb = booke206_get_tlbm(env, i, address, j);
2874 if (!tlb) {
2875 continue;
2878 if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
2879 continue;
2882 if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
2883 continue;
2886 booke206_tlb_to_mas(env, tlb);
2887 return;
2891 /* no entry found, fill with defaults */
2892 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
2893 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
2894 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
2895 env->spr[SPR_BOOKE_MAS3] = 0;
2896 env->spr[SPR_BOOKE_MAS7] = 0;
2898 if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
2899 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
2902 env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
2903 << MAS1_TID_SHIFT;
2905 /* next victim logic */
2906 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
2907 env->last_way++;
2908 env->last_way &= booke206_tlb_ways(env, 0) - 1;
2909 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2912 static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
2913 uint32_t ea)
2915 int i;
2916 int ways = booke206_tlb_ways(env, tlbn);
2917 target_ulong mask;
2919 for (i = 0; i < ways; i++) {
2920 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
2921 if (!tlb) {
2922 continue;
2924 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2925 if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
2926 !(tlb->mas1 & MAS1_IPROT)) {
2927 tlb->mas1 &= ~MAS1_VALID;
2932 void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address)
2934 CPUState *cs;
2936 if (address & 0x4) {
2937 /* flush all entries */
2938 if (address & 0x8) {
2939 /* flush all of TLB1 */
2940 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
2941 } else {
2942 /* flush all of TLB0 */
2943 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
2945 return;
2948 if (address & 0x8) {
2949 /* flush TLB1 entries */
2950 booke206_invalidate_ea_tlb(env, 1, address);
2951 CPU_FOREACH(cs) {
2952 tlb_flush(cs);
2954 } else {
2955 /* flush TLB0 entries */
2956 booke206_invalidate_ea_tlb(env, 0, address);
2957 CPU_FOREACH(cs) {
2958 tlb_flush_page(cs, address & MAS2_EPN_MASK);
2963 void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address)
2965 /* XXX missing LPID handling */
2966 booke206_flush_tlb(env, -1, 1);
2969 void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address)
2971 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2972 int i, j;
2973 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2974 ppcmas_tlb_t *tlb = env->tlb.tlbm;
2975 int tlb_size;
2977 /* XXX missing LPID handling */
2978 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2979 tlb_size = booke206_tlb_size(env, i);
2980 for (j = 0; j < tlb_size; j++) {
2981 if (!(tlb[j].mas1 & MAS1_IPROT) &&
2982 ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
2983 tlb[j].mas1 &= ~MAS1_VALID;
2986 tlb += booke206_tlb_size(env, i);
2988 tlb_flush(CPU(cpu));
2991 void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
2993 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2994 int i, j;
2995 ppcmas_tlb_t *tlb;
2996 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2997 int pid = tid >> MAS6_SPID_SHIFT;
2998 int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
2999 int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
3000 /* XXX check for unsupported isize and raise an invalid opcode then */
3001 int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
3002 /* XXX implement MAV2 handling */
3003 bool mav2 = false;
3005 /* XXX missing LPID handling */
3006 /* flush by pid and ea */
3007 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
3008 int ways = booke206_tlb_ways(env, i);
3010 for (j = 0; j < ways; j++) {
3011 tlb = booke206_get_tlbm(env, i, address, j);
3012 if (!tlb) {
3013 continue;
3015 if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
3016 (tlb->mas1 & MAS1_IPROT) ||
3017 ((tlb->mas1 & MAS1_IND) != ind) ||
3018 ((tlb->mas8 & MAS8_TGS) != sgs)) {
3019 continue;
3021 if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
3022 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
3023 continue;
3025 /* XXX e500mc doesn't match SAS, but other cores might */
3026 tlb->mas1 &= ~MAS1_VALID;
3029 tlb_flush(CPU(cpu));
3032 void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type)
3034 int flags = 0;
3036 if (type & 2) {
3037 flags |= BOOKE206_FLUSH_TLB1;
3040 if (type & 4) {
3041 flags |= BOOKE206_FLUSH_TLB0;
3044 booke206_flush_tlb(env, flags, 1);
3048 void helper_check_tlb_flush_local(CPUPPCState *env)
3050 check_tlb_flush(env, false);
3053 void helper_check_tlb_flush_global(CPUPPCState *env)
3055 check_tlb_flush(env, true);
3058 /*****************************************************************************/
3061 * try to fill the TLB and return an exception if error. If retaddr is
3062 * NULL, it means that the function was called in C code (i.e. not
3063 * from generated code or from helper.c)
3065 * XXX: fix it to restore all registers
3067 void tlb_fill(CPUState *cs, target_ulong addr, int size,
3068 MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
3070 PowerPCCPU *cpu = POWERPC_CPU(cs);
3071 PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
3072 CPUPPCState *env = &cpu->env;
3073 int ret;
3075 if (pcc->handle_mmu_fault) {
3076 ret = pcc->handle_mmu_fault(cpu, addr, access_type, mmu_idx);
3077 } else {
3078 ret = cpu_ppc_handle_mmu_fault(env, addr, access_type, mmu_idx);
3080 if (unlikely(ret != 0)) {
3081 raise_exception_err_ra(env, cs->exception_index, env->error_code,
3082 retaddr);