PPC: e500: Fix MMUCSR0 emulation
[qemu-kvm.git] / target-ppc / mmu_helper.c
blob1e70536e361d2922a520d9594792b145db13f51e
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 "exec/helper-proto.h"
21 #include "sysemu/kvm.h"
22 #include "kvm_ppc.h"
23 #include "mmu-hash64.h"
24 #include "mmu-hash32.h"
25 #include "exec/cpu_ldst.h"
27 //#define DEBUG_MMU
28 //#define DEBUG_BATS
29 //#define DEBUG_SOFTWARE_TLB
30 //#define DUMP_PAGE_TABLES
31 //#define DEBUG_SOFTWARE_TLB
32 //#define FLUSH_ALL_TLBS
34 #ifdef DEBUG_MMU
35 # define LOG_MMU(...) qemu_log(__VA_ARGS__)
36 # define LOG_MMU_STATE(cpu) log_cpu_state((cpu), 0)
37 #else
38 # define LOG_MMU(...) do { } while (0)
39 # define LOG_MMU_STATE(cpu) do { } while (0)
40 #endif
42 #ifdef DEBUG_SOFTWARE_TLB
43 # define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
44 #else
45 # define LOG_SWTLB(...) do { } while (0)
46 #endif
48 #ifdef DEBUG_BATS
49 # define LOG_BATS(...) qemu_log(__VA_ARGS__)
50 #else
51 # define LOG_BATS(...) do { } while (0)
52 #endif
54 /*****************************************************************************/
55 /* PowerPC MMU emulation */
57 /* Context used internally during MMU translations */
58 typedef struct mmu_ctx_t mmu_ctx_t;
59 struct mmu_ctx_t {
60 hwaddr raddr; /* Real address */
61 hwaddr eaddr; /* Effective address */
62 int prot; /* Protection bits */
63 hwaddr hash[2]; /* Pagetable hash values */
64 target_ulong ptem; /* Virtual segment ID | API */
65 int key; /* Access key */
66 int nx; /* Non-execute area */
69 /* Common routines used by software and hardware TLBs emulation */
70 static inline int pte_is_valid(target_ulong pte0)
72 return pte0 & 0x80000000 ? 1 : 0;
75 static inline void pte_invalidate(target_ulong *pte0)
77 *pte0 &= ~0x80000000;
80 #define PTE_PTEM_MASK 0x7FFFFFBF
81 #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
83 static int pp_check(int key, int pp, int nx)
85 int access;
87 /* Compute access rights */
88 access = 0;
89 if (key == 0) {
90 switch (pp) {
91 case 0x0:
92 case 0x1:
93 case 0x2:
94 access |= PAGE_WRITE;
95 /* No break here */
96 case 0x3:
97 access |= PAGE_READ;
98 break;
100 } else {
101 switch (pp) {
102 case 0x0:
103 access = 0;
104 break;
105 case 0x1:
106 case 0x3:
107 access = PAGE_READ;
108 break;
109 case 0x2:
110 access = PAGE_READ | PAGE_WRITE;
111 break;
114 if (nx == 0) {
115 access |= PAGE_EXEC;
118 return access;
121 static int check_prot(int prot, int rw, int access_type)
123 int ret;
125 if (access_type == ACCESS_CODE) {
126 if (prot & PAGE_EXEC) {
127 ret = 0;
128 } else {
129 ret = -2;
131 } else if (rw) {
132 if (prot & PAGE_WRITE) {
133 ret = 0;
134 } else {
135 ret = -2;
137 } else {
138 if (prot & PAGE_READ) {
139 ret = 0;
140 } else {
141 ret = -2;
145 return ret;
148 static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
149 target_ulong pte1, int h, int rw, int type)
151 target_ulong ptem, mmask;
152 int access, ret, pteh, ptev, pp;
154 ret = -1;
155 /* Check validity and table match */
156 ptev = pte_is_valid(pte0);
157 pteh = (pte0 >> 6) & 1;
158 if (ptev && h == pteh) {
159 /* Check vsid & api */
160 ptem = pte0 & PTE_PTEM_MASK;
161 mmask = PTE_CHECK_MASK;
162 pp = pte1 & 0x00000003;
163 if (ptem == ctx->ptem) {
164 if (ctx->raddr != (hwaddr)-1ULL) {
165 /* all matches should have equal RPN, WIMG & PP */
166 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
167 qemu_log("Bad RPN/WIMG/PP\n");
168 return -3;
171 /* Compute access rights */
172 access = pp_check(ctx->key, pp, ctx->nx);
173 /* Keep the matching PTE informations */
174 ctx->raddr = pte1;
175 ctx->prot = access;
176 ret = check_prot(ctx->prot, rw, type);
177 if (ret == 0) {
178 /* Access granted */
179 LOG_MMU("PTE access granted !\n");
180 } else {
181 /* Access right violation */
182 LOG_MMU("PTE access rejected\n");
187 return ret;
190 static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
191 int ret, int rw)
193 int store = 0;
195 /* Update page flags */
196 if (!(*pte1p & 0x00000100)) {
197 /* Update accessed flag */
198 *pte1p |= 0x00000100;
199 store = 1;
201 if (!(*pte1p & 0x00000080)) {
202 if (rw == 1 && ret == 0) {
203 /* Update changed flag */
204 *pte1p |= 0x00000080;
205 store = 1;
206 } else {
207 /* Force page fault for first write access */
208 ctx->prot &= ~PAGE_WRITE;
212 return store;
215 /* Software driven TLB helpers */
216 static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
217 int way, int is_code)
219 int nr;
221 /* Select TLB num in a way from address */
222 nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
223 /* Select TLB way */
224 nr += env->tlb_per_way * way;
225 /* 6xx have separate TLBs for instructions and data */
226 if (is_code && env->id_tlbs == 1) {
227 nr += env->nb_tlb;
230 return nr;
233 static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
235 PowerPCCPU *cpu = ppc_env_get_cpu(env);
236 ppc6xx_tlb_t *tlb;
237 int nr, max;
239 /* LOG_SWTLB("Invalidate all TLBs\n"); */
240 /* Invalidate all defined software TLB */
241 max = env->nb_tlb;
242 if (env->id_tlbs == 1) {
243 max *= 2;
245 for (nr = 0; nr < max; nr++) {
246 tlb = &env->tlb.tlb6[nr];
247 pte_invalidate(&tlb->pte0);
249 tlb_flush(CPU(cpu), 1);
252 static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env,
253 target_ulong eaddr,
254 int is_code, int match_epn)
256 #if !defined(FLUSH_ALL_TLBS)
257 CPUState *cs = CPU(ppc_env_get_cpu(env));
258 ppc6xx_tlb_t *tlb;
259 int way, nr;
261 /* Invalidate ITLB + DTLB, all ways */
262 for (way = 0; way < env->nb_ways; way++) {
263 nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
264 tlb = &env->tlb.tlb6[nr];
265 if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
266 LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
267 env->nb_tlb, eaddr);
268 pte_invalidate(&tlb->pte0);
269 tlb_flush_page(cs, tlb->EPN);
272 #else
273 /* XXX: PowerPC specification say this is valid as well */
274 ppc6xx_tlb_invalidate_all(env);
275 #endif
278 static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
279 target_ulong eaddr, int is_code)
281 ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0);
284 static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way,
285 int is_code, target_ulong pte0, target_ulong pte1)
287 ppc6xx_tlb_t *tlb;
288 int nr;
290 nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
291 tlb = &env->tlb.tlb6[nr];
292 LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
293 " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
294 /* Invalidate any pending reference in QEMU for this virtual address */
295 ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1);
296 tlb->pte0 = pte0;
297 tlb->pte1 = pte1;
298 tlb->EPN = EPN;
299 /* Store last way for LRU mechanism */
300 env->last_way = way;
303 static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
304 target_ulong eaddr, int rw, int access_type)
306 ppc6xx_tlb_t *tlb;
307 int nr, best, way;
308 int ret;
310 best = -1;
311 ret = -1; /* No TLB found */
312 for (way = 0; way < env->nb_ways; way++) {
313 nr = ppc6xx_tlb_getnum(env, eaddr, way,
314 access_type == ACCESS_CODE ? 1 : 0);
315 tlb = &env->tlb.tlb6[nr];
316 /* This test "emulates" the PTE index match for hardware TLBs */
317 if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
318 LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
319 "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
320 pte_is_valid(tlb->pte0) ? "valid" : "inval",
321 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
322 continue;
324 LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
325 TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
326 pte_is_valid(tlb->pte0) ? "valid" : "inval",
327 tlb->EPN, eaddr, tlb->pte1,
328 rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
329 switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
330 case -3:
331 /* TLB inconsistency */
332 return -1;
333 case -2:
334 /* Access violation */
335 ret = -2;
336 best = nr;
337 break;
338 case -1:
339 default:
340 /* No match */
341 break;
342 case 0:
343 /* access granted */
344 /* XXX: we should go on looping to check all TLBs consistency
345 * but we can speed-up the whole thing as the
346 * result would be undefined if TLBs are not consistent.
348 ret = 0;
349 best = nr;
350 goto done;
353 if (best != -1) {
354 done:
355 LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
356 ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
357 /* Update page flags */
358 pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
361 return ret;
364 /* Perform BAT hit & translation */
365 static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
366 int *validp, int *protp, target_ulong *BATu,
367 target_ulong *BATl)
369 target_ulong bl;
370 int pp, valid, prot;
372 bl = (*BATu & 0x00001FFC) << 15;
373 valid = 0;
374 prot = 0;
375 if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
376 ((msr_pr != 0) && (*BATu & 0x00000001))) {
377 valid = 1;
378 pp = *BATl & 0x00000003;
379 if (pp != 0) {
380 prot = PAGE_READ | PAGE_EXEC;
381 if (pp == 0x2) {
382 prot |= PAGE_WRITE;
386 *blp = bl;
387 *validp = valid;
388 *protp = prot;
391 static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
392 target_ulong virtual, int rw, int type)
394 target_ulong *BATlt, *BATut, *BATu, *BATl;
395 target_ulong BEPIl, BEPIu, bl;
396 int i, valid, prot;
397 int ret = -1;
399 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
400 type == ACCESS_CODE ? 'I' : 'D', virtual);
401 switch (type) {
402 case ACCESS_CODE:
403 BATlt = env->IBAT[1];
404 BATut = env->IBAT[0];
405 break;
406 default:
407 BATlt = env->DBAT[1];
408 BATut = env->DBAT[0];
409 break;
411 for (i = 0; i < env->nb_BATs; i++) {
412 BATu = &BATut[i];
413 BATl = &BATlt[i];
414 BEPIu = *BATu & 0xF0000000;
415 BEPIl = *BATu & 0x0FFE0000;
416 bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
417 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
418 " BATl " TARGET_FMT_lx "\n", __func__,
419 type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
420 if ((virtual & 0xF0000000) == BEPIu &&
421 ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
422 /* BAT matches */
423 if (valid != 0) {
424 /* Get physical address */
425 ctx->raddr = (*BATl & 0xF0000000) |
426 ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
427 (virtual & 0x0001F000);
428 /* Compute access rights */
429 ctx->prot = prot;
430 ret = check_prot(ctx->prot, rw, type);
431 if (ret == 0) {
432 LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
433 i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
434 ctx->prot & PAGE_WRITE ? 'W' : '-');
436 break;
440 if (ret < 0) {
441 #if defined(DEBUG_BATS)
442 if (qemu_log_enabled()) {
443 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
444 for (i = 0; i < 4; i++) {
445 BATu = &BATut[i];
446 BATl = &BATlt[i];
447 BEPIu = *BATu & 0xF0000000;
448 BEPIl = *BATu & 0x0FFE0000;
449 bl = (*BATu & 0x00001FFC) << 15;
450 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
451 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
452 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
453 __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
454 *BATu, *BATl, BEPIu, BEPIl, bl);
457 #endif
459 /* No hit */
460 return ret;
463 /* Perform segment based translation */
464 static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
465 target_ulong eaddr, int rw, int type)
467 hwaddr hash;
468 target_ulong vsid;
469 int ds, pr, target_page_bits;
470 int ret;
471 target_ulong sr, pgidx;
473 pr = msr_pr;
474 ctx->eaddr = eaddr;
476 sr = env->sr[eaddr >> 28];
477 ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
478 ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
479 ds = sr & 0x80000000 ? 1 : 0;
480 ctx->nx = sr & 0x10000000 ? 1 : 0;
481 vsid = sr & 0x00FFFFFF;
482 target_page_bits = TARGET_PAGE_BITS;
483 LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
484 TARGET_FMT_lx " lr=" TARGET_FMT_lx
485 " ir=%d dr=%d pr=%d %d t=%d\n",
486 eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
487 (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
488 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
489 hash = vsid ^ pgidx;
490 ctx->ptem = (vsid << 7) | (pgidx >> 10);
492 LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
493 ctx->key, ds, ctx->nx, vsid);
494 ret = -1;
495 if (!ds) {
496 /* Check if instruction fetch is allowed, if needed */
497 if (type != ACCESS_CODE || ctx->nx == 0) {
498 /* Page address translation */
499 LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
500 " hash " TARGET_FMT_plx "\n",
501 env->htab_base, env->htab_mask, hash);
502 ctx->hash[0] = hash;
503 ctx->hash[1] = ~hash;
505 /* Initialize real address with an invalid value */
506 ctx->raddr = (hwaddr)-1ULL;
507 /* Software TLB search */
508 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
509 #if defined(DUMP_PAGE_TABLES)
510 if (qemu_log_enabled()) {
511 hwaddr curaddr;
512 uint32_t a0, a1, a2, a3;
514 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
515 "\n", sdr, mask + 0x80);
516 for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
517 curaddr += 16) {
518 a0 = ldl_phys(curaddr);
519 a1 = ldl_phys(curaddr + 4);
520 a2 = ldl_phys(curaddr + 8);
521 a3 = ldl_phys(curaddr + 12);
522 if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
523 qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
524 curaddr, a0, a1, a2, a3);
528 #endif
529 } else {
530 LOG_MMU("No access allowed\n");
531 ret = -3;
533 } else {
534 target_ulong sr;
536 LOG_MMU("direct store...\n");
537 /* Direct-store segment : absolutely *BUGGY* for now */
539 /* Direct-store implies a 32-bit MMU.
540 * Check the Segment Register's bus unit ID (BUID).
542 sr = env->sr[eaddr >> 28];
543 if ((sr & 0x1FF00000) >> 20 == 0x07f) {
544 /* Memory-forced I/O controller interface access */
545 /* If T=1 and BUID=x'07F', the 601 performs a memory access
546 * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
548 ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
549 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
550 return 0;
553 switch (type) {
554 case ACCESS_INT:
555 /* Integer load/store : only access allowed */
556 break;
557 case ACCESS_CODE:
558 /* No code fetch is allowed in direct-store areas */
559 return -4;
560 case ACCESS_FLOAT:
561 /* Floating point load/store */
562 return -4;
563 case ACCESS_RES:
564 /* lwarx, ldarx or srwcx. */
565 return -4;
566 case ACCESS_CACHE:
567 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
568 /* Should make the instruction do no-op.
569 * As it already do no-op, it's quite easy :-)
571 ctx->raddr = eaddr;
572 return 0;
573 case ACCESS_EXT:
574 /* eciwx or ecowx */
575 return -4;
576 default:
577 qemu_log("ERROR: instruction should not need "
578 "address translation\n");
579 return -4;
581 if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
582 ctx->raddr = eaddr;
583 ret = 2;
584 } else {
585 ret = -2;
589 return ret;
592 /* Generic TLB check function for embedded PowerPC implementations */
593 static int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
594 hwaddr *raddrp,
595 target_ulong address, uint32_t pid, int ext,
596 int i)
598 target_ulong mask;
600 /* Check valid flag */
601 if (!(tlb->prot & PAGE_VALID)) {
602 return -1;
604 mask = ~(tlb->size - 1);
605 LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
606 " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
607 mask, (uint32_t)tlb->PID, tlb->prot);
608 /* Check PID */
609 if (tlb->PID != 0 && tlb->PID != pid) {
610 return -1;
612 /* Check effective address */
613 if ((address & mask) != tlb->EPN) {
614 return -1;
616 *raddrp = (tlb->RPN & mask) | (address & ~mask);
617 if (ext) {
618 /* Extend the physical address to 36 bits */
619 *raddrp |= (uint64_t)(tlb->RPN & 0xF) << 32;
622 return 0;
625 /* Generic TLB search function for PowerPC embedded implementations */
626 static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address,
627 uint32_t pid)
629 ppcemb_tlb_t *tlb;
630 hwaddr raddr;
631 int i, ret;
633 /* Default return value is no match */
634 ret = -1;
635 for (i = 0; i < env->nb_tlb; i++) {
636 tlb = &env->tlb.tlbe[i];
637 if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
638 ret = i;
639 break;
643 return ret;
646 /* Helpers specific to PowerPC 40x implementations */
647 static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
649 PowerPCCPU *cpu = ppc_env_get_cpu(env);
650 ppcemb_tlb_t *tlb;
651 int i;
653 for (i = 0; i < env->nb_tlb; i++) {
654 tlb = &env->tlb.tlbe[i];
655 tlb->prot &= ~PAGE_VALID;
657 tlb_flush(CPU(cpu), 1);
660 static inline void ppc4xx_tlb_invalidate_virt(CPUPPCState *env,
661 target_ulong eaddr, uint32_t pid)
663 #if !defined(FLUSH_ALL_TLBS)
664 CPUState *cs = CPU(ppc_env_get_cpu(env));
665 ppcemb_tlb_t *tlb;
666 hwaddr raddr;
667 target_ulong page, end;
668 int i;
670 for (i = 0; i < env->nb_tlb; i++) {
671 tlb = &env->tlb.tlbe[i];
672 if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
673 end = tlb->EPN + tlb->size;
674 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
675 tlb_flush_page(cs, page);
677 tlb->prot &= ~PAGE_VALID;
678 break;
681 #else
682 ppc4xx_tlb_invalidate_all(env);
683 #endif
686 static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
687 target_ulong address, int rw,
688 int access_type)
690 ppcemb_tlb_t *tlb;
691 hwaddr raddr;
692 int i, ret, zsel, zpr, pr;
694 ret = -1;
695 raddr = (hwaddr)-1ULL;
696 pr = msr_pr;
697 for (i = 0; i < env->nb_tlb; i++) {
698 tlb = &env->tlb.tlbe[i];
699 if (ppcemb_tlb_check(env, tlb, &raddr, address,
700 env->spr[SPR_40x_PID], 0, i) < 0) {
701 continue;
703 zsel = (tlb->attr >> 4) & 0xF;
704 zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
705 LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
706 __func__, i, zsel, zpr, rw, tlb->attr);
707 /* Check execute enable bit */
708 switch (zpr) {
709 case 0x2:
710 if (pr != 0) {
711 goto check_perms;
713 /* No break here */
714 case 0x3:
715 /* All accesses granted */
716 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
717 ret = 0;
718 break;
719 case 0x0:
720 if (pr != 0) {
721 /* Raise Zone protection fault. */
722 env->spr[SPR_40x_ESR] = 1 << 22;
723 ctx->prot = 0;
724 ret = -2;
725 break;
727 /* No break here */
728 case 0x1:
729 check_perms:
730 /* Check from TLB entry */
731 ctx->prot = tlb->prot;
732 ret = check_prot(ctx->prot, rw, access_type);
733 if (ret == -2) {
734 env->spr[SPR_40x_ESR] = 0;
736 break;
738 if (ret >= 0) {
739 ctx->raddr = raddr;
740 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
741 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
742 ret);
743 return 0;
746 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
747 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
749 return ret;
752 void store_40x_sler(CPUPPCState *env, uint32_t val)
754 PowerPCCPU *cpu = ppc_env_get_cpu(env);
756 /* XXX: TO BE FIXED */
757 if (val != 0x00000000) {
758 cpu_abort(CPU(cpu), "Little-endian regions are not supported by now\n");
760 env->spr[SPR_405_SLER] = val;
763 static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
764 hwaddr *raddr, int *prot,
765 target_ulong address, int rw,
766 int access_type, int i)
768 int ret, prot2;
770 if (ppcemb_tlb_check(env, tlb, raddr, address,
771 env->spr[SPR_BOOKE_PID],
772 !env->nb_pids, i) >= 0) {
773 goto found_tlb;
776 if (env->spr[SPR_BOOKE_PID1] &&
777 ppcemb_tlb_check(env, tlb, raddr, address,
778 env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
779 goto found_tlb;
782 if (env->spr[SPR_BOOKE_PID2] &&
783 ppcemb_tlb_check(env, tlb, raddr, address,
784 env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
785 goto found_tlb;
788 LOG_SWTLB("%s: TLB entry not found\n", __func__);
789 return -1;
791 found_tlb:
793 if (msr_pr != 0) {
794 prot2 = tlb->prot & 0xF;
795 } else {
796 prot2 = (tlb->prot >> 4) & 0xF;
799 /* Check the address space */
800 if (access_type == ACCESS_CODE) {
801 if (msr_ir != (tlb->attr & 1)) {
802 LOG_SWTLB("%s: AS doesn't match\n", __func__);
803 return -1;
806 *prot = prot2;
807 if (prot2 & PAGE_EXEC) {
808 LOG_SWTLB("%s: good TLB!\n", __func__);
809 return 0;
812 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
813 ret = -3;
814 } else {
815 if (msr_dr != (tlb->attr & 1)) {
816 LOG_SWTLB("%s: AS doesn't match\n", __func__);
817 return -1;
820 *prot = prot2;
821 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
822 LOG_SWTLB("%s: found TLB!\n", __func__);
823 return 0;
826 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
827 ret = -2;
830 return ret;
833 static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
834 target_ulong address, int rw,
835 int access_type)
837 ppcemb_tlb_t *tlb;
838 hwaddr raddr;
839 int i, ret;
841 ret = -1;
842 raddr = (hwaddr)-1ULL;
843 for (i = 0; i < env->nb_tlb; i++) {
844 tlb = &env->tlb.tlbe[i];
845 ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
846 access_type, i);
847 if (!ret) {
848 break;
852 if (ret >= 0) {
853 ctx->raddr = raddr;
854 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
855 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
856 ret);
857 } else {
858 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
859 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
862 return ret;
865 static void booke206_flush_tlb(CPUPPCState *env, int flags,
866 const int check_iprot)
868 PowerPCCPU *cpu = ppc_env_get_cpu(env);
869 int tlb_size;
870 int i, j;
871 ppcmas_tlb_t *tlb = env->tlb.tlbm;
873 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
874 if (flags & (1 << i)) {
875 tlb_size = booke206_tlb_size(env, i);
876 for (j = 0; j < tlb_size; j++) {
877 if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
878 tlb[j].mas1 &= ~MAS1_VALID;
882 tlb += booke206_tlb_size(env, i);
885 tlb_flush(CPU(cpu), 1);
888 static hwaddr booke206_tlb_to_page_size(CPUPPCState *env,
889 ppcmas_tlb_t *tlb)
891 int tlbm_size;
893 tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
895 return 1024ULL << tlbm_size;
898 /* TLB check function for MAS based SoftTLBs */
899 static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
900 hwaddr *raddrp,
901 target_ulong address, uint32_t pid)
903 target_ulong mask;
904 uint32_t tlb_pid;
906 /* Check valid flag */
907 if (!(tlb->mas1 & MAS1_VALID)) {
908 return -1;
911 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
912 LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
913 PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n",
914 __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3,
915 tlb->mas8);
917 /* Check PID */
918 tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
919 if (tlb_pid != 0 && tlb_pid != pid) {
920 return -1;
923 /* Check effective address */
924 if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
925 return -1;
928 if (raddrp) {
929 *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
932 return 0;
935 static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
936 hwaddr *raddr, int *prot,
937 target_ulong address, int rw,
938 int access_type)
940 int ret;
941 int prot2 = 0;
943 if (ppcmas_tlb_check(env, tlb, raddr, address,
944 env->spr[SPR_BOOKE_PID]) >= 0) {
945 goto found_tlb;
948 if (env->spr[SPR_BOOKE_PID1] &&
949 ppcmas_tlb_check(env, tlb, raddr, address,
950 env->spr[SPR_BOOKE_PID1]) >= 0) {
951 goto found_tlb;
954 if (env->spr[SPR_BOOKE_PID2] &&
955 ppcmas_tlb_check(env, tlb, raddr, address,
956 env->spr[SPR_BOOKE_PID2]) >= 0) {
957 goto found_tlb;
960 LOG_SWTLB("%s: TLB entry not found\n", __func__);
961 return -1;
963 found_tlb:
965 if (msr_pr != 0) {
966 if (tlb->mas7_3 & MAS3_UR) {
967 prot2 |= PAGE_READ;
969 if (tlb->mas7_3 & MAS3_UW) {
970 prot2 |= PAGE_WRITE;
972 if (tlb->mas7_3 & MAS3_UX) {
973 prot2 |= PAGE_EXEC;
975 } else {
976 if (tlb->mas7_3 & MAS3_SR) {
977 prot2 |= PAGE_READ;
979 if (tlb->mas7_3 & MAS3_SW) {
980 prot2 |= PAGE_WRITE;
982 if (tlb->mas7_3 & MAS3_SX) {
983 prot2 |= PAGE_EXEC;
987 /* Check the address space and permissions */
988 if (access_type == ACCESS_CODE) {
989 if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
990 LOG_SWTLB("%s: AS doesn't match\n", __func__);
991 return -1;
994 *prot = prot2;
995 if (prot2 & PAGE_EXEC) {
996 LOG_SWTLB("%s: good TLB!\n", __func__);
997 return 0;
1000 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
1001 ret = -3;
1002 } else {
1003 if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
1004 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1005 return -1;
1008 *prot = prot2;
1009 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
1010 LOG_SWTLB("%s: found TLB!\n", __func__);
1011 return 0;
1014 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
1015 ret = -2;
1018 return ret;
1021 static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1022 target_ulong address, int rw,
1023 int access_type)
1025 ppcmas_tlb_t *tlb;
1026 hwaddr raddr;
1027 int i, j, ret;
1029 ret = -1;
1030 raddr = (hwaddr)-1ULL;
1032 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1033 int ways = booke206_tlb_ways(env, i);
1035 for (j = 0; j < ways; j++) {
1036 tlb = booke206_get_tlbm(env, i, address, j);
1037 if (!tlb) {
1038 continue;
1040 ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
1041 rw, access_type);
1042 if (ret != -1) {
1043 goto found_tlb;
1048 found_tlb:
1050 if (ret >= 0) {
1051 ctx->raddr = raddr;
1052 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1053 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1054 ret);
1055 } else {
1056 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1057 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1060 return ret;
1063 static const char *book3e_tsize_to_str[32] = {
1064 "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
1065 "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
1066 "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
1067 "1T", "2T"
1070 static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1071 CPUPPCState *env)
1073 ppcemb_tlb_t *entry;
1074 int i;
1076 if (kvm_enabled() && !env->kvm_sw_tlb) {
1077 cpu_fprintf(f, "Cannot access KVM TLB\n");
1078 return;
1081 cpu_fprintf(f, "\nTLB:\n");
1082 cpu_fprintf(f, "Effective Physical Size PID Prot "
1083 "Attr\n");
1085 entry = &env->tlb.tlbe[0];
1086 for (i = 0; i < env->nb_tlb; i++, entry++) {
1087 hwaddr ea, pa;
1088 target_ulong mask;
1089 uint64_t size = (uint64_t)entry->size;
1090 char size_buf[20];
1092 /* Check valid flag */
1093 if (!(entry->prot & PAGE_VALID)) {
1094 continue;
1097 mask = ~(entry->size - 1);
1098 ea = entry->EPN & mask;
1099 pa = entry->RPN & mask;
1100 /* Extend the physical address to 36 bits */
1101 pa |= (hwaddr)(entry->RPN & 0xF) << 32;
1102 size /= 1024;
1103 if (size >= 1024) {
1104 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024);
1105 } else {
1106 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size);
1108 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
1109 (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
1110 entry->prot, entry->attr);
1115 static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
1116 CPUPPCState *env, int tlbn, int offset,
1117 int tlbsize)
1119 ppcmas_tlb_t *entry;
1120 int i;
1122 cpu_fprintf(f, "\nTLB%d:\n", tlbn);
1123 cpu_fprintf(f, "Effective Physical Size TID TS SRWX"
1124 " URWX WIMGE U0123\n");
1126 entry = &env->tlb.tlbm[offset];
1127 for (i = 0; i < tlbsize; i++, entry++) {
1128 hwaddr ea, pa, size;
1129 int tsize;
1131 if (!(entry->mas1 & MAS1_VALID)) {
1132 continue;
1135 tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1136 size = 1024ULL << tsize;
1137 ea = entry->mas2 & ~(size - 1);
1138 pa = entry->mas7_3 & ~(size - 1);
1140 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c"
1141 "U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
1142 (uint64_t)ea, (uint64_t)pa,
1143 book3e_tsize_to_str[tsize],
1144 (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
1145 (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
1146 entry->mas7_3 & MAS3_SR ? 'R' : '-',
1147 entry->mas7_3 & MAS3_SW ? 'W' : '-',
1148 entry->mas7_3 & MAS3_SX ? 'X' : '-',
1149 entry->mas7_3 & MAS3_UR ? 'R' : '-',
1150 entry->mas7_3 & MAS3_UW ? 'W' : '-',
1151 entry->mas7_3 & MAS3_UX ? 'X' : '-',
1152 entry->mas2 & MAS2_W ? 'W' : '-',
1153 entry->mas2 & MAS2_I ? 'I' : '-',
1154 entry->mas2 & MAS2_M ? 'M' : '-',
1155 entry->mas2 & MAS2_G ? 'G' : '-',
1156 entry->mas2 & MAS2_E ? 'E' : '-',
1157 entry->mas7_3 & MAS3_U0 ? '0' : '-',
1158 entry->mas7_3 & MAS3_U1 ? '1' : '-',
1159 entry->mas7_3 & MAS3_U2 ? '2' : '-',
1160 entry->mas7_3 & MAS3_U3 ? '3' : '-');
1164 static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1165 CPUPPCState *env)
1167 int offset = 0;
1168 int i;
1170 if (kvm_enabled() && !env->kvm_sw_tlb) {
1171 cpu_fprintf(f, "Cannot access KVM TLB\n");
1172 return;
1175 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1176 int size = booke206_tlb_size(env, i);
1178 if (size == 0) {
1179 continue;
1182 mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size);
1183 offset += size;
1187 static void mmu6xx_dump_BATs(FILE *f, fprintf_function cpu_fprintf,
1188 CPUPPCState *env, int type)
1190 target_ulong *BATlt, *BATut, *BATu, *BATl;
1191 target_ulong BEPIl, BEPIu, bl;
1192 int i;
1194 switch (type) {
1195 case ACCESS_CODE:
1196 BATlt = env->IBAT[1];
1197 BATut = env->IBAT[0];
1198 break;
1199 default:
1200 BATlt = env->DBAT[1];
1201 BATut = env->DBAT[0];
1202 break;
1205 for (i = 0; i < env->nb_BATs; i++) {
1206 BATu = &BATut[i];
1207 BATl = &BATlt[i];
1208 BEPIu = *BATu & 0xF0000000;
1209 BEPIl = *BATu & 0x0FFE0000;
1210 bl = (*BATu & 0x00001FFC) << 15;
1211 cpu_fprintf(f, "%s BAT%d BATu " TARGET_FMT_lx
1212 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
1213 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
1214 type == ACCESS_CODE ? "code" : "data", i,
1215 *BATu, *BATl, BEPIu, BEPIl, bl);
1219 static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1220 CPUPPCState *env)
1222 ppc6xx_tlb_t *tlb;
1223 target_ulong sr;
1224 int type, way, entry, i;
1226 cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", env->htab_base);
1227 cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", env->htab_mask);
1229 cpu_fprintf(f, "\nSegment registers:\n");
1230 for (i = 0; i < 32; i++) {
1231 sr = env->sr[i];
1232 if (sr & 0x80000000) {
1233 cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d BUID=0x%03x "
1234 "CNTLR_SPEC=0x%05x\n", i,
1235 sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1236 sr & 0x20000000 ? 1 : 0, (uint32_t)((sr >> 20) & 0x1FF),
1237 (uint32_t)(sr & 0xFFFFF));
1238 } else {
1239 cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d N=%d VSID=0x%06x\n", i,
1240 sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1241 sr & 0x20000000 ? 1 : 0, sr & 0x10000000 ? 1 : 0,
1242 (uint32_t)(sr & 0x00FFFFFF));
1246 cpu_fprintf(f, "\nBATs:\n");
1247 mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_INT);
1248 mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_CODE);
1250 if (env->id_tlbs != 1) {
1251 cpu_fprintf(f, "ERROR: 6xx MMU should have separated TLB"
1252 " for code and data\n");
1255 cpu_fprintf(f, "\nTLBs [EPN EPN + SIZE]\n");
1257 for (type = 0; type < 2; type++) {
1258 for (way = 0; way < env->nb_ways; way++) {
1259 for (entry = env->nb_tlb * type + env->tlb_per_way * way;
1260 entry < (env->nb_tlb * type + env->tlb_per_way * (way + 1));
1261 entry++) {
1263 tlb = &env->tlb.tlb6[entry];
1264 cpu_fprintf(f, "%s TLB %02d/%02d way:%d %s ["
1265 TARGET_FMT_lx " " TARGET_FMT_lx "]\n",
1266 type ? "code" : "data", entry % env->nb_tlb,
1267 env->nb_tlb, way,
1268 pte_is_valid(tlb->pte0) ? "valid" : "inval",
1269 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE);
1275 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
1277 switch (env->mmu_model) {
1278 case POWERPC_MMU_BOOKE:
1279 mmubooke_dump_mmu(f, cpu_fprintf, env);
1280 break;
1281 case POWERPC_MMU_BOOKE206:
1282 mmubooke206_dump_mmu(f, cpu_fprintf, env);
1283 break;
1284 case POWERPC_MMU_SOFT_6xx:
1285 case POWERPC_MMU_SOFT_74xx:
1286 mmu6xx_dump_mmu(f, cpu_fprintf, env);
1287 break;
1288 #if defined(TARGET_PPC64)
1289 case POWERPC_MMU_64B:
1290 case POWERPC_MMU_2_06:
1291 case POWERPC_MMU_2_06a:
1292 case POWERPC_MMU_2_06d:
1293 dump_slb(f, cpu_fprintf, env);
1294 break;
1295 #endif
1296 default:
1297 qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
1301 static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
1302 target_ulong eaddr, int rw)
1304 int in_plb, ret;
1306 ctx->raddr = eaddr;
1307 ctx->prot = PAGE_READ | PAGE_EXEC;
1308 ret = 0;
1309 switch (env->mmu_model) {
1310 case POWERPC_MMU_SOFT_6xx:
1311 case POWERPC_MMU_SOFT_74xx:
1312 case POWERPC_MMU_SOFT_4xx:
1313 case POWERPC_MMU_REAL:
1314 case POWERPC_MMU_BOOKE:
1315 ctx->prot |= PAGE_WRITE;
1316 break;
1318 case POWERPC_MMU_SOFT_4xx_Z:
1319 if (unlikely(msr_pe != 0)) {
1320 /* 403 family add some particular protections,
1321 * using PBL/PBU registers for accesses with no translation.
1323 in_plb =
1324 /* Check PLB validity */
1325 (env->pb[0] < env->pb[1] &&
1326 /* and address in plb area */
1327 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
1328 (env->pb[2] < env->pb[3] &&
1329 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
1330 if (in_plb ^ msr_px) {
1331 /* Access in protected area */
1332 if (rw == 1) {
1333 /* Access is not allowed */
1334 ret = -2;
1336 } else {
1337 /* Read-write access is allowed */
1338 ctx->prot |= PAGE_WRITE;
1341 break;
1343 default:
1344 /* Caller's checks mean we should never get here for other models */
1345 abort();
1346 return -1;
1349 return ret;
1352 static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1353 target_ulong eaddr, int rw, int access_type)
1355 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1356 int ret = -1;
1357 bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
1358 || (access_type != ACCESS_CODE && msr_dr == 0);
1360 #if 0
1361 qemu_log("%s\n", __func__);
1362 #endif
1364 switch (env->mmu_model) {
1365 case POWERPC_MMU_SOFT_6xx:
1366 case POWERPC_MMU_SOFT_74xx:
1367 if (real_mode) {
1368 ret = check_physical(env, ctx, eaddr, rw);
1369 } else {
1370 /* Try to find a BAT */
1371 if (env->nb_BATs != 0) {
1372 ret = get_bat_6xx_tlb(env, ctx, eaddr, rw, access_type);
1374 if (ret < 0) {
1375 /* We didn't match any BAT entry or don't have BATs */
1376 ret = get_segment_6xx_tlb(env, ctx, eaddr, rw, access_type);
1379 break;
1381 case POWERPC_MMU_SOFT_4xx:
1382 case POWERPC_MMU_SOFT_4xx_Z:
1383 if (real_mode) {
1384 ret = check_physical(env, ctx, eaddr, rw);
1385 } else {
1386 ret = mmu40x_get_physical_address(env, ctx, eaddr,
1387 rw, access_type);
1389 break;
1390 case POWERPC_MMU_BOOKE:
1391 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1392 rw, access_type);
1393 break;
1394 case POWERPC_MMU_BOOKE206:
1395 ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
1396 access_type);
1397 break;
1398 case POWERPC_MMU_MPC8xx:
1399 /* XXX: TODO */
1400 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1401 break;
1402 case POWERPC_MMU_REAL:
1403 if (real_mode) {
1404 ret = check_physical(env, ctx, eaddr, rw);
1405 } else {
1406 cpu_abort(CPU(cpu), "PowerPC in real mode do not do any translation\n");
1408 return -1;
1409 default:
1410 cpu_abort(CPU(cpu), "Unknown or invalid MMU model\n");
1411 return -1;
1413 #if 0
1414 qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
1415 __func__, eaddr, ret, ctx->raddr);
1416 #endif
1418 return ret;
1421 hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
1423 PowerPCCPU *cpu = POWERPC_CPU(cs);
1424 CPUPPCState *env = &cpu->env;
1425 mmu_ctx_t ctx;
1427 switch (env->mmu_model) {
1428 #if defined(TARGET_PPC64)
1429 case POWERPC_MMU_64B:
1430 case POWERPC_MMU_2_06:
1431 case POWERPC_MMU_2_06a:
1432 case POWERPC_MMU_2_06d:
1433 return ppc_hash64_get_phys_page_debug(env, addr);
1434 #endif
1436 case POWERPC_MMU_32B:
1437 case POWERPC_MMU_601:
1438 return ppc_hash32_get_phys_page_debug(env, addr);
1440 default:
1444 if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {
1446 /* Some MMUs have separate TLBs for code and data. If we only try an
1447 * ACCESS_INT, we may not be able to read instructions mapped by code
1448 * TLBs, so we also try a ACCESS_CODE.
1450 if (unlikely(get_physical_address(env, &ctx, addr, 0,
1451 ACCESS_CODE) != 0)) {
1452 return -1;
1456 return ctx.raddr & TARGET_PAGE_MASK;
1459 static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
1460 int rw)
1462 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
1463 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
1464 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
1465 env->spr[SPR_BOOKE_MAS3] = 0;
1466 env->spr[SPR_BOOKE_MAS6] = 0;
1467 env->spr[SPR_BOOKE_MAS7] = 0;
1469 /* AS */
1470 if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
1471 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
1472 env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
1475 env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
1476 env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
1478 switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
1479 case MAS4_TIDSELD_PID0:
1480 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
1481 break;
1482 case MAS4_TIDSELD_PID1:
1483 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
1484 break;
1485 case MAS4_TIDSELD_PID2:
1486 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
1487 break;
1490 env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
1492 /* next victim logic */
1493 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
1494 env->last_way++;
1495 env->last_way &= booke206_tlb_ways(env, 0) - 1;
1496 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
1499 /* Perform address translation */
1500 static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
1501 int rw, int mmu_idx)
1503 CPUState *cs = CPU(ppc_env_get_cpu(env));
1504 mmu_ctx_t ctx;
1505 int access_type;
1506 int ret = 0;
1508 if (rw == 2) {
1509 /* code access */
1510 rw = 0;
1511 access_type = ACCESS_CODE;
1512 } else {
1513 /* data access */
1514 access_type = env->access_type;
1516 ret = get_physical_address(env, &ctx, address, rw, access_type);
1517 if (ret == 0) {
1518 tlb_set_page(cs, address & TARGET_PAGE_MASK,
1519 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
1520 mmu_idx, TARGET_PAGE_SIZE);
1521 ret = 0;
1522 } else if (ret < 0) {
1523 LOG_MMU_STATE(cs);
1524 if (access_type == ACCESS_CODE) {
1525 switch (ret) {
1526 case -1:
1527 /* No matches in page tables or TLB */
1528 switch (env->mmu_model) {
1529 case POWERPC_MMU_SOFT_6xx:
1530 cs->exception_index = POWERPC_EXCP_IFTLB;
1531 env->error_code = 1 << 18;
1532 env->spr[SPR_IMISS] = address;
1533 env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
1534 goto tlb_miss;
1535 case POWERPC_MMU_SOFT_74xx:
1536 cs->exception_index = POWERPC_EXCP_IFTLB;
1537 goto tlb_miss_74xx;
1538 case POWERPC_MMU_SOFT_4xx:
1539 case POWERPC_MMU_SOFT_4xx_Z:
1540 cs->exception_index = POWERPC_EXCP_ITLB;
1541 env->error_code = 0;
1542 env->spr[SPR_40x_DEAR] = address;
1543 env->spr[SPR_40x_ESR] = 0x00000000;
1544 break;
1545 case POWERPC_MMU_BOOKE206:
1546 booke206_update_mas_tlb_miss(env, address, rw);
1547 /* fall through */
1548 case POWERPC_MMU_BOOKE:
1549 cs->exception_index = POWERPC_EXCP_ITLB;
1550 env->error_code = 0;
1551 env->spr[SPR_BOOKE_DEAR] = address;
1552 return -1;
1553 case POWERPC_MMU_MPC8xx:
1554 /* XXX: TODO */
1555 cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1556 break;
1557 case POWERPC_MMU_REAL:
1558 cpu_abort(cs, "PowerPC in real mode should never raise "
1559 "any MMU exceptions\n");
1560 return -1;
1561 default:
1562 cpu_abort(cs, "Unknown or invalid MMU model\n");
1563 return -1;
1565 break;
1566 case -2:
1567 /* Access rights violation */
1568 cs->exception_index = POWERPC_EXCP_ISI;
1569 env->error_code = 0x08000000;
1570 break;
1571 case -3:
1572 /* No execute protection violation */
1573 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1574 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1575 env->spr[SPR_BOOKE_ESR] = 0x00000000;
1577 cs->exception_index = POWERPC_EXCP_ISI;
1578 env->error_code = 0x10000000;
1579 break;
1580 case -4:
1581 /* Direct store exception */
1582 /* No code fetch is allowed in direct-store areas */
1583 cs->exception_index = POWERPC_EXCP_ISI;
1584 env->error_code = 0x10000000;
1585 break;
1587 } else {
1588 switch (ret) {
1589 case -1:
1590 /* No matches in page tables or TLB */
1591 switch (env->mmu_model) {
1592 case POWERPC_MMU_SOFT_6xx:
1593 if (rw == 1) {
1594 cs->exception_index = POWERPC_EXCP_DSTLB;
1595 env->error_code = 1 << 16;
1596 } else {
1597 cs->exception_index = POWERPC_EXCP_DLTLB;
1598 env->error_code = 0;
1600 env->spr[SPR_DMISS] = address;
1601 env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
1602 tlb_miss:
1603 env->error_code |= ctx.key << 19;
1604 env->spr[SPR_HASH1] = env->htab_base +
1605 get_pteg_offset32(env, ctx.hash[0]);
1606 env->spr[SPR_HASH2] = env->htab_base +
1607 get_pteg_offset32(env, ctx.hash[1]);
1608 break;
1609 case POWERPC_MMU_SOFT_74xx:
1610 if (rw == 1) {
1611 cs->exception_index = POWERPC_EXCP_DSTLB;
1612 } else {
1613 cs->exception_index = POWERPC_EXCP_DLTLB;
1615 tlb_miss_74xx:
1616 /* Implement LRU algorithm */
1617 env->error_code = ctx.key << 19;
1618 env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
1619 ((env->last_way + 1) & (env->nb_ways - 1));
1620 env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
1621 break;
1622 case POWERPC_MMU_SOFT_4xx:
1623 case POWERPC_MMU_SOFT_4xx_Z:
1624 cs->exception_index = POWERPC_EXCP_DTLB;
1625 env->error_code = 0;
1626 env->spr[SPR_40x_DEAR] = address;
1627 if (rw) {
1628 env->spr[SPR_40x_ESR] = 0x00800000;
1629 } else {
1630 env->spr[SPR_40x_ESR] = 0x00000000;
1632 break;
1633 case POWERPC_MMU_MPC8xx:
1634 /* XXX: TODO */
1635 cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1636 break;
1637 case POWERPC_MMU_BOOKE206:
1638 booke206_update_mas_tlb_miss(env, address, rw);
1639 /* fall through */
1640 case POWERPC_MMU_BOOKE:
1641 cs->exception_index = POWERPC_EXCP_DTLB;
1642 env->error_code = 0;
1643 env->spr[SPR_BOOKE_DEAR] = address;
1644 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1645 return -1;
1646 case POWERPC_MMU_REAL:
1647 cpu_abort(cs, "PowerPC in real mode should never raise "
1648 "any MMU exceptions\n");
1649 return -1;
1650 default:
1651 cpu_abort(cs, "Unknown or invalid MMU model\n");
1652 return -1;
1654 break;
1655 case -2:
1656 /* Access rights violation */
1657 cs->exception_index = POWERPC_EXCP_DSI;
1658 env->error_code = 0;
1659 if (env->mmu_model == POWERPC_MMU_SOFT_4xx
1660 || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
1661 env->spr[SPR_40x_DEAR] = address;
1662 if (rw) {
1663 env->spr[SPR_40x_ESR] |= 0x00800000;
1665 } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1666 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1667 env->spr[SPR_BOOKE_DEAR] = address;
1668 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1669 } else {
1670 env->spr[SPR_DAR] = address;
1671 if (rw == 1) {
1672 env->spr[SPR_DSISR] = 0x0A000000;
1673 } else {
1674 env->spr[SPR_DSISR] = 0x08000000;
1677 break;
1678 case -4:
1679 /* Direct store exception */
1680 switch (access_type) {
1681 case ACCESS_FLOAT:
1682 /* Floating point load/store */
1683 cs->exception_index = POWERPC_EXCP_ALIGN;
1684 env->error_code = POWERPC_EXCP_ALIGN_FP;
1685 env->spr[SPR_DAR] = address;
1686 break;
1687 case ACCESS_RES:
1688 /* lwarx, ldarx or stwcx. */
1689 cs->exception_index = POWERPC_EXCP_DSI;
1690 env->error_code = 0;
1691 env->spr[SPR_DAR] = address;
1692 if (rw == 1) {
1693 env->spr[SPR_DSISR] = 0x06000000;
1694 } else {
1695 env->spr[SPR_DSISR] = 0x04000000;
1697 break;
1698 case ACCESS_EXT:
1699 /* eciwx or ecowx */
1700 cs->exception_index = POWERPC_EXCP_DSI;
1701 env->error_code = 0;
1702 env->spr[SPR_DAR] = address;
1703 if (rw == 1) {
1704 env->spr[SPR_DSISR] = 0x06100000;
1705 } else {
1706 env->spr[SPR_DSISR] = 0x04100000;
1708 break;
1709 default:
1710 printf("DSI: invalid exception (%d)\n", ret);
1711 cs->exception_index = POWERPC_EXCP_PROGRAM;
1712 env->error_code =
1713 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
1714 env->spr[SPR_DAR] = address;
1715 break;
1717 break;
1720 #if 0
1721 printf("%s: set exception to %d %02x\n", __func__,
1722 cs->exception, env->error_code);
1723 #endif
1724 ret = 1;
1727 return ret;
1730 /*****************************************************************************/
1731 /* BATs management */
1732 #if !defined(FLUSH_ALL_TLBS)
1733 static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
1734 target_ulong mask)
1736 CPUState *cs = CPU(ppc_env_get_cpu(env));
1737 target_ulong base, end, page;
1739 base = BATu & ~0x0001FFFF;
1740 end = base + mask + 0x00020000;
1741 LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
1742 TARGET_FMT_lx ")\n", base, end, mask);
1743 for (page = base; page != end; page += TARGET_PAGE_SIZE) {
1744 tlb_flush_page(cs, page);
1746 LOG_BATS("Flush done\n");
1748 #endif
1750 static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
1751 target_ulong value)
1753 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
1754 nr, ul == 0 ? 'u' : 'l', value, env->nip);
1757 void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1759 target_ulong mask;
1761 dump_store_bat(env, 'I', 0, nr, value);
1762 if (env->IBAT[0][nr] != value) {
1763 mask = (value << 15) & 0x0FFE0000UL;
1764 #if !defined(FLUSH_ALL_TLBS)
1765 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1766 #endif
1767 /* When storing valid upper BAT, mask BEPI and BRPN
1768 * and invalidate all TLBs covered by this BAT
1770 mask = (value << 15) & 0x0FFE0000UL;
1771 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1772 (value & ~0x0001FFFFUL & ~mask);
1773 env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
1774 (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
1775 #if !defined(FLUSH_ALL_TLBS)
1776 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1777 #else
1778 tlb_flush(env, 1);
1779 #endif
1783 void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1785 dump_store_bat(env, 'I', 1, nr, value);
1786 env->IBAT[1][nr] = value;
1789 void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1791 target_ulong mask;
1793 dump_store_bat(env, 'D', 0, nr, value);
1794 if (env->DBAT[0][nr] != value) {
1795 /* When storing valid upper BAT, mask BEPI and BRPN
1796 * and invalidate all TLBs covered by this BAT
1798 mask = (value << 15) & 0x0FFE0000UL;
1799 #if !defined(FLUSH_ALL_TLBS)
1800 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1801 #endif
1802 mask = (value << 15) & 0x0FFE0000UL;
1803 env->DBAT[0][nr] = (value & 0x00001FFFUL) |
1804 (value & ~0x0001FFFFUL & ~mask);
1805 env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
1806 (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
1807 #if !defined(FLUSH_ALL_TLBS)
1808 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1809 #else
1810 tlb_flush(env, 1);
1811 #endif
1815 void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1817 dump_store_bat(env, 'D', 1, nr, value);
1818 env->DBAT[1][nr] = value;
1821 void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value)
1823 target_ulong mask;
1824 #if defined(FLUSH_ALL_TLBS)
1825 int do_inval;
1826 #endif
1828 dump_store_bat(env, 'I', 0, nr, value);
1829 if (env->IBAT[0][nr] != value) {
1830 #if defined(FLUSH_ALL_TLBS)
1831 do_inval = 0;
1832 #endif
1833 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1834 if (env->IBAT[1][nr] & 0x40) {
1835 /* Invalidate BAT only if it is valid */
1836 #if !defined(FLUSH_ALL_TLBS)
1837 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1838 #else
1839 do_inval = 1;
1840 #endif
1842 /* When storing valid upper BAT, mask BEPI and BRPN
1843 * and invalidate all TLBs covered by this BAT
1845 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1846 (value & ~0x0001FFFFUL & ~mask);
1847 env->DBAT[0][nr] = env->IBAT[0][nr];
1848 if (env->IBAT[1][nr] & 0x40) {
1849 #if !defined(FLUSH_ALL_TLBS)
1850 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1851 #else
1852 do_inval = 1;
1853 #endif
1855 #if defined(FLUSH_ALL_TLBS)
1856 if (do_inval) {
1857 tlb_flush(env, 1);
1859 #endif
1863 void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value)
1865 #if !defined(FLUSH_ALL_TLBS)
1866 target_ulong mask;
1867 #else
1868 int do_inval;
1869 #endif
1871 dump_store_bat(env, 'I', 1, nr, value);
1872 if (env->IBAT[1][nr] != value) {
1873 #if defined(FLUSH_ALL_TLBS)
1874 do_inval = 0;
1875 #endif
1876 if (env->IBAT[1][nr] & 0x40) {
1877 #if !defined(FLUSH_ALL_TLBS)
1878 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1879 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1880 #else
1881 do_inval = 1;
1882 #endif
1884 if (value & 0x40) {
1885 #if !defined(FLUSH_ALL_TLBS)
1886 mask = (value << 17) & 0x0FFE0000UL;
1887 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1888 #else
1889 do_inval = 1;
1890 #endif
1892 env->IBAT[1][nr] = value;
1893 env->DBAT[1][nr] = value;
1894 #if defined(FLUSH_ALL_TLBS)
1895 if (do_inval) {
1896 tlb_flush(env, 1);
1898 #endif
1902 /*****************************************************************************/
1903 /* TLB management */
1904 void ppc_tlb_invalidate_all(CPUPPCState *env)
1906 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1908 switch (env->mmu_model) {
1909 case POWERPC_MMU_SOFT_6xx:
1910 case POWERPC_MMU_SOFT_74xx:
1911 ppc6xx_tlb_invalidate_all(env);
1912 break;
1913 case POWERPC_MMU_SOFT_4xx:
1914 case POWERPC_MMU_SOFT_4xx_Z:
1915 ppc4xx_tlb_invalidate_all(env);
1916 break;
1917 case POWERPC_MMU_REAL:
1918 cpu_abort(CPU(cpu), "No TLB for PowerPC 4xx in real mode\n");
1919 break;
1920 case POWERPC_MMU_MPC8xx:
1921 /* XXX: TODO */
1922 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1923 break;
1924 case POWERPC_MMU_BOOKE:
1925 tlb_flush(CPU(cpu), 1);
1926 break;
1927 case POWERPC_MMU_BOOKE206:
1928 booke206_flush_tlb(env, -1, 0);
1929 break;
1930 case POWERPC_MMU_32B:
1931 case POWERPC_MMU_601:
1932 #if defined(TARGET_PPC64)
1933 case POWERPC_MMU_64B:
1934 case POWERPC_MMU_2_06:
1935 case POWERPC_MMU_2_06a:
1936 case POWERPC_MMU_2_06d:
1937 #endif /* defined(TARGET_PPC64) */
1938 tlb_flush(CPU(cpu), 1);
1939 break;
1940 default:
1941 /* XXX: TODO */
1942 cpu_abort(CPU(cpu), "Unknown MMU model\n");
1943 break;
1947 void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
1949 #if !defined(FLUSH_ALL_TLBS)
1950 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1951 CPUState *cs;
1953 addr &= TARGET_PAGE_MASK;
1954 switch (env->mmu_model) {
1955 case POWERPC_MMU_SOFT_6xx:
1956 case POWERPC_MMU_SOFT_74xx:
1957 ppc6xx_tlb_invalidate_virt(env, addr, 0);
1958 if (env->id_tlbs == 1) {
1959 ppc6xx_tlb_invalidate_virt(env, addr, 1);
1961 break;
1962 case POWERPC_MMU_SOFT_4xx:
1963 case POWERPC_MMU_SOFT_4xx_Z:
1964 ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
1965 break;
1966 case POWERPC_MMU_REAL:
1967 cpu_abort(CPU(cpu), "No TLB for PowerPC 4xx in real mode\n");
1968 break;
1969 case POWERPC_MMU_MPC8xx:
1970 /* XXX: TODO */
1971 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1972 break;
1973 case POWERPC_MMU_BOOKE:
1974 /* XXX: TODO */
1975 cpu_abort(CPU(cpu), "BookE MMU model is not implemented\n");
1976 break;
1977 case POWERPC_MMU_BOOKE206:
1978 /* XXX: TODO */
1979 cpu_abort(CPU(cpu), "BookE 2.06 MMU model is not implemented\n");
1980 break;
1981 case POWERPC_MMU_32B:
1982 case POWERPC_MMU_601:
1983 /* tlbie invalidate TLBs for all segments */
1984 addr &= ~((target_ulong)-1ULL << 28);
1985 cs = CPU(cpu);
1986 /* XXX: this case should be optimized,
1987 * giving a mask to tlb_flush_page
1989 tlb_flush_page(cs, addr | (0x0 << 28));
1990 tlb_flush_page(cs, addr | (0x1 << 28));
1991 tlb_flush_page(cs, addr | (0x2 << 28));
1992 tlb_flush_page(cs, addr | (0x3 << 28));
1993 tlb_flush_page(cs, addr | (0x4 << 28));
1994 tlb_flush_page(cs, addr | (0x5 << 28));
1995 tlb_flush_page(cs, addr | (0x6 << 28));
1996 tlb_flush_page(cs, addr | (0x7 << 28));
1997 tlb_flush_page(cs, addr | (0x8 << 28));
1998 tlb_flush_page(cs, addr | (0x9 << 28));
1999 tlb_flush_page(cs, addr | (0xA << 28));
2000 tlb_flush_page(cs, addr | (0xB << 28));
2001 tlb_flush_page(cs, addr | (0xC << 28));
2002 tlb_flush_page(cs, addr | (0xD << 28));
2003 tlb_flush_page(cs, addr | (0xE << 28));
2004 tlb_flush_page(cs, addr | (0xF << 28));
2005 break;
2006 #if defined(TARGET_PPC64)
2007 case POWERPC_MMU_64B:
2008 case POWERPC_MMU_2_06:
2009 case POWERPC_MMU_2_06a:
2010 case POWERPC_MMU_2_06d:
2011 /* tlbie invalidate TLBs for all segments */
2012 /* XXX: given the fact that there are too many segments to invalidate,
2013 * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
2014 * we just invalidate all TLBs
2016 tlb_flush(CPU(cpu), 1);
2017 break;
2018 #endif /* defined(TARGET_PPC64) */
2019 default:
2020 /* XXX: TODO */
2021 cpu_abort(CPU(cpu), "Unknown MMU model\n");
2022 break;
2024 #else
2025 ppc_tlb_invalidate_all(env);
2026 #endif
2029 /*****************************************************************************/
2030 /* Special registers manipulation */
2031 void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
2033 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2035 LOG_MMU("%s: " TARGET_FMT_lx "\n", __func__, value);
2036 assert(!env->external_htab);
2037 if (env->spr[SPR_SDR1] != value) {
2038 env->spr[SPR_SDR1] = value;
2039 #if defined(TARGET_PPC64)
2040 if (env->mmu_model & POWERPC_MMU_64) {
2041 target_ulong htabsize = value & SDR_64_HTABSIZE;
2043 if (htabsize > 28) {
2044 fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx
2045 " stored in SDR1\n", htabsize);
2046 htabsize = 28;
2048 env->htab_mask = (1ULL << (htabsize + 18 - 7)) - 1;
2049 env->htab_base = value & SDR_64_HTABORG;
2050 } else
2051 #endif /* defined(TARGET_PPC64) */
2053 /* FIXME: Should check for valid HTABMASK values */
2054 env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
2055 env->htab_base = value & SDR_32_HTABORG;
2057 tlb_flush(CPU(cpu), 1);
2061 /* Segment registers load and store */
2062 target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
2064 #if defined(TARGET_PPC64)
2065 if (env->mmu_model & POWERPC_MMU_64) {
2066 /* XXX */
2067 return 0;
2069 #endif
2070 return env->sr[sr_num];
2073 void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
2075 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2077 LOG_MMU("%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
2078 (int)srnum, value, env->sr[srnum]);
2079 #if defined(TARGET_PPC64)
2080 if (env->mmu_model & POWERPC_MMU_64) {
2081 uint64_t rb = 0, rs = 0;
2083 /* ESID = srnum */
2084 rb |= ((uint32_t)srnum & 0xf) << 28;
2085 /* Set the valid bit */
2086 rb |= SLB_ESID_V;
2087 /* Index = ESID */
2088 rb |= (uint32_t)srnum;
2090 /* VSID = VSID */
2091 rs |= (value & 0xfffffff) << 12;
2092 /* flags = flags */
2093 rs |= ((value >> 27) & 0xf) << 8;
2095 ppc_store_slb(env, rb, rs);
2096 } else
2097 #endif
2098 if (env->sr[srnum] != value) {
2099 env->sr[srnum] = value;
2100 /* Invalidating 256MB of virtual memory in 4kB pages is way longer than
2101 flusing the whole TLB. */
2102 #if !defined(FLUSH_ALL_TLBS) && 0
2104 target_ulong page, end;
2105 /* Invalidate 256 MB of virtual memory */
2106 page = (16 << 20) * srnum;
2107 end = page + (16 << 20);
2108 for (; page != end; page += TARGET_PAGE_SIZE) {
2109 tlb_flush_page(CPU(cpu), page);
2112 #else
2113 tlb_flush(CPU(cpu), 1);
2114 #endif
2118 /* TLB management */
2119 void helper_tlbia(CPUPPCState *env)
2121 ppc_tlb_invalidate_all(env);
2124 void helper_tlbie(CPUPPCState *env, target_ulong addr)
2126 ppc_tlb_invalidate_one(env, addr);
2129 /* Software driven TLBs management */
2130 /* PowerPC 602/603 software TLB load instructions helpers */
2131 static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2133 target_ulong RPN, CMP, EPN;
2134 int way;
2136 RPN = env->spr[SPR_RPA];
2137 if (is_code) {
2138 CMP = env->spr[SPR_ICMP];
2139 EPN = env->spr[SPR_IMISS];
2140 } else {
2141 CMP = env->spr[SPR_DCMP];
2142 EPN = env->spr[SPR_DMISS];
2144 way = (env->spr[SPR_SRR1] >> 17) & 1;
2145 (void)EPN; /* avoid a compiler warning */
2146 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2147 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2148 RPN, way);
2149 /* Store this TLB */
2150 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2151 way, is_code, CMP, RPN);
2154 void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN)
2156 do_6xx_tlb(env, EPN, 0);
2159 void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
2161 do_6xx_tlb(env, EPN, 1);
2164 /* PowerPC 74xx software TLB load instructions helpers */
2165 static void do_74xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2167 target_ulong RPN, CMP, EPN;
2168 int way;
2170 RPN = env->spr[SPR_PTELO];
2171 CMP = env->spr[SPR_PTEHI];
2172 EPN = env->spr[SPR_TLBMISS] & ~0x3;
2173 way = env->spr[SPR_TLBMISS] & 0x3;
2174 (void)EPN; /* avoid a compiler warning */
2175 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2176 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2177 RPN, way);
2178 /* Store this TLB */
2179 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2180 way, is_code, CMP, RPN);
2183 void helper_74xx_tlbd(CPUPPCState *env, target_ulong EPN)
2185 do_74xx_tlb(env, EPN, 0);
2188 void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN)
2190 do_74xx_tlb(env, EPN, 1);
2193 /*****************************************************************************/
2194 /* PowerPC 601 specific instructions (POWER bridge) */
2196 target_ulong helper_rac(CPUPPCState *env, target_ulong addr)
2198 mmu_ctx_t ctx;
2199 int nb_BATs;
2200 target_ulong ret = 0;
2202 /* We don't have to generate many instances of this instruction,
2203 * as rac is supervisor only.
2205 /* XXX: FIX THIS: Pretend we have no BAT */
2206 nb_BATs = env->nb_BATs;
2207 env->nb_BATs = 0;
2208 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
2209 ret = ctx.raddr;
2211 env->nb_BATs = nb_BATs;
2212 return ret;
2215 static inline target_ulong booke_tlb_to_page_size(int size)
2217 return 1024 << (2 * size);
2220 static inline int booke_page_size_to_tlb(target_ulong page_size)
2222 int size;
2224 switch (page_size) {
2225 case 0x00000400UL:
2226 size = 0x0;
2227 break;
2228 case 0x00001000UL:
2229 size = 0x1;
2230 break;
2231 case 0x00004000UL:
2232 size = 0x2;
2233 break;
2234 case 0x00010000UL:
2235 size = 0x3;
2236 break;
2237 case 0x00040000UL:
2238 size = 0x4;
2239 break;
2240 case 0x00100000UL:
2241 size = 0x5;
2242 break;
2243 case 0x00400000UL:
2244 size = 0x6;
2245 break;
2246 case 0x01000000UL:
2247 size = 0x7;
2248 break;
2249 case 0x04000000UL:
2250 size = 0x8;
2251 break;
2252 case 0x10000000UL:
2253 size = 0x9;
2254 break;
2255 case 0x40000000UL:
2256 size = 0xA;
2257 break;
2258 #if defined(TARGET_PPC64)
2259 case 0x000100000000ULL:
2260 size = 0xB;
2261 break;
2262 case 0x000400000000ULL:
2263 size = 0xC;
2264 break;
2265 case 0x001000000000ULL:
2266 size = 0xD;
2267 break;
2268 case 0x004000000000ULL:
2269 size = 0xE;
2270 break;
2271 case 0x010000000000ULL:
2272 size = 0xF;
2273 break;
2274 #endif
2275 default:
2276 size = -1;
2277 break;
2280 return size;
2283 /* Helpers for 4xx TLB management */
2284 #define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
2286 #define PPC4XX_TLBHI_V 0x00000040
2287 #define PPC4XX_TLBHI_E 0x00000020
2288 #define PPC4XX_TLBHI_SIZE_MIN 0
2289 #define PPC4XX_TLBHI_SIZE_MAX 7
2290 #define PPC4XX_TLBHI_SIZE_DEFAULT 1
2291 #define PPC4XX_TLBHI_SIZE_SHIFT 7
2292 #define PPC4XX_TLBHI_SIZE_MASK 0x00000007
2294 #define PPC4XX_TLBLO_EX 0x00000200
2295 #define PPC4XX_TLBLO_WR 0x00000100
2296 #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
2297 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
2299 target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
2301 ppcemb_tlb_t *tlb;
2302 target_ulong ret;
2303 int size;
2305 entry &= PPC4XX_TLB_ENTRY_MASK;
2306 tlb = &env->tlb.tlbe[entry];
2307 ret = tlb->EPN;
2308 if (tlb->prot & PAGE_VALID) {
2309 ret |= PPC4XX_TLBHI_V;
2311 size = booke_page_size_to_tlb(tlb->size);
2312 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
2313 size = PPC4XX_TLBHI_SIZE_DEFAULT;
2315 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
2316 env->spr[SPR_40x_PID] = tlb->PID;
2317 return ret;
2320 target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry)
2322 ppcemb_tlb_t *tlb;
2323 target_ulong ret;
2325 entry &= PPC4XX_TLB_ENTRY_MASK;
2326 tlb = &env->tlb.tlbe[entry];
2327 ret = tlb->RPN;
2328 if (tlb->prot & PAGE_EXEC) {
2329 ret |= PPC4XX_TLBLO_EX;
2331 if (tlb->prot & PAGE_WRITE) {
2332 ret |= PPC4XX_TLBLO_WR;
2334 return ret;
2337 void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
2338 target_ulong val)
2340 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2341 CPUState *cs = CPU(cpu);
2342 ppcemb_tlb_t *tlb;
2343 target_ulong page, end;
2345 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
2346 val);
2347 entry &= PPC4XX_TLB_ENTRY_MASK;
2348 tlb = &env->tlb.tlbe[entry];
2349 /* Invalidate previous TLB (if it's valid) */
2350 if (tlb->prot & PAGE_VALID) {
2351 end = tlb->EPN + tlb->size;
2352 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
2353 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2354 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2355 tlb_flush_page(cs, page);
2358 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
2359 & PPC4XX_TLBHI_SIZE_MASK);
2360 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2361 * If this ever occurs, one should use the ppcemb target instead
2362 * of the ppc or ppc64 one
2364 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
2365 cpu_abort(cs, "TLB size " TARGET_FMT_lu " < %u "
2366 "are not supported (%d)\n",
2367 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
2369 tlb->EPN = val & ~(tlb->size - 1);
2370 if (val & PPC4XX_TLBHI_V) {
2371 tlb->prot |= PAGE_VALID;
2372 if (val & PPC4XX_TLBHI_E) {
2373 /* XXX: TO BE FIXED */
2374 cpu_abort(cs,
2375 "Little-endian TLB entries are not supported by now\n");
2377 } else {
2378 tlb->prot &= ~PAGE_VALID;
2380 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2381 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2382 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2383 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2384 tlb->prot & PAGE_READ ? 'r' : '-',
2385 tlb->prot & PAGE_WRITE ? 'w' : '-',
2386 tlb->prot & PAGE_EXEC ? 'x' : '-',
2387 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2388 /* Invalidate new TLB (if valid) */
2389 if (tlb->prot & PAGE_VALID) {
2390 end = tlb->EPN + tlb->size;
2391 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
2392 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2393 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2394 tlb_flush_page(cs, page);
2399 void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
2400 target_ulong val)
2402 ppcemb_tlb_t *tlb;
2404 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
2405 val);
2406 entry &= PPC4XX_TLB_ENTRY_MASK;
2407 tlb = &env->tlb.tlbe[entry];
2408 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
2409 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
2410 tlb->prot = PAGE_READ;
2411 if (val & PPC4XX_TLBLO_EX) {
2412 tlb->prot |= PAGE_EXEC;
2414 if (val & PPC4XX_TLBLO_WR) {
2415 tlb->prot |= PAGE_WRITE;
2417 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2418 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2419 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2420 tlb->prot & PAGE_READ ? 'r' : '-',
2421 tlb->prot & PAGE_WRITE ? 'w' : '-',
2422 tlb->prot & PAGE_EXEC ? 'x' : '-',
2423 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2426 target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
2428 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
2431 /* PowerPC 440 TLB management */
2432 void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry,
2433 target_ulong value)
2435 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2436 ppcemb_tlb_t *tlb;
2437 target_ulong EPN, RPN, size;
2438 int do_flush_tlbs;
2440 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
2441 __func__, word, (int)entry, value);
2442 do_flush_tlbs = 0;
2443 entry &= 0x3F;
2444 tlb = &env->tlb.tlbe[entry];
2445 switch (word) {
2446 default:
2447 /* Just here to please gcc */
2448 case 0:
2449 EPN = value & 0xFFFFFC00;
2450 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
2451 do_flush_tlbs = 1;
2453 tlb->EPN = EPN;
2454 size = booke_tlb_to_page_size((value >> 4) & 0xF);
2455 if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
2456 do_flush_tlbs = 1;
2458 tlb->size = size;
2459 tlb->attr &= ~0x1;
2460 tlb->attr |= (value >> 8) & 1;
2461 if (value & 0x200) {
2462 tlb->prot |= PAGE_VALID;
2463 } else {
2464 if (tlb->prot & PAGE_VALID) {
2465 tlb->prot &= ~PAGE_VALID;
2466 do_flush_tlbs = 1;
2469 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
2470 if (do_flush_tlbs) {
2471 tlb_flush(CPU(cpu), 1);
2473 break;
2474 case 1:
2475 RPN = value & 0xFFFFFC0F;
2476 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
2477 tlb_flush(CPU(cpu), 1);
2479 tlb->RPN = RPN;
2480 break;
2481 case 2:
2482 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
2483 tlb->prot = tlb->prot & PAGE_VALID;
2484 if (value & 0x1) {
2485 tlb->prot |= PAGE_READ << 4;
2487 if (value & 0x2) {
2488 tlb->prot |= PAGE_WRITE << 4;
2490 if (value & 0x4) {
2491 tlb->prot |= PAGE_EXEC << 4;
2493 if (value & 0x8) {
2494 tlb->prot |= PAGE_READ;
2496 if (value & 0x10) {
2497 tlb->prot |= PAGE_WRITE;
2499 if (value & 0x20) {
2500 tlb->prot |= PAGE_EXEC;
2502 break;
2506 target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word,
2507 target_ulong entry)
2509 ppcemb_tlb_t *tlb;
2510 target_ulong ret;
2511 int size;
2513 entry &= 0x3F;
2514 tlb = &env->tlb.tlbe[entry];
2515 switch (word) {
2516 default:
2517 /* Just here to please gcc */
2518 case 0:
2519 ret = tlb->EPN;
2520 size = booke_page_size_to_tlb(tlb->size);
2521 if (size < 0 || size > 0xF) {
2522 size = 1;
2524 ret |= size << 4;
2525 if (tlb->attr & 0x1) {
2526 ret |= 0x100;
2528 if (tlb->prot & PAGE_VALID) {
2529 ret |= 0x200;
2531 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
2532 env->spr[SPR_440_MMUCR] |= tlb->PID;
2533 break;
2534 case 1:
2535 ret = tlb->RPN;
2536 break;
2537 case 2:
2538 ret = tlb->attr & ~0x1;
2539 if (tlb->prot & (PAGE_READ << 4)) {
2540 ret |= 0x1;
2542 if (tlb->prot & (PAGE_WRITE << 4)) {
2543 ret |= 0x2;
2545 if (tlb->prot & (PAGE_EXEC << 4)) {
2546 ret |= 0x4;
2548 if (tlb->prot & PAGE_READ) {
2549 ret |= 0x8;
2551 if (tlb->prot & PAGE_WRITE) {
2552 ret |= 0x10;
2554 if (tlb->prot & PAGE_EXEC) {
2555 ret |= 0x20;
2557 break;
2559 return ret;
2562 target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address)
2564 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
2567 /* PowerPC BookE 2.06 TLB management */
2569 static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
2571 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2572 uint32_t tlbncfg = 0;
2573 int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
2574 int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
2575 int tlb;
2577 tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2578 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
2580 if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
2581 cpu_abort(CPU(cpu), "we don't support HES yet\n");
2584 return booke206_get_tlbm(env, tlb, ea, esel);
2587 void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid)
2589 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2591 env->spr[pidn] = pid;
2592 /* changing PIDs mean we're in a different address space now */
2593 tlb_flush(CPU(cpu), 1);
2596 void helper_booke206_tlbwe(CPUPPCState *env)
2598 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2599 uint32_t tlbncfg, tlbn;
2600 ppcmas_tlb_t *tlb;
2601 uint32_t size_tlb, size_ps;
2602 target_ulong mask;
2605 switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
2606 case MAS0_WQ_ALWAYS:
2607 /* good to go, write that entry */
2608 break;
2609 case MAS0_WQ_COND:
2610 /* XXX check if reserved */
2611 if (0) {
2612 return;
2614 break;
2615 case MAS0_WQ_CLR_RSRV:
2616 /* XXX clear entry */
2617 return;
2618 default:
2619 /* no idea what to do */
2620 return;
2623 if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
2624 !msr_gs) {
2625 /* XXX we don't support direct LRAT setting yet */
2626 fprintf(stderr, "cpu: don't support LRAT setting yet\n");
2627 return;
2630 tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2631 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
2633 tlb = booke206_cur_tlb(env);
2635 if (!tlb) {
2636 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2637 POWERPC_EXCP_INVAL |
2638 POWERPC_EXCP_INVAL_INVAL);
2641 /* check that we support the targeted size */
2642 size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
2643 size_ps = booke206_tlbnps(env, tlbn);
2644 if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
2645 !(size_ps & (1 << size_tlb))) {
2646 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2647 POWERPC_EXCP_INVAL |
2648 POWERPC_EXCP_INVAL_INVAL);
2651 if (msr_gs) {
2652 cpu_abort(CPU(cpu), "missing HV implementation\n");
2654 tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
2655 env->spr[SPR_BOOKE_MAS3];
2656 tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
2658 /* MAV 1.0 only */
2659 if (!(tlbncfg & TLBnCFG_AVAIL)) {
2660 /* force !AVAIL TLB entries to correct page size */
2661 tlb->mas1 &= ~MAS1_TSIZE_MASK;
2662 /* XXX can be configured in MMUCSR0 */
2663 tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
2666 /* Make a mask from TLB size to discard invalid bits in EPN field */
2667 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2668 /* Add a mask for page attributes */
2669 mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E;
2671 if (!msr_cm) {
2672 /* Executing a tlbwe instruction in 32-bit mode will set
2673 * bits 0:31 of the TLB EPN field to zero.
2675 mask &= 0xffffffff;
2678 tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & mask;
2680 if (!(tlbncfg & TLBnCFG_IPROT)) {
2681 /* no IPROT supported by TLB */
2682 tlb->mas1 &= ~MAS1_IPROT;
2685 if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
2686 tlb_flush_page(CPU(cpu), tlb->mas2 & MAS2_EPN_MASK);
2687 } else {
2688 tlb_flush(CPU(cpu), 1);
2692 static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
2694 int tlbn = booke206_tlbm_to_tlbn(env, tlb);
2695 int way = booke206_tlbm_to_way(env, tlb);
2697 env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
2698 env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
2699 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2701 env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
2702 env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
2703 env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
2704 env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
2707 void helper_booke206_tlbre(CPUPPCState *env)
2709 ppcmas_tlb_t *tlb = NULL;
2711 tlb = booke206_cur_tlb(env);
2712 if (!tlb) {
2713 env->spr[SPR_BOOKE_MAS1] = 0;
2714 } else {
2715 booke206_tlb_to_mas(env, tlb);
2719 void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address)
2721 ppcmas_tlb_t *tlb = NULL;
2722 int i, j;
2723 hwaddr raddr;
2724 uint32_t spid, sas;
2726 spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
2727 sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
2729 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2730 int ways = booke206_tlb_ways(env, i);
2732 for (j = 0; j < ways; j++) {
2733 tlb = booke206_get_tlbm(env, i, address, j);
2735 if (!tlb) {
2736 continue;
2739 if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
2740 continue;
2743 if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
2744 continue;
2747 booke206_tlb_to_mas(env, tlb);
2748 return;
2752 /* no entry found, fill with defaults */
2753 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
2754 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
2755 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
2756 env->spr[SPR_BOOKE_MAS3] = 0;
2757 env->spr[SPR_BOOKE_MAS7] = 0;
2759 if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
2760 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
2763 env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
2764 << MAS1_TID_SHIFT;
2766 /* next victim logic */
2767 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
2768 env->last_way++;
2769 env->last_way &= booke206_tlb_ways(env, 0) - 1;
2770 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2773 static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
2774 uint32_t ea)
2776 int i;
2777 int ways = booke206_tlb_ways(env, tlbn);
2778 target_ulong mask;
2780 for (i = 0; i < ways; i++) {
2781 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
2782 if (!tlb) {
2783 continue;
2785 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2786 if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
2787 !(tlb->mas1 & MAS1_IPROT)) {
2788 tlb->mas1 &= ~MAS1_VALID;
2793 void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address)
2795 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2797 if (address & 0x4) {
2798 /* flush all entries */
2799 if (address & 0x8) {
2800 /* flush all of TLB1 */
2801 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
2802 } else {
2803 /* flush all of TLB0 */
2804 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
2806 return;
2809 if (address & 0x8) {
2810 /* flush TLB1 entries */
2811 booke206_invalidate_ea_tlb(env, 1, address);
2812 tlb_flush(CPU(cpu), 1);
2813 } else {
2814 /* flush TLB0 entries */
2815 booke206_invalidate_ea_tlb(env, 0, address);
2816 tlb_flush_page(CPU(cpu), address & MAS2_EPN_MASK);
2820 void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address)
2822 /* XXX missing LPID handling */
2823 booke206_flush_tlb(env, -1, 1);
2826 void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address)
2828 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2829 int i, j;
2830 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2831 ppcmas_tlb_t *tlb = env->tlb.tlbm;
2832 int tlb_size;
2834 /* XXX missing LPID handling */
2835 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2836 tlb_size = booke206_tlb_size(env, i);
2837 for (j = 0; j < tlb_size; j++) {
2838 if (!(tlb[j].mas1 & MAS1_IPROT) &&
2839 ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
2840 tlb[j].mas1 &= ~MAS1_VALID;
2843 tlb += booke206_tlb_size(env, i);
2845 tlb_flush(CPU(cpu), 1);
2848 void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
2850 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2851 int i, j;
2852 ppcmas_tlb_t *tlb;
2853 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2854 int pid = tid >> MAS6_SPID_SHIFT;
2855 int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
2856 int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
2857 /* XXX check for unsupported isize and raise an invalid opcode then */
2858 int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
2859 /* XXX implement MAV2 handling */
2860 bool mav2 = false;
2862 /* XXX missing LPID handling */
2863 /* flush by pid and ea */
2864 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2865 int ways = booke206_tlb_ways(env, i);
2867 for (j = 0; j < ways; j++) {
2868 tlb = booke206_get_tlbm(env, i, address, j);
2869 if (!tlb) {
2870 continue;
2872 if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
2873 (tlb->mas1 & MAS1_IPROT) ||
2874 ((tlb->mas1 & MAS1_IND) != ind) ||
2875 ((tlb->mas8 & MAS8_TGS) != sgs)) {
2876 continue;
2878 if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
2879 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
2880 continue;
2882 /* XXX e500mc doesn't match SAS, but other cores might */
2883 tlb->mas1 &= ~MAS1_VALID;
2886 tlb_flush(CPU(cpu), 1);
2889 void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type)
2891 int flags = 0;
2893 if (type & 2) {
2894 flags |= BOOKE206_FLUSH_TLB1;
2897 if (type & 4) {
2898 flags |= BOOKE206_FLUSH_TLB0;
2901 booke206_flush_tlb(env, flags, 1);
2905 /*****************************************************************************/
2907 /* try to fill the TLB and return an exception if error. If retaddr is
2908 NULL, it means that the function was called in C code (i.e. not
2909 from generated code or from helper.c) */
2910 /* XXX: fix it to restore all registers */
2911 void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
2912 uintptr_t retaddr)
2914 PowerPCCPU *cpu = POWERPC_CPU(cs);
2915 PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
2916 CPUPPCState *env = &cpu->env;
2917 int ret;
2919 if (pcc->handle_mmu_fault) {
2920 ret = pcc->handle_mmu_fault(cpu, addr, is_write, mmu_idx);
2921 } else {
2922 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
2924 if (unlikely(ret != 0)) {
2925 if (likely(retaddr)) {
2926 /* now we have a real cpu fault */
2927 cpu_restore_state(cs, retaddr);
2929 helper_raise_exception_err(env, cs->exception_index, env->error_code);