fw_cfg: replace ioport data read with generic method
[qemu/ar7.git] / target-ppc / mmu_helper.c
blob30298d8d4a3f5a3dd69ff823629434e7c04d3e26
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_STATE(cpu) log_cpu_state((cpu), 0)
36 #else
37 # define LOG_MMU_STATE(cpu) do { } while (0)
38 #endif
40 #ifdef DEBUG_SOFTWARE_TLB
41 # define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
42 #else
43 # define LOG_SWTLB(...) do { } while (0)
44 #endif
46 #ifdef DEBUG_BATS
47 # define LOG_BATS(...) qemu_log(__VA_ARGS__)
48 #else
49 # define LOG_BATS(...) do { } while (0)
50 #endif
52 /*****************************************************************************/
53 /* PowerPC MMU emulation */
55 /* Context used internally during MMU translations */
56 typedef struct mmu_ctx_t mmu_ctx_t;
57 struct mmu_ctx_t {
58 hwaddr raddr; /* Real address */
59 hwaddr eaddr; /* Effective address */
60 int prot; /* Protection bits */
61 hwaddr hash[2]; /* Pagetable hash values */
62 target_ulong ptem; /* Virtual segment ID | API */
63 int key; /* Access key */
64 int nx; /* Non-execute area */
67 /* Common routines used by software and hardware TLBs emulation */
68 static inline int pte_is_valid(target_ulong pte0)
70 return pte0 & 0x80000000 ? 1 : 0;
73 static inline void pte_invalidate(target_ulong *pte0)
75 *pte0 &= ~0x80000000;
78 #define PTE_PTEM_MASK 0x7FFFFFBF
79 #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
81 static int pp_check(int key, int pp, int nx)
83 int access;
85 /* Compute access rights */
86 access = 0;
87 if (key == 0) {
88 switch (pp) {
89 case 0x0:
90 case 0x1:
91 case 0x2:
92 access |= PAGE_WRITE;
93 /* No break here */
94 case 0x3:
95 access |= PAGE_READ;
96 break;
98 } else {
99 switch (pp) {
100 case 0x0:
101 access = 0;
102 break;
103 case 0x1:
104 case 0x3:
105 access = PAGE_READ;
106 break;
107 case 0x2:
108 access = PAGE_READ | PAGE_WRITE;
109 break;
112 if (nx == 0) {
113 access |= PAGE_EXEC;
116 return access;
119 static int check_prot(int prot, int rw, int access_type)
121 int ret;
123 if (access_type == ACCESS_CODE) {
124 if (prot & PAGE_EXEC) {
125 ret = 0;
126 } else {
127 ret = -2;
129 } else if (rw) {
130 if (prot & PAGE_WRITE) {
131 ret = 0;
132 } else {
133 ret = -2;
135 } else {
136 if (prot & PAGE_READ) {
137 ret = 0;
138 } else {
139 ret = -2;
143 return ret;
146 static inline int ppc6xx_tlb_pte_check(mmu_ctx_t *ctx, target_ulong pte0,
147 target_ulong pte1, int h, int rw, int type)
149 target_ulong ptem, mmask;
150 int access, ret, pteh, ptev, pp;
152 ret = -1;
153 /* Check validity and table match */
154 ptev = pte_is_valid(pte0);
155 pteh = (pte0 >> 6) & 1;
156 if (ptev && h == pteh) {
157 /* Check vsid & api */
158 ptem = pte0 & PTE_PTEM_MASK;
159 mmask = PTE_CHECK_MASK;
160 pp = pte1 & 0x00000003;
161 if (ptem == ctx->ptem) {
162 if (ctx->raddr != (hwaddr)-1ULL) {
163 /* all matches should have equal RPN, WIMG & PP */
164 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
165 qemu_log("Bad RPN/WIMG/PP\n");
166 return -3;
169 /* Compute access rights */
170 access = pp_check(ctx->key, pp, ctx->nx);
171 /* Keep the matching PTE informations */
172 ctx->raddr = pte1;
173 ctx->prot = access;
174 ret = check_prot(ctx->prot, rw, type);
175 if (ret == 0) {
176 /* Access granted */
177 qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
178 } else {
179 /* Access right violation */
180 qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
185 return ret;
188 static int pte_update_flags(mmu_ctx_t *ctx, target_ulong *pte1p,
189 int ret, int rw)
191 int store = 0;
193 /* Update page flags */
194 if (!(*pte1p & 0x00000100)) {
195 /* Update accessed flag */
196 *pte1p |= 0x00000100;
197 store = 1;
199 if (!(*pte1p & 0x00000080)) {
200 if (rw == 1 && ret == 0) {
201 /* Update changed flag */
202 *pte1p |= 0x00000080;
203 store = 1;
204 } else {
205 /* Force page fault for first write access */
206 ctx->prot &= ~PAGE_WRITE;
210 return store;
213 /* Software driven TLB helpers */
214 static inline int ppc6xx_tlb_getnum(CPUPPCState *env, target_ulong eaddr,
215 int way, int is_code)
217 int nr;
219 /* Select TLB num in a way from address */
220 nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
221 /* Select TLB way */
222 nr += env->tlb_per_way * way;
223 /* 6xx have separate TLBs for instructions and data */
224 if (is_code && env->id_tlbs == 1) {
225 nr += env->nb_tlb;
228 return nr;
231 static inline void ppc6xx_tlb_invalidate_all(CPUPPCState *env)
233 PowerPCCPU *cpu = ppc_env_get_cpu(env);
234 ppc6xx_tlb_t *tlb;
235 int nr, max;
237 /* LOG_SWTLB("Invalidate all TLBs\n"); */
238 /* Invalidate all defined software TLB */
239 max = env->nb_tlb;
240 if (env->id_tlbs == 1) {
241 max *= 2;
243 for (nr = 0; nr < max; nr++) {
244 tlb = &env->tlb.tlb6[nr];
245 pte_invalidate(&tlb->pte0);
247 tlb_flush(CPU(cpu), 1);
250 static inline void ppc6xx_tlb_invalidate_virt2(CPUPPCState *env,
251 target_ulong eaddr,
252 int is_code, int match_epn)
254 #if !defined(FLUSH_ALL_TLBS)
255 CPUState *cs = CPU(ppc_env_get_cpu(env));
256 ppc6xx_tlb_t *tlb;
257 int way, nr;
259 /* Invalidate ITLB + DTLB, all ways */
260 for (way = 0; way < env->nb_ways; way++) {
261 nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
262 tlb = &env->tlb.tlb6[nr];
263 if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
264 LOG_SWTLB("TLB invalidate %d/%d " TARGET_FMT_lx "\n", nr,
265 env->nb_tlb, eaddr);
266 pte_invalidate(&tlb->pte0);
267 tlb_flush_page(cs, tlb->EPN);
270 #else
271 /* XXX: PowerPC specification say this is valid as well */
272 ppc6xx_tlb_invalidate_all(env);
273 #endif
276 static inline void ppc6xx_tlb_invalidate_virt(CPUPPCState *env,
277 target_ulong eaddr, int is_code)
279 ppc6xx_tlb_invalidate_virt2(env, eaddr, is_code, 0);
282 static void ppc6xx_tlb_store(CPUPPCState *env, target_ulong EPN, int way,
283 int is_code, target_ulong pte0, target_ulong pte1)
285 ppc6xx_tlb_t *tlb;
286 int nr;
288 nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
289 tlb = &env->tlb.tlb6[nr];
290 LOG_SWTLB("Set TLB %d/%d EPN " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
291 " PTE1 " TARGET_FMT_lx "\n", nr, env->nb_tlb, EPN, pte0, pte1);
292 /* Invalidate any pending reference in QEMU for this virtual address */
293 ppc6xx_tlb_invalidate_virt2(env, EPN, is_code, 1);
294 tlb->pte0 = pte0;
295 tlb->pte1 = pte1;
296 tlb->EPN = EPN;
297 /* Store last way for LRU mechanism */
298 env->last_way = way;
301 static inline int ppc6xx_tlb_check(CPUPPCState *env, mmu_ctx_t *ctx,
302 target_ulong eaddr, int rw, int access_type)
304 ppc6xx_tlb_t *tlb;
305 int nr, best, way;
306 int ret;
308 best = -1;
309 ret = -1; /* No TLB found */
310 for (way = 0; way < env->nb_ways; way++) {
311 nr = ppc6xx_tlb_getnum(env, eaddr, way,
312 access_type == ACCESS_CODE ? 1 : 0);
313 tlb = &env->tlb.tlb6[nr];
314 /* This test "emulates" the PTE index match for hardware TLBs */
315 if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
316 LOG_SWTLB("TLB %d/%d %s [" TARGET_FMT_lx " " TARGET_FMT_lx
317 "] <> " TARGET_FMT_lx "\n", nr, env->nb_tlb,
318 pte_is_valid(tlb->pte0) ? "valid" : "inval",
319 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
320 continue;
322 LOG_SWTLB("TLB %d/%d %s " TARGET_FMT_lx " <> " TARGET_FMT_lx " "
323 TARGET_FMT_lx " %c %c\n", nr, env->nb_tlb,
324 pte_is_valid(tlb->pte0) ? "valid" : "inval",
325 tlb->EPN, eaddr, tlb->pte1,
326 rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
327 switch (ppc6xx_tlb_pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
328 case -3:
329 /* TLB inconsistency */
330 return -1;
331 case -2:
332 /* Access violation */
333 ret = -2;
334 best = nr;
335 break;
336 case -1:
337 default:
338 /* No match */
339 break;
340 case 0:
341 /* access granted */
342 /* XXX: we should go on looping to check all TLBs consistency
343 * but we can speed-up the whole thing as the
344 * result would be undefined if TLBs are not consistent.
346 ret = 0;
347 best = nr;
348 goto done;
351 if (best != -1) {
352 done:
353 LOG_SWTLB("found TLB at addr " TARGET_FMT_plx " prot=%01x ret=%d\n",
354 ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
355 /* Update page flags */
356 pte_update_flags(ctx, &env->tlb.tlb6[best].pte1, ret, rw);
359 return ret;
362 /* Perform BAT hit & translation */
363 static inline void bat_size_prot(CPUPPCState *env, target_ulong *blp,
364 int *validp, int *protp, target_ulong *BATu,
365 target_ulong *BATl)
367 target_ulong bl;
368 int pp, valid, prot;
370 bl = (*BATu & 0x00001FFC) << 15;
371 valid = 0;
372 prot = 0;
373 if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
374 ((msr_pr != 0) && (*BATu & 0x00000001))) {
375 valid = 1;
376 pp = *BATl & 0x00000003;
377 if (pp != 0) {
378 prot = PAGE_READ | PAGE_EXEC;
379 if (pp == 0x2) {
380 prot |= PAGE_WRITE;
384 *blp = bl;
385 *validp = valid;
386 *protp = prot;
389 static int get_bat_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
390 target_ulong virtual, int rw, int type)
392 target_ulong *BATlt, *BATut, *BATu, *BATl;
393 target_ulong BEPIl, BEPIu, bl;
394 int i, valid, prot;
395 int ret = -1;
397 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
398 type == ACCESS_CODE ? 'I' : 'D', virtual);
399 switch (type) {
400 case ACCESS_CODE:
401 BATlt = env->IBAT[1];
402 BATut = env->IBAT[0];
403 break;
404 default:
405 BATlt = env->DBAT[1];
406 BATut = env->DBAT[0];
407 break;
409 for (i = 0; i < env->nb_BATs; i++) {
410 BATu = &BATut[i];
411 BATl = &BATlt[i];
412 BEPIu = *BATu & 0xF0000000;
413 BEPIl = *BATu & 0x0FFE0000;
414 bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
415 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
416 " BATl " TARGET_FMT_lx "\n", __func__,
417 type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
418 if ((virtual & 0xF0000000) == BEPIu &&
419 ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
420 /* BAT matches */
421 if (valid != 0) {
422 /* Get physical address */
423 ctx->raddr = (*BATl & 0xF0000000) |
424 ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
425 (virtual & 0x0001F000);
426 /* Compute access rights */
427 ctx->prot = prot;
428 ret = check_prot(ctx->prot, rw, type);
429 if (ret == 0) {
430 LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
431 i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
432 ctx->prot & PAGE_WRITE ? 'W' : '-');
434 break;
438 if (ret < 0) {
439 #if defined(DEBUG_BATS)
440 if (qemu_log_enabled()) {
441 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
442 for (i = 0; i < 4; i++) {
443 BATu = &BATut[i];
444 BATl = &BATlt[i];
445 BEPIu = *BATu & 0xF0000000;
446 BEPIl = *BATu & 0x0FFE0000;
447 bl = (*BATu & 0x00001FFC) << 15;
448 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
449 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
450 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
451 __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
452 *BATu, *BATl, BEPIu, BEPIl, bl);
455 #endif
457 /* No hit */
458 return ret;
461 /* Perform segment based translation */
462 static inline int get_segment_6xx_tlb(CPUPPCState *env, mmu_ctx_t *ctx,
463 target_ulong eaddr, int rw, int type)
465 hwaddr hash;
466 target_ulong vsid;
467 int ds, pr, target_page_bits;
468 int ret;
469 target_ulong sr, pgidx;
471 pr = msr_pr;
472 ctx->eaddr = eaddr;
474 sr = env->sr[eaddr >> 28];
475 ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
476 ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
477 ds = sr & 0x80000000 ? 1 : 0;
478 ctx->nx = sr & 0x10000000 ? 1 : 0;
479 vsid = sr & 0x00FFFFFF;
480 target_page_bits = TARGET_PAGE_BITS;
481 qemu_log_mask(CPU_LOG_MMU,
482 "Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx
483 " nip=" TARGET_FMT_lx " lr=" TARGET_FMT_lx
484 " ir=%d dr=%d pr=%d %d t=%d\n",
485 eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
486 (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
487 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
488 hash = vsid ^ pgidx;
489 ctx->ptem = (vsid << 7) | (pgidx >> 10);
491 qemu_log_mask(CPU_LOG_MMU,
492 "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 qemu_log_mask(CPU_LOG_MMU, "htab_base " TARGET_FMT_plx
500 " htab_mask " TARGET_FMT_plx
501 " hash " TARGET_FMT_plx "\n",
502 env->htab_base, env->htab_mask, hash);
503 ctx->hash[0] = hash;
504 ctx->hash[1] = ~hash;
506 /* Initialize real address with an invalid value */
507 ctx->raddr = (hwaddr)-1ULL;
508 /* Software TLB search */
509 ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
510 #if defined(DUMP_PAGE_TABLES)
511 if (qemu_log_enabled()) {
512 hwaddr curaddr;
513 uint32_t a0, a1, a2, a3;
515 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
516 "\n", sdr, mask + 0x80);
517 for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
518 curaddr += 16) {
519 a0 = ldl_phys(curaddr);
520 a1 = ldl_phys(curaddr + 4);
521 a2 = ldl_phys(curaddr + 8);
522 a3 = ldl_phys(curaddr + 12);
523 if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
524 qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
525 curaddr, a0, a1, a2, a3);
529 #endif
530 } else {
531 qemu_log_mask(CPU_LOG_MMU, "No access allowed\n");
532 ret = -3;
534 } else {
535 target_ulong sr;
537 qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
538 /* Direct-store segment : absolutely *BUGGY* for now */
540 /* Direct-store implies a 32-bit MMU.
541 * Check the Segment Register's bus unit ID (BUID).
543 sr = env->sr[eaddr >> 28];
544 if ((sr & 0x1FF00000) >> 20 == 0x07f) {
545 /* Memory-forced I/O controller interface access */
546 /* If T=1 and BUID=x'07F', the 601 performs a memory access
547 * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
549 ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
550 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
551 return 0;
554 switch (type) {
555 case ACCESS_INT:
556 /* Integer load/store : only access allowed */
557 break;
558 case ACCESS_CODE:
559 /* No code fetch is allowed in direct-store areas */
560 return -4;
561 case ACCESS_FLOAT:
562 /* Floating point load/store */
563 return -4;
564 case ACCESS_RES:
565 /* lwarx, ldarx or srwcx. */
566 return -4;
567 case ACCESS_CACHE:
568 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
569 /* Should make the instruction do no-op.
570 * As it already do no-op, it's quite easy :-)
572 ctx->raddr = eaddr;
573 return 0;
574 case ACCESS_EXT:
575 /* eciwx or ecowx */
576 return -4;
577 default:
578 qemu_log("ERROR: instruction should not need "
579 "address translation\n");
580 return -4;
582 if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
583 ctx->raddr = eaddr;
584 ret = 2;
585 } else {
586 ret = -2;
590 return ret;
593 /* Generic TLB check function for embedded PowerPC implementations */
594 static int ppcemb_tlb_check(CPUPPCState *env, ppcemb_tlb_t *tlb,
595 hwaddr *raddrp,
596 target_ulong address, uint32_t pid, int ext,
597 int i)
599 target_ulong mask;
601 /* Check valid flag */
602 if (!(tlb->prot & PAGE_VALID)) {
603 return -1;
605 mask = ~(tlb->size - 1);
606 LOG_SWTLB("%s: TLB %d address " TARGET_FMT_lx " PID %u <=> " TARGET_FMT_lx
607 " " TARGET_FMT_lx " %u %x\n", __func__, i, address, pid, tlb->EPN,
608 mask, (uint32_t)tlb->PID, tlb->prot);
609 /* Check PID */
610 if (tlb->PID != 0 && tlb->PID != pid) {
611 return -1;
613 /* Check effective address */
614 if ((address & mask) != tlb->EPN) {
615 return -1;
617 *raddrp = (tlb->RPN & mask) | (address & ~mask);
618 if (ext) {
619 /* Extend the physical address to 36 bits */
620 *raddrp |= (uint64_t)(tlb->RPN & 0xF) << 32;
623 return 0;
626 /* Generic TLB search function for PowerPC embedded implementations */
627 static int ppcemb_tlb_search(CPUPPCState *env, target_ulong address,
628 uint32_t pid)
630 ppcemb_tlb_t *tlb;
631 hwaddr raddr;
632 int i, ret;
634 /* Default return value is no match */
635 ret = -1;
636 for (i = 0; i < env->nb_tlb; i++) {
637 tlb = &env->tlb.tlbe[i];
638 if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
639 ret = i;
640 break;
644 return ret;
647 /* Helpers specific to PowerPC 40x implementations */
648 static inline void ppc4xx_tlb_invalidate_all(CPUPPCState *env)
650 PowerPCCPU *cpu = ppc_env_get_cpu(env);
651 ppcemb_tlb_t *tlb;
652 int i;
654 for (i = 0; i < env->nb_tlb; i++) {
655 tlb = &env->tlb.tlbe[i];
656 tlb->prot &= ~PAGE_VALID;
658 tlb_flush(CPU(cpu), 1);
661 static inline void ppc4xx_tlb_invalidate_virt(CPUPPCState *env,
662 target_ulong eaddr, uint32_t pid)
664 #if !defined(FLUSH_ALL_TLBS)
665 CPUState *cs = CPU(ppc_env_get_cpu(env));
666 ppcemb_tlb_t *tlb;
667 hwaddr raddr;
668 target_ulong page, end;
669 int i;
671 for (i = 0; i < env->nb_tlb; i++) {
672 tlb = &env->tlb.tlbe[i];
673 if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
674 end = tlb->EPN + tlb->size;
675 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
676 tlb_flush_page(cs, page);
678 tlb->prot &= ~PAGE_VALID;
679 break;
682 #else
683 ppc4xx_tlb_invalidate_all(env);
684 #endif
687 static int mmu40x_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
688 target_ulong address, int rw,
689 int access_type)
691 ppcemb_tlb_t *tlb;
692 hwaddr raddr;
693 int i, ret, zsel, zpr, pr;
695 ret = -1;
696 raddr = (hwaddr)-1ULL;
697 pr = msr_pr;
698 for (i = 0; i < env->nb_tlb; i++) {
699 tlb = &env->tlb.tlbe[i];
700 if (ppcemb_tlb_check(env, tlb, &raddr, address,
701 env->spr[SPR_40x_PID], 0, i) < 0) {
702 continue;
704 zsel = (tlb->attr >> 4) & 0xF;
705 zpr = (env->spr[SPR_40x_ZPR] >> (30 - (2 * zsel))) & 0x3;
706 LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
707 __func__, i, zsel, zpr, rw, tlb->attr);
708 /* Check execute enable bit */
709 switch (zpr) {
710 case 0x2:
711 if (pr != 0) {
712 goto check_perms;
714 /* No break here */
715 case 0x3:
716 /* All accesses granted */
717 ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
718 ret = 0;
719 break;
720 case 0x0:
721 if (pr != 0) {
722 /* Raise Zone protection fault. */
723 env->spr[SPR_40x_ESR] = 1 << 22;
724 ctx->prot = 0;
725 ret = -2;
726 break;
728 /* No break here */
729 case 0x1:
730 check_perms:
731 /* Check from TLB entry */
732 ctx->prot = tlb->prot;
733 ret = check_prot(ctx->prot, rw, access_type);
734 if (ret == -2) {
735 env->spr[SPR_40x_ESR] = 0;
737 break;
739 if (ret >= 0) {
740 ctx->raddr = raddr;
741 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
742 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
743 ret);
744 return 0;
747 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
748 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
750 return ret;
753 void store_40x_sler(CPUPPCState *env, uint32_t val)
755 PowerPCCPU *cpu = ppc_env_get_cpu(env);
757 /* XXX: TO BE FIXED */
758 if (val != 0x00000000) {
759 cpu_abort(CPU(cpu), "Little-endian regions are not supported by now\n");
761 env->spr[SPR_405_SLER] = val;
764 static inline int mmubooke_check_tlb(CPUPPCState *env, ppcemb_tlb_t *tlb,
765 hwaddr *raddr, int *prot,
766 target_ulong address, int rw,
767 int access_type, int i)
769 int ret, prot2;
771 if (ppcemb_tlb_check(env, tlb, raddr, address,
772 env->spr[SPR_BOOKE_PID],
773 !env->nb_pids, i) >= 0) {
774 goto found_tlb;
777 if (env->spr[SPR_BOOKE_PID1] &&
778 ppcemb_tlb_check(env, tlb, raddr, address,
779 env->spr[SPR_BOOKE_PID1], 0, i) >= 0) {
780 goto found_tlb;
783 if (env->spr[SPR_BOOKE_PID2] &&
784 ppcemb_tlb_check(env, tlb, raddr, address,
785 env->spr[SPR_BOOKE_PID2], 0, i) >= 0) {
786 goto found_tlb;
789 LOG_SWTLB("%s: TLB entry not found\n", __func__);
790 return -1;
792 found_tlb:
794 if (msr_pr != 0) {
795 prot2 = tlb->prot & 0xF;
796 } else {
797 prot2 = (tlb->prot >> 4) & 0xF;
800 /* Check the address space */
801 if (access_type == ACCESS_CODE) {
802 if (msr_ir != (tlb->attr & 1)) {
803 LOG_SWTLB("%s: AS doesn't match\n", __func__);
804 return -1;
807 *prot = prot2;
808 if (prot2 & PAGE_EXEC) {
809 LOG_SWTLB("%s: good TLB!\n", __func__);
810 return 0;
813 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
814 ret = -3;
815 } else {
816 if (msr_dr != (tlb->attr & 1)) {
817 LOG_SWTLB("%s: AS doesn't match\n", __func__);
818 return -1;
821 *prot = prot2;
822 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
823 LOG_SWTLB("%s: found TLB!\n", __func__);
824 return 0;
827 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
828 ret = -2;
831 return ret;
834 static int mmubooke_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
835 target_ulong address, int rw,
836 int access_type)
838 ppcemb_tlb_t *tlb;
839 hwaddr raddr;
840 int i, ret;
842 ret = -1;
843 raddr = (hwaddr)-1ULL;
844 for (i = 0; i < env->nb_tlb; i++) {
845 tlb = &env->tlb.tlbe[i];
846 ret = mmubooke_check_tlb(env, tlb, &raddr, &ctx->prot, address, rw,
847 access_type, i);
848 if (!ret) {
849 break;
853 if (ret >= 0) {
854 ctx->raddr = raddr;
855 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
856 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
857 ret);
858 } else {
859 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
860 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
863 return ret;
866 static void booke206_flush_tlb(CPUPPCState *env, int flags,
867 const int check_iprot)
869 PowerPCCPU *cpu = ppc_env_get_cpu(env);
870 int tlb_size;
871 int i, j;
872 ppcmas_tlb_t *tlb = env->tlb.tlbm;
874 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
875 if (flags & (1 << i)) {
876 tlb_size = booke206_tlb_size(env, i);
877 for (j = 0; j < tlb_size; j++) {
878 if (!check_iprot || !(tlb[j].mas1 & MAS1_IPROT)) {
879 tlb[j].mas1 &= ~MAS1_VALID;
883 tlb += booke206_tlb_size(env, i);
886 tlb_flush(CPU(cpu), 1);
889 static hwaddr booke206_tlb_to_page_size(CPUPPCState *env,
890 ppcmas_tlb_t *tlb)
892 int tlbm_size;
894 tlbm_size = (tlb->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
896 return 1024ULL << tlbm_size;
899 /* TLB check function for MAS based SoftTLBs */
900 static int ppcmas_tlb_check(CPUPPCState *env, ppcmas_tlb_t *tlb,
901 hwaddr *raddrp, target_ulong address,
902 uint32_t pid)
904 hwaddr mask;
905 uint32_t tlb_pid;
907 if (!msr_cm) {
908 /* In 32bit mode we can only address 32bit EAs */
909 address = (uint32_t)address;
912 /* Check valid flag */
913 if (!(tlb->mas1 & MAS1_VALID)) {
914 return -1;
917 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
918 LOG_SWTLB("%s: TLB ADDR=0x" TARGET_FMT_lx " PID=0x%x MAS1=0x%x MAS2=0x%"
919 PRIx64 " mask=0x" TARGET_FMT_lx " MAS7_3=0x%" PRIx64 " MAS8=%x\n",
920 __func__, address, pid, tlb->mas1, tlb->mas2, mask, tlb->mas7_3,
921 tlb->mas8);
923 /* Check PID */
924 tlb_pid = (tlb->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT;
925 if (tlb_pid != 0 && tlb_pid != pid) {
926 return -1;
929 /* Check effective address */
930 if ((address & mask) != (tlb->mas2 & MAS2_EPN_MASK)) {
931 return -1;
934 if (raddrp) {
935 *raddrp = (tlb->mas7_3 & mask) | (address & ~mask);
938 return 0;
941 static int mmubooke206_check_tlb(CPUPPCState *env, ppcmas_tlb_t *tlb,
942 hwaddr *raddr, int *prot,
943 target_ulong address, int rw,
944 int access_type)
946 int ret;
947 int prot2 = 0;
949 if (ppcmas_tlb_check(env, tlb, raddr, address,
950 env->spr[SPR_BOOKE_PID]) >= 0) {
951 goto found_tlb;
954 if (env->spr[SPR_BOOKE_PID1] &&
955 ppcmas_tlb_check(env, tlb, raddr, address,
956 env->spr[SPR_BOOKE_PID1]) >= 0) {
957 goto found_tlb;
960 if (env->spr[SPR_BOOKE_PID2] &&
961 ppcmas_tlb_check(env, tlb, raddr, address,
962 env->spr[SPR_BOOKE_PID2]) >= 0) {
963 goto found_tlb;
966 LOG_SWTLB("%s: TLB entry not found\n", __func__);
967 return -1;
969 found_tlb:
971 if (msr_pr != 0) {
972 if (tlb->mas7_3 & MAS3_UR) {
973 prot2 |= PAGE_READ;
975 if (tlb->mas7_3 & MAS3_UW) {
976 prot2 |= PAGE_WRITE;
978 if (tlb->mas7_3 & MAS3_UX) {
979 prot2 |= PAGE_EXEC;
981 } else {
982 if (tlb->mas7_3 & MAS3_SR) {
983 prot2 |= PAGE_READ;
985 if (tlb->mas7_3 & MAS3_SW) {
986 prot2 |= PAGE_WRITE;
988 if (tlb->mas7_3 & MAS3_SX) {
989 prot2 |= PAGE_EXEC;
993 /* Check the address space and permissions */
994 if (access_type == ACCESS_CODE) {
995 if (msr_ir != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
996 LOG_SWTLB("%s: AS doesn't match\n", __func__);
997 return -1;
1000 *prot = prot2;
1001 if (prot2 & PAGE_EXEC) {
1002 LOG_SWTLB("%s: good TLB!\n", __func__);
1003 return 0;
1006 LOG_SWTLB("%s: no PAGE_EXEC: %x\n", __func__, prot2);
1007 ret = -3;
1008 } else {
1009 if (msr_dr != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
1010 LOG_SWTLB("%s: AS doesn't match\n", __func__);
1011 return -1;
1014 *prot = prot2;
1015 if ((!rw && prot2 & PAGE_READ) || (rw && (prot2 & PAGE_WRITE))) {
1016 LOG_SWTLB("%s: found TLB!\n", __func__);
1017 return 0;
1020 LOG_SWTLB("%s: PAGE_READ/WRITE doesn't match: %x\n", __func__, prot2);
1021 ret = -2;
1024 return ret;
1027 static int mmubooke206_get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1028 target_ulong address, int rw,
1029 int access_type)
1031 ppcmas_tlb_t *tlb;
1032 hwaddr raddr;
1033 int i, j, ret;
1035 ret = -1;
1036 raddr = (hwaddr)-1ULL;
1038 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1039 int ways = booke206_tlb_ways(env, i);
1041 for (j = 0; j < ways; j++) {
1042 tlb = booke206_get_tlbm(env, i, address, j);
1043 if (!tlb) {
1044 continue;
1046 ret = mmubooke206_check_tlb(env, tlb, &raddr, &ctx->prot, address,
1047 rw, access_type);
1048 if (ret != -1) {
1049 goto found_tlb;
1054 found_tlb:
1056 if (ret >= 0) {
1057 ctx->raddr = raddr;
1058 LOG_SWTLB("%s: access granted " TARGET_FMT_lx " => " TARGET_FMT_plx
1059 " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1060 ret);
1061 } else {
1062 LOG_SWTLB("%s: access refused " TARGET_FMT_lx " => " TARGET_FMT_plx
1063 " %d %d\n", __func__, address, raddr, ctx->prot, ret);
1066 return ret;
1069 static const char *book3e_tsize_to_str[32] = {
1070 "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K", "512K",
1071 "1M", "2M", "4M", "8M", "16M", "32M", "64M", "128M", "256M", "512M",
1072 "1G", "2G", "4G", "8G", "16G", "32G", "64G", "128G", "256G", "512G",
1073 "1T", "2T"
1076 static void mmubooke_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1077 CPUPPCState *env)
1079 ppcemb_tlb_t *entry;
1080 int i;
1082 if (kvm_enabled() && !env->kvm_sw_tlb) {
1083 cpu_fprintf(f, "Cannot access KVM TLB\n");
1084 return;
1087 cpu_fprintf(f, "\nTLB:\n");
1088 cpu_fprintf(f, "Effective Physical Size PID Prot "
1089 "Attr\n");
1091 entry = &env->tlb.tlbe[0];
1092 for (i = 0; i < env->nb_tlb; i++, entry++) {
1093 hwaddr ea, pa;
1094 target_ulong mask;
1095 uint64_t size = (uint64_t)entry->size;
1096 char size_buf[20];
1098 /* Check valid flag */
1099 if (!(entry->prot & PAGE_VALID)) {
1100 continue;
1103 mask = ~(entry->size - 1);
1104 ea = entry->EPN & mask;
1105 pa = entry->RPN & mask;
1106 /* Extend the physical address to 36 bits */
1107 pa |= (hwaddr)(entry->RPN & 0xF) << 32;
1108 size /= 1024;
1109 if (size >= 1024) {
1110 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "M", size / 1024);
1111 } else {
1112 snprintf(size_buf, sizeof(size_buf), "%3" PRId64 "k", size);
1114 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %s %-5u %08x %08x\n",
1115 (uint64_t)ea, (uint64_t)pa, size_buf, (uint32_t)entry->PID,
1116 entry->prot, entry->attr);
1121 static void mmubooke206_dump_one_tlb(FILE *f, fprintf_function cpu_fprintf,
1122 CPUPPCState *env, int tlbn, int offset,
1123 int tlbsize)
1125 ppcmas_tlb_t *entry;
1126 int i;
1128 cpu_fprintf(f, "\nTLB%d:\n", tlbn);
1129 cpu_fprintf(f, "Effective Physical Size TID TS SRWX"
1130 " URWX WIMGE U0123\n");
1132 entry = &env->tlb.tlbm[offset];
1133 for (i = 0; i < tlbsize; i++, entry++) {
1134 hwaddr ea, pa, size;
1135 int tsize;
1137 if (!(entry->mas1 & MAS1_VALID)) {
1138 continue;
1141 tsize = (entry->mas1 & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
1142 size = 1024ULL << tsize;
1143 ea = entry->mas2 & ~(size - 1);
1144 pa = entry->mas7_3 & ~(size - 1);
1146 cpu_fprintf(f, "0x%016" PRIx64 " 0x%016" PRIx64 " %4s %-5u %1u S%c%c%c"
1147 "U%c%c%c %c%c%c%c%c U%c%c%c%c\n",
1148 (uint64_t)ea, (uint64_t)pa,
1149 book3e_tsize_to_str[tsize],
1150 (entry->mas1 & MAS1_TID_MASK) >> MAS1_TID_SHIFT,
1151 (entry->mas1 & MAS1_TS) >> MAS1_TS_SHIFT,
1152 entry->mas7_3 & MAS3_SR ? 'R' : '-',
1153 entry->mas7_3 & MAS3_SW ? 'W' : '-',
1154 entry->mas7_3 & MAS3_SX ? 'X' : '-',
1155 entry->mas7_3 & MAS3_UR ? 'R' : '-',
1156 entry->mas7_3 & MAS3_UW ? 'W' : '-',
1157 entry->mas7_3 & MAS3_UX ? 'X' : '-',
1158 entry->mas2 & MAS2_W ? 'W' : '-',
1159 entry->mas2 & MAS2_I ? 'I' : '-',
1160 entry->mas2 & MAS2_M ? 'M' : '-',
1161 entry->mas2 & MAS2_G ? 'G' : '-',
1162 entry->mas2 & MAS2_E ? 'E' : '-',
1163 entry->mas7_3 & MAS3_U0 ? '0' : '-',
1164 entry->mas7_3 & MAS3_U1 ? '1' : '-',
1165 entry->mas7_3 & MAS3_U2 ? '2' : '-',
1166 entry->mas7_3 & MAS3_U3 ? '3' : '-');
1170 static void mmubooke206_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1171 CPUPPCState *env)
1173 int offset = 0;
1174 int i;
1176 if (kvm_enabled() && !env->kvm_sw_tlb) {
1177 cpu_fprintf(f, "Cannot access KVM TLB\n");
1178 return;
1181 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
1182 int size = booke206_tlb_size(env, i);
1184 if (size == 0) {
1185 continue;
1188 mmubooke206_dump_one_tlb(f, cpu_fprintf, env, i, offset, size);
1189 offset += size;
1193 static void mmu6xx_dump_BATs(FILE *f, fprintf_function cpu_fprintf,
1194 CPUPPCState *env, int type)
1196 target_ulong *BATlt, *BATut, *BATu, *BATl;
1197 target_ulong BEPIl, BEPIu, bl;
1198 int i;
1200 switch (type) {
1201 case ACCESS_CODE:
1202 BATlt = env->IBAT[1];
1203 BATut = env->IBAT[0];
1204 break;
1205 default:
1206 BATlt = env->DBAT[1];
1207 BATut = env->DBAT[0];
1208 break;
1211 for (i = 0; i < env->nb_BATs; i++) {
1212 BATu = &BATut[i];
1213 BATl = &BATlt[i];
1214 BEPIu = *BATu & 0xF0000000;
1215 BEPIl = *BATu & 0x0FFE0000;
1216 bl = (*BATu & 0x00001FFC) << 15;
1217 cpu_fprintf(f, "%s BAT%d BATu " TARGET_FMT_lx
1218 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
1219 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
1220 type == ACCESS_CODE ? "code" : "data", i,
1221 *BATu, *BATl, BEPIu, BEPIl, bl);
1225 static void mmu6xx_dump_mmu(FILE *f, fprintf_function cpu_fprintf,
1226 CPUPPCState *env)
1228 ppc6xx_tlb_t *tlb;
1229 target_ulong sr;
1230 int type, way, entry, i;
1232 cpu_fprintf(f, "HTAB base = 0x%"HWADDR_PRIx"\n", env->htab_base);
1233 cpu_fprintf(f, "HTAB mask = 0x%"HWADDR_PRIx"\n", env->htab_mask);
1235 cpu_fprintf(f, "\nSegment registers:\n");
1236 for (i = 0; i < 32; i++) {
1237 sr = env->sr[i];
1238 if (sr & 0x80000000) {
1239 cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d BUID=0x%03x "
1240 "CNTLR_SPEC=0x%05x\n", i,
1241 sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1242 sr & 0x20000000 ? 1 : 0, (uint32_t)((sr >> 20) & 0x1FF),
1243 (uint32_t)(sr & 0xFFFFF));
1244 } else {
1245 cpu_fprintf(f, "%02d T=%d Ks=%d Kp=%d N=%d VSID=0x%06x\n", i,
1246 sr & 0x80000000 ? 1 : 0, sr & 0x40000000 ? 1 : 0,
1247 sr & 0x20000000 ? 1 : 0, sr & 0x10000000 ? 1 : 0,
1248 (uint32_t)(sr & 0x00FFFFFF));
1252 cpu_fprintf(f, "\nBATs:\n");
1253 mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_INT);
1254 mmu6xx_dump_BATs(f, cpu_fprintf, env, ACCESS_CODE);
1256 if (env->id_tlbs != 1) {
1257 cpu_fprintf(f, "ERROR: 6xx MMU should have separated TLB"
1258 " for code and data\n");
1261 cpu_fprintf(f, "\nTLBs [EPN EPN + SIZE]\n");
1263 for (type = 0; type < 2; type++) {
1264 for (way = 0; way < env->nb_ways; way++) {
1265 for (entry = env->nb_tlb * type + env->tlb_per_way * way;
1266 entry < (env->nb_tlb * type + env->tlb_per_way * (way + 1));
1267 entry++) {
1269 tlb = &env->tlb.tlb6[entry];
1270 cpu_fprintf(f, "%s TLB %02d/%02d way:%d %s ["
1271 TARGET_FMT_lx " " TARGET_FMT_lx "]\n",
1272 type ? "code" : "data", entry % env->nb_tlb,
1273 env->nb_tlb, way,
1274 pte_is_valid(tlb->pte0) ? "valid" : "inval",
1275 tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE);
1281 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUPPCState *env)
1283 switch (env->mmu_model) {
1284 case POWERPC_MMU_BOOKE:
1285 mmubooke_dump_mmu(f, cpu_fprintf, env);
1286 break;
1287 case POWERPC_MMU_BOOKE206:
1288 mmubooke206_dump_mmu(f, cpu_fprintf, env);
1289 break;
1290 case POWERPC_MMU_SOFT_6xx:
1291 case POWERPC_MMU_SOFT_74xx:
1292 mmu6xx_dump_mmu(f, cpu_fprintf, env);
1293 break;
1294 #if defined(TARGET_PPC64)
1295 case POWERPC_MMU_64B:
1296 case POWERPC_MMU_2_03:
1297 case POWERPC_MMU_2_06:
1298 case POWERPC_MMU_2_06a:
1299 case POWERPC_MMU_2_07:
1300 case POWERPC_MMU_2_07a:
1301 dump_slb(f, cpu_fprintf, env);
1302 break;
1303 #endif
1304 default:
1305 qemu_log_mask(LOG_UNIMP, "%s: unimplemented\n", __func__);
1309 static inline int check_physical(CPUPPCState *env, mmu_ctx_t *ctx,
1310 target_ulong eaddr, int rw)
1312 int in_plb, ret;
1314 ctx->raddr = eaddr;
1315 ctx->prot = PAGE_READ | PAGE_EXEC;
1316 ret = 0;
1317 switch (env->mmu_model) {
1318 case POWERPC_MMU_SOFT_6xx:
1319 case POWERPC_MMU_SOFT_74xx:
1320 case POWERPC_MMU_SOFT_4xx:
1321 case POWERPC_MMU_REAL:
1322 case POWERPC_MMU_BOOKE:
1323 ctx->prot |= PAGE_WRITE;
1324 break;
1326 case POWERPC_MMU_SOFT_4xx_Z:
1327 if (unlikely(msr_pe != 0)) {
1328 /* 403 family add some particular protections,
1329 * using PBL/PBU registers for accesses with no translation.
1331 in_plb =
1332 /* Check PLB validity */
1333 (env->pb[0] < env->pb[1] &&
1334 /* and address in plb area */
1335 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
1336 (env->pb[2] < env->pb[3] &&
1337 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
1338 if (in_plb ^ msr_px) {
1339 /* Access in protected area */
1340 if (rw == 1) {
1341 /* Access is not allowed */
1342 ret = -2;
1344 } else {
1345 /* Read-write access is allowed */
1346 ctx->prot |= PAGE_WRITE;
1349 break;
1351 default:
1352 /* Caller's checks mean we should never get here for other models */
1353 abort();
1354 return -1;
1357 return ret;
1360 static int get_physical_address(CPUPPCState *env, mmu_ctx_t *ctx,
1361 target_ulong eaddr, int rw, int access_type)
1363 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1364 int ret = -1;
1365 bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
1366 || (access_type != ACCESS_CODE && msr_dr == 0);
1368 #if 0
1369 qemu_log("%s\n", __func__);
1370 #endif
1372 switch (env->mmu_model) {
1373 case POWERPC_MMU_SOFT_6xx:
1374 case POWERPC_MMU_SOFT_74xx:
1375 if (real_mode) {
1376 ret = check_physical(env, ctx, eaddr, rw);
1377 } else {
1378 /* Try to find a BAT */
1379 if (env->nb_BATs != 0) {
1380 ret = get_bat_6xx_tlb(env, ctx, eaddr, rw, access_type);
1382 if (ret < 0) {
1383 /* We didn't match any BAT entry or don't have BATs */
1384 ret = get_segment_6xx_tlb(env, ctx, eaddr, rw, access_type);
1387 break;
1389 case POWERPC_MMU_SOFT_4xx:
1390 case POWERPC_MMU_SOFT_4xx_Z:
1391 if (real_mode) {
1392 ret = check_physical(env, ctx, eaddr, rw);
1393 } else {
1394 ret = mmu40x_get_physical_address(env, ctx, eaddr,
1395 rw, access_type);
1397 break;
1398 case POWERPC_MMU_BOOKE:
1399 ret = mmubooke_get_physical_address(env, ctx, eaddr,
1400 rw, access_type);
1401 break;
1402 case POWERPC_MMU_BOOKE206:
1403 ret = mmubooke206_get_physical_address(env, ctx, eaddr, rw,
1404 access_type);
1405 break;
1406 case POWERPC_MMU_MPC8xx:
1407 /* XXX: TODO */
1408 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1409 break;
1410 case POWERPC_MMU_REAL:
1411 if (real_mode) {
1412 ret = check_physical(env, ctx, eaddr, rw);
1413 } else {
1414 cpu_abort(CPU(cpu), "PowerPC in real mode do not do any translation\n");
1416 return -1;
1417 default:
1418 cpu_abort(CPU(cpu), "Unknown or invalid MMU model\n");
1419 return -1;
1421 #if 0
1422 qemu_log("%s address " TARGET_FMT_lx " => %d " TARGET_FMT_plx "\n",
1423 __func__, eaddr, ret, ctx->raddr);
1424 #endif
1426 return ret;
1429 hwaddr ppc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
1431 PowerPCCPU *cpu = POWERPC_CPU(cs);
1432 CPUPPCState *env = &cpu->env;
1433 mmu_ctx_t ctx;
1435 switch (env->mmu_model) {
1436 #if defined(TARGET_PPC64)
1437 case POWERPC_MMU_64B:
1438 case POWERPC_MMU_2_03:
1439 case POWERPC_MMU_2_06:
1440 case POWERPC_MMU_2_06a:
1441 case POWERPC_MMU_2_07:
1442 case POWERPC_MMU_2_07a:
1443 return ppc_hash64_get_phys_page_debug(env, addr);
1444 #endif
1446 case POWERPC_MMU_32B:
1447 case POWERPC_MMU_601:
1448 return ppc_hash32_get_phys_page_debug(env, addr);
1450 default:
1454 if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0)) {
1456 /* Some MMUs have separate TLBs for code and data. If we only try an
1457 * ACCESS_INT, we may not be able to read instructions mapped by code
1458 * TLBs, so we also try a ACCESS_CODE.
1460 if (unlikely(get_physical_address(env, &ctx, addr, 0,
1461 ACCESS_CODE) != 0)) {
1462 return -1;
1466 return ctx.raddr & TARGET_PAGE_MASK;
1469 static void booke206_update_mas_tlb_miss(CPUPPCState *env, target_ulong address,
1470 int rw)
1472 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
1473 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
1474 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
1475 env->spr[SPR_BOOKE_MAS3] = 0;
1476 env->spr[SPR_BOOKE_MAS6] = 0;
1477 env->spr[SPR_BOOKE_MAS7] = 0;
1479 /* AS */
1480 if (((rw == 2) && msr_ir) || ((rw != 2) && msr_dr)) {
1481 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
1482 env->spr[SPR_BOOKE_MAS6] |= MAS6_SAS;
1485 env->spr[SPR_BOOKE_MAS1] |= MAS1_VALID;
1486 env->spr[SPR_BOOKE_MAS2] |= address & MAS2_EPN_MASK;
1488 switch (env->spr[SPR_BOOKE_MAS4] & MAS4_TIDSELD_PIDZ) {
1489 case MAS4_TIDSELD_PID0:
1490 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID] << MAS1_TID_SHIFT;
1491 break;
1492 case MAS4_TIDSELD_PID1:
1493 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID1] << MAS1_TID_SHIFT;
1494 break;
1495 case MAS4_TIDSELD_PID2:
1496 env->spr[SPR_BOOKE_MAS1] |= env->spr[SPR_BOOKE_PID2] << MAS1_TID_SHIFT;
1497 break;
1500 env->spr[SPR_BOOKE_MAS6] |= env->spr[SPR_BOOKE_PID] << 16;
1502 /* next victim logic */
1503 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
1504 env->last_way++;
1505 env->last_way &= booke206_tlb_ways(env, 0) - 1;
1506 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
1509 /* Perform address translation */
1510 static int cpu_ppc_handle_mmu_fault(CPUPPCState *env, target_ulong address,
1511 int rw, int mmu_idx)
1513 CPUState *cs = CPU(ppc_env_get_cpu(env));
1514 mmu_ctx_t ctx;
1515 int access_type;
1516 int ret = 0;
1518 if (rw == 2) {
1519 /* code access */
1520 rw = 0;
1521 access_type = ACCESS_CODE;
1522 } else {
1523 /* data access */
1524 access_type = env->access_type;
1526 ret = get_physical_address(env, &ctx, address, rw, access_type);
1527 if (ret == 0) {
1528 tlb_set_page(cs, address & TARGET_PAGE_MASK,
1529 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
1530 mmu_idx, TARGET_PAGE_SIZE);
1531 ret = 0;
1532 } else if (ret < 0) {
1533 LOG_MMU_STATE(cs);
1534 if (access_type == ACCESS_CODE) {
1535 switch (ret) {
1536 case -1:
1537 /* No matches in page tables or TLB */
1538 switch (env->mmu_model) {
1539 case POWERPC_MMU_SOFT_6xx:
1540 cs->exception_index = POWERPC_EXCP_IFTLB;
1541 env->error_code = 1 << 18;
1542 env->spr[SPR_IMISS] = address;
1543 env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
1544 goto tlb_miss;
1545 case POWERPC_MMU_SOFT_74xx:
1546 cs->exception_index = POWERPC_EXCP_IFTLB;
1547 goto tlb_miss_74xx;
1548 case POWERPC_MMU_SOFT_4xx:
1549 case POWERPC_MMU_SOFT_4xx_Z:
1550 cs->exception_index = POWERPC_EXCP_ITLB;
1551 env->error_code = 0;
1552 env->spr[SPR_40x_DEAR] = address;
1553 env->spr[SPR_40x_ESR] = 0x00000000;
1554 break;
1555 case POWERPC_MMU_BOOKE206:
1556 booke206_update_mas_tlb_miss(env, address, rw);
1557 /* fall through */
1558 case POWERPC_MMU_BOOKE:
1559 cs->exception_index = POWERPC_EXCP_ITLB;
1560 env->error_code = 0;
1561 env->spr[SPR_BOOKE_DEAR] = address;
1562 return -1;
1563 case POWERPC_MMU_MPC8xx:
1564 /* XXX: TODO */
1565 cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1566 break;
1567 case POWERPC_MMU_REAL:
1568 cpu_abort(cs, "PowerPC in real mode should never raise "
1569 "any MMU exceptions\n");
1570 return -1;
1571 default:
1572 cpu_abort(cs, "Unknown or invalid MMU model\n");
1573 return -1;
1575 break;
1576 case -2:
1577 /* Access rights violation */
1578 cs->exception_index = POWERPC_EXCP_ISI;
1579 env->error_code = 0x08000000;
1580 break;
1581 case -3:
1582 /* No execute protection violation */
1583 if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1584 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1585 env->spr[SPR_BOOKE_ESR] = 0x00000000;
1587 cs->exception_index = POWERPC_EXCP_ISI;
1588 env->error_code = 0x10000000;
1589 break;
1590 case -4:
1591 /* Direct store exception */
1592 /* No code fetch is allowed in direct-store areas */
1593 cs->exception_index = POWERPC_EXCP_ISI;
1594 env->error_code = 0x10000000;
1595 break;
1597 } else {
1598 switch (ret) {
1599 case -1:
1600 /* No matches in page tables or TLB */
1601 switch (env->mmu_model) {
1602 case POWERPC_MMU_SOFT_6xx:
1603 if (rw == 1) {
1604 cs->exception_index = POWERPC_EXCP_DSTLB;
1605 env->error_code = 1 << 16;
1606 } else {
1607 cs->exception_index = POWERPC_EXCP_DLTLB;
1608 env->error_code = 0;
1610 env->spr[SPR_DMISS] = address;
1611 env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
1612 tlb_miss:
1613 env->error_code |= ctx.key << 19;
1614 env->spr[SPR_HASH1] = env->htab_base +
1615 get_pteg_offset32(env, ctx.hash[0]);
1616 env->spr[SPR_HASH2] = env->htab_base +
1617 get_pteg_offset32(env, ctx.hash[1]);
1618 break;
1619 case POWERPC_MMU_SOFT_74xx:
1620 if (rw == 1) {
1621 cs->exception_index = POWERPC_EXCP_DSTLB;
1622 } else {
1623 cs->exception_index = POWERPC_EXCP_DLTLB;
1625 tlb_miss_74xx:
1626 /* Implement LRU algorithm */
1627 env->error_code = ctx.key << 19;
1628 env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
1629 ((env->last_way + 1) & (env->nb_ways - 1));
1630 env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
1631 break;
1632 case POWERPC_MMU_SOFT_4xx:
1633 case POWERPC_MMU_SOFT_4xx_Z:
1634 cs->exception_index = POWERPC_EXCP_DTLB;
1635 env->error_code = 0;
1636 env->spr[SPR_40x_DEAR] = address;
1637 if (rw) {
1638 env->spr[SPR_40x_ESR] = 0x00800000;
1639 } else {
1640 env->spr[SPR_40x_ESR] = 0x00000000;
1642 break;
1643 case POWERPC_MMU_MPC8xx:
1644 /* XXX: TODO */
1645 cpu_abort(cs, "MPC8xx MMU model is not implemented\n");
1646 break;
1647 case POWERPC_MMU_BOOKE206:
1648 booke206_update_mas_tlb_miss(env, address, rw);
1649 /* fall through */
1650 case POWERPC_MMU_BOOKE:
1651 cs->exception_index = POWERPC_EXCP_DTLB;
1652 env->error_code = 0;
1653 env->spr[SPR_BOOKE_DEAR] = address;
1654 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1655 return -1;
1656 case POWERPC_MMU_REAL:
1657 cpu_abort(cs, "PowerPC in real mode should never raise "
1658 "any MMU exceptions\n");
1659 return -1;
1660 default:
1661 cpu_abort(cs, "Unknown or invalid MMU model\n");
1662 return -1;
1664 break;
1665 case -2:
1666 /* Access rights violation */
1667 cs->exception_index = POWERPC_EXCP_DSI;
1668 env->error_code = 0;
1669 if (env->mmu_model == POWERPC_MMU_SOFT_4xx
1670 || env->mmu_model == POWERPC_MMU_SOFT_4xx_Z) {
1671 env->spr[SPR_40x_DEAR] = address;
1672 if (rw) {
1673 env->spr[SPR_40x_ESR] |= 0x00800000;
1675 } else if ((env->mmu_model == POWERPC_MMU_BOOKE) ||
1676 (env->mmu_model == POWERPC_MMU_BOOKE206)) {
1677 env->spr[SPR_BOOKE_DEAR] = address;
1678 env->spr[SPR_BOOKE_ESR] = rw ? ESR_ST : 0;
1679 } else {
1680 env->spr[SPR_DAR] = address;
1681 if (rw == 1) {
1682 env->spr[SPR_DSISR] = 0x0A000000;
1683 } else {
1684 env->spr[SPR_DSISR] = 0x08000000;
1687 break;
1688 case -4:
1689 /* Direct store exception */
1690 switch (access_type) {
1691 case ACCESS_FLOAT:
1692 /* Floating point load/store */
1693 cs->exception_index = POWERPC_EXCP_ALIGN;
1694 env->error_code = POWERPC_EXCP_ALIGN_FP;
1695 env->spr[SPR_DAR] = address;
1696 break;
1697 case ACCESS_RES:
1698 /* lwarx, ldarx or stwcx. */
1699 cs->exception_index = POWERPC_EXCP_DSI;
1700 env->error_code = 0;
1701 env->spr[SPR_DAR] = address;
1702 if (rw == 1) {
1703 env->spr[SPR_DSISR] = 0x06000000;
1704 } else {
1705 env->spr[SPR_DSISR] = 0x04000000;
1707 break;
1708 case ACCESS_EXT:
1709 /* eciwx or ecowx */
1710 cs->exception_index = POWERPC_EXCP_DSI;
1711 env->error_code = 0;
1712 env->spr[SPR_DAR] = address;
1713 if (rw == 1) {
1714 env->spr[SPR_DSISR] = 0x06100000;
1715 } else {
1716 env->spr[SPR_DSISR] = 0x04100000;
1718 break;
1719 default:
1720 printf("DSI: invalid exception (%d)\n", ret);
1721 cs->exception_index = POWERPC_EXCP_PROGRAM;
1722 env->error_code =
1723 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
1724 env->spr[SPR_DAR] = address;
1725 break;
1727 break;
1730 #if 0
1731 printf("%s: set exception to %d %02x\n", __func__,
1732 cs->exception, env->error_code);
1733 #endif
1734 ret = 1;
1737 return ret;
1740 /*****************************************************************************/
1741 /* BATs management */
1742 #if !defined(FLUSH_ALL_TLBS)
1743 static inline void do_invalidate_BAT(CPUPPCState *env, target_ulong BATu,
1744 target_ulong mask)
1746 CPUState *cs = CPU(ppc_env_get_cpu(env));
1747 target_ulong base, end, page;
1749 base = BATu & ~0x0001FFFF;
1750 end = base + mask + 0x00020000;
1751 LOG_BATS("Flush BAT from " TARGET_FMT_lx " to " TARGET_FMT_lx " ("
1752 TARGET_FMT_lx ")\n", base, end, mask);
1753 for (page = base; page != end; page += TARGET_PAGE_SIZE) {
1754 tlb_flush_page(cs, page);
1756 LOG_BATS("Flush done\n");
1758 #endif
1760 static inline void dump_store_bat(CPUPPCState *env, char ID, int ul, int nr,
1761 target_ulong value)
1763 LOG_BATS("Set %cBAT%d%c to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", ID,
1764 nr, ul == 0 ? 'u' : 'l', value, env->nip);
1767 void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1769 target_ulong mask;
1771 dump_store_bat(env, 'I', 0, nr, value);
1772 if (env->IBAT[0][nr] != value) {
1773 mask = (value << 15) & 0x0FFE0000UL;
1774 #if !defined(FLUSH_ALL_TLBS)
1775 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1776 #endif
1777 /* When storing valid upper BAT, mask BEPI and BRPN
1778 * and invalidate all TLBs covered by this BAT
1780 mask = (value << 15) & 0x0FFE0000UL;
1781 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1782 (value & ~0x0001FFFFUL & ~mask);
1783 env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
1784 (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
1785 #if !defined(FLUSH_ALL_TLBS)
1786 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1787 #else
1788 tlb_flush(env, 1);
1789 #endif
1793 void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1795 dump_store_bat(env, 'I', 1, nr, value);
1796 env->IBAT[1][nr] = value;
1799 void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong value)
1801 target_ulong mask;
1803 dump_store_bat(env, 'D', 0, nr, value);
1804 if (env->DBAT[0][nr] != value) {
1805 /* When storing valid upper BAT, mask BEPI and BRPN
1806 * and invalidate all TLBs covered by this BAT
1808 mask = (value << 15) & 0x0FFE0000UL;
1809 #if !defined(FLUSH_ALL_TLBS)
1810 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1811 #endif
1812 mask = (value << 15) & 0x0FFE0000UL;
1813 env->DBAT[0][nr] = (value & 0x00001FFFUL) |
1814 (value & ~0x0001FFFFUL & ~mask);
1815 env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
1816 (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
1817 #if !defined(FLUSH_ALL_TLBS)
1818 do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1819 #else
1820 tlb_flush(env, 1);
1821 #endif
1825 void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong value)
1827 dump_store_bat(env, 'D', 1, nr, value);
1828 env->DBAT[1][nr] = value;
1831 void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value)
1833 target_ulong mask;
1834 #if defined(FLUSH_ALL_TLBS)
1835 int do_inval;
1836 #endif
1838 dump_store_bat(env, 'I', 0, nr, value);
1839 if (env->IBAT[0][nr] != value) {
1840 #if defined(FLUSH_ALL_TLBS)
1841 do_inval = 0;
1842 #endif
1843 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1844 if (env->IBAT[1][nr] & 0x40) {
1845 /* Invalidate BAT only if it is valid */
1846 #if !defined(FLUSH_ALL_TLBS)
1847 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1848 #else
1849 do_inval = 1;
1850 #endif
1852 /* When storing valid upper BAT, mask BEPI and BRPN
1853 * and invalidate all TLBs covered by this BAT
1855 env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1856 (value & ~0x0001FFFFUL & ~mask);
1857 env->DBAT[0][nr] = env->IBAT[0][nr];
1858 if (env->IBAT[1][nr] & 0x40) {
1859 #if !defined(FLUSH_ALL_TLBS)
1860 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1861 #else
1862 do_inval = 1;
1863 #endif
1865 #if defined(FLUSH_ALL_TLBS)
1866 if (do_inval) {
1867 tlb_flush(env, 1);
1869 #endif
1873 void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value)
1875 #if !defined(FLUSH_ALL_TLBS)
1876 target_ulong mask;
1877 #else
1878 int do_inval;
1879 #endif
1881 dump_store_bat(env, 'I', 1, nr, value);
1882 if (env->IBAT[1][nr] != value) {
1883 #if defined(FLUSH_ALL_TLBS)
1884 do_inval = 0;
1885 #endif
1886 if (env->IBAT[1][nr] & 0x40) {
1887 #if !defined(FLUSH_ALL_TLBS)
1888 mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1889 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1890 #else
1891 do_inval = 1;
1892 #endif
1894 if (value & 0x40) {
1895 #if !defined(FLUSH_ALL_TLBS)
1896 mask = (value << 17) & 0x0FFE0000UL;
1897 do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1898 #else
1899 do_inval = 1;
1900 #endif
1902 env->IBAT[1][nr] = value;
1903 env->DBAT[1][nr] = value;
1904 #if defined(FLUSH_ALL_TLBS)
1905 if (do_inval) {
1906 tlb_flush(env, 1);
1908 #endif
1912 /*****************************************************************************/
1913 /* TLB management */
1914 void ppc_tlb_invalidate_all(CPUPPCState *env)
1916 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1918 switch (env->mmu_model) {
1919 case POWERPC_MMU_SOFT_6xx:
1920 case POWERPC_MMU_SOFT_74xx:
1921 ppc6xx_tlb_invalidate_all(env);
1922 break;
1923 case POWERPC_MMU_SOFT_4xx:
1924 case POWERPC_MMU_SOFT_4xx_Z:
1925 ppc4xx_tlb_invalidate_all(env);
1926 break;
1927 case POWERPC_MMU_REAL:
1928 cpu_abort(CPU(cpu), "No TLB for PowerPC 4xx in real mode\n");
1929 break;
1930 case POWERPC_MMU_MPC8xx:
1931 /* XXX: TODO */
1932 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1933 break;
1934 case POWERPC_MMU_BOOKE:
1935 tlb_flush(CPU(cpu), 1);
1936 break;
1937 case POWERPC_MMU_BOOKE206:
1938 booke206_flush_tlb(env, -1, 0);
1939 break;
1940 case POWERPC_MMU_32B:
1941 case POWERPC_MMU_601:
1942 #if defined(TARGET_PPC64)
1943 case POWERPC_MMU_64B:
1944 case POWERPC_MMU_2_03:
1945 case POWERPC_MMU_2_06:
1946 case POWERPC_MMU_2_06a:
1947 case POWERPC_MMU_2_07:
1948 case POWERPC_MMU_2_07a:
1949 #endif /* defined(TARGET_PPC64) */
1950 tlb_flush(CPU(cpu), 1);
1951 break;
1952 default:
1953 /* XXX: TODO */
1954 cpu_abort(CPU(cpu), "Unknown MMU model\n");
1955 break;
1959 void ppc_tlb_invalidate_one(CPUPPCState *env, target_ulong addr)
1961 #if !defined(FLUSH_ALL_TLBS)
1962 PowerPCCPU *cpu = ppc_env_get_cpu(env);
1963 CPUState *cs;
1965 addr &= TARGET_PAGE_MASK;
1966 switch (env->mmu_model) {
1967 case POWERPC_MMU_SOFT_6xx:
1968 case POWERPC_MMU_SOFT_74xx:
1969 ppc6xx_tlb_invalidate_virt(env, addr, 0);
1970 if (env->id_tlbs == 1) {
1971 ppc6xx_tlb_invalidate_virt(env, addr, 1);
1973 break;
1974 case POWERPC_MMU_SOFT_4xx:
1975 case POWERPC_MMU_SOFT_4xx_Z:
1976 ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
1977 break;
1978 case POWERPC_MMU_REAL:
1979 cpu_abort(CPU(cpu), "No TLB for PowerPC 4xx in real mode\n");
1980 break;
1981 case POWERPC_MMU_MPC8xx:
1982 /* XXX: TODO */
1983 cpu_abort(CPU(cpu), "MPC8xx MMU model is not implemented\n");
1984 break;
1985 case POWERPC_MMU_BOOKE:
1986 /* XXX: TODO */
1987 cpu_abort(CPU(cpu), "BookE MMU model is not implemented\n");
1988 break;
1989 case POWERPC_MMU_BOOKE206:
1990 /* XXX: TODO */
1991 cpu_abort(CPU(cpu), "BookE 2.06 MMU model is not implemented\n");
1992 break;
1993 case POWERPC_MMU_32B:
1994 case POWERPC_MMU_601:
1995 /* tlbie invalidate TLBs for all segments */
1996 addr &= ~((target_ulong)-1ULL << 28);
1997 cs = CPU(cpu);
1998 /* XXX: this case should be optimized,
1999 * giving a mask to tlb_flush_page
2001 tlb_flush_page(cs, addr | (0x0 << 28));
2002 tlb_flush_page(cs, addr | (0x1 << 28));
2003 tlb_flush_page(cs, addr | (0x2 << 28));
2004 tlb_flush_page(cs, addr | (0x3 << 28));
2005 tlb_flush_page(cs, addr | (0x4 << 28));
2006 tlb_flush_page(cs, addr | (0x5 << 28));
2007 tlb_flush_page(cs, addr | (0x6 << 28));
2008 tlb_flush_page(cs, addr | (0x7 << 28));
2009 tlb_flush_page(cs, addr | (0x8 << 28));
2010 tlb_flush_page(cs, addr | (0x9 << 28));
2011 tlb_flush_page(cs, addr | (0xA << 28));
2012 tlb_flush_page(cs, addr | (0xB << 28));
2013 tlb_flush_page(cs, addr | (0xC << 28));
2014 tlb_flush_page(cs, addr | (0xD << 28));
2015 tlb_flush_page(cs, addr | (0xE << 28));
2016 tlb_flush_page(cs, addr | (0xF << 28));
2017 break;
2018 #if defined(TARGET_PPC64)
2019 case POWERPC_MMU_64B:
2020 case POWERPC_MMU_2_03:
2021 case POWERPC_MMU_2_06:
2022 case POWERPC_MMU_2_06a:
2023 case POWERPC_MMU_2_07:
2024 case POWERPC_MMU_2_07a:
2025 /* tlbie invalidate TLBs for all segments */
2026 /* XXX: given the fact that there are too many segments to invalidate,
2027 * and we still don't have a tlb_flush_mask(env, n, mask) in QEMU,
2028 * we just invalidate all TLBs
2030 tlb_flush(CPU(cpu), 1);
2031 break;
2032 #endif /* defined(TARGET_PPC64) */
2033 default:
2034 /* XXX: TODO */
2035 cpu_abort(CPU(cpu), "Unknown MMU model\n");
2036 break;
2038 #else
2039 ppc_tlb_invalidate_all(env);
2040 #endif
2043 /*****************************************************************************/
2044 /* Special registers manipulation */
2045 void ppc_store_sdr1(CPUPPCState *env, target_ulong value)
2047 qemu_log_mask(CPU_LOG_MMU, "%s: " TARGET_FMT_lx "\n", __func__, value);
2048 assert(!env->external_htab);
2049 env->spr[SPR_SDR1] = value;
2050 #if defined(TARGET_PPC64)
2051 if (env->mmu_model & POWERPC_MMU_64) {
2052 target_ulong htabsize = value & SDR_64_HTABSIZE;
2054 if (htabsize > 28) {
2055 fprintf(stderr, "Invalid HTABSIZE 0x" TARGET_FMT_lx
2056 " stored in SDR1\n", htabsize);
2057 htabsize = 28;
2059 env->htab_mask = (1ULL << (htabsize + 18 - 7)) - 1;
2060 env->htab_base = value & SDR_64_HTABORG;
2061 } else
2062 #endif /* defined(TARGET_PPC64) */
2064 /* FIXME: Should check for valid HTABMASK values */
2065 env->htab_mask = ((value & SDR_32_HTABMASK) << 16) | 0xFFFF;
2066 env->htab_base = value & SDR_32_HTABORG;
2070 /* Segment registers load and store */
2071 target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
2073 #if defined(TARGET_PPC64)
2074 if (env->mmu_model & POWERPC_MMU_64) {
2075 /* XXX */
2076 return 0;
2078 #endif
2079 return env->sr[sr_num];
2082 void helper_store_sr(CPUPPCState *env, target_ulong srnum, target_ulong value)
2084 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2086 qemu_log_mask(CPU_LOG_MMU,
2087 "%s: reg=%d " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__,
2088 (int)srnum, value, env->sr[srnum]);
2089 #if defined(TARGET_PPC64)
2090 if (env->mmu_model & POWERPC_MMU_64) {
2091 uint64_t rb = 0, rs = 0;
2093 /* ESID = srnum */
2094 rb |= ((uint32_t)srnum & 0xf) << 28;
2095 /* Set the valid bit */
2096 rb |= SLB_ESID_V;
2097 /* Index = ESID */
2098 rb |= (uint32_t)srnum;
2100 /* VSID = VSID */
2101 rs |= (value & 0xfffffff) << 12;
2102 /* flags = flags */
2103 rs |= ((value >> 27) & 0xf) << 8;
2105 ppc_store_slb(env, rb, rs);
2106 } else
2107 #endif
2108 if (env->sr[srnum] != value) {
2109 env->sr[srnum] = value;
2110 /* Invalidating 256MB of virtual memory in 4kB pages is way longer than
2111 flusing the whole TLB. */
2112 #if !defined(FLUSH_ALL_TLBS) && 0
2114 target_ulong page, end;
2115 /* Invalidate 256 MB of virtual memory */
2116 page = (16 << 20) * srnum;
2117 end = page + (16 << 20);
2118 for (; page != end; page += TARGET_PAGE_SIZE) {
2119 tlb_flush_page(CPU(cpu), page);
2122 #else
2123 tlb_flush(CPU(cpu), 1);
2124 #endif
2128 /* TLB management */
2129 void helper_tlbia(CPUPPCState *env)
2131 ppc_tlb_invalidate_all(env);
2134 void helper_tlbie(CPUPPCState *env, target_ulong addr)
2136 ppc_tlb_invalidate_one(env, addr);
2139 /* Software driven TLBs management */
2140 /* PowerPC 602/603 software TLB load instructions helpers */
2141 static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2143 target_ulong RPN, CMP, EPN;
2144 int way;
2146 RPN = env->spr[SPR_RPA];
2147 if (is_code) {
2148 CMP = env->spr[SPR_ICMP];
2149 EPN = env->spr[SPR_IMISS];
2150 } else {
2151 CMP = env->spr[SPR_DCMP];
2152 EPN = env->spr[SPR_DMISS];
2154 way = (env->spr[SPR_SRR1] >> 17) & 1;
2155 (void)EPN; /* avoid a compiler warning */
2156 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2157 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2158 RPN, way);
2159 /* Store this TLB */
2160 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2161 way, is_code, CMP, RPN);
2164 void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN)
2166 do_6xx_tlb(env, EPN, 0);
2169 void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
2171 do_6xx_tlb(env, EPN, 1);
2174 /* PowerPC 74xx software TLB load instructions helpers */
2175 static void do_74xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
2177 target_ulong RPN, CMP, EPN;
2178 int way;
2180 RPN = env->spr[SPR_PTELO];
2181 CMP = env->spr[SPR_PTEHI];
2182 EPN = env->spr[SPR_TLBMISS] & ~0x3;
2183 way = env->spr[SPR_TLBMISS] & 0x3;
2184 (void)EPN; /* avoid a compiler warning */
2185 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
2186 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
2187 RPN, way);
2188 /* Store this TLB */
2189 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
2190 way, is_code, CMP, RPN);
2193 void helper_74xx_tlbd(CPUPPCState *env, target_ulong EPN)
2195 do_74xx_tlb(env, EPN, 0);
2198 void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN)
2200 do_74xx_tlb(env, EPN, 1);
2203 /*****************************************************************************/
2204 /* PowerPC 601 specific instructions (POWER bridge) */
2206 target_ulong helper_rac(CPUPPCState *env, target_ulong addr)
2208 mmu_ctx_t ctx;
2209 int nb_BATs;
2210 target_ulong ret = 0;
2212 /* We don't have to generate many instances of this instruction,
2213 * as rac is supervisor only.
2215 /* XXX: FIX THIS: Pretend we have no BAT */
2216 nb_BATs = env->nb_BATs;
2217 env->nb_BATs = 0;
2218 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
2219 ret = ctx.raddr;
2221 env->nb_BATs = nb_BATs;
2222 return ret;
2225 static inline target_ulong booke_tlb_to_page_size(int size)
2227 return 1024 << (2 * size);
2230 static inline int booke_page_size_to_tlb(target_ulong page_size)
2232 int size;
2234 switch (page_size) {
2235 case 0x00000400UL:
2236 size = 0x0;
2237 break;
2238 case 0x00001000UL:
2239 size = 0x1;
2240 break;
2241 case 0x00004000UL:
2242 size = 0x2;
2243 break;
2244 case 0x00010000UL:
2245 size = 0x3;
2246 break;
2247 case 0x00040000UL:
2248 size = 0x4;
2249 break;
2250 case 0x00100000UL:
2251 size = 0x5;
2252 break;
2253 case 0x00400000UL:
2254 size = 0x6;
2255 break;
2256 case 0x01000000UL:
2257 size = 0x7;
2258 break;
2259 case 0x04000000UL:
2260 size = 0x8;
2261 break;
2262 case 0x10000000UL:
2263 size = 0x9;
2264 break;
2265 case 0x40000000UL:
2266 size = 0xA;
2267 break;
2268 #if defined(TARGET_PPC64)
2269 case 0x000100000000ULL:
2270 size = 0xB;
2271 break;
2272 case 0x000400000000ULL:
2273 size = 0xC;
2274 break;
2275 case 0x001000000000ULL:
2276 size = 0xD;
2277 break;
2278 case 0x004000000000ULL:
2279 size = 0xE;
2280 break;
2281 case 0x010000000000ULL:
2282 size = 0xF;
2283 break;
2284 #endif
2285 default:
2286 size = -1;
2287 break;
2290 return size;
2293 /* Helpers for 4xx TLB management */
2294 #define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
2296 #define PPC4XX_TLBHI_V 0x00000040
2297 #define PPC4XX_TLBHI_E 0x00000020
2298 #define PPC4XX_TLBHI_SIZE_MIN 0
2299 #define PPC4XX_TLBHI_SIZE_MAX 7
2300 #define PPC4XX_TLBHI_SIZE_DEFAULT 1
2301 #define PPC4XX_TLBHI_SIZE_SHIFT 7
2302 #define PPC4XX_TLBHI_SIZE_MASK 0x00000007
2304 #define PPC4XX_TLBLO_EX 0x00000200
2305 #define PPC4XX_TLBLO_WR 0x00000100
2306 #define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
2307 #define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
2309 target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
2311 ppcemb_tlb_t *tlb;
2312 target_ulong ret;
2313 int size;
2315 entry &= PPC4XX_TLB_ENTRY_MASK;
2316 tlb = &env->tlb.tlbe[entry];
2317 ret = tlb->EPN;
2318 if (tlb->prot & PAGE_VALID) {
2319 ret |= PPC4XX_TLBHI_V;
2321 size = booke_page_size_to_tlb(tlb->size);
2322 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
2323 size = PPC4XX_TLBHI_SIZE_DEFAULT;
2325 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
2326 env->spr[SPR_40x_PID] = tlb->PID;
2327 return ret;
2330 target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry)
2332 ppcemb_tlb_t *tlb;
2333 target_ulong ret;
2335 entry &= PPC4XX_TLB_ENTRY_MASK;
2336 tlb = &env->tlb.tlbe[entry];
2337 ret = tlb->RPN;
2338 if (tlb->prot & PAGE_EXEC) {
2339 ret |= PPC4XX_TLBLO_EX;
2341 if (tlb->prot & PAGE_WRITE) {
2342 ret |= PPC4XX_TLBLO_WR;
2344 return ret;
2347 void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
2348 target_ulong val)
2350 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2351 CPUState *cs = CPU(cpu);
2352 ppcemb_tlb_t *tlb;
2353 target_ulong page, end;
2355 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
2356 val);
2357 entry &= PPC4XX_TLB_ENTRY_MASK;
2358 tlb = &env->tlb.tlbe[entry];
2359 /* Invalidate previous TLB (if it's valid) */
2360 if (tlb->prot & PAGE_VALID) {
2361 end = tlb->EPN + tlb->size;
2362 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
2363 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2364 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2365 tlb_flush_page(cs, page);
2368 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
2369 & PPC4XX_TLBHI_SIZE_MASK);
2370 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2371 * If this ever occurs, one should use the ppcemb target instead
2372 * of the ppc or ppc64 one
2374 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
2375 cpu_abort(cs, "TLB size " TARGET_FMT_lu " < %u "
2376 "are not supported (%d)\n",
2377 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
2379 tlb->EPN = val & ~(tlb->size - 1);
2380 if (val & PPC4XX_TLBHI_V) {
2381 tlb->prot |= PAGE_VALID;
2382 if (val & PPC4XX_TLBHI_E) {
2383 /* XXX: TO BE FIXED */
2384 cpu_abort(cs,
2385 "Little-endian TLB entries are not supported by now\n");
2387 } else {
2388 tlb->prot &= ~PAGE_VALID;
2390 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
2391 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2392 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2393 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2394 tlb->prot & PAGE_READ ? 'r' : '-',
2395 tlb->prot & PAGE_WRITE ? 'w' : '-',
2396 tlb->prot & PAGE_EXEC ? 'x' : '-',
2397 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2398 /* Invalidate new TLB (if valid) */
2399 if (tlb->prot & PAGE_VALID) {
2400 end = tlb->EPN + tlb->size;
2401 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
2402 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
2403 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
2404 tlb_flush_page(cs, page);
2409 void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
2410 target_ulong val)
2412 ppcemb_tlb_t *tlb;
2414 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
2415 val);
2416 entry &= PPC4XX_TLB_ENTRY_MASK;
2417 tlb = &env->tlb.tlbe[entry];
2418 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
2419 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
2420 tlb->prot = PAGE_READ;
2421 if (val & PPC4XX_TLBLO_EX) {
2422 tlb->prot |= PAGE_EXEC;
2424 if (val & PPC4XX_TLBLO_WR) {
2425 tlb->prot |= PAGE_WRITE;
2427 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
2428 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
2429 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
2430 tlb->prot & PAGE_READ ? 'r' : '-',
2431 tlb->prot & PAGE_WRITE ? 'w' : '-',
2432 tlb->prot & PAGE_EXEC ? 'x' : '-',
2433 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2436 target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
2438 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
2441 /* PowerPC 440 TLB management */
2442 void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry,
2443 target_ulong value)
2445 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2446 ppcemb_tlb_t *tlb;
2447 target_ulong EPN, RPN, size;
2448 int do_flush_tlbs;
2450 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
2451 __func__, word, (int)entry, value);
2452 do_flush_tlbs = 0;
2453 entry &= 0x3F;
2454 tlb = &env->tlb.tlbe[entry];
2455 switch (word) {
2456 default:
2457 /* Just here to please gcc */
2458 case 0:
2459 EPN = value & 0xFFFFFC00;
2460 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
2461 do_flush_tlbs = 1;
2463 tlb->EPN = EPN;
2464 size = booke_tlb_to_page_size((value >> 4) & 0xF);
2465 if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
2466 do_flush_tlbs = 1;
2468 tlb->size = size;
2469 tlb->attr &= ~0x1;
2470 tlb->attr |= (value >> 8) & 1;
2471 if (value & 0x200) {
2472 tlb->prot |= PAGE_VALID;
2473 } else {
2474 if (tlb->prot & PAGE_VALID) {
2475 tlb->prot &= ~PAGE_VALID;
2476 do_flush_tlbs = 1;
2479 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
2480 if (do_flush_tlbs) {
2481 tlb_flush(CPU(cpu), 1);
2483 break;
2484 case 1:
2485 RPN = value & 0xFFFFFC0F;
2486 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
2487 tlb_flush(CPU(cpu), 1);
2489 tlb->RPN = RPN;
2490 break;
2491 case 2:
2492 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
2493 tlb->prot = tlb->prot & PAGE_VALID;
2494 if (value & 0x1) {
2495 tlb->prot |= PAGE_READ << 4;
2497 if (value & 0x2) {
2498 tlb->prot |= PAGE_WRITE << 4;
2500 if (value & 0x4) {
2501 tlb->prot |= PAGE_EXEC << 4;
2503 if (value & 0x8) {
2504 tlb->prot |= PAGE_READ;
2506 if (value & 0x10) {
2507 tlb->prot |= PAGE_WRITE;
2509 if (value & 0x20) {
2510 tlb->prot |= PAGE_EXEC;
2512 break;
2516 target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word,
2517 target_ulong entry)
2519 ppcemb_tlb_t *tlb;
2520 target_ulong ret;
2521 int size;
2523 entry &= 0x3F;
2524 tlb = &env->tlb.tlbe[entry];
2525 switch (word) {
2526 default:
2527 /* Just here to please gcc */
2528 case 0:
2529 ret = tlb->EPN;
2530 size = booke_page_size_to_tlb(tlb->size);
2531 if (size < 0 || size > 0xF) {
2532 size = 1;
2534 ret |= size << 4;
2535 if (tlb->attr & 0x1) {
2536 ret |= 0x100;
2538 if (tlb->prot & PAGE_VALID) {
2539 ret |= 0x200;
2541 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
2542 env->spr[SPR_440_MMUCR] |= tlb->PID;
2543 break;
2544 case 1:
2545 ret = tlb->RPN;
2546 break;
2547 case 2:
2548 ret = tlb->attr & ~0x1;
2549 if (tlb->prot & (PAGE_READ << 4)) {
2550 ret |= 0x1;
2552 if (tlb->prot & (PAGE_WRITE << 4)) {
2553 ret |= 0x2;
2555 if (tlb->prot & (PAGE_EXEC << 4)) {
2556 ret |= 0x4;
2558 if (tlb->prot & PAGE_READ) {
2559 ret |= 0x8;
2561 if (tlb->prot & PAGE_WRITE) {
2562 ret |= 0x10;
2564 if (tlb->prot & PAGE_EXEC) {
2565 ret |= 0x20;
2567 break;
2569 return ret;
2572 target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address)
2574 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
2577 /* PowerPC BookE 2.06 TLB management */
2579 static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
2581 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2582 uint32_t tlbncfg = 0;
2583 int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
2584 int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
2585 int tlb;
2587 tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2588 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
2590 if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
2591 cpu_abort(CPU(cpu), "we don't support HES yet\n");
2594 return booke206_get_tlbm(env, tlb, ea, esel);
2597 void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid)
2599 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2601 env->spr[pidn] = pid;
2602 /* changing PIDs mean we're in a different address space now */
2603 tlb_flush(CPU(cpu), 1);
2606 void helper_booke206_tlbwe(CPUPPCState *env)
2608 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2609 uint32_t tlbncfg, tlbn;
2610 ppcmas_tlb_t *tlb;
2611 uint32_t size_tlb, size_ps;
2612 target_ulong mask;
2615 switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
2616 case MAS0_WQ_ALWAYS:
2617 /* good to go, write that entry */
2618 break;
2619 case MAS0_WQ_COND:
2620 /* XXX check if reserved */
2621 if (0) {
2622 return;
2624 break;
2625 case MAS0_WQ_CLR_RSRV:
2626 /* XXX clear entry */
2627 return;
2628 default:
2629 /* no idea what to do */
2630 return;
2633 if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
2634 !msr_gs) {
2635 /* XXX we don't support direct LRAT setting yet */
2636 fprintf(stderr, "cpu: don't support LRAT setting yet\n");
2637 return;
2640 tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
2641 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
2643 tlb = booke206_cur_tlb(env);
2645 if (!tlb) {
2646 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2647 POWERPC_EXCP_INVAL |
2648 POWERPC_EXCP_INVAL_INVAL);
2651 /* check that we support the targeted size */
2652 size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
2653 size_ps = booke206_tlbnps(env, tlbn);
2654 if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
2655 !(size_ps & (1 << size_tlb))) {
2656 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
2657 POWERPC_EXCP_INVAL |
2658 POWERPC_EXCP_INVAL_INVAL);
2661 if (msr_gs) {
2662 cpu_abort(CPU(cpu), "missing HV implementation\n");
2664 tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
2665 env->spr[SPR_BOOKE_MAS3];
2666 tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
2668 /* MAV 1.0 only */
2669 if (!(tlbncfg & TLBnCFG_AVAIL)) {
2670 /* force !AVAIL TLB entries to correct page size */
2671 tlb->mas1 &= ~MAS1_TSIZE_MASK;
2672 /* XXX can be configured in MMUCSR0 */
2673 tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
2676 /* Make a mask from TLB size to discard invalid bits in EPN field */
2677 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2678 /* Add a mask for page attributes */
2679 mask |= MAS2_ACM | MAS2_VLE | MAS2_W | MAS2_I | MAS2_M | MAS2_G | MAS2_E;
2681 if (!msr_cm) {
2682 /* Executing a tlbwe instruction in 32-bit mode will set
2683 * bits 0:31 of the TLB EPN field to zero.
2685 mask &= 0xffffffff;
2688 tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & mask;
2690 if (!(tlbncfg & TLBnCFG_IPROT)) {
2691 /* no IPROT supported by TLB */
2692 tlb->mas1 &= ~MAS1_IPROT;
2695 if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
2696 tlb_flush_page(CPU(cpu), tlb->mas2 & MAS2_EPN_MASK);
2697 } else {
2698 tlb_flush(CPU(cpu), 1);
2702 static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
2704 int tlbn = booke206_tlbm_to_tlbn(env, tlb);
2705 int way = booke206_tlbm_to_way(env, tlb);
2707 env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
2708 env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
2709 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2711 env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
2712 env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
2713 env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
2714 env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
2717 void helper_booke206_tlbre(CPUPPCState *env)
2719 ppcmas_tlb_t *tlb = NULL;
2721 tlb = booke206_cur_tlb(env);
2722 if (!tlb) {
2723 env->spr[SPR_BOOKE_MAS1] = 0;
2724 } else {
2725 booke206_tlb_to_mas(env, tlb);
2729 void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address)
2731 ppcmas_tlb_t *tlb = NULL;
2732 int i, j;
2733 hwaddr raddr;
2734 uint32_t spid, sas;
2736 spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
2737 sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
2739 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2740 int ways = booke206_tlb_ways(env, i);
2742 for (j = 0; j < ways; j++) {
2743 tlb = booke206_get_tlbm(env, i, address, j);
2745 if (!tlb) {
2746 continue;
2749 if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
2750 continue;
2753 if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
2754 continue;
2757 booke206_tlb_to_mas(env, tlb);
2758 return;
2762 /* no entry found, fill with defaults */
2763 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
2764 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
2765 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
2766 env->spr[SPR_BOOKE_MAS3] = 0;
2767 env->spr[SPR_BOOKE_MAS7] = 0;
2769 if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
2770 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
2773 env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
2774 << MAS1_TID_SHIFT;
2776 /* next victim logic */
2777 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
2778 env->last_way++;
2779 env->last_way &= booke206_tlb_ways(env, 0) - 1;
2780 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
2783 static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
2784 uint32_t ea)
2786 int i;
2787 int ways = booke206_tlb_ways(env, tlbn);
2788 target_ulong mask;
2790 for (i = 0; i < ways; i++) {
2791 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
2792 if (!tlb) {
2793 continue;
2795 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
2796 if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
2797 !(tlb->mas1 & MAS1_IPROT)) {
2798 tlb->mas1 &= ~MAS1_VALID;
2803 void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address)
2805 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2807 if (address & 0x4) {
2808 /* flush all entries */
2809 if (address & 0x8) {
2810 /* flush all of TLB1 */
2811 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
2812 } else {
2813 /* flush all of TLB0 */
2814 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
2816 return;
2819 if (address & 0x8) {
2820 /* flush TLB1 entries */
2821 booke206_invalidate_ea_tlb(env, 1, address);
2822 tlb_flush(CPU(cpu), 1);
2823 } else {
2824 /* flush TLB0 entries */
2825 booke206_invalidate_ea_tlb(env, 0, address);
2826 tlb_flush_page(CPU(cpu), address & MAS2_EPN_MASK);
2830 void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address)
2832 /* XXX missing LPID handling */
2833 booke206_flush_tlb(env, -1, 1);
2836 void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address)
2838 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2839 int i, j;
2840 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2841 ppcmas_tlb_t *tlb = env->tlb.tlbm;
2842 int tlb_size;
2844 /* XXX missing LPID handling */
2845 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2846 tlb_size = booke206_tlb_size(env, i);
2847 for (j = 0; j < tlb_size; j++) {
2848 if (!(tlb[j].mas1 & MAS1_IPROT) &&
2849 ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
2850 tlb[j].mas1 &= ~MAS1_VALID;
2853 tlb += booke206_tlb_size(env, i);
2855 tlb_flush(CPU(cpu), 1);
2858 void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
2860 PowerPCCPU *cpu = ppc_env_get_cpu(env);
2861 int i, j;
2862 ppcmas_tlb_t *tlb;
2863 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
2864 int pid = tid >> MAS6_SPID_SHIFT;
2865 int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
2866 int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
2867 /* XXX check for unsupported isize and raise an invalid opcode then */
2868 int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
2869 /* XXX implement MAV2 handling */
2870 bool mav2 = false;
2872 /* XXX missing LPID handling */
2873 /* flush by pid and ea */
2874 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
2875 int ways = booke206_tlb_ways(env, i);
2877 for (j = 0; j < ways; j++) {
2878 tlb = booke206_get_tlbm(env, i, address, j);
2879 if (!tlb) {
2880 continue;
2882 if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
2883 (tlb->mas1 & MAS1_IPROT) ||
2884 ((tlb->mas1 & MAS1_IND) != ind) ||
2885 ((tlb->mas8 & MAS8_TGS) != sgs)) {
2886 continue;
2888 if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
2889 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
2890 continue;
2892 /* XXX e500mc doesn't match SAS, but other cores might */
2893 tlb->mas1 &= ~MAS1_VALID;
2896 tlb_flush(CPU(cpu), 1);
2899 void helper_booke206_tlbflush(CPUPPCState *env, target_ulong type)
2901 int flags = 0;
2903 if (type & 2) {
2904 flags |= BOOKE206_FLUSH_TLB1;
2907 if (type & 4) {
2908 flags |= BOOKE206_FLUSH_TLB0;
2911 booke206_flush_tlb(env, flags, 1);
2915 /*****************************************************************************/
2917 /* try to fill the TLB and return an exception if error. If retaddr is
2918 NULL, it means that the function was called in C code (i.e. not
2919 from generated code or from helper.c) */
2920 /* XXX: fix it to restore all registers */
2921 void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
2922 uintptr_t retaddr)
2924 PowerPCCPU *cpu = POWERPC_CPU(cs);
2925 PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
2926 CPUPPCState *env = &cpu->env;
2927 int ret;
2929 if (pcc->handle_mmu_fault) {
2930 ret = pcc->handle_mmu_fault(cpu, addr, is_write, mmu_idx);
2931 } else {
2932 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx);
2934 if (unlikely(ret != 0)) {
2935 if (likely(retaddr)) {
2936 /* now we have a real cpu fault */
2937 cpu_restore_state(cs, retaddr);
2939 helper_raise_exception_err(env, cs->exception_index, env->error_code);