hw/char: QOM'ify escc.c (fix)
[qemu/cris-port.git] / target-ppc / mmu_helper.c
blob1499af72a0513a4625ff110c2b8ef4fd8a9c0e0f
1 /*
2 * PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU.
4 * Copyright (c) 2003-2007 Jocelyn Mayer
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 #include "qemu/osdep.h"
20 #include "qapi/error.h"
21 #include "cpu.h"
22 #include "exec/helper-proto.h"
23 #include "sysemu/kvm.h"
24 #include "kvm_ppc.h"
25 #include "mmu-hash64.h"
26 #include "mmu-hash32.h"
27 #include "exec/exec-all.h"
28 #include "exec/cpu_ldst.h"
29 #include "exec/log.h"
30 #include "helper_regs.h"
32 //#define DEBUG_MMU
33 //#define DEBUG_BATS
34 //#define DEBUG_SOFTWARE_TLB
35 //#define DUMP_PAGE_TABLES
36 //#define FLUSH_ALL_TLBS
38 #ifdef DEBUG_MMU
39 # define LOG_MMU_STATE(cpu) log_cpu_state_mask(CPU_LOG_MMU, (cpu), 0)
40 #else
41 # define LOG_MMU_STATE(cpu) do { } while (0)
42 #endif
44 #ifdef DEBUG_SOFTWARE_TLB
45 # define LOG_SWTLB(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
46 #else
47 # define LOG_SWTLB(...) do { } while (0)
48 #endif
50 #ifdef DEBUG_BATS
51 # define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
52 #else
53 # define LOG_BATS(...) do { } while (0)
54 #endif
56 /*****************************************************************************/
57 /* PowerPC MMU emulation */
59 /* Context used internally during MMU translations */
60 typedef struct mmu_ctx_t mmu_ctx_t;
61 struct mmu_ctx_t {
62 hwaddr raddr; /* Real address */
63 hwaddr eaddr; /* Effective address */
64 int prot; /* Protection bits */
65 hwaddr hash[2]; /* Pagetable hash values */
66 target_ulong ptem; /* Virtual segment ID | API */
67 int key; /* Access key */
68 int nx; /* Non-execute area */
71 /* Common routines used by software and hardware TLBs emulation */
72 static inline int pte_is_valid(target_ulong pte0)
74 return pte0 & 0x80000000 ? 1 : 0;
77 static inline void pte_invalidate(target_ulong *pte0)
79 *pte0 &= ~0x80000000;
82 #define PTE_PTEM_MASK 0x7FFFFFBF
83 #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
85 static int pp_check(int key, int pp, int nx)
87 int access;
89 /* Compute access rights */
90 access = 0;
91 if (key == 0) {
92 switch (pp) {
93 case 0x0:
94 case 0x1:
95 case 0x2:
96 access |= PAGE_WRITE;
97 /* No break here */
98 case 0x3:
99 access |= PAGE_READ;
100 break;
102 } else {
103 switch (pp) {
104 case 0x0:
105 access = 0;
106 break;
107 case 0x1:
108 case 0x3:
109 access = PAGE_READ;
110 break;
111 case 0x2:
112 access = PAGE_READ | PAGE_WRITE;
113 break;
116 if (nx == 0) {
117 access |= PAGE_EXEC;
120 return access;
123 static int check_prot(int prot, int rw, int access_type)
125 int ret;
127 if (access_type == ACCESS_CODE) {
128 if (prot & PAGE_EXEC) {
129 ret = 0;
130 } else {
131 ret = -2;
133 } else if (rw) {
134 if (prot & PAGE_WRITE) {
135 ret = 0;
136 } else {
137 ret = -2;
139 } else {
140 if (prot & PAGE_READ) {
141 ret = 0;
142 } else {
143 ret = -2;
147 return ret;
150 static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
151 target_ulong pte1, int h, int rw, int type)
153 target_ulong ptem, mmask;
154 int access, ret, pteh, ptev, pp;
156 ret = -1;
157 /* Check validity and table match */
158 ptev = pte_is_valid(pte0);
159 pteh = (pte0 >> 6) & 1;
160 if (ptev && h == pteh) {
161 /* Check vsid & api */
162 ptem = pte0 & PTE_PTEM_MASK;
163 mmask = PTE_CHECK_MASK;
164 pp = pte1 & 0x00000003;
165 if (ptem == ctx->ptem) {
166 if (ctx->raddr != (hwaddr)-1ULL) {
167 /* all matches should have equal RPN, WIMG & PP */
168 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
169 qemu_log_mask(CPU_LOG_MMU, "Bad RPN/WIMG/PP\n");
170 return -3;
173 /* Compute access rights */
174 access = pp_check(ctx->key, pp, ctx->nx);
175 /* Keep the matching PTE informations */
176 ctx->raddr = pte1;
177 ctx->prot = access;
178 ret = check_prot(ctx->prot, rw, type);
179 if (ret == 0) {
180 /* Access granted */
181 qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
182 } else {
183 /* Access right violation */
184 qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
189 return ret;
192 static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
193 int ret, int rw)
195 int store = 0;
197 /* Update page flags */
198 if (!(*pte1p & 0x00000100)) {
199 /* Update accessed flag */
200 *pte1p |= 0x00000100;
201 store = 1;
203 if (!(*pte1p & 0x00000080)) {
204 if (rw == 1 && ret == 0) {
205 /* Update changed flag */
206 *pte1p |= 0x00000080;
207 store = 1;
208 } else {
209 /* Force page fault for first write access */
210 ctx->prot &= ~PAGE_WRITE;
214 return store;
217 /* Software driven TLB helpers */
218 static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
219 int way, int is_code)
221 int nr;
223 /* Select TLB num in a way from address */
224 nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
225 /* Select TLB way */
226 nr += env->tlb_per_way * way;
227 /* 6xx have separate TLBs for instructions and data */
228 if (is_code && env->id_tlbs == 1) {
229 nr += env->nb_tlb;
232 return nr;
235 static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
237 PowerPCCPU *cpu = ppc_env_get_cpu(env);
238 ppc6xx_tlb_t *tlb;
239 int nr, max;
241 /* LOG_SWTLB("Invalidate all TLBs\n"); */
242 /* Invalidate all defined software TLB */
243 max = env->nb_tlb;
244 if (env->id_tlbs == 1) {
245 max *= 2;
247 for (nr = 0; nr < max; nr++) {
248 tlb = &env->tlb.tlb6[nr];
249 pte_invalidate(&tlb->pte0);
251 tlb_flush(CPU(cpu), 1);
254 static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env,
255 target_ulong eaddr,
256 int is_code, int match_epn)
258 #if !defined(FLUSH_ALL_TLBS)
259 CPUState *cs = CPU(ppc_env_get_cpu(env));
260 ppc6xx_tlb_t *tlb;
261 int way, nr;
263 /* Invalidate ITLB + DTLB, all ways */
264 for (way = 0; way < env->nb_ways; way++) {
265 nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
266 tlb = &env->tlb.tlb6[nr];
267 if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
268 LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
269 env->nb_tlb, eaddr);
270 pte_invalidate(&tlb->pte0);
271 tlb_flush_page(cs, tlb->EPN);
274 #else
275 /* XXX: PowerPC specification say this is valid as well */
276 ppc6xx_tlb_invalidate_all(env);
277 #endif
280 static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
281 target_ulong eaddr, int is_code)
283 ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0);
286 static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way,
287 int is_code, target_ulong pte0, target_ulong pte1)
289 ppc6xx_tlb_t *tlb;
290 int nr;
292 nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
293 tlb = &env->tlb.tlb6[nr];
294 LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
295 " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
296 /* Invalidate any pending reference in QEMU for this virtual address */
297 ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1);
298 tlb->pte0 = pte0;
299 tlb->pte1 = pte1;
300 tlb->EPN = EPN;
301 /* Store last way for LRU mechanism */
302 env->last_way = way;
305 static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
306 target_ulong eaddr, int rw, int access_type)
308 ppc6xx_tlb_t *tlb;
309 int nr, best, way;
310 int ret;
312 best = -1;
313 ret = -1; /* No TLB found */
314 for (way = 0; way < env->nb_ways; way++) {
315 nr = ppc6xx_tlb_getnum(env, eaddr, way,
316 access_type == ACCESS_CODE ? 1 : 0);
317 tlb = &env->tlb.tlb6[nr];
318 /* This test "emulates" the PTE index match for hardware TLBs */
319 if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
320 LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
321 "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
322 pte_is_valid(tlb->pte0) ? "valid" : "inval",
323 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
324 continue;
326 LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
327 TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
328 pte_is_valid(tlb->pte0) ? "valid" : "inval",
329 tlb->EPN, eaddr, tlb->pte1,
330 rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
331 switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
332 case -3:
333 /* TLB inconsistency */
334 return -1;
335 case -2:
336 /* Access violation */
337 ret = -2;
338 best = nr;
339 break;
340 case -1:
341 default:
342 /* No match */
343 break;
344 case 0:
345 /* access granted */
346 /* XXX: we should go on looping to check all TLBs consistency
347 * but we can speed-up the whole thing as the
348 * result would be undefined if TLBs are not consistent.
350 ret = 0;
351 best = nr;
352 goto done;
355 if (best != -1) {
356 done:
357 LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
358 ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
359 /* Update page flags */
360 pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
363 return ret;
366 /* Perform BAT hit & translation */
367 static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
368 int *validp, int *protp, target_ulong *BATu,
369 target_ulong *BATl)
371 target_ulong bl;
372 int pp, valid, prot;
374 bl = (*BATu & 0x00001FFC) << 15;
375 valid = 0;
376 prot = 0;
377 if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
378 ((msr_pr != 0) && (*BATu & 0x00000001))) {
379 valid = 1;
380 pp = *BATl & 0x00000003;
381 if (pp != 0) {
382 prot = PAGE_READ | PAGE_EXEC;
383 if (pp == 0x2) {
384 prot |= PAGE_WRITE;
388 *blp = bl;
389 *validp = valid;
390 *protp = prot;
393 static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
394 target_ulong virtual, int rw, int type)
396 target_ulong *BATlt, *BATut, *BATu, *BATl;
397 target_ulong BEPIl, BEPIu, bl;
398 int i, valid, prot;
399 int ret = -1;
401 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
402 type == ACCESS_CODE ? 'I' : 'D', virtual);
403 switch (type) {
404 case ACCESS_CODE:
405 BATlt = env->IBAT[1];
406 BATut = env->IBAT[0];
407 break;
408 default:
409 BATlt = env->DBAT[1];
410 BATut = env->DBAT[0];
411 break;
413 for (i = 0; i < env->nb_BATs; i++) {
414 BATu = &BATut[i];
415 BATl = &BATlt[i];
416 BEPIu = *BATu & 0xF0000000;
417 BEPIl = *BATu & 0x0FFE0000;
418 bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
419 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
420 " BATl " TARGET_FMT_lx "\n", __func__,
421 type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
422 if ((virtual & 0xF0000000) == BEPIu &&
423 ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
424 /* BAT matches */
425 if (valid != 0) {
426 /* Get physical address */
427 ctx->raddr = (*BATl & 0xF0000000) |
428 ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
429 (virtual & 0x0001F000);
430 /* Compute access rights */
431 ctx->prot = prot;
432 ret = check_prot(ctx->prot, rw, type);
433 if (ret == 0) {
434 LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
435 i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
436 ctx->prot & PAGE_WRITE ? 'W' : '-');
438 break;
442 if (ret < 0) {
443 #if defined(DEBUG_BATS)
444 if (qemu_log_enabled()) {
445 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
446 for (i = 0; i < 4; i++) {
447 BATu = &BATut[i];
448 BATl = &BATlt[i];
449 BEPIu = *BATu & 0xF0000000;
450 BEPIl = *BATu & 0x0FFE0000;
451 bl = (*BATu & 0x00001FFC) << 15;
452 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
453 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
454 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
455 __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
456 *BATu, *BATl, BEPIu, BEPIl, bl);
459 #endif
461 /* No hit */
462 return ret;
465 /* Perform segment based translation */
466 static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
467 target_ulong eaddr, int rw, int type)
469 hwaddr hash;
470 target_ulong vsid;
471 int ds, pr, target_page_bits;
472 int ret;
473 target_ulong sr, pgidx;
475 pr = msr_pr;
476 ctx->eaddr = eaddr;
478 sr = env->sr[eaddr >> 28];
479 ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
480 ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
481 ds = sr & 0x80000000 ? 1 : 0;
482 ctx->nx = sr & 0x10000000 ? 1 : 0;
483 vsid = sr & 0x00FFFFFF;
484 target_page_bits = TARGET_PAGE_BITS;
485 qemu_log_mask(CPU_LOG_MMU,
486 "Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx
487 " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx
488 " ir=%d dr=%d pr=%d %d t=%d\n",
489 eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
490 (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
491 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
492 hash = vsid ^ pgidx;
493 ctx->ptem = (vsid << 7) | (pgidx >> 10);
495 qemu_log_mask(CPU_LOG_MMU,
496 "pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
497 ctx->key, ds, ctx->nx, vsid);
498 ret = -1;
499 if (!ds) {
500 /* Check if instruction fetch is allowed, if needed */
501 if (type != ACCESS_CODE || ctx->nx == 0) {
502 /* Page address translation */
503 qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
504 " htab_mask " TARGET_FMT_plx
505 " hash " TARGET_FMT_plx "\n",
506 env->htab_base, env->htab_mask, hash);
507 ctx->hash[0] = hash;
508 ctx->hash[1] = ~hash;
510 /* Initialize real address with an invalid value */
511 ctx->raddr = (hwaddr)-1ULL;
512 /* Software TLB search */
513 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
514 #if defined(DUMP_PAGE_TABLES)
515 if (qemu_log_mask(CPU_LOG_MMU)) {
516 hwaddr curaddr;
517 uint32_t a0, a1, a2, a3;
519 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
520 "\n", sdr, mask + 0x80);
521 for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
522 curaddr += 16) {
523 a0 = ldl_phys(curaddr);
524 a1 = ldl_phys(curaddr + 4);
525 a2 = ldl_phys(curaddr + 8);
526 a3 = ldl_phys(curaddr + 12);
527 if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
528 qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
529 curaddr, a0, a1, a2, a3);
533 #endif
534 } else {
535 qemu_log_mask(CPU_LOG_MMU, "No access allowed\n");
536 ret = -3;
538 } else {
539 target_ulong sr;
541 qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
542 /* Direct-store segment : absolutely *BUGGY* for now */
544 /* Direct-store implies a 32-bit MMU.
545 * Check the Segment Register's bus unit ID (BUID).
547 sr = env->sr[eaddr >> 28];
548 if ((sr & 0x1FF00000) >> 20 == 0x07f) {
549 /* Memory-forced I/O controller interface access */
550 /* If T=1 and BUID=x'07F', the 601 performs a memory access
551 * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
553 ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
554 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
555 return 0;
558 switch (type) {
559 case ACCESS_INT:
560 /* Integer load/store : only access allowed */
561 break;
562 case ACCESS_CODE:
563 /* No code fetch is allowed in direct-store areas */
564 return -4;
565 case ACCESS_FLOAT:
566 /* Floating point load/store */
567 return -4;
568 case ACCESS_RES:
569 /* lwarx, ldarx or srwcx. */
570 return -4;
571 case ACCESS_CACHE:
572 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
573 /* Should make the instruction do no-op.
574 * As it already do no-op, it's quite easy :-)
576 ctx->raddr = eaddr;
577 return 0;
578 case ACCESS_EXT:
579 /* eciwx or ecowx */
580 return -4;
581 default:
582 qemu_log_mask(CPU_LOG_MMU, "ERROR: instruction should not need "
583 "address translation\n");
584 return -4;
586 if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
587 ctx->raddr = eaddr;
588 ret = 2;
589 } else {
590 ret = -2;
594 return ret;
597 /* Generic TLB check function for embedded PowerPC implementations */
598 static int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
599 hwaddr *raddrp,
600 target_ulong address, uint32_t pid, int ext,
601 int i)
603 target_ulong mask;
605 /* Check valid flag */
606 if (!(tlb->prot & PAGE_VALID)) {
607 return -1;
609 mask = ~(tlb->size - 1);
610 LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
611 " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
612 mask, (uint32_t)tlb->PID, tlb->prot);
613 /* Check PID */
614 if (tlb->PID != 0 && tlb->PID != pid) {
615 return -1;
617 /* Check effective address */
618 if ((address & mask) != tlb->EPN) {
619 return -1;
621 *raddrp = (tlb->RPN & mask) | (address & ~mask);
622 if (ext) {
623 /* Extend the physical address to 36 bits */
624 *raddrp |= (uint64_t)(tlb->RPN & 0xF) << 32;
627 return 0;
630 /* Generic TLB search function for PowerPC embedded implementations */
631 static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address,
632 uint32_t pid)
634 ppcemb_tlb_t *tlb;
635 hwaddr raddr;
636 int i, ret;
638 /* Default return value is no match */
639 ret = -1;
640 for (i = 0; i < env->nb_tlb; i++) {
641 tlb = &env->tlb.tlbe[i];
642 if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
643 ret = i;
644 break;
648 return ret;
651 /* Helpers specific to PowerPC 40x implementations */
652 static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
654 PowerPCCPU *cpu = ppc_env_get_cpu(env);
655 ppcemb_tlb_t *tlb;
656 int i;
658 for (i = 0; i < env->nb_tlb; i++) {
659 tlb = &env->tlb.tlbe[i];
660 tlb->prot &= ~PAGE_VALID;
662 tlb_flush(CPU(cpu), 1);
665 static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
666 target_ulong address, int rw,
667 int access_type)
669 ppcemb_tlb_t *tlb;
670 hwaddr raddr;
671 int i, ret, zsel, zpr, pr;
673 ret = -1;
674 raddr = (hwaddr)-1ULL;
675 pr = msr_pr;
676 for (i = 0; i < env->nb_tlb; i++) {
677 tlb = &env->tlb.tlbe[i];
678 if (ppcemb_tlb_check(env, tlb, &raddr, address,
679 env->spr[SPR_40x_PID], 0, i) < 0) {
680 continue;
682 zsel = (tlb->attr >> 4) & 0xF;
683 zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
684 LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
685 __func__, i, zsel, zpr, rw, tlb->attr);
686 /* Check execute enable bit */
687 switch (zpr) {
688 case 0x2:
689 if (pr != 0) {
690 goto check_perms;
692 /* No break here */
693 case 0x3:
694 /* All accesses granted */
695 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
696 ret = 0;
697 break;
698 case 0x0:
699 if (pr != 0) {
700 /* Raise Zone protection fault. */
701 env->spr[SPR_40x_ESR] = 1 << 22;
702 ctx->prot = 0;
703 ret = -2;
704 break;
706 /* No break here */
707 case 0x1:
708 check_perms:
709 /* Check from TLB entry */
710 ctx->prot = tlb->prot;
711 ret = check_prot(ctx->prot, rw, access_type);
712 if (ret == -2) {
713 env->spr[SPR_40x_ESR] = 0;
715 break;
717 if (ret >= 0) {
718 ctx->raddr = raddr;
719 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
720 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
721 ret);
722 return 0;
725 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
726 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
728 return ret;
731 void store_40x_sler(CPUPPCState *env, uint32_t val)
733 PowerPCCPU *cpu = ppc_env_get_cpu(env);
735 /* XXX: TO BE FIXED */
736 if (val != 0x00000000) {
737 cpu_abort(CPU(cpu), "Little-endian regions are not supported by now\n");
739 env->spr[SPR_405_SLER] = val;
742 static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
743 hwaddr *raddr, int *prot,
744 target_ulong address, int rw,
745 int access_type, int i)
747 int ret, prot2;
749 if (ppcemb_tlb_check(env, tlb, raddr, address,
750 env->spr[SPR_BOOKE_PID],
751 !env->nb_pids, i) >= 0) {
752 goto found_tlb;
755 if (env->spr[SPR_BOOKE_PID1] &&
756 ppcemb_tlb_check(env, tlb, raddr, address,
757 env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
758 goto found_tlb;
761 if (env->spr[SPR_BOOKE_PID2] &&
762 ppcemb_tlb_check(env, tlb, raddr, address,
763 env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
764 goto found_tlb;
767 LOG_SWTLB("%s: TLB entry not found\n", __func__);
768 return -1;
770 found_tlb:
772 if (msr_pr != 0) {
773 prot2 = tlb->prot & 0xF;
774 } else {
775 prot2 = (tlb->prot >> 4) & 0xF;
778 /* Check the address space */
779 if (access_type == ACCESS_CODE) {
780 if (msr_ir != (tlb->attr & 1)) {
781 LOG_SWTLB("%s: AS doesn't match\n", __func__);
782 return -1;
785 *prot = prot2;
786 if (prot2 & PAGE_EXEC) {
787 LOG_SWTLB("%s: good TLB!\n", __func__);
788 return 0;
791 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
792 ret = -3;
793 } else {
794 if (msr_dr != (tlb->attr & 1)) {
795 LOG_SWTLB("%s: AS doesn't match\n", __func__);
796 return -1;
799 *prot = prot2;
800 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
801 LOG_SWTLB("%s: found TLB!\n", __func__);
802 return 0;
805 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
806 ret = -2;
809 return ret;
812 static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
813 target_ulong address, int rw,
814 int access_type)
816 ppcemb_tlb_t *tlb;
817 hwaddr raddr;
818 int i, ret;
820 ret = -1;
821 raddr = (hwaddr)-1ULL;
822 for (i = 0; i < env->nb_tlb; i++) {
823 tlb = &env->tlb.tlbe[i];
824 ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
825 access_type, i);
826 if (!ret) {
827 break;
831 if (ret >= 0) {
832 ctx->raddr = raddr;
833 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
834 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
835 ret);
836 } else {
837 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
838 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
841 return ret;
844 static void booke206_flush_tlb(CPUPPCState *env, int flags,
845 const int check_iprot)
847 PowerPCCPU *cpu = ppc_env_get_cpu(env);
848 int tlb_size;
849 int i, j;
850 ppcmas_tlb_t *tlb = env->tlb.tlbm;
852 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
853 if (flags & (1 << i)) {
854 tlb_size = booke206_tlb_size(env, i);
855 for (j = 0; j < tlb_size; j++) {
856 if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
857 tlb[j].mas1 &= ~MAS1_VALID;
861 tlb += booke206_tlb_size(env, i);
864 tlb_flush(CPU(cpu), 1);
867 static hwaddr booke206_tlb_to_page_size(CPUPPCState *env,
868 ppcmas_tlb_t *tlb)
870 int tlbm_size;
872 tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
874 return 1024ULL << tlbm_size;
877 /* TLB check function for MAS based SoftTLBs */
878 static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
879 hwaddr *raddrp, target_ulong address,
880 uint32_t pid)
882 hwaddr mask;
883 uint32_t tlb_pid;
885 if (!msr_cm) {
886 /* In 32bit mode we can only address 32bit EAs */
887 address = (uint32_t)address;
890 /* Check valid flag */
891 if (!(tlb->mas1 & MAS1_VALID)) {
892 return -1;
895 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
896 LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
897 PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n",
898 __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3,
899 tlb->mas8);
901 /* Check PID */
902 tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
903 if (tlb_pid != 0 && tlb_pid != pid) {
904 return -1;
907 /* Check effective address */
908 if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
909 return -1;
912 if (raddrp) {
913 *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
916 return 0;
919 static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
920 hwaddr *raddr, int *prot,
921 target_ulong address, int rw,
922 int access_type)
924 int ret;
925 int prot2 = 0;
927 if (ppcmas_tlb_check(env, tlb, raddr, address,
928 env->spr[SPR_BOOKE_PID]) >= 0) {
929 goto found_tlb;
932 if (env->spr[SPR_BOOKE_PID1] &&
933 ppcmas_tlb_check(env, tlb, raddr, address,
934 env->spr[SPR_BOOKE_PID1]) >= 0) {
935 goto found_tlb;
938 if (env->spr[SPR_BOOKE_PID2] &&
939 ppcmas_tlb_check(env, tlb, raddr, address,
940 env->spr[SPR_BOOKE_PID2]) >= 0) {
941 goto found_tlb;
944 LOG_SWTLB("%s: TLB entry not found\n", __func__);
945 return -1;
947 found_tlb:
949 if (msr_pr != 0) {
950 if (tlb->mas7_3 & MAS3_UR) {
951 prot2 |= PAGE_READ;
953 if (tlb->mas7_3 & MAS3_UW) {
954 prot2 |= PAGE_WRITE;
956 if (tlb->mas7_3 & MAS3_UX) {
957 prot2 |= PAGE_EXEC;
959 } else {
960 if (tlb->mas7_3 & MAS3_SR) {
961 prot2 |= PAGE_READ;
963 if (tlb->mas7_3 & MAS3_SW) {
964 prot2 |= PAGE_WRITE;
966 if (tlb->mas7_3 & MAS3_SX) {
967 prot2 |= PAGE_EXEC;
971 /* Check the address space and permissions */
972 if (access_type == ACCESS_CODE) {
973 if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
974 LOG_SWTLB("%s: AS doesn't match\n", __func__);
975 return -1;
978 *prot = prot2;
979 if (prot2 & PAGE_EXEC) {
980 LOG_SWTLB("%s: good TLB!\n", __func__);
981 return 0;
984 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
985 ret = -3;
986 } else {
987 if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
988 LOG_SWTLB("%s: AS doesn't match\n", __func__);
989 return -1;
992 *prot = prot2;
993 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
994 LOG_SWTLB("%s: found TLB!\n", __func__);
995 return 0;
998 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
999 ret = -2;
1002 return ret;
1005 static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1006 target_ulong address, int rw,
1007 int access_type)
1009 ppcmas_tlb_t *tlb;
1010 hwaddr raddr;
1011 int i, j, ret;
1013 ret = -1;
1014 raddr = (hwaddr)-1ULL;
1016 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1017 int ways = booke206_tlb_ways(env, i);
1019 for (j = 0; j < ways; j++) {
1020 tlb = booke206_get_tlbm(env, i, address, j);
1021 if (!tlb) {
1022 continue;
1024 ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
1025 rw, access_type);
1026 if (ret != -1) {
1027 goto found_tlb;
1032 found_tlb:
1034 if (ret >= 0) {
1035 ctx->raddr = raddr;
1036 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1037 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1038 ret);
1039 } else {
1040 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1041 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1044 return ret;
1047 static const char *book3e_tsize_to_str[32] = {
1048 "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
1049 "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
1050 "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
1051 "1T", "2T"
1054 static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1055 CPUPPCState *env)
1057 ppcemb_tlb_t *entry;
1058 int i;
1060 if (kvm_enabled() && !env->kvm_sw_tlb) {
1061 cpu_fprintf(f, "Cannot access KVM TLB\n");
1062 return;
1065 cpu_fprintf(f, "\nTLB:\n");
1066 cpu_fprintf(f, "Effective Physical Size PID Prot "
1067 "Attr\n");
1069 entry = &env->tlb.tlbe[0];
1070 for (i = 0; i < env->nb_tlb; i++, entry++) {
1071 hwaddr ea, pa;
1072 target_ulong mask;
1073 uint64_t size = (uint64_t)entry->size;
1074 char size_buf[20];
1076 /* Check valid flag */
1077 if (!(entry->prot & PAGE_VALID)) {
1078 continue;
1081 mask = ~(entry->size - 1);
1082 ea = entry->EPN & mask;
1083 pa = entry->RPN & mask;
1084 /* Extend the physical address to 36 bits */
1085 pa |= (hwaddr)(entry->RPN & 0xF) << 32;
1086 size /= 1024;
1087 if (size >= 1024) {
1088 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024);
1089 } else {
1090 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size);
1092 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
1093 (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
1094 entry->prot, entry->attr);
1099 static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
1100 CPUPPCState *env, int tlbn, int offset,
1101 int tlbsize)
1103 ppcmas_tlb_t *entry;
1104 int i;
1106 cpu_fprintf(f, "\nTLB%d:\n", tlbn);
1107 cpu_fprintf(f, "Effective Physical Size TID TS SRWX"
1108 " URWX WIMGE U0123\n");
1110 entry = &env->tlb.tlbm[offset];
1111 for (i = 0; i < tlbsize; i++, entry++) {
1112 hwaddr ea, pa, size;
1113 int tsize;
1115 if (!(entry->mas1 & MAS1_VALID)) {
1116 continue;
1119 tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1120 size = 1024ULL << tsize;
1121 ea = entry->mas2 & ~(size - 1);
1122 pa = entry->mas7_3 & ~(size - 1);
1124 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c"
1125 "U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
1126 (uint64_t)ea, (uint64_t)pa,
1127 book3e_tsize_to_str[tsize],
1128 (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
1129 (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
1130 entry->mas7_3 & MAS3_SR ? 'R' : '-',
1131 entry->mas7_3 & MAS3_SW ? 'W' : '-',
1132 entry->mas7_3 & MAS3_SX ? 'X' : '-',
1133 entry->mas7_3 & MAS3_UR ? 'R' : '-',
1134 entry->mas7_3 & MAS3_UW ? 'W' : '-',
1135 entry->mas7_3 & MAS3_UX ? 'X' : '-',
1136 entry->mas2 & MAS2_W ? 'W' : '-',
1137 entry->mas2 & MAS2_I ? 'I' : '-',
1138 entry->mas2 & MAS2_M ? 'M' : '-',
1139 entry->mas2 & MAS2_G ? 'G' : '-',
1140 entry->mas2 & MAS2_E ? 'E' : '-',
1141 entry->mas7_3 & MAS3_U0 ? '0' : '-',
1142 entry->mas7_3 & MAS3_U1 ? '1' : '-',
1143 entry->mas7_3 & MAS3_U2 ? '2' : '-',
1144 entry->mas7_3 & MAS3_U3 ? '3' : '-');
1148 static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1149 CPUPPCState *env)
1151 int offset = 0;
1152 int i;
1154 if (kvm_enabled() && !env->kvm_sw_tlb) {
1155 cpu_fprintf(f, "Cannot access KVM TLB\n");
1156 return;
1159 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1160 int size = booke206_tlb_size(env, i);
1162 if (size == 0) {
1163 continue;
1166 mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size);
1167 offset += size;
1171 static void mmu6xx_dump_BATs(FILE *f, fprintf_function cpu_fprintf,
1172 CPUPPCState *env, int type)
1174 target_ulong *BATlt, *BATut, *BATu, *BATl;
1175 target_ulong BEPIl, BEPIu, bl;
1176 int i;
1178 switch (type) {
1179 case ACCESS_CODE:
1180 BATlt = env->IBAT[1];
1181 BATut = env->IBAT[0];
1182 break;
1183 default:
1184 BATlt = env->DBAT[1];
1185 BATut = env->DBAT[0];
1186 break;
1189 for (i = 0; i < env->nb_BATs; i++) {
1190 BATu = &BATut[i];
1191 BATl = &BATlt[i];
1192 BEPIu = *BATu & 0xF0000000;
1193 BEPIl = *BATu & 0x0FFE0000;
1194 bl = (*BATu & 0x00001FFC) << 15;
1195 cpu_fprintf(f, "%s BAT%d BATu " TARGET_FMT_lx
1196 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
1197 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
1198 type == ACCESS_CODE ? "code" : "data", i,
1199 *BATu, *BATl, BEPIu, BEPIl, bl);
1203 static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1204 CPUPPCState *env)
1206 ppc6xx_tlb_t *tlb;
1207 target_ulong sr;
1208 int type, way, entry, i;
1210 cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", env->htab_base);
1211 cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", env->htab_mask);
1213 cpu_fprintf(f, "\nSegment registers:\n");
1214 for (i = 0; i < 32; i++) {
1215 sr = env->sr[i];
1216 if (sr & 0x80000000) {
1217 cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d BUID=0x%03x "
1218 "CNTLR_SPEC=0x%05x\n", i,
1219 sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1220 sr & 0x20000000 ? 1 : 0, (uint32_t)((sr >> 20) & 0x1FF),
1221 (uint32_t)(sr & 0xFFFFF));
1222 } else {
1223 cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d N=%d VSID=0x%06x\n", i,
1224 sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1225 sr & 0x20000000 ? 1 : 0, sr & 0x10000000 ? 1 : 0,
1226 (uint32_t)(sr & 0x00FFFFFF));
1230 cpu_fprintf(f, "\nBATs:\n");
1231 mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_INT);
1232 mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_CODE);
1234 if (env->id_tlbs != 1) {
1235 cpu_fprintf(f, "ERROR: 6xx MMU should have separated TLB"
1236 " for code and data\n");
1239 cpu_fprintf(f, "\nTLBs [EPN EPN + SIZE]\n");
1241 for (type = 0; type < 2; type++) {
1242 for (way = 0; way < env->nb_ways; way++) {
1243 for (entry = env->nb_tlb * type + env->tlb_per_way * way;
1244 entry < (env->nb_tlb * type + env->tlb_per_way * (way + 1));
1245 entry++) {
1247 tlb = &env->tlb.tlb6[entry];
1248 cpu_fprintf(f, "%s TLB %02d/%02d way:%d %s ["
1249 TARGET_FMT_lx " " TARGET_FMT_lx "]\n",
1250 type ? "code" : "data", entry % env->nb_tlb,
1251 env->nb_tlb, way,
1252 pte_is_valid(tlb->pte0) ? "valid" : "inval",
1253 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE);
1259 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
1261 switch (env->mmu_model) {
1262 case POWERPC_MMU_BOOKE:
1263 mmubooke_dump_mmu(f, cpu_fprintf, env);
1264 break;
1265 case POWERPC_MMU_BOOKE206:
1266 mmubooke206_dump_mmu(f, cpu_fprintf, env);
1267 break;
1268 case POWERPC_MMU_SOFT_6xx:
1269 case POWERPC_MMU_SOFT_74xx:
1270 mmu6xx_dump_mmu(f, cpu_fprintf, env);
1271 break;
1272 #if defined(TARGET_PPC64)
1273 case POWERPC_MMU_64B:
1274 case POWERPC_MMU_2_03:
1275 case POWERPC_MMU_2_06:
1276 case POWERPC_MMU_2_06a:
1277 case POWERPC_MMU_2_07:
1278 case POWERPC_MMU_2_07a:
1279 dump_slb(f, cpu_fprintf, ppc_env_get_cpu(env));
1280 break;
1281 #endif
1282 default:
1283 qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
1287 static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
1288 target_ulong eaddr, int rw)
1290 int in_plb, ret;
1292 ctx->raddr = eaddr;
1293 ctx->prot = PAGE_READ | PAGE_EXEC;
1294 ret = 0;
1295 switch (env->mmu_model) {
1296 case POWERPC_MMU_SOFT_6xx:
1297 case POWERPC_MMU_SOFT_74xx:
1298 case POWERPC_MMU_SOFT_4xx:
1299 case POWERPC_MMU_REAL:
1300 case POWERPC_MMU_BOOKE:
1301 ctx->prot |= PAGE_WRITE;
1302 break;
1304 case POWERPC_MMU_SOFT_4xx_Z:
1305 if (unlikely(msr_pe != 0)) {
1306 /* 403 family add some particular protections,
1307 * using PBL/PBU registers for accesses with no translation.
1309 in_plb =
1310 /* Check PLB validity */
1311 (env->pb[0] < env->pb[1] &&
1312 /* and address in plb area */
1313 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
1314 (env->pb[2] < env->pb[3] &&
1315 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
1316 if (in_plb ^ msr_px) {
1317 /* Access in protected area */
1318 if (rw == 1) {
1319 /* Access is not allowed */
1320 ret = -2;
1322 } else {
1323 /* Read-write access is allowed */
1324 ctx->prot |= PAGE_WRITE;
1327 break;
1329 default:
1330 /* Caller's checks mean we should never get here for other models */
1331 abort();
1332 return -1;
1335 return ret;
1338 static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1339 target_ulong eaddr, int rw, int access_type)
1341 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1342 int ret = -1;
1343 bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
1344 || (access_type != ACCESS_CODE && msr_dr == 0);
1346 #if 0
1347 qemu_log("%s\n", __func__);
1348 #endif
1350 switch (env->mmu_model) {
1351 case POWERPC_MMU_SOFT_6xx:
1352 case POWERPC_MMU_SOFT_74xx:
1353 if (real_mode) {
1354 ret = check_physical(env, ctx, eaddr, rw);
1355 } else {
1356 /* Try to find a BAT */
1357 if (env->nb_BATs != 0) {
1358 ret = get_bat_6xx_tlb(env, ctx, eaddr, rw, access_type);
1360 if (ret < 0) {
1361 /* We didn't match any BAT entry or don't have BATs */
1362 ret = get_segment_6xx_tlb(env, ctx, eaddr, rw, access_type);
1365 break;
1367 case POWERPC_MMU_SOFT_4xx:
1368 case POWERPC_MMU_SOFT_4xx_Z:
1369 if (real_mode) {
1370 ret = check_physical(env, ctx, eaddr, rw);
1371 } else {
1372 ret = mmu40x_get_physical_address(env, ctx, eaddr,
1373 rw, access_type);
1375 break;
1376 case POWERPC_MMU_BOOKE:
1377 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1378 rw, access_type);
1379 break;
1380 case POWERPC_MMU_BOOKE206:
1381 ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
1382 access_type);
1383 break;
1384 case POWERPC_MMU_MPC8xx:
1385 /* XXX: TODO */
1386 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1387 break;
1388 case POWERPC_MMU_REAL:
1389 if (real_mode) {
1390 ret = check_physical(env, ctx, eaddr, rw);
1391 } else {
1392 cpu_abort(CPU(cpu), "PowerPC in real mode do not do any translation\n");
1394 return -1;
1395 default:
1396 cpu_abort(CPU(cpu), "Unknown or invalid MMU model\n");
1397 return -1;
1399 #if 0
1400 qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
1401 __func__, eaddr, ret, ctx->raddr);
1402 #endif
1404 return ret;
1407 hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
1409 PowerPCCPU *cpu = POWERPC_CPU(cs);
1410 CPUPPCState *env = &cpu->env;
1411 mmu_ctx_t ctx;
1413 switch (env->mmu_model) {
1414 #if defined(TARGET_PPC64)
1415 case POWERPC_MMU_64B:
1416 case POWERPC_MMU_2_03:
1417 case POWERPC_MMU_2_06:
1418 case POWERPC_MMU_2_06a:
1419 case POWERPC_MMU_2_07:
1420 case POWERPC_MMU_2_07a:
1421 return ppc_hash64_get_phys_page_debug(cpu, addr);
1422 #endif
1424 case POWERPC_MMU_32B:
1425 case POWERPC_MMU_601:
1426 return ppc_hash32_get_phys_page_debug(cpu, addr);
1428 default:
1432 if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {
1434 /* Some MMUs have separate TLBs for code and data. If we only try an
1435 * ACCESS_INT, we may not be able to read instructions mapped by code
1436 * TLBs, so we also try a ACCESS_CODE.
1438 if (unlikely(get_physical_address(env, &ctx, addr, 0,
1439 ACCESS_CODE) != 0)) {
1440 return -1;
1444 return ctx.raddr & TARGET_PAGE_MASK;
1447 static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
1448 int rw)
1450 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
1451 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
1452 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
1453 env->spr[SPR_BOOKE_MAS3] = 0;
1454 env->spr[SPR_BOOKE_MAS6] = 0;
1455 env->spr[SPR_BOOKE_MAS7] = 0;
1457 /* AS */
1458 if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
1459 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
1460 env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
1463 env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
1464 env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
1466 switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
1467 case MAS4_TIDSELD_PID0:
1468 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
1469 break;
1470 case MAS4_TIDSELD_PID1:
1471 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
1472 break;
1473 case MAS4_TIDSELD_PID2:
1474 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
1475 break;
1478 env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
1480 /* next victim logic */
1481 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
1482 env->last_way++;
1483 env->last_way &= booke206_tlb_ways(env, 0) - 1;
1484 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
1487 /* Perform address translation */
1488 static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
1489 int rw, int mmu_idx)
1491 CPUState *cs = CPU(ppc_env_get_cpu(env));
1492 PowerPCCPU *cpu = POWERPC_CPU(cs);
1493 mmu_ctx_t ctx;
1494 int access_type;
1495 int ret = 0;
1497 if (rw == 2) {
1498 /* code access */
1499 rw = 0;
1500 access_type = ACCESS_CODE;
1501 } else {
1502 /* data access */
1503 access_type = env->access_type;
1505 ret = get_physical_address(env, &ctx, address, rw, access_type);
1506 if (ret == 0) {
1507 tlb_set_page(cs, address & TARGET_PAGE_MASK,
1508 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
1509 mmu_idx, TARGET_PAGE_SIZE);
1510 ret = 0;
1511 } else if (ret < 0) {
1512 LOG_MMU_STATE(cs);
1513 if (access_type == ACCESS_CODE) {
1514 switch (ret) {
1515 case -1:
1516 /* No matches in page tables or TLB */
1517 switch (env->mmu_model) {
1518 case POWERPC_MMU_SOFT_6xx:
1519 cs->exception_index = POWERPC_EXCP_IFTLB;
1520 env->error_code = 1 << 18;
1521 env->spr[SPR_IMISS] = address;
1522 env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
1523 goto tlb_miss;
1524 case POWERPC_MMU_SOFT_74xx:
1525 cs->exception_index = POWERPC_EXCP_IFTLB;
1526 goto tlb_miss_74xx;
1527 case POWERPC_MMU_SOFT_4xx:
1528 case POWERPC_MMU_SOFT_4xx_Z:
1529 cs->exception_index = POWERPC_EXCP_ITLB;
1530 env->error_code = 0;
1531 env->spr[SPR_40x_DEAR] = address;
1532 env->spr[SPR_40x_ESR] = 0x00000000;
1533 break;
1534 case POWERPC_MMU_BOOKE206:
1535 booke206_update_mas_tlb_miss(env, address, rw);
1536 /* fall through */
1537 case POWERPC_MMU_BOOKE:
1538 cs->exception_index = POWERPC_EXCP_ITLB;
1539 env->error_code = 0;
1540 env->spr[SPR_BOOKE_DEAR] = address;
1541 return -1;
1542 case POWERPC_MMU_MPC8xx:
1543 /* XXX: TODO */
1544 cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1545 break;
1546 case POWERPC_MMU_REAL:
1547 cpu_abort(cs, "PowerPC in real mode should never raise "
1548 "any MMU exceptions\n");
1549 return -1;
1550 default:
1551 cpu_abort(cs, "Unknown or invalid MMU model\n");
1552 return -1;
1554 break;
1555 case -2:
1556 /* Access rights violation */
1557 cs->exception_index = POWERPC_EXCP_ISI;
1558 env->error_code = 0x08000000;
1559 break;
1560 case -3:
1561 /* No execute protection violation */
1562 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1563 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1564 env->spr[SPR_BOOKE_ESR] = 0x00000000;
1566 cs->exception_index = POWERPC_EXCP_ISI;
1567 env->error_code = 0x10000000;
1568 break;
1569 case -4:
1570 /* Direct store exception */
1571 /* No code fetch is allowed in direct-store areas */
1572 cs->exception_index = POWERPC_EXCP_ISI;
1573 env->error_code = 0x10000000;
1574 break;
1576 } else {
1577 switch (ret) {
1578 case -1:
1579 /* No matches in page tables or TLB */
1580 switch (env->mmu_model) {
1581 case POWERPC_MMU_SOFT_6xx:
1582 if (rw == 1) {
1583 cs->exception_index = POWERPC_EXCP_DSTLB;
1584 env->error_code = 1 << 16;
1585 } else {
1586 cs->exception_index = POWERPC_EXCP_DLTLB;
1587 env->error_code = 0;
1589 env->spr[SPR_DMISS] = address;
1590 env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
1591 tlb_miss:
1592 env->error_code |= ctx.key << 19;
1593 env->spr[SPR_HASH1] = env->htab_base +
1594 get_pteg_offset32(cpu, ctx.hash[0]);
1595 env->spr[SPR_HASH2] = env->htab_base +
1596 get_pteg_offset32(cpu, ctx.hash[1]);
1597 break;
1598 case POWERPC_MMU_SOFT_74xx:
1599 if (rw == 1) {
1600 cs->exception_index = POWERPC_EXCP_DSTLB;
1601 } else {
1602 cs->exception_index = POWERPC_EXCP_DLTLB;
1604 tlb_miss_74xx:
1605 /* Implement LRU algorithm */
1606 env->error_code = ctx.key << 19;
1607 env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
1608 ((env->last_way + 1) & (env->nb_ways - 1));
1609 env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
1610 break;
1611 case POWERPC_MMU_SOFT_4xx:
1612 case POWERPC_MMU_SOFT_4xx_Z:
1613 cs->exception_index = POWERPC_EXCP_DTLB;
1614 env->error_code = 0;
1615 env->spr[SPR_40x_DEAR] = address;
1616 if (rw) {
1617 env->spr[SPR_40x_ESR] = 0x00800000;
1618 } else {
1619 env->spr[SPR_40x_ESR] = 0x00000000;
1621 break;
1622 case POWERPC_MMU_MPC8xx:
1623 /* XXX: TODO */
1624 cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1625 break;
1626 case POWERPC_MMU_BOOKE206:
1627 booke206_update_mas_tlb_miss(env, address, rw);
1628 /* fall through */
1629 case POWERPC_MMU_BOOKE:
1630 cs->exception_index = POWERPC_EXCP_DTLB;
1631 env->error_code = 0;
1632 env->spr[SPR_BOOKE_DEAR] = address;
1633 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1634 return -1;
1635 case POWERPC_MMU_REAL:
1636 cpu_abort(cs, "PowerPC in real mode should never raise "
1637 "any MMU exceptions\n");
1638 return -1;
1639 default:
1640 cpu_abort(cs, "Unknown or invalid MMU model\n");
1641 return -1;
1643 break;
1644 case -2:
1645 /* Access rights violation */
1646 cs->exception_index = POWERPC_EXCP_DSI;
1647 env->error_code = 0;
1648 if (env->mmu_model == POWERPC_MMU_SOFT_4xx
1649 || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
1650 env->spr[SPR_40x_DEAR] = address;
1651 if (rw) {
1652 env->spr[SPR_40x_ESR] |= 0x00800000;
1654 } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1655 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1656 env->spr[SPR_BOOKE_DEAR] = address;
1657 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1658 } else {
1659 env->spr[SPR_DAR] = address;
1660 if (rw == 1) {
1661 env->spr[SPR_DSISR] = 0x0A000000;
1662 } else {
1663 env->spr[SPR_DSISR] = 0x08000000;
1666 break;
1667 case -4:
1668 /* Direct store exception */
1669 switch (access_type) {
1670 case ACCESS_FLOAT:
1671 /* Floating point load/store */
1672 cs->exception_index = POWERPC_EXCP_ALIGN;
1673 env->error_code = POWERPC_EXCP_ALIGN_FP;
1674 env->spr[SPR_DAR] = address;
1675 break;
1676 case ACCESS_RES:
1677 /* lwarx, ldarx or stwcx. */
1678 cs->exception_index = POWERPC_EXCP_DSI;
1679 env->error_code = 0;
1680 env->spr[SPR_DAR] = address;
1681 if (rw == 1) {
1682 env->spr[SPR_DSISR] = 0x06000000;
1683 } else {
1684 env->spr[SPR_DSISR] = 0x04000000;
1686 break;
1687 case ACCESS_EXT:
1688 /* eciwx or ecowx */
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] = 0x06100000;
1694 } else {
1695 env->spr[SPR_DSISR] = 0x04100000;
1697 break;
1698 default:
1699 printf("DSI: invalid exception (%d)\n", ret);
1700 cs->exception_index = POWERPC_EXCP_PROGRAM;
1701 env->error_code =
1702 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
1703 env->spr[SPR_DAR] = address;
1704 break;
1706 break;
1709 #if 0
1710 printf("%s: set exception to %d %02x\n", __func__,
1711 cs->exception, env->error_code);
1712 #endif
1713 ret = 1;
1716 return ret;
1719 /*****************************************************************************/
1720 /* BATs management */
1721 #if !defined(FLUSH_ALL_TLBS)
1722 static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
1723 target_ulong mask)
1725 CPUState *cs = CPU(ppc_env_get_cpu(env));
1726 target_ulong base, end, page;
1728 base = BATu & ~0x0001FFFF;
1729 end = base + mask + 0x00020000;
1730 LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
1731 TARGET_FMT_lx ")\n", base, end, mask);
1732 for (page = base; page != end; page += TARGET_PAGE_SIZE) {
1733 tlb_flush_page(cs, page);
1735 LOG_BATS("Flush done\n");
1737 #endif
1739 static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
1740 target_ulong value)
1742 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
1743 nr, ul == 0 ? 'u' : 'l', value, env->nip);
1746 void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1748 target_ulong mask;
1750 dump_store_bat(env, 'I', 0, nr, value);
1751 if (env->IBAT[0][nr] != value) {
1752 mask = (value << 15) & 0x0FFE0000UL;
1753 #if !defined(FLUSH_ALL_TLBS)
1754 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1755 #endif
1756 /* When storing valid upper BAT, mask BEPI and BRPN
1757 * and invalidate all TLBs covered by this BAT
1759 mask = (value << 15) & 0x0FFE0000UL;
1760 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1761 (value & ~0x0001FFFFUL & ~mask);
1762 env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
1763 (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
1764 #if !defined(FLUSH_ALL_TLBS)
1765 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1766 #else
1767 tlb_flush(env, 1);
1768 #endif
1772 void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1774 dump_store_bat(env, 'I', 1, nr, value);
1775 env->IBAT[1][nr] = value;
1778 void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1780 target_ulong mask;
1782 dump_store_bat(env, 'D', 0, nr, value);
1783 if (env->DBAT[0][nr] != value) {
1784 /* When storing valid upper BAT, mask BEPI and BRPN
1785 * and invalidate all TLBs covered by this BAT
1787 mask = (value << 15) & 0x0FFE0000UL;
1788 #if !defined(FLUSH_ALL_TLBS)
1789 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1790 #endif
1791 mask = (value << 15) & 0x0FFE0000UL;
1792 env->DBAT[0][nr] = (value & 0x00001FFFUL) |
1793 (value & ~0x0001FFFFUL & ~mask);
1794 env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
1795 (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
1796 #if !defined(FLUSH_ALL_TLBS)
1797 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1798 #else
1799 tlb_flush(env, 1);
1800 #endif
1804 void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1806 dump_store_bat(env, 'D', 1, nr, value);
1807 env->DBAT[1][nr] = value;
1810 void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value)
1812 target_ulong mask;
1813 #if defined(FLUSH_ALL_TLBS)
1814 int do_inval;
1815 #endif
1817 dump_store_bat(env, 'I', 0, nr, value);
1818 if (env->IBAT[0][nr] != value) {
1819 #if defined(FLUSH_ALL_TLBS)
1820 do_inval = 0;
1821 #endif
1822 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1823 if (env->IBAT[1][nr] & 0x40) {
1824 /* Invalidate BAT only if it is valid */
1825 #if !defined(FLUSH_ALL_TLBS)
1826 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1827 #else
1828 do_inval = 1;
1829 #endif
1831 /* When storing valid upper BAT, mask BEPI and BRPN
1832 * and invalidate all TLBs covered by this BAT
1834 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1835 (value & ~0x0001FFFFUL & ~mask);
1836 env->DBAT[0][nr] = env->IBAT[0][nr];
1837 if (env->IBAT[1][nr] & 0x40) {
1838 #if !defined(FLUSH_ALL_TLBS)
1839 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1840 #else
1841 do_inval = 1;
1842 #endif
1844 #if defined(FLUSH_ALL_TLBS)
1845 if (do_inval) {
1846 tlb_flush(env, 1);
1848 #endif
1852 void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value)
1854 #if !defined(FLUSH_ALL_TLBS)
1855 target_ulong mask;
1856 #else
1857 int do_inval;
1858 #endif
1860 dump_store_bat(env, 'I', 1, nr, value);
1861 if (env->IBAT[1][nr] != value) {
1862 #if defined(FLUSH_ALL_TLBS)
1863 do_inval = 0;
1864 #endif
1865 if (env->IBAT[1][nr] & 0x40) {
1866 #if !defined(FLUSH_ALL_TLBS)
1867 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1868 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1869 #else
1870 do_inval = 1;
1871 #endif
1873 if (value & 0x40) {
1874 #if !defined(FLUSH_ALL_TLBS)
1875 mask = (value << 17) & 0x0FFE0000UL;
1876 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1877 #else
1878 do_inval = 1;
1879 #endif
1881 env->IBAT[1][nr] = value;
1882 env->DBAT[1][nr] = value;
1883 #if defined(FLUSH_ALL_TLBS)
1884 if (do_inval) {
1885 tlb_flush(env, 1);
1887 #endif
1891 /*****************************************************************************/
1892 /* TLB management */
1893 void ppc_tlb_invalidate_all(CPUPPCState *env)
1895 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1897 switch (env->mmu_model) {
1898 case POWERPC_MMU_SOFT_6xx:
1899 case POWERPC_MMU_SOFT_74xx:
1900 ppc6xx_tlb_invalidate_all(env);
1901 break;
1902 case POWERPC_MMU_SOFT_4xx:
1903 case POWERPC_MMU_SOFT_4xx_Z:
1904 ppc4xx_tlb_invalidate_all(env);
1905 break;
1906 case POWERPC_MMU_REAL:
1907 cpu_abort(CPU(cpu), "No TLB for PowerPC 4xx in real mode\n");
1908 break;
1909 case POWERPC_MMU_MPC8xx:
1910 /* XXX: TODO */
1911 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1912 break;
1913 case POWERPC_MMU_BOOKE:
1914 tlb_flush(CPU(cpu), 1);
1915 break;
1916 case POWERPC_MMU_BOOKE206:
1917 booke206_flush_tlb(env, -1, 0);
1918 break;
1919 case POWERPC_MMU_32B:
1920 case POWERPC_MMU_601:
1921 #if defined(TARGET_PPC64)
1922 case POWERPC_MMU_64B:
1923 case POWERPC_MMU_2_03:
1924 case POWERPC_MMU_2_06:
1925 case POWERPC_MMU_2_06a:
1926 case POWERPC_MMU_2_07:
1927 case POWERPC_MMU_2_07a:
1928 env->tlb_need_flush = 0;
1929 #endif /* defined(TARGET_PPC64) */
1930 tlb_flush(CPU(cpu), 1);
1931 break;
1932 default:
1933 /* XXX: TODO */
1934 cpu_abort(CPU(cpu), "Unknown MMU model\n");
1935 break;
1939 void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
1941 #if !defined(FLUSH_ALL_TLBS)
1942 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1943 CPUState *cs;
1945 addr &= TARGET_PAGE_MASK;
1946 switch (env->mmu_model) {
1947 case POWERPC_MMU_SOFT_6xx:
1948 case POWERPC_MMU_SOFT_74xx:
1949 ppc6xx_tlb_invalidate_virt(env, addr, 0);
1950 if (env->id_tlbs == 1) {
1951 ppc6xx_tlb_invalidate_virt(env, addr, 1);
1953 break;
1954 case POWERPC_MMU_32B:
1955 case POWERPC_MMU_601:
1956 /* tlbie invalidate TLBs for all segments */
1957 addr &= ~((target_ulong)-1ULL << 28);
1958 cs = CPU(cpu);
1959 /* XXX: this case should be optimized,
1960 * giving a mask to tlb_flush_page
1962 tlb_flush_page(cs, addr | (0x0 << 28));
1963 tlb_flush_page(cs, addr | (0x1 << 28));
1964 tlb_flush_page(cs, addr | (0x2 << 28));
1965 tlb_flush_page(cs, addr | (0x3 << 28));
1966 tlb_flush_page(cs, addr | (0x4 << 28));
1967 tlb_flush_page(cs, addr | (0x5 << 28));
1968 tlb_flush_page(cs, addr | (0x6 << 28));
1969 tlb_flush_page(cs, addr | (0x7 << 28));
1970 tlb_flush_page(cs, addr | (0x8 << 28));
1971 tlb_flush_page(cs, addr | (0x9 << 28));
1972 tlb_flush_page(cs, addr | (0xA << 28));
1973 tlb_flush_page(cs, addr | (0xB << 28));
1974 tlb_flush_page(cs, addr | (0xC << 28));
1975 tlb_flush_page(cs, addr | (0xD << 28));
1976 tlb_flush_page(cs, addr | (0xE << 28));
1977 tlb_flush_page(cs, addr | (0xF << 28));
1978 break;
1979 #if defined(TARGET_PPC64)
1980 case POWERPC_MMU_64B:
1981 case POWERPC_MMU_2_03:
1982 case POWERPC_MMU_2_06:
1983 case POWERPC_MMU_2_06a:
1984 case POWERPC_MMU_2_07:
1985 case POWERPC_MMU_2_07a:
1986 /* tlbie invalidate TLBs for all segments */
1987 /* XXX: given the fact that there are too many segments to invalidate,
1988 * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
1989 * we just invalidate all TLBs
1991 env->tlb_need_flush = 1;
1992 break;
1993 #endif /* defined(TARGET_PPC64) */
1994 default:
1995 /* Should never reach here with other MMU models */
1996 assert(0);
1998 #else
1999 ppc_tlb_invalidate_all(env);
2000 #endif
2003 /*****************************************************************************/
2004 /* Special registers manipulation */
2005 void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
2007 qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
2008 assert(!env->external_htab);
2009 env->spr[SPR_SDR1] = value;
2010 #if defined(TARGET_PPC64)
2011 if (env->mmu_model & POWERPC_MMU_64) {
2012 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2013 Error *local_err = NULL;
2015 ppc_hash64_set_sdr1(cpu, value, &local_err);
2016 if (local_err) {
2017 error_report_err(local_err);
2018 error_free(local_err);
2020 } else
2021 #endif /* defined(TARGET_PPC64) */
2023 /* FIXME: Should check for valid HTABMASK values */
2024 env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
2025 env->htab_base = value & SDR_32_HTABORG;
2029 /* Segment registers load and store */
2030 target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
2032 #if defined(TARGET_PPC64)
2033 if (env->mmu_model & POWERPC_MMU_64) {
2034 /* XXX */
2035 return 0;
2037 #endif
2038 return env->sr[sr_num];
2041 void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
2043 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2045 qemu_log_mask(CPU_LOG_MMU,
2046 "%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
2047 (int)srnum, value, env->sr[srnum]);
2048 #if defined(TARGET_PPC64)
2049 if (env->mmu_model & POWERPC_MMU_64) {
2050 uint64_t esid, vsid;
2052 /* ESID = srnum */
2053 esid = ((uint64_t)(srnum & 0xf) << 28) | SLB_ESID_V;
2055 /* VSID = VSID */
2056 vsid = (value & 0xfffffff) << 12;
2057 /* flags = flags */
2058 vsid |= ((value >> 27) & 0xf) << 8;
2060 ppc_store_slb(cpu, srnum, esid, vsid);
2061 } else
2062 #endif
2063 if (env->sr[srnum] != value) {
2064 env->sr[srnum] = value;
2065 /* Invalidating 256MB of virtual memory in 4kB pages is way longer than
2066 flusing the whole TLB. */
2067 #if !defined(FLUSH_ALL_TLBS) && 0
2069 target_ulong page, end;
2070 /* Invalidate 256 MB of virtual memory */
2071 page = (16 << 20) * srnum;
2072 end = page + (16 << 20);
2073 for (; page != end; page += TARGET_PAGE_SIZE) {
2074 tlb_flush_page(CPU(cpu), page);
2077 #else
2078 tlb_flush(CPU(cpu), 1);
2079 #endif
2083 /* TLB management */
2084 void helper_tlbia(CPUPPCState *env)
2086 ppc_tlb_invalidate_all(env);
2089 void helper_tlbie(CPUPPCState *env, target_ulong addr)
2091 ppc_tlb_invalidate_one(env, addr);
2094 void helper_tlbiva(CPUPPCState *env, target_ulong addr)
2096 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2098 /* tlbiva instruction only exists on BookE */
2099 assert(env->mmu_model == POWERPC_MMU_BOOKE);
2100 /* XXX: TODO */
2101 cpu_abort(CPU(cpu), "BookE MMU model is not implemented\n");
2104 /* Software driven TLBs management */
2105 /* PowerPC 602/603 software TLB load instructions helpers */
2106 static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2108 target_ulong RPN, CMP, EPN;
2109 int way;
2111 RPN = env->spr[SPR_RPA];
2112 if (is_code) {
2113 CMP = env->spr[SPR_ICMP];
2114 EPN = env->spr[SPR_IMISS];
2115 } else {
2116 CMP = env->spr[SPR_DCMP];
2117 EPN = env->spr[SPR_DMISS];
2119 way = (env->spr[SPR_SRR1] >> 17) & 1;
2120 (void)EPN; /* avoid a compiler warning */
2121 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2122 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2123 RPN, way);
2124 /* Store this TLB */
2125 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2126 way, is_code, CMP, RPN);
2129 void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN)
2131 do_6xx_tlb(env, EPN, 0);
2134 void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
2136 do_6xx_tlb(env, EPN, 1);
2139 /* PowerPC 74xx software TLB load instructions helpers */
2140 static void do_74xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2142 target_ulong RPN, CMP, EPN;
2143 int way;
2145 RPN = env->spr[SPR_PTELO];
2146 CMP = env->spr[SPR_PTEHI];
2147 EPN = env->spr[SPR_TLBMISS] & ~0x3;
2148 way = env->spr[SPR_TLBMISS] & 0x3;
2149 (void)EPN; /* avoid a compiler warning */
2150 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2151 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2152 RPN, way);
2153 /* Store this TLB */
2154 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2155 way, is_code, CMP, RPN);
2158 void helper_74xx_tlbd(CPUPPCState *env, target_ulong EPN)
2160 do_74xx_tlb(env, EPN, 0);
2163 void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN)
2165 do_74xx_tlb(env, EPN, 1);
2168 /*****************************************************************************/
2169 /* PowerPC 601 specific instructions (POWER bridge) */
2171 target_ulong helper_rac(CPUPPCState *env, target_ulong addr)
2173 mmu_ctx_t ctx;
2174 int nb_BATs;
2175 target_ulong ret = 0;
2177 /* We don't have to generate many instances of this instruction,
2178 * as rac is supervisor only.
2180 /* XXX: FIX THIS: Pretend we have no BAT */
2181 nb_BATs = env->nb_BATs;
2182 env->nb_BATs = 0;
2183 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
2184 ret = ctx.raddr;
2186 env->nb_BATs = nb_BATs;
2187 return ret;
2190 static inline target_ulong booke_tlb_to_page_size(int size)
2192 return 1024 << (2 * size);
2195 static inline int booke_page_size_to_tlb(target_ulong page_size)
2197 int size;
2199 switch (page_size) {
2200 case 0x00000400UL:
2201 size = 0x0;
2202 break;
2203 case 0x00001000UL:
2204 size = 0x1;
2205 break;
2206 case 0x00004000UL:
2207 size = 0x2;
2208 break;
2209 case 0x00010000UL:
2210 size = 0x3;
2211 break;
2212 case 0x00040000UL:
2213 size = 0x4;
2214 break;
2215 case 0x00100000UL:
2216 size = 0x5;
2217 break;
2218 case 0x00400000UL:
2219 size = 0x6;
2220 break;
2221 case 0x01000000UL:
2222 size = 0x7;
2223 break;
2224 case 0x04000000UL:
2225 size = 0x8;
2226 break;
2227 case 0x10000000UL:
2228 size = 0x9;
2229 break;
2230 case 0x40000000UL:
2231 size = 0xA;
2232 break;
2233 #if defined(TARGET_PPC64)
2234 case 0x000100000000ULL:
2235 size = 0xB;
2236 break;
2237 case 0x000400000000ULL:
2238 size = 0xC;
2239 break;
2240 case 0x001000000000ULL:
2241 size = 0xD;
2242 break;
2243 case 0x004000000000ULL:
2244 size = 0xE;
2245 break;
2246 case 0x010000000000ULL:
2247 size = 0xF;
2248 break;
2249 #endif
2250 default:
2251 size = -1;
2252 break;
2255 return size;
2258 /* Helpers for 4xx TLB management */
2259 #define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
2261 #define PPC4XX_TLBHI_V 0x00000040
2262 #define PPC4XX_TLBHI_E 0x00000020
2263 #define PPC4XX_TLBHI_SIZE_MIN 0
2264 #define PPC4XX_TLBHI_SIZE_MAX 7
2265 #define PPC4XX_TLBHI_SIZE_DEFAULT 1
2266 #define PPC4XX_TLBHI_SIZE_SHIFT 7
2267 #define PPC4XX_TLBHI_SIZE_MASK 0x00000007
2269 #define PPC4XX_TLBLO_EX 0x00000200
2270 #define PPC4XX_TLBLO_WR 0x00000100
2271 #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
2272 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
2274 target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
2276 ppcemb_tlb_t *tlb;
2277 target_ulong ret;
2278 int size;
2280 entry &= PPC4XX_TLB_ENTRY_MASK;
2281 tlb = &env->tlb.tlbe[entry];
2282 ret = tlb->EPN;
2283 if (tlb->prot & PAGE_VALID) {
2284 ret |= PPC4XX_TLBHI_V;
2286 size = booke_page_size_to_tlb(tlb->size);
2287 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
2288 size = PPC4XX_TLBHI_SIZE_DEFAULT;
2290 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
2291 env->spr[SPR_40x_PID] = tlb->PID;
2292 return ret;
2295 target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry)
2297 ppcemb_tlb_t *tlb;
2298 target_ulong ret;
2300 entry &= PPC4XX_TLB_ENTRY_MASK;
2301 tlb = &env->tlb.tlbe[entry];
2302 ret = tlb->RPN;
2303 if (tlb->prot & PAGE_EXEC) {
2304 ret |= PPC4XX_TLBLO_EX;
2306 if (tlb->prot & PAGE_WRITE) {
2307 ret |= PPC4XX_TLBLO_WR;
2309 return ret;
2312 void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
2313 target_ulong val)
2315 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2316 CPUState *cs = CPU(cpu);
2317 ppcemb_tlb_t *tlb;
2318 target_ulong page, end;
2320 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
2321 val);
2322 entry &= PPC4XX_TLB_ENTRY_MASK;
2323 tlb = &env->tlb.tlbe[entry];
2324 /* Invalidate previous TLB (if it's valid) */
2325 if (tlb->prot & PAGE_VALID) {
2326 end = tlb->EPN + tlb->size;
2327 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
2328 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2329 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2330 tlb_flush_page(cs, page);
2333 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
2334 & PPC4XX_TLBHI_SIZE_MASK);
2335 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2336 * If this ever occurs, one should use the ppcemb target instead
2337 * of the ppc or ppc64 one
2339 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
2340 cpu_abort(cs, "TLB size " TARGET_FMT_lu " < %u "
2341 "are not supported (%d)\n",
2342 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
2344 tlb->EPN = val & ~(tlb->size - 1);
2345 if (val & PPC4XX_TLBHI_V) {
2346 tlb->prot |= PAGE_VALID;
2347 if (val & PPC4XX_TLBHI_E) {
2348 /* XXX: TO BE FIXED */
2349 cpu_abort(cs,
2350 "Little-endian TLB entries are not supported by now\n");
2352 } else {
2353 tlb->prot &= ~PAGE_VALID;
2355 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2356 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2357 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2358 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2359 tlb->prot & PAGE_READ ? 'r' : '-',
2360 tlb->prot & PAGE_WRITE ? 'w' : '-',
2361 tlb->prot & PAGE_EXEC ? 'x' : '-',
2362 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2363 /* Invalidate new TLB (if valid) */
2364 if (tlb->prot & PAGE_VALID) {
2365 end = tlb->EPN + tlb->size;
2366 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
2367 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2368 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2369 tlb_flush_page(cs, page);
2374 void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
2375 target_ulong val)
2377 ppcemb_tlb_t *tlb;
2379 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
2380 val);
2381 entry &= PPC4XX_TLB_ENTRY_MASK;
2382 tlb = &env->tlb.tlbe[entry];
2383 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
2384 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
2385 tlb->prot = PAGE_READ;
2386 if (val & PPC4XX_TLBLO_EX) {
2387 tlb->prot |= PAGE_EXEC;
2389 if (val & PPC4XX_TLBLO_WR) {
2390 tlb->prot |= PAGE_WRITE;
2392 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2393 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2394 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2395 tlb->prot & PAGE_READ ? 'r' : '-',
2396 tlb->prot & PAGE_WRITE ? 'w' : '-',
2397 tlb->prot & PAGE_EXEC ? 'x' : '-',
2398 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2401 target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
2403 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
2406 /* PowerPC 440 TLB management */
2407 void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry,
2408 target_ulong value)
2410 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2411 ppcemb_tlb_t *tlb;
2412 target_ulong EPN, RPN, size;
2413 int do_flush_tlbs;
2415 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
2416 __func__, word, (int)entry, value);
2417 do_flush_tlbs = 0;
2418 entry &= 0x3F;
2419 tlb = &env->tlb.tlbe[entry];
2420 switch (word) {
2421 default:
2422 /* Just here to please gcc */
2423 case 0:
2424 EPN = value & 0xFFFFFC00;
2425 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
2426 do_flush_tlbs = 1;
2428 tlb->EPN = EPN;
2429 size = booke_tlb_to_page_size((value >> 4) & 0xF);
2430 if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
2431 do_flush_tlbs = 1;
2433 tlb->size = size;
2434 tlb->attr &= ~0x1;
2435 tlb->attr |= (value >> 8) & 1;
2436 if (value & 0x200) {
2437 tlb->prot |= PAGE_VALID;
2438 } else {
2439 if (tlb->prot & PAGE_VALID) {
2440 tlb->prot &= ~PAGE_VALID;
2441 do_flush_tlbs = 1;
2444 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
2445 if (do_flush_tlbs) {
2446 tlb_flush(CPU(cpu), 1);
2448 break;
2449 case 1:
2450 RPN = value & 0xFFFFFC0F;
2451 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
2452 tlb_flush(CPU(cpu), 1);
2454 tlb->RPN = RPN;
2455 break;
2456 case 2:
2457 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
2458 tlb->prot = tlb->prot & PAGE_VALID;
2459 if (value & 0x1) {
2460 tlb->prot |= PAGE_READ << 4;
2462 if (value & 0x2) {
2463 tlb->prot |= PAGE_WRITE << 4;
2465 if (value & 0x4) {
2466 tlb->prot |= PAGE_EXEC << 4;
2468 if (value & 0x8) {
2469 tlb->prot |= PAGE_READ;
2471 if (value & 0x10) {
2472 tlb->prot |= PAGE_WRITE;
2474 if (value & 0x20) {
2475 tlb->prot |= PAGE_EXEC;
2477 break;
2481 target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word,
2482 target_ulong entry)
2484 ppcemb_tlb_t *tlb;
2485 target_ulong ret;
2486 int size;
2488 entry &= 0x3F;
2489 tlb = &env->tlb.tlbe[entry];
2490 switch (word) {
2491 default:
2492 /* Just here to please gcc */
2493 case 0:
2494 ret = tlb->EPN;
2495 size = booke_page_size_to_tlb(tlb->size);
2496 if (size < 0 || size > 0xF) {
2497 size = 1;
2499 ret |= size << 4;
2500 if (tlb->attr & 0x1) {
2501 ret |= 0x100;
2503 if (tlb->prot & PAGE_VALID) {
2504 ret |= 0x200;
2506 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
2507 env->spr[SPR_440_MMUCR] |= tlb->PID;
2508 break;
2509 case 1:
2510 ret = tlb->RPN;
2511 break;
2512 case 2:
2513 ret = tlb->attr & ~0x1;
2514 if (tlb->prot & (PAGE_READ << 4)) {
2515 ret |= 0x1;
2517 if (tlb->prot & (PAGE_WRITE << 4)) {
2518 ret |= 0x2;
2520 if (tlb->prot & (PAGE_EXEC << 4)) {
2521 ret |= 0x4;
2523 if (tlb->prot & PAGE_READ) {
2524 ret |= 0x8;
2526 if (tlb->prot & PAGE_WRITE) {
2527 ret |= 0x10;
2529 if (tlb->prot & PAGE_EXEC) {
2530 ret |= 0x20;
2532 break;
2534 return ret;
2537 target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address)
2539 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
2542 /* PowerPC BookE 2.06 TLB management */
2544 static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
2546 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2547 uint32_t tlbncfg = 0;
2548 int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
2549 int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
2550 int tlb;
2552 tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2553 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
2555 if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
2556 cpu_abort(CPU(cpu), "we don't support HES yet\n");
2559 return booke206_get_tlbm(env, tlb, ea, esel);
2562 void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid)
2564 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2566 env->spr[pidn] = pid;
2567 /* changing PIDs mean we're in a different address space now */
2568 tlb_flush(CPU(cpu), 1);
2571 void helper_booke206_tlbwe(CPUPPCState *env)
2573 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2574 uint32_t tlbncfg, tlbn;
2575 ppcmas_tlb_t *tlb;
2576 uint32_t size_tlb, size_ps;
2577 target_ulong mask;
2580 switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
2581 case MAS0_WQ_ALWAYS:
2582 /* good to go, write that entry */
2583 break;
2584 case MAS0_WQ_COND:
2585 /* XXX check if reserved */
2586 if (0) {
2587 return;
2589 break;
2590 case MAS0_WQ_CLR_RSRV:
2591 /* XXX clear entry */
2592 return;
2593 default:
2594 /* no idea what to do */
2595 return;
2598 if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
2599 !msr_gs) {
2600 /* XXX we don't support direct LRAT setting yet */
2601 fprintf(stderr, "cpu: don't support LRAT setting yet\n");
2602 return;
2605 tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2606 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
2608 tlb = booke206_cur_tlb(env);
2610 if (!tlb) {
2611 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2612 POWERPC_EXCP_INVAL |
2613 POWERPC_EXCP_INVAL_INVAL);
2616 /* check that we support the targeted size */
2617 size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
2618 size_ps = booke206_tlbnps(env, tlbn);
2619 if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
2620 !(size_ps & (1 << size_tlb))) {
2621 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2622 POWERPC_EXCP_INVAL |
2623 POWERPC_EXCP_INVAL_INVAL);
2626 if (msr_gs) {
2627 cpu_abort(CPU(cpu), "missing HV implementation\n");
2629 tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
2630 env->spr[SPR_BOOKE_MAS3];
2631 tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
2633 /* MAV 1.0 only */
2634 if (!(tlbncfg & TLBnCFG_AVAIL)) {
2635 /* force !AVAIL TLB entries to correct page size */
2636 tlb->mas1 &= ~MAS1_TSIZE_MASK;
2637 /* XXX can be configured in MMUCSR0 */
2638 tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
2641 /* Make a mask from TLB size to discard invalid bits in EPN field */
2642 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2643 /* Add a mask for page attributes */
2644 mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E;
2646 if (!msr_cm) {
2647 /* Executing a tlbwe instruction in 32-bit mode will set
2648 * bits 0:31 of the TLB EPN field to zero.
2650 mask &= 0xffffffff;
2653 tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & mask;
2655 if (!(tlbncfg & TLBnCFG_IPROT)) {
2656 /* no IPROT supported by TLB */
2657 tlb->mas1 &= ~MAS1_IPROT;
2660 if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
2661 tlb_flush_page(CPU(cpu), tlb->mas2 & MAS2_EPN_MASK);
2662 } else {
2663 tlb_flush(CPU(cpu), 1);
2667 static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
2669 int tlbn = booke206_tlbm_to_tlbn(env, tlb);
2670 int way = booke206_tlbm_to_way(env, tlb);
2672 env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
2673 env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
2674 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2676 env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
2677 env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
2678 env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
2679 env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
2682 void helper_booke206_tlbre(CPUPPCState *env)
2684 ppcmas_tlb_t *tlb = NULL;
2686 tlb = booke206_cur_tlb(env);
2687 if (!tlb) {
2688 env->spr[SPR_BOOKE_MAS1] = 0;
2689 } else {
2690 booke206_tlb_to_mas(env, tlb);
2694 void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address)
2696 ppcmas_tlb_t *tlb = NULL;
2697 int i, j;
2698 hwaddr raddr;
2699 uint32_t spid, sas;
2701 spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
2702 sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
2704 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2705 int ways = booke206_tlb_ways(env, i);
2707 for (j = 0; j < ways; j++) {
2708 tlb = booke206_get_tlbm(env, i, address, j);
2710 if (!tlb) {
2711 continue;
2714 if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
2715 continue;
2718 if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
2719 continue;
2722 booke206_tlb_to_mas(env, tlb);
2723 return;
2727 /* no entry found, fill with defaults */
2728 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
2729 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
2730 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
2731 env->spr[SPR_BOOKE_MAS3] = 0;
2732 env->spr[SPR_BOOKE_MAS7] = 0;
2734 if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
2735 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
2738 env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
2739 << MAS1_TID_SHIFT;
2741 /* next victim logic */
2742 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
2743 env->last_way++;
2744 env->last_way &= booke206_tlb_ways(env, 0) - 1;
2745 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2748 static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
2749 uint32_t ea)
2751 int i;
2752 int ways = booke206_tlb_ways(env, tlbn);
2753 target_ulong mask;
2755 for (i = 0; i < ways; i++) {
2756 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
2757 if (!tlb) {
2758 continue;
2760 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2761 if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
2762 !(tlb->mas1 & MAS1_IPROT)) {
2763 tlb->mas1 &= ~MAS1_VALID;
2768 void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address)
2770 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2772 if (address & 0x4) {
2773 /* flush all entries */
2774 if (address & 0x8) {
2775 /* flush all of TLB1 */
2776 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
2777 } else {
2778 /* flush all of TLB0 */
2779 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
2781 return;
2784 if (address & 0x8) {
2785 /* flush TLB1 entries */
2786 booke206_invalidate_ea_tlb(env, 1, address);
2787 tlb_flush(CPU(cpu), 1);
2788 } else {
2789 /* flush TLB0 entries */
2790 booke206_invalidate_ea_tlb(env, 0, address);
2791 tlb_flush_page(CPU(cpu), address & MAS2_EPN_MASK);
2795 void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address)
2797 /* XXX missing LPID handling */
2798 booke206_flush_tlb(env, -1, 1);
2801 void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address)
2803 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2804 int i, j;
2805 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2806 ppcmas_tlb_t *tlb = env->tlb.tlbm;
2807 int tlb_size;
2809 /* XXX missing LPID handling */
2810 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2811 tlb_size = booke206_tlb_size(env, i);
2812 for (j = 0; j < tlb_size; j++) {
2813 if (!(tlb[j].mas1 & MAS1_IPROT) &&
2814 ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
2815 tlb[j].mas1 &= ~MAS1_VALID;
2818 tlb += booke206_tlb_size(env, i);
2820 tlb_flush(CPU(cpu), 1);
2823 void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
2825 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2826 int i, j;
2827 ppcmas_tlb_t *tlb;
2828 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2829 int pid = tid >> MAS6_SPID_SHIFT;
2830 int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
2831 int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
2832 /* XXX check for unsupported isize and raise an invalid opcode then */
2833 int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
2834 /* XXX implement MAV2 handling */
2835 bool mav2 = false;
2837 /* XXX missing LPID handling */
2838 /* flush by pid and ea */
2839 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2840 int ways = booke206_tlb_ways(env, i);
2842 for (j = 0; j < ways; j++) {
2843 tlb = booke206_get_tlbm(env, i, address, j);
2844 if (!tlb) {
2845 continue;
2847 if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
2848 (tlb->mas1 & MAS1_IPROT) ||
2849 ((tlb->mas1 & MAS1_IND) != ind) ||
2850 ((tlb->mas8 & MAS8_TGS) != sgs)) {
2851 continue;
2853 if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
2854 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
2855 continue;
2857 /* XXX e500mc doesn't match SAS, but other cores might */
2858 tlb->mas1 &= ~MAS1_VALID;
2861 tlb_flush(CPU(cpu), 1);
2864 void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type)
2866 int flags = 0;
2868 if (type & 2) {
2869 flags |= BOOKE206_FLUSH_TLB1;
2872 if (type & 4) {
2873 flags |= BOOKE206_FLUSH_TLB0;
2876 booke206_flush_tlb(env, flags, 1);
2880 void helper_check_tlb_flush(CPUPPCState *env)
2882 check_tlb_flush(env);
2885 /*****************************************************************************/
2887 /* try to fill the TLB and return an exception if error. If retaddr is
2888 NULL, it means that the function was called in C code (i.e. not
2889 from generated code or from helper.c) */
2890 /* XXX: fix it to restore all registers */
2891 void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
2892 uintptr_t retaddr)
2894 PowerPCCPU *cpu = POWERPC_CPU(cs);
2895 PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
2896 CPUPPCState *env = &cpu->env;
2897 int ret;
2899 if (pcc->handle_mmu_fault) {
2900 ret = pcc->handle_mmu_fault(cpu, addr, is_write, mmu_idx);
2901 } else {
2902 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
2904 if (unlikely(ret != 0)) {
2905 if (likely(retaddr)) {
2906 /* now we have a real cpu fault */
2907 cpu_restore_state(cs, retaddr);
2909 helper_raise_exception_err(env, cs->exception_index, env->error_code);