qdev: Fix crash by validating the object type
[qemu/cris-port.git] / target-ppc / mmu_helper.c
blob1771863dffdd17af408a547f35937c31ea0e7d62
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(cpu) log_cpu_state((cpu), 0)
36 #else
37 # define LOG_MMU(...) do { } while (0)
38 # define LOG_MMU_STATE(cpu) 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 */
56 /* Context used internally during MMU translations */
57 typedef struct mmu_ctx_t mmu_ctx_t;
58 struct mmu_ctx_t {
59 hwaddr raddr; /* Real address */
60 hwaddr eaddr; /* Effective address */
61 int prot; /* Protection bits */
62 hwaddr hash[2]; /* Pagetable hash values */
63 target_ulong ptem; /* Virtual segment ID | API */
64 int key; /* Access key */
65 int nx; /* Non-execute area */
68 /* Common routines used by software and hardware TLBs emulation */
69 static inline int pte_is_valid(target_ulong pte0)
71 return pte0 & 0x80000000 ? 1 : 0;
74 static inline void pte_invalidate(target_ulong *pte0)
76 *pte0 &= ~0x80000000;
79 #define PTE_PTEM_MASK 0x7FFFFFBF
80 #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
82 static int pp_check(int key, int pp, int nx)
84 int access;
86 /* Compute access rights */
87 access = 0;
88 if (key == 0) {
89 switch (pp) {
90 case 0x0:
91 case 0x1:
92 case 0x2:
93 access |= PAGE_WRITE;
94 /* No break here */
95 case 0x3:
96 access |= PAGE_READ;
97 break;
99 } else {
100 switch (pp) {
101 case 0x0:
102 access = 0;
103 break;
104 case 0x1:
105 case 0x3:
106 access = PAGE_READ;
107 break;
108 case 0x2:
109 access = PAGE_READ | PAGE_WRITE;
110 break;
113 if (nx == 0) {
114 access |= PAGE_EXEC;
117 return access;
120 static int check_prot(int prot, int rw, int access_type)
122 int ret;
124 if (access_type == ACCESS_CODE) {
125 if (prot & PAGE_EXEC) {
126 ret = 0;
127 } else {
128 ret = -2;
130 } else if (rw) {
131 if (prot & PAGE_WRITE) {
132 ret = 0;
133 } else {
134 ret = -2;
136 } else {
137 if (prot & PAGE_READ) {
138 ret = 0;
139 } else {
140 ret = -2;
144 return ret;
147 static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
148 target_ulong pte1, int h, int rw, int type)
150 target_ulong ptem, mmask;
151 int access, ret, pteh, ptev, pp;
153 ret = -1;
154 /* Check validity and table match */
155 ptev = pte_is_valid(pte0);
156 pteh = (pte0 >> 6) & 1;
157 if (ptev && h == pteh) {
158 /* Check vsid & api */
159 ptem = pte0 & PTE_PTEM_MASK;
160 mmask = PTE_CHECK_MASK;
161 pp = pte1 & 0x00000003;
162 if (ptem == ctx->ptem) {
163 if (ctx->raddr != (hwaddr)-1ULL) {
164 /* all matches should have equal RPN, WIMG & PP */
165 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
166 qemu_log("Bad RPN/WIMG/PP\n");
167 return -3;
170 /* Compute access rights */
171 access = pp_check(ctx->key, pp, ctx->nx);
172 /* Keep the matching PTE informations */
173 ctx->raddr = pte1;
174 ctx->prot = access;
175 ret = check_prot(ctx->prot, rw, type);
176 if (ret == 0) {
177 /* Access granted */
178 LOG_MMU("PTE access granted !\n");
179 } else {
180 /* Access right violation */
181 LOG_MMU("PTE access rejected\n");
186 return ret;
189 static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
190 int ret, int rw)
192 int store = 0;
194 /* Update page flags */
195 if (!(*pte1p & 0x00000100)) {
196 /* Update accessed flag */
197 *pte1p |= 0x00000100;
198 store = 1;
200 if (!(*pte1p & 0x00000080)) {
201 if (rw == 1 && ret == 0) {
202 /* Update changed flag */
203 *pte1p |= 0x00000080;
204 store = 1;
205 } else {
206 /* Force page fault for first write access */
207 ctx->prot &= ~PAGE_WRITE;
211 return store;
214 /* Software driven TLB helpers */
215 static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
216 int way, int is_code)
218 int nr;
220 /* Select TLB num in a way from address */
221 nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
222 /* Select TLB way */
223 nr += env->tlb_per_way * way;
224 /* 6xx have separate TLBs for instructions and data */
225 if (is_code && env->id_tlbs == 1) {
226 nr += env->nb_tlb;
229 return nr;
232 static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
234 PowerPCCPU *cpu = ppc_env_get_cpu(env);
235 ppc6xx_tlb_t *tlb;
236 int nr, max;
238 /* LOG_SWTLB("Invalidate all TLBs\n"); */
239 /* Invalidate all defined software TLB */
240 max = env->nb_tlb;
241 if (env->id_tlbs == 1) {
242 max *= 2;
244 for (nr = 0; nr < max; nr++) {
245 tlb = &env->tlb.tlb6[nr];
246 pte_invalidate(&tlb->pte0);
248 tlb_flush(CPU(cpu), 1);
251 static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env,
252 target_ulong eaddr,
253 int is_code, int match_epn)
255 #if !defined(FLUSH_ALL_TLBS)
256 CPUState *cs = CPU(ppc_env_get_cpu(env));
257 ppc6xx_tlb_t *tlb;
258 int way, nr;
260 /* Invalidate ITLB + DTLB, all ways */
261 for (way = 0; way < env->nb_ways; way++) {
262 nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
263 tlb = &env->tlb.tlb6[nr];
264 if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
265 LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
266 env->nb_tlb, eaddr);
267 pte_invalidate(&tlb->pte0);
268 tlb_flush_page(cs, tlb->EPN);
271 #else
272 /* XXX: PowerPC specification say this is valid as well */
273 ppc6xx_tlb_invalidate_all(env);
274 #endif
277 static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
278 target_ulong eaddr, int is_code)
280 ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0);
283 static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way,
284 int is_code, target_ulong pte0, target_ulong pte1)
286 ppc6xx_tlb_t *tlb;
287 int nr;
289 nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
290 tlb = &env->tlb.tlb6[nr];
291 LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
292 " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
293 /* Invalidate any pending reference in QEMU for this virtual address */
294 ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1);
295 tlb->pte0 = pte0;
296 tlb->pte1 = pte1;
297 tlb->EPN = EPN;
298 /* Store last way for LRU mechanism */
299 env->last_way = way;
302 static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
303 target_ulong eaddr, int rw, int access_type)
305 ppc6xx_tlb_t *tlb;
306 int nr, best, way;
307 int ret;
309 best = -1;
310 ret = -1; /* No TLB found */
311 for (way = 0; way < env->nb_ways; way++) {
312 nr = ppc6xx_tlb_getnum(env, eaddr, way,
313 access_type == ACCESS_CODE ? 1 : 0);
314 tlb = &env->tlb.tlb6[nr];
315 /* This test "emulates" the PTE index match for hardware TLBs */
316 if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
317 LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
318 "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
319 pte_is_valid(tlb->pte0) ? "valid" : "inval",
320 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
321 continue;
323 LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
324 TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
325 pte_is_valid(tlb->pte0) ? "valid" : "inval",
326 tlb->EPN, eaddr, tlb->pte1,
327 rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
328 switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
329 case -3:
330 /* TLB inconsistency */
331 return -1;
332 case -2:
333 /* Access violation */
334 ret = -2;
335 best = nr;
336 break;
337 case -1:
338 default:
339 /* No match */
340 break;
341 case 0:
342 /* access granted */
343 /* XXX: we should go on looping to check all TLBs consistency
344 * but we can speed-up the whole thing as the
345 * result would be undefined if TLBs are not consistent.
347 ret = 0;
348 best = nr;
349 goto done;
352 if (best != -1) {
353 done:
354 LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
355 ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
356 /* Update page flags */
357 pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
360 return ret;
363 /* Perform BAT hit & translation */
364 static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
365 int *validp, int *protp, target_ulong *BATu,
366 target_ulong *BATl)
368 target_ulong bl;
369 int pp, valid, prot;
371 bl = (*BATu & 0x00001FFC) << 15;
372 valid = 0;
373 prot = 0;
374 if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
375 ((msr_pr != 0) && (*BATu & 0x00000001))) {
376 valid = 1;
377 pp = *BATl & 0x00000003;
378 if (pp != 0) {
379 prot = PAGE_READ | PAGE_EXEC;
380 if (pp == 0x2) {
381 prot |= PAGE_WRITE;
385 *blp = bl;
386 *validp = valid;
387 *protp = prot;
390 static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
391 target_ulong virtual, int rw, int type)
393 target_ulong *BATlt, *BATut, *BATu, *BATl;
394 target_ulong BEPIl, BEPIu, bl;
395 int i, valid, prot;
396 int ret = -1;
398 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
399 type == ACCESS_CODE ? 'I' : 'D', virtual);
400 switch (type) {
401 case ACCESS_CODE:
402 BATlt = env->IBAT[1];
403 BATut = env->IBAT[0];
404 break;
405 default:
406 BATlt = env->DBAT[1];
407 BATut = env->DBAT[0];
408 break;
410 for (i = 0; i < env->nb_BATs; i++) {
411 BATu = &BATut[i];
412 BATl = &BATlt[i];
413 BEPIu = *BATu & 0xF0000000;
414 BEPIl = *BATu & 0x0FFE0000;
415 bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
416 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
417 " BATl " TARGET_FMT_lx "\n", __func__,
418 type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
419 if ((virtual & 0xF0000000) == BEPIu &&
420 ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
421 /* BAT matches */
422 if (valid != 0) {
423 /* Get physical address */
424 ctx->raddr = (*BATl & 0xF0000000) |
425 ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
426 (virtual & 0x0001F000);
427 /* Compute access rights */
428 ctx->prot = prot;
429 ret = check_prot(ctx->prot, rw, type);
430 if (ret == 0) {
431 LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
432 i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
433 ctx->prot & PAGE_WRITE ? 'W' : '-');
435 break;
439 if (ret < 0) {
440 #if defined(DEBUG_BATS)
441 if (qemu_log_enabled()) {
442 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
443 for (i = 0; i < 4; i++) {
444 BATu = &BATut[i];
445 BATl = &BATlt[i];
446 BEPIu = *BATu & 0xF0000000;
447 BEPIl = *BATu & 0x0FFE0000;
448 bl = (*BATu & 0x00001FFC) << 15;
449 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
450 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
451 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
452 __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
453 *BATu, *BATl, BEPIu, BEPIl, bl);
456 #endif
458 /* No hit */
459 return ret;
462 /* Perform segment based translation */
463 static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
464 target_ulong eaddr, int rw, int type)
466 hwaddr hash;
467 target_ulong vsid;
468 int ds, pr, target_page_bits;
469 int ret;
470 target_ulong sr, pgidx;
472 pr = msr_pr;
473 ctx->eaddr = eaddr;
475 sr = env->sr[eaddr >> 28];
476 ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
477 ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
478 ds = sr & 0x80000000 ? 1 : 0;
479 ctx->nx = sr & 0x10000000 ? 1 : 0;
480 vsid = sr & 0x00FFFFFF;
481 target_page_bits = TARGET_PAGE_BITS;
482 LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
483 TARGET_FMT_lx " lr=" TARGET_FMT_lx
484 " ir=%d dr=%d pr=%d %d t=%d\n",
485 eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
486 (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
487 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
488 hash = vsid ^ pgidx;
489 ctx->ptem = (vsid << 7) | (pgidx >> 10);
491 LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
492 ctx->key, ds, ctx->nx, vsid);
493 ret = -1;
494 if (!ds) {
495 /* Check if instruction fetch is allowed, if needed */
496 if (type != ACCESS_CODE || ctx->nx == 0) {
497 /* Page address translation */
498 LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
499 " hash " TARGET_FMT_plx "\n",
500 env->htab_base, env->htab_mask, hash);
501 ctx->hash[0] = hash;
502 ctx->hash[1] = ~hash;
504 /* Initialize real address with an invalid value */
505 ctx->raddr = (hwaddr)-1ULL;
506 /* Software TLB search */
507 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
508 #if defined(DUMP_PAGE_TABLES)
509 if (qemu_log_enabled()) {
510 hwaddr curaddr;
511 uint32_t a0, a1, a2, a3;
513 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
514 "\n", sdr, mask + 0x80);
515 for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
516 curaddr += 16) {
517 a0 = ldl_phys(curaddr);
518 a1 = ldl_phys(curaddr + 4);
519 a2 = ldl_phys(curaddr + 8);
520 a3 = ldl_phys(curaddr + 12);
521 if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
522 qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
523 curaddr, a0, a1, a2, a3);
527 #endif
528 } else {
529 LOG_MMU("No access allowed\n");
530 ret = -3;
532 } else {
533 target_ulong sr;
535 LOG_MMU("direct store...\n");
536 /* Direct-store segment : absolutely *BUGGY* for now */
538 /* Direct-store implies a 32-bit MMU.
539 * Check the Segment Register's bus unit ID (BUID).
541 sr = env->sr[eaddr >> 28];
542 if ((sr & 0x1FF00000) >> 20 == 0x07f) {
543 /* Memory-forced I/O controller interface access */
544 /* If T=1 and BUID=x'07F', the 601 performs a memory access
545 * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
547 ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
548 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
549 return 0;
552 switch (type) {
553 case ACCESS_INT:
554 /* Integer load/store : only access allowed */
555 break;
556 case ACCESS_CODE:
557 /* No code fetch is allowed in direct-store areas */
558 return -4;
559 case ACCESS_FLOAT:
560 /* Floating point load/store */
561 return -4;
562 case ACCESS_RES:
563 /* lwarx, ldarx or srwcx. */
564 return -4;
565 case ACCESS_CACHE:
566 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
567 /* Should make the instruction do no-op.
568 * As it already do no-op, it's quite easy :-)
570 ctx->raddr = eaddr;
571 return 0;
572 case ACCESS_EXT:
573 /* eciwx or ecowx */
574 return -4;
575 default:
576 qemu_log("ERROR: instruction should not need "
577 "address translation\n");
578 return -4;
580 if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
581 ctx->raddr = eaddr;
582 ret = 2;
583 } else {
584 ret = -2;
588 return ret;
591 /* Generic TLB check function for embedded PowerPC implementations */
592 static int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
593 hwaddr *raddrp,
594 target_ulong address, uint32_t pid, int ext,
595 int i)
597 target_ulong mask;
599 /* Check valid flag */
600 if (!(tlb->prot & PAGE_VALID)) {
601 return -1;
603 mask = ~(tlb->size - 1);
604 LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
605 " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
606 mask, (uint32_t)tlb->PID, tlb->prot);
607 /* Check PID */
608 if (tlb->PID != 0 && tlb->PID != pid) {
609 return -1;
611 /* Check effective address */
612 if ((address & mask) != tlb->EPN) {
613 return -1;
615 *raddrp = (tlb->RPN & mask) | (address & ~mask);
616 if (ext) {
617 /* Extend the physical address to 36 bits */
618 *raddrp |= (uint64_t)(tlb->RPN & 0xF) << 32;
621 return 0;
624 /* Generic TLB search function for PowerPC embedded implementations */
625 static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address,
626 uint32_t pid)
628 ppcemb_tlb_t *tlb;
629 hwaddr raddr;
630 int i, ret;
632 /* Default return value is no match */
633 ret = -1;
634 for (i = 0; i < env->nb_tlb; i++) {
635 tlb = &env->tlb.tlbe[i];
636 if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
637 ret = i;
638 break;
642 return ret;
645 /* Helpers specific to PowerPC 40x implementations */
646 static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
648 PowerPCCPU *cpu = ppc_env_get_cpu(env);
649 ppcemb_tlb_t *tlb;
650 int i;
652 for (i = 0; i < env->nb_tlb; i++) {
653 tlb = &env->tlb.tlbe[i];
654 tlb->prot &= ~PAGE_VALID;
656 tlb_flush(CPU(cpu), 1);
659 static inline void ppc4xx_tlb_invalidate_virt(CPUPPCState *env,
660 target_ulong eaddr, uint32_t pid)
662 #if !defined(FLUSH_ALL_TLBS)
663 CPUState *cs = CPU(ppc_env_get_cpu(env));
664 ppcemb_tlb_t *tlb;
665 hwaddr raddr;
666 target_ulong page, end;
667 int i;
669 for (i = 0; i < env->nb_tlb; i++) {
670 tlb = &env->tlb.tlbe[i];
671 if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
672 end = tlb->EPN + tlb->size;
673 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
674 tlb_flush_page(cs, page);
676 tlb->prot &= ~PAGE_VALID;
677 break;
680 #else
681 ppc4xx_tlb_invalidate_all(env);
682 #endif
685 static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
686 target_ulong address, int rw,
687 int access_type)
689 ppcemb_tlb_t *tlb;
690 hwaddr raddr;
691 int i, ret, zsel, zpr, pr;
693 ret = -1;
694 raddr = (hwaddr)-1ULL;
695 pr = msr_pr;
696 for (i = 0; i < env->nb_tlb; i++) {
697 tlb = &env->tlb.tlbe[i];
698 if (ppcemb_tlb_check(env, tlb, &raddr, address,
699 env->spr[SPR_40x_PID], 0, i) < 0) {
700 continue;
702 zsel = (tlb->attr >> 4) & 0xF;
703 zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
704 LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
705 __func__, i, zsel, zpr, rw, tlb->attr);
706 /* Check execute enable bit */
707 switch (zpr) {
708 case 0x2:
709 if (pr != 0) {
710 goto check_perms;
712 /* No break here */
713 case 0x3:
714 /* All accesses granted */
715 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
716 ret = 0;
717 break;
718 case 0x0:
719 if (pr != 0) {
720 /* Raise Zone protection fault. */
721 env->spr[SPR_40x_ESR] = 1 << 22;
722 ctx->prot = 0;
723 ret = -2;
724 break;
726 /* No break here */
727 case 0x1:
728 check_perms:
729 /* Check from TLB entry */
730 ctx->prot = tlb->prot;
731 ret = check_prot(ctx->prot, rw, access_type);
732 if (ret == -2) {
733 env->spr[SPR_40x_ESR] = 0;
735 break;
737 if (ret >= 0) {
738 ctx->raddr = raddr;
739 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
740 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
741 ret);
742 return 0;
745 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
746 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
748 return ret;
751 void store_40x_sler(CPUPPCState *env, uint32_t val)
753 PowerPCCPU *cpu = ppc_env_get_cpu(env);
755 /* XXX: TO BE FIXED */
756 if (val != 0x00000000) {
757 cpu_abort(CPU(cpu), "Little-endian regions are not supported by now\n");
759 env->spr[SPR_405_SLER] = val;
762 static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
763 hwaddr *raddr, int *prot,
764 target_ulong address, int rw,
765 int access_type, int i)
767 int ret, prot2;
769 if (ppcemb_tlb_check(env, tlb, raddr, address,
770 env->spr[SPR_BOOKE_PID],
771 !env->nb_pids, i) >= 0) {
772 goto found_tlb;
775 if (env->spr[SPR_BOOKE_PID1] &&
776 ppcemb_tlb_check(env, tlb, raddr, address,
777 env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
778 goto found_tlb;
781 if (env->spr[SPR_BOOKE_PID2] &&
782 ppcemb_tlb_check(env, tlb, raddr, address,
783 env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
784 goto found_tlb;
787 LOG_SWTLB("%s: TLB entry not found\n", __func__);
788 return -1;
790 found_tlb:
792 if (msr_pr != 0) {
793 prot2 = tlb->prot & 0xF;
794 } else {
795 prot2 = (tlb->prot >> 4) & 0xF;
798 /* Check the address space */
799 if (access_type == ACCESS_CODE) {
800 if (msr_ir != (tlb->attr & 1)) {
801 LOG_SWTLB("%s: AS doesn't match\n", __func__);
802 return -1;
805 *prot = prot2;
806 if (prot2 & PAGE_EXEC) {
807 LOG_SWTLB("%s: good TLB!\n", __func__);
808 return 0;
811 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
812 ret = -3;
813 } else {
814 if (msr_dr != (tlb->attr & 1)) {
815 LOG_SWTLB("%s: AS doesn't match\n", __func__);
816 return -1;
819 *prot = prot2;
820 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
821 LOG_SWTLB("%s: found TLB!\n", __func__);
822 return 0;
825 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
826 ret = -2;
829 return ret;
832 static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
833 target_ulong address, int rw,
834 int access_type)
836 ppcemb_tlb_t *tlb;
837 hwaddr raddr;
838 int i, ret;
840 ret = -1;
841 raddr = (hwaddr)-1ULL;
842 for (i = 0; i < env->nb_tlb; i++) {
843 tlb = &env->tlb.tlbe[i];
844 ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
845 access_type, i);
846 if (!ret) {
847 break;
851 if (ret >= 0) {
852 ctx->raddr = raddr;
853 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
854 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
855 ret);
856 } else {
857 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
858 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
861 return ret;
864 static void booke206_flush_tlb(CPUPPCState *env, int flags,
865 const int check_iprot)
867 PowerPCCPU *cpu = ppc_env_get_cpu(env);
868 int tlb_size;
869 int i, j;
870 ppcmas_tlb_t *tlb = env->tlb.tlbm;
872 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
873 if (flags & (1 << i)) {
874 tlb_size = booke206_tlb_size(env, i);
875 for (j = 0; j < tlb_size; j++) {
876 if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
877 tlb[j].mas1 &= ~MAS1_VALID;
881 tlb += booke206_tlb_size(env, i);
884 tlb_flush(CPU(cpu), 1);
887 static hwaddr booke206_tlb_to_page_size(CPUPPCState *env,
888 ppcmas_tlb_t *tlb)
890 int tlbm_size;
892 tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
894 return 1024ULL << tlbm_size;
897 /* TLB check function for MAS based SoftTLBs */
898 static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
899 hwaddr *raddrp,
900 target_ulong address, uint32_t pid)
902 target_ulong mask;
903 uint32_t tlb_pid;
905 /* Check valid flag */
906 if (!(tlb->mas1 & MAS1_VALID)) {
907 return -1;
910 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
911 LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
912 PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n",
913 __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3,
914 tlb->mas8);
916 /* Check PID */
917 tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
918 if (tlb_pid != 0 && tlb_pid != pid) {
919 return -1;
922 /* Check effective address */
923 if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
924 return -1;
927 if (raddrp) {
928 *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
931 return 0;
934 static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
935 hwaddr *raddr, int *prot,
936 target_ulong address, int rw,
937 int access_type)
939 int ret;
940 int prot2 = 0;
942 if (ppcmas_tlb_check(env, tlb, raddr, address,
943 env->spr[SPR_BOOKE_PID]) >= 0) {
944 goto found_tlb;
947 if (env->spr[SPR_BOOKE_PID1] &&
948 ppcmas_tlb_check(env, tlb, raddr, address,
949 env->spr[SPR_BOOKE_PID1]) >= 0) {
950 goto found_tlb;
953 if (env->spr[SPR_BOOKE_PID2] &&
954 ppcmas_tlb_check(env, tlb, raddr, address,
955 env->spr[SPR_BOOKE_PID2]) >= 0) {
956 goto found_tlb;
959 LOG_SWTLB("%s: TLB entry not found\n", __func__);
960 return -1;
962 found_tlb:
964 if (msr_pr != 0) {
965 if (tlb->mas7_3 & MAS3_UR) {
966 prot2 |= PAGE_READ;
968 if (tlb->mas7_3 & MAS3_UW) {
969 prot2 |= PAGE_WRITE;
971 if (tlb->mas7_3 & MAS3_UX) {
972 prot2 |= PAGE_EXEC;
974 } else {
975 if (tlb->mas7_3 & MAS3_SR) {
976 prot2 |= PAGE_READ;
978 if (tlb->mas7_3 & MAS3_SW) {
979 prot2 |= PAGE_WRITE;
981 if (tlb->mas7_3 & MAS3_SX) {
982 prot2 |= PAGE_EXEC;
986 /* Check the address space and permissions */
987 if (access_type == ACCESS_CODE) {
988 if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
989 LOG_SWTLB("%s: AS doesn't match\n", __func__);
990 return -1;
993 *prot = prot2;
994 if (prot2 & PAGE_EXEC) {
995 LOG_SWTLB("%s: good TLB!\n", __func__);
996 return 0;
999 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
1000 ret = -3;
1001 } else {
1002 if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
1003 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1004 return -1;
1007 *prot = prot2;
1008 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
1009 LOG_SWTLB("%s: found TLB!\n", __func__);
1010 return 0;
1013 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
1014 ret = -2;
1017 return ret;
1020 static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1021 target_ulong address, int rw,
1022 int access_type)
1024 ppcmas_tlb_t *tlb;
1025 hwaddr raddr;
1026 int i, j, ret;
1028 ret = -1;
1029 raddr = (hwaddr)-1ULL;
1031 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1032 int ways = booke206_tlb_ways(env, i);
1034 for (j = 0; j < ways; j++) {
1035 tlb = booke206_get_tlbm(env, i, address, j);
1036 if (!tlb) {
1037 continue;
1039 ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
1040 rw, access_type);
1041 if (ret != -1) {
1042 goto found_tlb;
1047 found_tlb:
1049 if (ret >= 0) {
1050 ctx->raddr = raddr;
1051 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1052 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1053 ret);
1054 } else {
1055 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1056 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1059 return ret;
1062 static const char *book3e_tsize_to_str[32] = {
1063 "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
1064 "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
1065 "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
1066 "1T", "2T"
1069 static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1070 CPUPPCState *env)
1072 ppcemb_tlb_t *entry;
1073 int i;
1075 if (kvm_enabled() && !env->kvm_sw_tlb) {
1076 cpu_fprintf(f, "Cannot access KVM TLB\n");
1077 return;
1080 cpu_fprintf(f, "\nTLB:\n");
1081 cpu_fprintf(f, "Effective Physical Size PID Prot "
1082 "Attr\n");
1084 entry = &env->tlb.tlbe[0];
1085 for (i = 0; i < env->nb_tlb; i++, entry++) {
1086 hwaddr ea, pa;
1087 target_ulong mask;
1088 uint64_t size = (uint64_t)entry->size;
1089 char size_buf[20];
1091 /* Check valid flag */
1092 if (!(entry->prot & PAGE_VALID)) {
1093 continue;
1096 mask = ~(entry->size - 1);
1097 ea = entry->EPN & mask;
1098 pa = entry->RPN & mask;
1099 /* Extend the physical address to 36 bits */
1100 pa |= (hwaddr)(entry->RPN & 0xF) << 32;
1101 size /= 1024;
1102 if (size >= 1024) {
1103 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024);
1104 } else {
1105 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size);
1107 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
1108 (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
1109 entry->prot, entry->attr);
1114 static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
1115 CPUPPCState *env, int tlbn, int offset,
1116 int tlbsize)
1118 ppcmas_tlb_t *entry;
1119 int i;
1121 cpu_fprintf(f, "\nTLB%d:\n", tlbn);
1122 cpu_fprintf(f, "Effective Physical Size TID TS SRWX"
1123 " URWX WIMGE U0123\n");
1125 entry = &env->tlb.tlbm[offset];
1126 for (i = 0; i < tlbsize; i++, entry++) {
1127 hwaddr ea, pa, size;
1128 int tsize;
1130 if (!(entry->mas1 & MAS1_VALID)) {
1131 continue;
1134 tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1135 size = 1024ULL << tsize;
1136 ea = entry->mas2 & ~(size - 1);
1137 pa = entry->mas7_3 & ~(size - 1);
1139 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c"
1140 "U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
1141 (uint64_t)ea, (uint64_t)pa,
1142 book3e_tsize_to_str[tsize],
1143 (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
1144 (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
1145 entry->mas7_3 & MAS3_SR ? 'R' : '-',
1146 entry->mas7_3 & MAS3_SW ? 'W' : '-',
1147 entry->mas7_3 & MAS3_SX ? 'X' : '-',
1148 entry->mas7_3 & MAS3_UR ? 'R' : '-',
1149 entry->mas7_3 & MAS3_UW ? 'W' : '-',
1150 entry->mas7_3 & MAS3_UX ? 'X' : '-',
1151 entry->mas2 & MAS2_W ? 'W' : '-',
1152 entry->mas2 & MAS2_I ? 'I' : '-',
1153 entry->mas2 & MAS2_M ? 'M' : '-',
1154 entry->mas2 & MAS2_G ? 'G' : '-',
1155 entry->mas2 & MAS2_E ? 'E' : '-',
1156 entry->mas7_3 & MAS3_U0 ? '0' : '-',
1157 entry->mas7_3 & MAS3_U1 ? '1' : '-',
1158 entry->mas7_3 & MAS3_U2 ? '2' : '-',
1159 entry->mas7_3 & MAS3_U3 ? '3' : '-');
1163 static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1164 CPUPPCState *env)
1166 int offset = 0;
1167 int i;
1169 if (kvm_enabled() && !env->kvm_sw_tlb) {
1170 cpu_fprintf(f, "Cannot access KVM TLB\n");
1171 return;
1174 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1175 int size = booke206_tlb_size(env, i);
1177 if (size == 0) {
1178 continue;
1181 mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size);
1182 offset += size;
1186 static void mmu6xx_dump_BATs(FILE *f, fprintf_function cpu_fprintf,
1187 CPUPPCState *env, int type)
1189 target_ulong *BATlt, *BATut, *BATu, *BATl;
1190 target_ulong BEPIl, BEPIu, bl;
1191 int i;
1193 switch (type) {
1194 case ACCESS_CODE:
1195 BATlt = env->IBAT[1];
1196 BATut = env->IBAT[0];
1197 break;
1198 default:
1199 BATlt = env->DBAT[1];
1200 BATut = env->DBAT[0];
1201 break;
1204 for (i = 0; i < env->nb_BATs; i++) {
1205 BATu = &BATut[i];
1206 BATl = &BATlt[i];
1207 BEPIu = *BATu & 0xF0000000;
1208 BEPIl = *BATu & 0x0FFE0000;
1209 bl = (*BATu & 0x00001FFC) << 15;
1210 cpu_fprintf(f, "%s BAT%d BATu " TARGET_FMT_lx
1211 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
1212 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
1213 type == ACCESS_CODE ? "code" : "data", i,
1214 *BATu, *BATl, BEPIu, BEPIl, bl);
1218 static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1219 CPUPPCState *env)
1221 ppc6xx_tlb_t *tlb;
1222 target_ulong sr;
1223 int type, way, entry, i;
1225 cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", env->htab_base);
1226 cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", env->htab_mask);
1228 cpu_fprintf(f, "\nSegment registers:\n");
1229 for (i = 0; i < 32; i++) {
1230 sr = env->sr[i];
1231 if (sr & 0x80000000) {
1232 cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d BUID=0x%03x "
1233 "CNTLR_SPEC=0x%05x\n", i,
1234 sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1235 sr & 0x20000000 ? 1 : 0, (uint32_t)((sr >> 20) & 0x1FF),
1236 (uint32_t)(sr & 0xFFFFF));
1237 } else {
1238 cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d N=%d VSID=0x%06x\n", i,
1239 sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1240 sr & 0x20000000 ? 1 : 0, sr & 0x10000000 ? 1 : 0,
1241 (uint32_t)(sr & 0x00FFFFFF));
1245 cpu_fprintf(f, "\nBATs:\n");
1246 mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_INT);
1247 mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_CODE);
1249 if (env->id_tlbs != 1) {
1250 cpu_fprintf(f, "ERROR: 6xx MMU should have separated TLB"
1251 " for code and data\n");
1254 cpu_fprintf(f, "\nTLBs [EPN EPN + SIZE]\n");
1256 for (type = 0; type < 2; type++) {
1257 for (way = 0; way < env->nb_ways; way++) {
1258 for (entry = env->nb_tlb * type + env->tlb_per_way * way;
1259 entry < (env->nb_tlb * type + env->tlb_per_way * (way + 1));
1260 entry++) {
1262 tlb = &env->tlb.tlb6[entry];
1263 cpu_fprintf(f, "%s TLB %02d/%02d way:%d %s ["
1264 TARGET_FMT_lx " " TARGET_FMT_lx "]\n",
1265 type ? "code" : "data", entry % env->nb_tlb,
1266 env->nb_tlb, way,
1267 pte_is_valid(tlb->pte0) ? "valid" : "inval",
1268 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE);
1274 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
1276 switch (env->mmu_model) {
1277 case POWERPC_MMU_BOOKE:
1278 mmubooke_dump_mmu(f, cpu_fprintf, env);
1279 break;
1280 case POWERPC_MMU_BOOKE206:
1281 mmubooke206_dump_mmu(f, cpu_fprintf, env);
1282 break;
1283 case POWERPC_MMU_SOFT_6xx:
1284 case POWERPC_MMU_SOFT_74xx:
1285 mmu6xx_dump_mmu(f, cpu_fprintf, env);
1286 break;
1287 #if defined(TARGET_PPC64)
1288 case POWERPC_MMU_64B:
1289 case POWERPC_MMU_2_06:
1290 case POWERPC_MMU_2_06a:
1291 case POWERPC_MMU_2_06d:
1292 dump_slb(f, cpu_fprintf, env);
1293 break;
1294 #endif
1295 default:
1296 qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
1300 static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
1301 target_ulong eaddr, int rw)
1303 int in_plb, ret;
1305 ctx->raddr = eaddr;
1306 ctx->prot = PAGE_READ | PAGE_EXEC;
1307 ret = 0;
1308 switch (env->mmu_model) {
1309 case POWERPC_MMU_SOFT_6xx:
1310 case POWERPC_MMU_SOFT_74xx:
1311 case POWERPC_MMU_SOFT_4xx:
1312 case POWERPC_MMU_REAL:
1313 case POWERPC_MMU_BOOKE:
1314 ctx->prot |= PAGE_WRITE;
1315 break;
1317 case POWERPC_MMU_SOFT_4xx_Z:
1318 if (unlikely(msr_pe != 0)) {
1319 /* 403 family add some particular protections,
1320 * using PBL/PBU registers for accesses with no translation.
1322 in_plb =
1323 /* Check PLB validity */
1324 (env->pb[0] < env->pb[1] &&
1325 /* and address in plb area */
1326 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
1327 (env->pb[2] < env->pb[3] &&
1328 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
1329 if (in_plb ^ msr_px) {
1330 /* Access in protected area */
1331 if (rw == 1) {
1332 /* Access is not allowed */
1333 ret = -2;
1335 } else {
1336 /* Read-write access is allowed */
1337 ctx->prot |= PAGE_WRITE;
1340 break;
1342 default:
1343 /* Caller's checks mean we should never get here for other models */
1344 abort();
1345 return -1;
1348 return ret;
1351 static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1352 target_ulong eaddr, int rw, int access_type)
1354 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1355 int ret = -1;
1356 bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
1357 || (access_type != ACCESS_CODE && msr_dr == 0);
1359 #if 0
1360 qemu_log("%s\n", __func__);
1361 #endif
1363 switch (env->mmu_model) {
1364 case POWERPC_MMU_SOFT_6xx:
1365 case POWERPC_MMU_SOFT_74xx:
1366 if (real_mode) {
1367 ret = check_physical(env, ctx, eaddr, rw);
1368 } else {
1369 /* Try to find a BAT */
1370 if (env->nb_BATs != 0) {
1371 ret = get_bat_6xx_tlb(env, ctx, eaddr, rw, access_type);
1373 if (ret < 0) {
1374 /* We didn't match any BAT entry or don't have BATs */
1375 ret = get_segment_6xx_tlb(env, ctx, eaddr, rw, access_type);
1378 break;
1380 case POWERPC_MMU_SOFT_4xx:
1381 case POWERPC_MMU_SOFT_4xx_Z:
1382 if (real_mode) {
1383 ret = check_physical(env, ctx, eaddr, rw);
1384 } else {
1385 ret = mmu40x_get_physical_address(env, ctx, eaddr,
1386 rw, access_type);
1388 break;
1389 case POWERPC_MMU_BOOKE:
1390 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1391 rw, access_type);
1392 break;
1393 case POWERPC_MMU_BOOKE206:
1394 ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
1395 access_type);
1396 break;
1397 case POWERPC_MMU_MPC8xx:
1398 /* XXX: TODO */
1399 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1400 break;
1401 case POWERPC_MMU_REAL:
1402 if (real_mode) {
1403 ret = check_physical(env, ctx, eaddr, rw);
1404 } else {
1405 cpu_abort(CPU(cpu), "PowerPC in real mode do not do any translation\n");
1407 return -1;
1408 default:
1409 cpu_abort(CPU(cpu), "Unknown or invalid MMU model\n");
1410 return -1;
1412 #if 0
1413 qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
1414 __func__, eaddr, ret, ctx->raddr);
1415 #endif
1417 return ret;
1420 hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
1422 PowerPCCPU *cpu = POWERPC_CPU(cs);
1423 CPUPPCState *env = &cpu->env;
1424 mmu_ctx_t ctx;
1426 switch (env->mmu_model) {
1427 #if defined(TARGET_PPC64)
1428 case POWERPC_MMU_64B:
1429 case POWERPC_MMU_2_06:
1430 case POWERPC_MMU_2_06a:
1431 case POWERPC_MMU_2_06d:
1432 return ppc_hash64_get_phys_page_debug(env, addr);
1433 #endif
1435 case POWERPC_MMU_32B:
1436 case POWERPC_MMU_601:
1437 return ppc_hash32_get_phys_page_debug(env, addr);
1439 default:
1443 if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {
1445 /* Some MMUs have separate TLBs for code and data. If we only try an
1446 * ACCESS_INT, we may not be able to read instructions mapped by code
1447 * TLBs, so we also try a ACCESS_CODE.
1449 if (unlikely(get_physical_address(env, &ctx, addr, 0,
1450 ACCESS_CODE) != 0)) {
1451 return -1;
1455 return ctx.raddr & TARGET_PAGE_MASK;
1458 static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
1459 int rw)
1461 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
1462 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
1463 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
1464 env->spr[SPR_BOOKE_MAS3] = 0;
1465 env->spr[SPR_BOOKE_MAS6] = 0;
1466 env->spr[SPR_BOOKE_MAS7] = 0;
1468 /* AS */
1469 if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
1470 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
1471 env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
1474 env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
1475 env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
1477 switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
1478 case MAS4_TIDSELD_PID0:
1479 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
1480 break;
1481 case MAS4_TIDSELD_PID1:
1482 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
1483 break;
1484 case MAS4_TIDSELD_PID2:
1485 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
1486 break;
1489 env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
1491 /* next victim logic */
1492 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
1493 env->last_way++;
1494 env->last_way &= booke206_tlb_ways(env, 0) - 1;
1495 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
1498 /* Perform address translation */
1499 static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
1500 int rw, int mmu_idx)
1502 CPUState *cs = CPU(ppc_env_get_cpu(env));
1503 mmu_ctx_t ctx;
1504 int access_type;
1505 int ret = 0;
1507 if (rw == 2) {
1508 /* code access */
1509 rw = 0;
1510 access_type = ACCESS_CODE;
1511 } else {
1512 /* data access */
1513 access_type = env->access_type;
1515 ret = get_physical_address(env, &ctx, address, rw, access_type);
1516 if (ret == 0) {
1517 tlb_set_page(cs, address & TARGET_PAGE_MASK,
1518 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
1519 mmu_idx, TARGET_PAGE_SIZE);
1520 ret = 0;
1521 } else if (ret < 0) {
1522 LOG_MMU_STATE(cs);
1523 if (access_type == ACCESS_CODE) {
1524 switch (ret) {
1525 case -1:
1526 /* No matches in page tables or TLB */
1527 switch (env->mmu_model) {
1528 case POWERPC_MMU_SOFT_6xx:
1529 cs->exception_index = POWERPC_EXCP_IFTLB;
1530 env->error_code = 1 << 18;
1531 env->spr[SPR_IMISS] = address;
1532 env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
1533 goto tlb_miss;
1534 case POWERPC_MMU_SOFT_74xx:
1535 cs->exception_index = POWERPC_EXCP_IFTLB;
1536 goto tlb_miss_74xx;
1537 case POWERPC_MMU_SOFT_4xx:
1538 case POWERPC_MMU_SOFT_4xx_Z:
1539 cs->exception_index = POWERPC_EXCP_ITLB;
1540 env->error_code = 0;
1541 env->spr[SPR_40x_DEAR] = address;
1542 env->spr[SPR_40x_ESR] = 0x00000000;
1543 break;
1544 case POWERPC_MMU_BOOKE206:
1545 booke206_update_mas_tlb_miss(env, address, rw);
1546 /* fall through */
1547 case POWERPC_MMU_BOOKE:
1548 cs->exception_index = POWERPC_EXCP_ITLB;
1549 env->error_code = 0;
1550 env->spr[SPR_BOOKE_DEAR] = address;
1551 return -1;
1552 case POWERPC_MMU_MPC8xx:
1553 /* XXX: TODO */
1554 cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1555 break;
1556 case POWERPC_MMU_REAL:
1557 cpu_abort(cs, "PowerPC in real mode should never raise "
1558 "any MMU exceptions\n");
1559 return -1;
1560 default:
1561 cpu_abort(cs, "Unknown or invalid MMU model\n");
1562 return -1;
1564 break;
1565 case -2:
1566 /* Access rights violation */
1567 cs->exception_index = POWERPC_EXCP_ISI;
1568 env->error_code = 0x08000000;
1569 break;
1570 case -3:
1571 /* No execute protection violation */
1572 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1573 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1574 env->spr[SPR_BOOKE_ESR] = 0x00000000;
1576 cs->exception_index = POWERPC_EXCP_ISI;
1577 env->error_code = 0x10000000;
1578 break;
1579 case -4:
1580 /* Direct store exception */
1581 /* No code fetch is allowed in direct-store areas */
1582 cs->exception_index = POWERPC_EXCP_ISI;
1583 env->error_code = 0x10000000;
1584 break;
1586 } else {
1587 switch (ret) {
1588 case -1:
1589 /* No matches in page tables or TLB */
1590 switch (env->mmu_model) {
1591 case POWERPC_MMU_SOFT_6xx:
1592 if (rw == 1) {
1593 cs->exception_index = POWERPC_EXCP_DSTLB;
1594 env->error_code = 1 << 16;
1595 } else {
1596 cs->exception_index = POWERPC_EXCP_DLTLB;
1597 env->error_code = 0;
1599 env->spr[SPR_DMISS] = address;
1600 env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
1601 tlb_miss:
1602 env->error_code |= ctx.key << 19;
1603 env->spr[SPR_HASH1] = env->htab_base +
1604 get_pteg_offset32(env, ctx.hash[0]);
1605 env->spr[SPR_HASH2] = env->htab_base +
1606 get_pteg_offset32(env, ctx.hash[1]);
1607 break;
1608 case POWERPC_MMU_SOFT_74xx:
1609 if (rw == 1) {
1610 cs->exception_index = POWERPC_EXCP_DSTLB;
1611 } else {
1612 cs->exception_index = POWERPC_EXCP_DLTLB;
1614 tlb_miss_74xx:
1615 /* Implement LRU algorithm */
1616 env->error_code = ctx.key << 19;
1617 env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
1618 ((env->last_way + 1) & (env->nb_ways - 1));
1619 env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
1620 break;
1621 case POWERPC_MMU_SOFT_4xx:
1622 case POWERPC_MMU_SOFT_4xx_Z:
1623 cs->exception_index = POWERPC_EXCP_DTLB;
1624 env->error_code = 0;
1625 env->spr[SPR_40x_DEAR] = address;
1626 if (rw) {
1627 env->spr[SPR_40x_ESR] = 0x00800000;
1628 } else {
1629 env->spr[SPR_40x_ESR] = 0x00000000;
1631 break;
1632 case POWERPC_MMU_MPC8xx:
1633 /* XXX: TODO */
1634 cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1635 break;
1636 case POWERPC_MMU_BOOKE206:
1637 booke206_update_mas_tlb_miss(env, address, rw);
1638 /* fall through */
1639 case POWERPC_MMU_BOOKE:
1640 cs->exception_index = POWERPC_EXCP_DTLB;
1641 env->error_code = 0;
1642 env->spr[SPR_BOOKE_DEAR] = address;
1643 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1644 return -1;
1645 case POWERPC_MMU_REAL:
1646 cpu_abort(cs, "PowerPC in real mode should never raise "
1647 "any MMU exceptions\n");
1648 return -1;
1649 default:
1650 cpu_abort(cs, "Unknown or invalid MMU model\n");
1651 return -1;
1653 break;
1654 case -2:
1655 /* Access rights violation */
1656 cs->exception_index = POWERPC_EXCP_DSI;
1657 env->error_code = 0;
1658 if (env->mmu_model == POWERPC_MMU_SOFT_4xx
1659 || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
1660 env->spr[SPR_40x_DEAR] = address;
1661 if (rw) {
1662 env->spr[SPR_40x_ESR] |= 0x00800000;
1664 } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1665 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1666 env->spr[SPR_BOOKE_DEAR] = address;
1667 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1668 } else {
1669 env->spr[SPR_DAR] = address;
1670 if (rw == 1) {
1671 env->spr[SPR_DSISR] = 0x0A000000;
1672 } else {
1673 env->spr[SPR_DSISR] = 0x08000000;
1676 break;
1677 case -4:
1678 /* Direct store exception */
1679 switch (access_type) {
1680 case ACCESS_FLOAT:
1681 /* Floating point load/store */
1682 cs->exception_index = POWERPC_EXCP_ALIGN;
1683 env->error_code = POWERPC_EXCP_ALIGN_FP;
1684 env->spr[SPR_DAR] = address;
1685 break;
1686 case ACCESS_RES:
1687 /* lwarx, ldarx or stwcx. */
1688 cs->exception_index = POWERPC_EXCP_DSI;
1689 env->error_code = 0;
1690 env->spr[SPR_DAR] = address;
1691 if (rw == 1) {
1692 env->spr[SPR_DSISR] = 0x06000000;
1693 } else {
1694 env->spr[SPR_DSISR] = 0x04000000;
1696 break;
1697 case ACCESS_EXT:
1698 /* eciwx or ecowx */
1699 cs->exception_index = POWERPC_EXCP_DSI;
1700 env->error_code = 0;
1701 env->spr[SPR_DAR] = address;
1702 if (rw == 1) {
1703 env->spr[SPR_DSISR] = 0x06100000;
1704 } else {
1705 env->spr[SPR_DSISR] = 0x04100000;
1707 break;
1708 default:
1709 printf("DSI: invalid exception (%d)\n", ret);
1710 cs->exception_index = POWERPC_EXCP_PROGRAM;
1711 env->error_code =
1712 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
1713 env->spr[SPR_DAR] = address;
1714 break;
1716 break;
1719 #if 0
1720 printf("%s: set exception to %d %02x\n", __func__,
1721 cs->exception, env->error_code);
1722 #endif
1723 ret = 1;
1726 return ret;
1729 /*****************************************************************************/
1730 /* BATs management */
1731 #if !defined(FLUSH_ALL_TLBS)
1732 static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
1733 target_ulong mask)
1735 CPUState *cs = CPU(ppc_env_get_cpu(env));
1736 target_ulong base, end, page;
1738 base = BATu & ~0x0001FFFF;
1739 end = base + mask + 0x00020000;
1740 LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
1741 TARGET_FMT_lx ")\n", base, end, mask);
1742 for (page = base; page != end; page += TARGET_PAGE_SIZE) {
1743 tlb_flush_page(cs, page);
1745 LOG_BATS("Flush done\n");
1747 #endif
1749 static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
1750 target_ulong value)
1752 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
1753 nr, ul == 0 ? 'u' : 'l', value, env->nip);
1756 void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1758 target_ulong mask;
1760 dump_store_bat(env, 'I', 0, nr, value);
1761 if (env->IBAT[0][nr] != value) {
1762 mask = (value << 15) & 0x0FFE0000UL;
1763 #if !defined(FLUSH_ALL_TLBS)
1764 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1765 #endif
1766 /* When storing valid upper BAT, mask BEPI and BRPN
1767 * and invalidate all TLBs covered by this BAT
1769 mask = (value << 15) & 0x0FFE0000UL;
1770 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1771 (value & ~0x0001FFFFUL & ~mask);
1772 env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
1773 (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
1774 #if !defined(FLUSH_ALL_TLBS)
1775 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1776 #else
1777 tlb_flush(env, 1);
1778 #endif
1782 void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1784 dump_store_bat(env, 'I', 1, nr, value);
1785 env->IBAT[1][nr] = value;
1788 void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1790 target_ulong mask;
1792 dump_store_bat(env, 'D', 0, nr, value);
1793 if (env->DBAT[0][nr] != value) {
1794 /* When storing valid upper BAT, mask BEPI and BRPN
1795 * and invalidate all TLBs covered by this BAT
1797 mask = (value << 15) & 0x0FFE0000UL;
1798 #if !defined(FLUSH_ALL_TLBS)
1799 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1800 #endif
1801 mask = (value << 15) & 0x0FFE0000UL;
1802 env->DBAT[0][nr] = (value & 0x00001FFFUL) |
1803 (value & ~0x0001FFFFUL & ~mask);
1804 env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
1805 (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
1806 #if !defined(FLUSH_ALL_TLBS)
1807 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1808 #else
1809 tlb_flush(env, 1);
1810 #endif
1814 void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1816 dump_store_bat(env, 'D', 1, nr, value);
1817 env->DBAT[1][nr] = value;
1820 void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value)
1822 target_ulong mask;
1823 #if defined(FLUSH_ALL_TLBS)
1824 int do_inval;
1825 #endif
1827 dump_store_bat(env, 'I', 0, nr, value);
1828 if (env->IBAT[0][nr] != value) {
1829 #if defined(FLUSH_ALL_TLBS)
1830 do_inval = 0;
1831 #endif
1832 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1833 if (env->IBAT[1][nr] & 0x40) {
1834 /* Invalidate BAT only if it is valid */
1835 #if !defined(FLUSH_ALL_TLBS)
1836 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1837 #else
1838 do_inval = 1;
1839 #endif
1841 /* When storing valid upper BAT, mask BEPI and BRPN
1842 * and invalidate all TLBs covered by this BAT
1844 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1845 (value & ~0x0001FFFFUL & ~mask);
1846 env->DBAT[0][nr] = env->IBAT[0][nr];
1847 if (env->IBAT[1][nr] & 0x40) {
1848 #if !defined(FLUSH_ALL_TLBS)
1849 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1850 #else
1851 do_inval = 1;
1852 #endif
1854 #if defined(FLUSH_ALL_TLBS)
1855 if (do_inval) {
1856 tlb_flush(env, 1);
1858 #endif
1862 void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value)
1864 #if !defined(FLUSH_ALL_TLBS)
1865 target_ulong mask;
1866 #else
1867 int do_inval;
1868 #endif
1870 dump_store_bat(env, 'I', 1, nr, value);
1871 if (env->IBAT[1][nr] != value) {
1872 #if defined(FLUSH_ALL_TLBS)
1873 do_inval = 0;
1874 #endif
1875 if (env->IBAT[1][nr] & 0x40) {
1876 #if !defined(FLUSH_ALL_TLBS)
1877 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1878 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1879 #else
1880 do_inval = 1;
1881 #endif
1883 if (value & 0x40) {
1884 #if !defined(FLUSH_ALL_TLBS)
1885 mask = (value << 17) & 0x0FFE0000UL;
1886 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1887 #else
1888 do_inval = 1;
1889 #endif
1891 env->IBAT[1][nr] = value;
1892 env->DBAT[1][nr] = value;
1893 #if defined(FLUSH_ALL_TLBS)
1894 if (do_inval) {
1895 tlb_flush(env, 1);
1897 #endif
1901 /*****************************************************************************/
1902 /* TLB management */
1903 void ppc_tlb_invalidate_all(CPUPPCState *env)
1905 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1907 switch (env->mmu_model) {
1908 case POWERPC_MMU_SOFT_6xx:
1909 case POWERPC_MMU_SOFT_74xx:
1910 ppc6xx_tlb_invalidate_all(env);
1911 break;
1912 case POWERPC_MMU_SOFT_4xx:
1913 case POWERPC_MMU_SOFT_4xx_Z:
1914 ppc4xx_tlb_invalidate_all(env);
1915 break;
1916 case POWERPC_MMU_REAL:
1917 cpu_abort(CPU(cpu), "No TLB for PowerPC 4xx in real mode\n");
1918 break;
1919 case POWERPC_MMU_MPC8xx:
1920 /* XXX: TODO */
1921 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1922 break;
1923 case POWERPC_MMU_BOOKE:
1924 tlb_flush(CPU(cpu), 1);
1925 break;
1926 case POWERPC_MMU_BOOKE206:
1927 booke206_flush_tlb(env, -1, 0);
1928 break;
1929 case POWERPC_MMU_32B:
1930 case POWERPC_MMU_601:
1931 #if defined(TARGET_PPC64)
1932 case POWERPC_MMU_64B:
1933 case POWERPC_MMU_2_06:
1934 case POWERPC_MMU_2_06a:
1935 case POWERPC_MMU_2_06d:
1936 #endif /* defined(TARGET_PPC64) */
1937 tlb_flush(CPU(cpu), 1);
1938 break;
1939 default:
1940 /* XXX: TODO */
1941 cpu_abort(CPU(cpu), "Unknown MMU model\n");
1942 break;
1946 void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
1948 #if !defined(FLUSH_ALL_TLBS)
1949 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1950 CPUState *cs;
1952 addr &= TARGET_PAGE_MASK;
1953 switch (env->mmu_model) {
1954 case POWERPC_MMU_SOFT_6xx:
1955 case POWERPC_MMU_SOFT_74xx:
1956 ppc6xx_tlb_invalidate_virt(env, addr, 0);
1957 if (env->id_tlbs == 1) {
1958 ppc6xx_tlb_invalidate_virt(env, addr, 1);
1960 break;
1961 case POWERPC_MMU_SOFT_4xx:
1962 case POWERPC_MMU_SOFT_4xx_Z:
1963 ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
1964 break;
1965 case POWERPC_MMU_REAL:
1966 cpu_abort(CPU(cpu), "No TLB for PowerPC 4xx in real mode\n");
1967 break;
1968 case POWERPC_MMU_MPC8xx:
1969 /* XXX: TODO */
1970 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1971 break;
1972 case POWERPC_MMU_BOOKE:
1973 /* XXX: TODO */
1974 cpu_abort(CPU(cpu), "BookE MMU model is not implemented\n");
1975 break;
1976 case POWERPC_MMU_BOOKE206:
1977 /* XXX: TODO */
1978 cpu_abort(CPU(cpu), "BookE 2.06 MMU model is not implemented\n");
1979 break;
1980 case POWERPC_MMU_32B:
1981 case POWERPC_MMU_601:
1982 /* tlbie invalidate TLBs for all segments */
1983 addr &= ~((target_ulong)-1ULL << 28);
1984 cs = CPU(cpu);
1985 /* XXX: this case should be optimized,
1986 * giving a mask to tlb_flush_page
1988 tlb_flush_page(cs, addr | (0x0 << 28));
1989 tlb_flush_page(cs, addr | (0x1 << 28));
1990 tlb_flush_page(cs, addr | (0x2 << 28));
1991 tlb_flush_page(cs, addr | (0x3 << 28));
1992 tlb_flush_page(cs, addr | (0x4 << 28));
1993 tlb_flush_page(cs, addr | (0x5 << 28));
1994 tlb_flush_page(cs, addr | (0x6 << 28));
1995 tlb_flush_page(cs, addr | (0x7 << 28));
1996 tlb_flush_page(cs, addr | (0x8 << 28));
1997 tlb_flush_page(cs, addr | (0x9 << 28));
1998 tlb_flush_page(cs, addr | (0xA << 28));
1999 tlb_flush_page(cs, addr | (0xB << 28));
2000 tlb_flush_page(cs, addr | (0xC << 28));
2001 tlb_flush_page(cs, addr | (0xD << 28));
2002 tlb_flush_page(cs, addr | (0xE << 28));
2003 tlb_flush_page(cs, addr | (0xF << 28));
2004 break;
2005 #if defined(TARGET_PPC64)
2006 case POWERPC_MMU_64B:
2007 case POWERPC_MMU_2_06:
2008 case POWERPC_MMU_2_06a:
2009 case POWERPC_MMU_2_06d:
2010 /* tlbie invalidate TLBs for all segments */
2011 /* XXX: given the fact that there are too many segments to invalidate,
2012 * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
2013 * we just invalidate all TLBs
2015 tlb_flush(CPU(cpu), 1);
2016 break;
2017 #endif /* defined(TARGET_PPC64) */
2018 default:
2019 /* XXX: TODO */
2020 cpu_abort(CPU(cpu), "Unknown MMU model\n");
2021 break;
2023 #else
2024 ppc_tlb_invalidate_all(env);
2025 #endif
2028 /*****************************************************************************/
2029 /* Special registers manipulation */
2030 void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
2032 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2034 LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value);
2035 assert(!env->external_htab);
2036 if (env->spr[SPR_SDR1] != value) {
2037 env->spr[SPR_SDR1] = value;
2038 #if defined(TARGET_PPC64)
2039 if (env->mmu_model & POWERPC_MMU_64) {
2040 target_ulong htabsize = value & SDR_64_HTABSIZE;
2042 if (htabsize > 28) {
2043 fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx
2044 " stored in SDR1\n", htabsize);
2045 htabsize = 28;
2047 env->htab_mask = (1ULL << (htabsize + 18 - 7)) - 1;
2048 env->htab_base = value & SDR_64_HTABORG;
2049 } else
2050 #endif /* defined(TARGET_PPC64) */
2052 /* FIXME: Should check for valid HTABMASK values */
2053 env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
2054 env->htab_base = value & SDR_32_HTABORG;
2056 tlb_flush(CPU(cpu), 1);
2060 /* Segment registers load and store */
2061 target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
2063 #if defined(TARGET_PPC64)
2064 if (env->mmu_model & POWERPC_MMU_64) {
2065 /* XXX */
2066 return 0;
2068 #endif
2069 return env->sr[sr_num];
2072 void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
2074 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2076 LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
2077 (int)srnum, value, env->sr[srnum]);
2078 #if defined(TARGET_PPC64)
2079 if (env->mmu_model & POWERPC_MMU_64) {
2080 uint64_t rb = 0, rs = 0;
2082 /* ESID = srnum */
2083 rb |= ((uint32_t)srnum & 0xf) << 28;
2084 /* Set the valid bit */
2085 rb |= SLB_ESID_V;
2086 /* Index = ESID */
2087 rb |= (uint32_t)srnum;
2089 /* VSID = VSID */
2090 rs |= (value & 0xfffffff) << 12;
2091 /* flags = flags */
2092 rs |= ((value >> 27) & 0xf) << 8;
2094 ppc_store_slb(env, rb, rs);
2095 } else
2096 #endif
2097 if (env->sr[srnum] != value) {
2098 env->sr[srnum] = value;
2099 /* Invalidating 256MB of virtual memory in 4kB pages is way longer than
2100 flusing the whole TLB. */
2101 #if !defined(FLUSH_ALL_TLBS) && 0
2103 target_ulong page, end;
2104 /* Invalidate 256 MB of virtual memory */
2105 page = (16 << 20) * srnum;
2106 end = page + (16 << 20);
2107 for (; page != end; page += TARGET_PAGE_SIZE) {
2108 tlb_flush_page(CPU(cpu), page);
2111 #else
2112 tlb_flush(CPU(cpu), 1);
2113 #endif
2117 /* TLB management */
2118 void helper_tlbia(CPUPPCState *env)
2120 ppc_tlb_invalidate_all(env);
2123 void helper_tlbie(CPUPPCState *env, target_ulong addr)
2125 ppc_tlb_invalidate_one(env, addr);
2128 /* Software driven TLBs management */
2129 /* PowerPC 602/603 software TLB load instructions helpers */
2130 static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2132 target_ulong RPN, CMP, EPN;
2133 int way;
2135 RPN = env->spr[SPR_RPA];
2136 if (is_code) {
2137 CMP = env->spr[SPR_ICMP];
2138 EPN = env->spr[SPR_IMISS];
2139 } else {
2140 CMP = env->spr[SPR_DCMP];
2141 EPN = env->spr[SPR_DMISS];
2143 way = (env->spr[SPR_SRR1] >> 17) & 1;
2144 (void)EPN; /* avoid a compiler warning */
2145 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2146 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2147 RPN, way);
2148 /* Store this TLB */
2149 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2150 way, is_code, CMP, RPN);
2153 void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN)
2155 do_6xx_tlb(env, EPN, 0);
2158 void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
2160 do_6xx_tlb(env, EPN, 1);
2163 /* PowerPC 74xx software TLB load instructions helpers */
2164 static void do_74xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2166 target_ulong RPN, CMP, EPN;
2167 int way;
2169 RPN = env->spr[SPR_PTELO];
2170 CMP = env->spr[SPR_PTEHI];
2171 EPN = env->spr[SPR_TLBMISS] & ~0x3;
2172 way = env->spr[SPR_TLBMISS] & 0x3;
2173 (void)EPN; /* avoid a compiler warning */
2174 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2175 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2176 RPN, way);
2177 /* Store this TLB */
2178 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2179 way, is_code, CMP, RPN);
2182 void helper_74xx_tlbd(CPUPPCState *env, target_ulong EPN)
2184 do_74xx_tlb(env, EPN, 0);
2187 void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN)
2189 do_74xx_tlb(env, EPN, 1);
2192 /*****************************************************************************/
2193 /* PowerPC 601 specific instructions (POWER bridge) */
2195 target_ulong helper_rac(CPUPPCState *env, target_ulong addr)
2197 mmu_ctx_t ctx;
2198 int nb_BATs;
2199 target_ulong ret = 0;
2201 /* We don't have to generate many instances of this instruction,
2202 * as rac is supervisor only.
2204 /* XXX: FIX THIS: Pretend we have no BAT */
2205 nb_BATs = env->nb_BATs;
2206 env->nb_BATs = 0;
2207 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
2208 ret = ctx.raddr;
2210 env->nb_BATs = nb_BATs;
2211 return ret;
2214 static inline target_ulong booke_tlb_to_page_size(int size)
2216 return 1024 << (2 * size);
2219 static inline int booke_page_size_to_tlb(target_ulong page_size)
2221 int size;
2223 switch (page_size) {
2224 case 0x00000400UL:
2225 size = 0x0;
2226 break;
2227 case 0x00001000UL:
2228 size = 0x1;
2229 break;
2230 case 0x00004000UL:
2231 size = 0x2;
2232 break;
2233 case 0x00010000UL:
2234 size = 0x3;
2235 break;
2236 case 0x00040000UL:
2237 size = 0x4;
2238 break;
2239 case 0x00100000UL:
2240 size = 0x5;
2241 break;
2242 case 0x00400000UL:
2243 size = 0x6;
2244 break;
2245 case 0x01000000UL:
2246 size = 0x7;
2247 break;
2248 case 0x04000000UL:
2249 size = 0x8;
2250 break;
2251 case 0x10000000UL:
2252 size = 0x9;
2253 break;
2254 case 0x40000000UL:
2255 size = 0xA;
2256 break;
2257 #if defined(TARGET_PPC64)
2258 case 0x000100000000ULL:
2259 size = 0xB;
2260 break;
2261 case 0x000400000000ULL:
2262 size = 0xC;
2263 break;
2264 case 0x001000000000ULL:
2265 size = 0xD;
2266 break;
2267 case 0x004000000000ULL:
2268 size = 0xE;
2269 break;
2270 case 0x010000000000ULL:
2271 size = 0xF;
2272 break;
2273 #endif
2274 default:
2275 size = -1;
2276 break;
2279 return size;
2282 /* Helpers for 4xx TLB management */
2283 #define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
2285 #define PPC4XX_TLBHI_V 0x00000040
2286 #define PPC4XX_TLBHI_E 0x00000020
2287 #define PPC4XX_TLBHI_SIZE_MIN 0
2288 #define PPC4XX_TLBHI_SIZE_MAX 7
2289 #define PPC4XX_TLBHI_SIZE_DEFAULT 1
2290 #define PPC4XX_TLBHI_SIZE_SHIFT 7
2291 #define PPC4XX_TLBHI_SIZE_MASK 0x00000007
2293 #define PPC4XX_TLBLO_EX 0x00000200
2294 #define PPC4XX_TLBLO_WR 0x00000100
2295 #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
2296 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
2298 target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
2300 ppcemb_tlb_t *tlb;
2301 target_ulong ret;
2302 int size;
2304 entry &= PPC4XX_TLB_ENTRY_MASK;
2305 tlb = &env->tlb.tlbe[entry];
2306 ret = tlb->EPN;
2307 if (tlb->prot & PAGE_VALID) {
2308 ret |= PPC4XX_TLBHI_V;
2310 size = booke_page_size_to_tlb(tlb->size);
2311 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
2312 size = PPC4XX_TLBHI_SIZE_DEFAULT;
2314 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
2315 env->spr[SPR_40x_PID] = tlb->PID;
2316 return ret;
2319 target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry)
2321 ppcemb_tlb_t *tlb;
2322 target_ulong ret;
2324 entry &= PPC4XX_TLB_ENTRY_MASK;
2325 tlb = &env->tlb.tlbe[entry];
2326 ret = tlb->RPN;
2327 if (tlb->prot & PAGE_EXEC) {
2328 ret |= PPC4XX_TLBLO_EX;
2330 if (tlb->prot & PAGE_WRITE) {
2331 ret |= PPC4XX_TLBLO_WR;
2333 return ret;
2336 void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
2337 target_ulong val)
2339 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2340 CPUState *cs = CPU(cpu);
2341 ppcemb_tlb_t *tlb;
2342 target_ulong page, end;
2344 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
2345 val);
2346 entry &= PPC4XX_TLB_ENTRY_MASK;
2347 tlb = &env->tlb.tlbe[entry];
2348 /* Invalidate previous TLB (if it's valid) */
2349 if (tlb->prot & PAGE_VALID) {
2350 end = tlb->EPN + tlb->size;
2351 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
2352 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2353 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2354 tlb_flush_page(cs, page);
2357 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
2358 & PPC4XX_TLBHI_SIZE_MASK);
2359 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2360 * If this ever occurs, one should use the ppcemb target instead
2361 * of the ppc or ppc64 one
2363 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
2364 cpu_abort(cs, "TLB size " TARGET_FMT_lu " < %u "
2365 "are not supported (%d)\n",
2366 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
2368 tlb->EPN = val & ~(tlb->size - 1);
2369 if (val & PPC4XX_TLBHI_V) {
2370 tlb->prot |= PAGE_VALID;
2371 if (val & PPC4XX_TLBHI_E) {
2372 /* XXX: TO BE FIXED */
2373 cpu_abort(cs,
2374 "Little-endian TLB entries are not supported by now\n");
2376 } else {
2377 tlb->prot &= ~PAGE_VALID;
2379 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2380 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2381 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2382 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2383 tlb->prot & PAGE_READ ? 'r' : '-',
2384 tlb->prot & PAGE_WRITE ? 'w' : '-',
2385 tlb->prot & PAGE_EXEC ? 'x' : '-',
2386 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2387 /* Invalidate new TLB (if valid) */
2388 if (tlb->prot & PAGE_VALID) {
2389 end = tlb->EPN + tlb->size;
2390 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
2391 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2392 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2393 tlb_flush_page(cs, page);
2398 void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
2399 target_ulong val)
2401 ppcemb_tlb_t *tlb;
2403 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
2404 val);
2405 entry &= PPC4XX_TLB_ENTRY_MASK;
2406 tlb = &env->tlb.tlbe[entry];
2407 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
2408 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
2409 tlb->prot = PAGE_READ;
2410 if (val & PPC4XX_TLBLO_EX) {
2411 tlb->prot |= PAGE_EXEC;
2413 if (val & PPC4XX_TLBLO_WR) {
2414 tlb->prot |= PAGE_WRITE;
2416 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2417 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2418 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2419 tlb->prot & PAGE_READ ? 'r' : '-',
2420 tlb->prot & PAGE_WRITE ? 'w' : '-',
2421 tlb->prot & PAGE_EXEC ? 'x' : '-',
2422 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2425 target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
2427 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
2430 /* PowerPC 440 TLB management */
2431 void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry,
2432 target_ulong value)
2434 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2435 ppcemb_tlb_t *tlb;
2436 target_ulong EPN, RPN, size;
2437 int do_flush_tlbs;
2439 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
2440 __func__, word, (int)entry, value);
2441 do_flush_tlbs = 0;
2442 entry &= 0x3F;
2443 tlb = &env->tlb.tlbe[entry];
2444 switch (word) {
2445 default:
2446 /* Just here to please gcc */
2447 case 0:
2448 EPN = value & 0xFFFFFC00;
2449 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
2450 do_flush_tlbs = 1;
2452 tlb->EPN = EPN;
2453 size = booke_tlb_to_page_size((value >> 4) & 0xF);
2454 if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
2455 do_flush_tlbs = 1;
2457 tlb->size = size;
2458 tlb->attr &= ~0x1;
2459 tlb->attr |= (value >> 8) & 1;
2460 if (value & 0x200) {
2461 tlb->prot |= PAGE_VALID;
2462 } else {
2463 if (tlb->prot & PAGE_VALID) {
2464 tlb->prot &= ~PAGE_VALID;
2465 do_flush_tlbs = 1;
2468 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
2469 if (do_flush_tlbs) {
2470 tlb_flush(CPU(cpu), 1);
2472 break;
2473 case 1:
2474 RPN = value & 0xFFFFFC0F;
2475 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
2476 tlb_flush(CPU(cpu), 1);
2478 tlb->RPN = RPN;
2479 break;
2480 case 2:
2481 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
2482 tlb->prot = tlb->prot & PAGE_VALID;
2483 if (value & 0x1) {
2484 tlb->prot |= PAGE_READ << 4;
2486 if (value & 0x2) {
2487 tlb->prot |= PAGE_WRITE << 4;
2489 if (value & 0x4) {
2490 tlb->prot |= PAGE_EXEC << 4;
2492 if (value & 0x8) {
2493 tlb->prot |= PAGE_READ;
2495 if (value & 0x10) {
2496 tlb->prot |= PAGE_WRITE;
2498 if (value & 0x20) {
2499 tlb->prot |= PAGE_EXEC;
2501 break;
2505 target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word,
2506 target_ulong entry)
2508 ppcemb_tlb_t *tlb;
2509 target_ulong ret;
2510 int size;
2512 entry &= 0x3F;
2513 tlb = &env->tlb.tlbe[entry];
2514 switch (word) {
2515 default:
2516 /* Just here to please gcc */
2517 case 0:
2518 ret = tlb->EPN;
2519 size = booke_page_size_to_tlb(tlb->size);
2520 if (size < 0 || size > 0xF) {
2521 size = 1;
2523 ret |= size << 4;
2524 if (tlb->attr & 0x1) {
2525 ret |= 0x100;
2527 if (tlb->prot & PAGE_VALID) {
2528 ret |= 0x200;
2530 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
2531 env->spr[SPR_440_MMUCR] |= tlb->PID;
2532 break;
2533 case 1:
2534 ret = tlb->RPN;
2535 break;
2536 case 2:
2537 ret = tlb->attr & ~0x1;
2538 if (tlb->prot & (PAGE_READ << 4)) {
2539 ret |= 0x1;
2541 if (tlb->prot & (PAGE_WRITE << 4)) {
2542 ret |= 0x2;
2544 if (tlb->prot & (PAGE_EXEC << 4)) {
2545 ret |= 0x4;
2547 if (tlb->prot & PAGE_READ) {
2548 ret |= 0x8;
2550 if (tlb->prot & PAGE_WRITE) {
2551 ret |= 0x10;
2553 if (tlb->prot & PAGE_EXEC) {
2554 ret |= 0x20;
2556 break;
2558 return ret;
2561 target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address)
2563 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
2566 /* PowerPC BookE 2.06 TLB management */
2568 static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
2570 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2571 uint32_t tlbncfg = 0;
2572 int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
2573 int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
2574 int tlb;
2576 tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2577 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
2579 if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
2580 cpu_abort(CPU(cpu), "we don't support HES yet\n");
2583 return booke206_get_tlbm(env, tlb, ea, esel);
2586 void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid)
2588 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2590 env->spr[pidn] = pid;
2591 /* changing PIDs mean we're in a different address space now */
2592 tlb_flush(CPU(cpu), 1);
2595 void helper_booke206_tlbwe(CPUPPCState *env)
2597 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2598 uint32_t tlbncfg, tlbn;
2599 ppcmas_tlb_t *tlb;
2600 uint32_t size_tlb, size_ps;
2601 target_ulong mask;
2604 switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
2605 case MAS0_WQ_ALWAYS:
2606 /* good to go, write that entry */
2607 break;
2608 case MAS0_WQ_COND:
2609 /* XXX check if reserved */
2610 if (0) {
2611 return;
2613 break;
2614 case MAS0_WQ_CLR_RSRV:
2615 /* XXX clear entry */
2616 return;
2617 default:
2618 /* no idea what to do */
2619 return;
2622 if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
2623 !msr_gs) {
2624 /* XXX we don't support direct LRAT setting yet */
2625 fprintf(stderr, "cpu: don't support LRAT setting yet\n");
2626 return;
2629 tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2630 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
2632 tlb = booke206_cur_tlb(env);
2634 if (!tlb) {
2635 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2636 POWERPC_EXCP_INVAL |
2637 POWERPC_EXCP_INVAL_INVAL);
2640 /* check that we support the targeted size */
2641 size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
2642 size_ps = booke206_tlbnps(env, tlbn);
2643 if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
2644 !(size_ps & (1 << size_tlb))) {
2645 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2646 POWERPC_EXCP_INVAL |
2647 POWERPC_EXCP_INVAL_INVAL);
2650 if (msr_gs) {
2651 cpu_abort(CPU(cpu), "missing HV implementation\n");
2653 tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
2654 env->spr[SPR_BOOKE_MAS3];
2655 tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
2657 /* MAV 1.0 only */
2658 if (!(tlbncfg & TLBnCFG_AVAIL)) {
2659 /* force !AVAIL TLB entries to correct page size */
2660 tlb->mas1 &= ~MAS1_TSIZE_MASK;
2661 /* XXX can be configured in MMUCSR0 */
2662 tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
2665 /* Make a mask from TLB size to discard invalid bits in EPN field */
2666 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2667 /* Add a mask for page attributes */
2668 mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E;
2670 if (!msr_cm) {
2671 /* Executing a tlbwe instruction in 32-bit mode will set
2672 * bits 0:31 of the TLB EPN field to zero.
2674 mask &= 0xffffffff;
2677 tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & mask;
2679 if (!(tlbncfg & TLBnCFG_IPROT)) {
2680 /* no IPROT supported by TLB */
2681 tlb->mas1 &= ~MAS1_IPROT;
2684 if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
2685 tlb_flush_page(CPU(cpu), tlb->mas2 & MAS2_EPN_MASK);
2686 } else {
2687 tlb_flush(CPU(cpu), 1);
2691 static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
2693 int tlbn = booke206_tlbm_to_tlbn(env, tlb);
2694 int way = booke206_tlbm_to_way(env, tlb);
2696 env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
2697 env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
2698 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2700 env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
2701 env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
2702 env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
2703 env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
2706 void helper_booke206_tlbre(CPUPPCState *env)
2708 ppcmas_tlb_t *tlb = NULL;
2710 tlb = booke206_cur_tlb(env);
2711 if (!tlb) {
2712 env->spr[SPR_BOOKE_MAS1] = 0;
2713 } else {
2714 booke206_tlb_to_mas(env, tlb);
2718 void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address)
2720 ppcmas_tlb_t *tlb = NULL;
2721 int i, j;
2722 hwaddr raddr;
2723 uint32_t spid, sas;
2725 spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
2726 sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
2728 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2729 int ways = booke206_tlb_ways(env, i);
2731 for (j = 0; j < ways; j++) {
2732 tlb = booke206_get_tlbm(env, i, address, j);
2734 if (!tlb) {
2735 continue;
2738 if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
2739 continue;
2742 if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
2743 continue;
2746 booke206_tlb_to_mas(env, tlb);
2747 return;
2751 /* no entry found, fill with defaults */
2752 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
2753 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
2754 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
2755 env->spr[SPR_BOOKE_MAS3] = 0;
2756 env->spr[SPR_BOOKE_MAS7] = 0;
2758 if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
2759 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
2762 env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
2763 << MAS1_TID_SHIFT;
2765 /* next victim logic */
2766 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
2767 env->last_way++;
2768 env->last_way &= booke206_tlb_ways(env, 0) - 1;
2769 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2772 static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
2773 uint32_t ea)
2775 int i;
2776 int ways = booke206_tlb_ways(env, tlbn);
2777 target_ulong mask;
2779 for (i = 0; i < ways; i++) {
2780 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
2781 if (!tlb) {
2782 continue;
2784 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2785 if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
2786 !(tlb->mas1 & MAS1_IPROT)) {
2787 tlb->mas1 &= ~MAS1_VALID;
2792 void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address)
2794 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2796 if (address & 0x4) {
2797 /* flush all entries */
2798 if (address & 0x8) {
2799 /* flush all of TLB1 */
2800 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
2801 } else {
2802 /* flush all of TLB0 */
2803 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
2805 return;
2808 if (address & 0x8) {
2809 /* flush TLB1 entries */
2810 booke206_invalidate_ea_tlb(env, 1, address);
2811 tlb_flush(CPU(cpu), 1);
2812 } else {
2813 /* flush TLB0 entries */
2814 booke206_invalidate_ea_tlb(env, 0, address);
2815 tlb_flush_page(CPU(cpu), address & MAS2_EPN_MASK);
2819 void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address)
2821 /* XXX missing LPID handling */
2822 booke206_flush_tlb(env, -1, 1);
2825 void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address)
2827 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2828 int i, j;
2829 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2830 ppcmas_tlb_t *tlb = env->tlb.tlbm;
2831 int tlb_size;
2833 /* XXX missing LPID handling */
2834 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2835 tlb_size = booke206_tlb_size(env, i);
2836 for (j = 0; j < tlb_size; j++) {
2837 if (!(tlb[j].mas1 & MAS1_IPROT) &&
2838 ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
2839 tlb[j].mas1 &= ~MAS1_VALID;
2842 tlb += booke206_tlb_size(env, i);
2844 tlb_flush(CPU(cpu), 1);
2847 void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
2849 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2850 int i, j;
2851 ppcmas_tlb_t *tlb;
2852 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2853 int pid = tid >> MAS6_SPID_SHIFT;
2854 int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
2855 int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
2856 /* XXX check for unsupported isize and raise an invalid opcode then */
2857 int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
2858 /* XXX implement MAV2 handling */
2859 bool mav2 = false;
2861 /* XXX missing LPID handling */
2862 /* flush by pid and ea */
2863 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2864 int ways = booke206_tlb_ways(env, i);
2866 for (j = 0; j < ways; j++) {
2867 tlb = booke206_get_tlbm(env, i, address, j);
2868 if (!tlb) {
2869 continue;
2871 if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
2872 (tlb->mas1 & MAS1_IPROT) ||
2873 ((tlb->mas1 & MAS1_IND) != ind) ||
2874 ((tlb->mas8 & MAS8_TGS) != sgs)) {
2875 continue;
2877 if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
2878 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
2879 continue;
2881 /* XXX e500mc doesn't match SAS, but other cores might */
2882 tlb->mas1 &= ~MAS1_VALID;
2885 tlb_flush(CPU(cpu), 1);
2888 void helper_booke206_tlbflush(CPUPPCState *env, uint32_t type)
2890 int flags = 0;
2892 if (type & 2) {
2893 flags |= BOOKE206_FLUSH_TLB1;
2896 if (type & 4) {
2897 flags |= BOOKE206_FLUSH_TLB0;
2900 booke206_flush_tlb(env, flags, 1);
2904 /*****************************************************************************/
2906 #include "exec/softmmu_exec.h"
2908 #define MMUSUFFIX _mmu
2910 #define SHIFT 0
2911 #include "exec/softmmu_template.h"
2913 #define SHIFT 1
2914 #include "exec/softmmu_template.h"
2916 #define SHIFT 2
2917 #include "exec/softmmu_template.h"
2919 #define SHIFT 3
2920 #include "exec/softmmu_template.h"
2922 /* try to fill the TLB and return an exception if error. If retaddr is
2923 NULL, it means that the function was called in C code (i.e. not
2924 from generated code or from helper.c) */
2925 /* XXX: fix it to restore all registers */
2926 void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
2927 uintptr_t retaddr)
2929 PowerPCCPU *cpu = POWERPC_CPU(cs);
2930 PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
2931 CPUPPCState *env = &cpu->env;
2932 int ret;
2934 if (pcc->handle_mmu_fault) {
2935 ret = pcc->handle_mmu_fault(cpu, addr, is_write, mmu_idx);
2936 } else {
2937 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
2939 if (unlikely(ret != 0)) {
2940 if (likely(retaddr)) {
2941 /* now we have a real cpu fault */
2942 cpu_restore_state(cs, retaddr);
2944 helper_raise_exception_err(env, cs->exception_index, env->error_code);